Spam-Schutz für Gästebuch

Status
Nicht offen für weitere Antworten.

psifactory

Erfahrenes Mitglied
Hi. Habe ein Problem. Auf meiner privaten Seite habe ich ein Gästebuch in PHP installiert. Seit kurzem gibt es aber ein Problem mit Spam. Ich habe bereits auf anderen Seiten etwas gesehen dass es da einen Code in einer Grafik gibt der sowas verhindert. Wie kann ich sowas bei mir einbauen? Hier der Code meines Gb´s

guestbook.inc

PHP:
<?php

/**
 * Copyright (C) 2001 Oliver Hitz <oliver@net-track.ch>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 * MA  02111-1307, USA.
 */

/**
 * Customizable guestbook class
 */

class Guestbook {

  /** Configurable options */

  var $files = array( "config"   => "config.gb",
		      "book"     => "book.gb",
		      "header"   => "header.gb",
		      "footer"   => "footer.gb",
		      "body"     => "body.gb",
		      "thanks"   => "thanks.gb",
		      "form"     => "form.gb",
		      "next"     => "next.gb",
		      "previous" => "previous.gb",
		      "aheader"  => "aheader.gb",
		      "afooter"  => "afooter.gb",
		      "abody"    => "abody.gb" );
  var $pagelength  = 20;
  var $dateformat  = "H:i d.m.Y";
  var $checkemail  = array();
  var $error       = array( "email-check" => "Invalid e-mail address",
			   "required" => "Required field missing" );
  var $mailto      = "";
  var $mailsubject = "Guestbook Entry";

  /** For internal use */

  var $path;
  var $entries     = array();
  var $fields      = array();
  var $required    = array();

  /**
   * Constructor
   *
   * @param $path The path where the guestbook files are stored
   */

  function Guestbook($path, $config = "config.gb") {
    $this->path  = $path;
    $this->files["config"] = $config;
  }

  /**
   * Entry point for users of the guestbook, allows to view entries
   * and add new entries
   */

  function user() {
    global $HTTP_GET_VARS;
    global $HTTP_POST_VARS;

    if (isset($HTTP_GET_VARS["new"]) || isset($HTTP_POST_VARS["save"])) {
      $this->add();
    } else {
      $this->view();
    }
  }

  /**
   * Entry point for administrators of the guestbook, entries can be edited
   * and deleted.
   */

  function admin() {
    global $HTTP_GET_VARS;
    global $HTTP_POST_VARS;

    if ($HTTP_GET_VARS["delete"]) {
      $this->deleteEntry($HTTP_GET_VARS["id"]);
      $this->view("aheader", "afooter", "abody");
    } else if (isset($HTTP_GET_VARS["edit"]) || isset($HTTP_POST_VARS["save"])) {
      $this->editEntry();
    } else {
      $this->view("aheader", "afooter", "abody");
    }
  }

  function editEntry() {
    global $HTTP_GET_VARS;
    global $HTTP_POST_VARS;

    $this->loadConfiguration();
    $this->loadBook();

    if ($HTTP_POST_VARS["save"]) {
      $id = intval($HTTP_POST_VARS["id"]);
      $entry = $this->deserialize($this->entries[$id]);
      for ($i = 0; $i < count($this->fields); $i++) {
	if (isset($HTTP_POST_VARS[$this->fields[$i]])) {
	  $entry[$this->fields[$i]] = nl2br(htmlentities(trim($HTTP_POST_VARS[$this->fields[$i]])));
	}
      }
      $this->entries[$id] = $this->serialize($entry);
      $this->saveBook();
      $this->view("aheader", "afooter", "abody");
    } else {
      $id = $HTTP_GET_VARS["id"];
      $entry = $this->deserialize($this->entries[$id]);
      $entry["id"] = $id;
      $entry["error"] = "";
      $entry = $this->stripBR($entry);
      print $this->myfile("form", $entry);
    }
  }

  function deleteEntry($i) {
    $this->loadConfiguration();
    $this->loadBook();
    unset($this->entries[$i]);
    $this->saveBook();
  }

  function setVars($text, $replace) {
    reset ($replace);
    while (list($key, $val) = each($replace)) {
      $text = eregi_replace("\{".$key."\}", $val, $text);
    }
    return $text;
  }

  function stripBR($entry) {
    reset ($entry);
    while (list($key, $val) = each($entry)) {
      $entry[$key] = ereg_replace ("(<br />|<br/>)","", $val);
    }
    return $entry;
  }

  function myfile($file, $replace = array()) {
    global $HTTP_SERVER_VARS;
    $content = join(" ", file($this->fpath($file)));
    $content = eregi_replace("\{script\}", $HTTP_SERVER_VARS["SCRIPT_NAME"], $content);
    $content = $this->setVars($content, $replace);
    return $content;
  }

  function fpath($file) {
    return $this->path."/".$this->files[$file];
  }

  function loadConfiguration() {
    if (!file_exists($this->fpath("config"))) {
      $this->error("Unable to find guestbook configuration.");
    }
    if (!$fd = fopen($this->fpath("config"), "r")) {
      $this->error("Unable to load guestbook configuration.");
    }
    while (!feof($fd)) {
      $line = fgets($fd, 8192);
      if (ereg("^#", $line)) {
	// comment
      } else if (ereg("^fields:\ *", $line)) {
	$this->fields = explode(",", trim(ereg_replace("fields:\ *", "", $line)));
      } else if (ereg("^check:", $line)) {
	$check = explode(",", ereg_replace("check:\ *", "", trim($line)));
	$field = $check[0];
	for ($i = 1; $i < count($check); $i++) {
	  if (ereg("required", $check[$i])) {
	    $this->required[] = $field;
	  } else if (ereg("email-check", $check[$i])) {
	    $this->checkemail[] = $field;
	  }
	}
      } else if (ereg("^error-", $line)) {
	if (ereg("^error-([^:]*): (.*)$", $line, $match)) {
	  $this->error[$match[1]] = $match[2];
	}
      } else if (ereg("^dateformat:\ *", $line)) {
	$this->dateformat = trim(ereg_replace("dateformat:\ *", "", $line));
      } else if (ereg("^pagelength:\ *", $line)) {
	$this->pagelength = intval(trim(ereg_replace("pagelength:\ *", "", $line)));
      } else if (ereg("^mailto:\ *", $line)) {
	$this->mailto = trim(ereg_replace("mailto:\ *", "", $line));
      } else if (ereg("^mailsubject:\ *", $line)) {
	$this->mailsubject = trim(ereg_replace("mailsubject:\ *", "", $line));
      } else {
	// unknown configuration data
      }
    }
    fclose($fd);
  }

  function loadBook() {
    $this->entries = array();
    if (file_exists($this->fpath("book"))) {
      if (!$fd = fopen($this->fpath("book"), "r")) {
	$this->error("Unable to load guestbook data file.");
      }
      if (!flock($fd, LOCK_SH)) {
	$this->error("Unable to lock guestbook data file.");
      }
      while (!feof($fd)) {
	$line = fgets($fd, 8192);
	if (trim($line) != "") $this->entries[] = $line;
      }
      flock($fd, LOCK_UN);
      fclose($fd);
    }
  }

  function saveBook() {
    if (!$fd = fopen($this->fpath("book"), "w")) {
      $this->error("Unable to write guestbook data file.");
    }
    if (!flock($fd, LOCK_EX)) {
      $this->error("Unable to lock guestbook data file.");
    }
    reset($this->entries);
    while(list($key, $val) = each($this->entries)) {
      fputs($fd, $val);
    }
    flock($fd, LOCK_UN);
    fclose($fd);
  }

  /**
   * Serializes the given entry to a string.
   *
   * @param $entry The entry to serialize.
   * @return The serialized entry.
   */

  function serialize($entry) {
    $s = "";
    reset ($entry);
    while (list($key, $val) = each($entry)) {
      $s .= rawurlencode($key)."=".rawurlencode($val)." ";
    }
    return "$s\n";
  }

  /**
   * Deserializes an entry from a string.
   *
   * @param $s The serialized entry.
   * @return The deserialized entry.
   */

  function deserialize($s) {
    $entry = array();
    $values = explode(" ", $s);
    for ($i = 0; $i < count($values); $i++) {
      list($key, $val) = explode("=", $values[$i]);
      $entry[rawurldecode($key)] = rawurldecode($val);
    }
    return $entry;
  }

  /**
   * Adds an entry to the guestbook.
   */

  function add() {
    global $HTTP_SERVER_VARS;
    global $HTTP_POST_VARS;

    $this->loadConfiguration();
    $this->loadBook();

    $entry   = array();
    $ok      = true;
    $error   = "";
    $message = "";

    if ($HTTP_POST_VARS["save"]) {
      $entry["date"] = date($this->dateformat);
      $entry["ip"] = $HTTP_SERVER_VARS["REMOTE_ADDR"];

      for ($i = 0; $i < count($this->fields); $i++) {
	if (isset($HTTP_POST_VARS[$this->fields[$i]])) {
	  $entry[$this->fields[$i]] = nl2br(htmlentities(trim($HTTP_POST_VARS[$this->fields[$i]])));
	  $message .= $this->fields[$i].":\n".
	    "    ".str_replace("\n", "\n    ", wordwrap($HTTP_POST_VARS[$this->fields[$i]], 70, "\n")).
	    "\n";
	}
      }
      for ($i = 0; $i < count($this->required); $i++) {
	if (empty($entry[$this->required[$i]])) {
	  $ok = false;
	  $error = $this->error["required"];
	}
      }
      for ($i = 0; $i < count($this->checkemail); $i++) {
	$email = trim($entry[$this->checkemail[$i]]);
	if (!eregi("^[0-9a-z_.-]+@([0-9a-z-]+\\.)+[0-9a-z-]+$", $email)) {
	  $ok = false;
	  $error = $this->error["email-check"];
	}
      }
      if ($ok) {
	if ($this->mailto != "") {
	  mail($this->mailto, $this->mailsubject, $message, "From: guestbook@".$HTTP_SERVER_VARS["SERVER_NAME"]);
	}
	$serialized = $this->serialize($entry);
	if (!$fd = fopen($this->fpath("book"), "a")) {
	  $this->error("Unable to create guestbook data file.");
	}
	if (!flock($fd, LOCK_EX)) {
	  $this->error("Unable to lock guestbook data file.");
	}
	fseek($fd, 0, SEEK_END);
	fwrite($fd, $serialized."\n");
	flock($fd, LOCK_UN);
	fclose($fd);
	print $this->myfile("thanks");
	return;
      }
    }
    $entry["error"] = $error;
    for ($i = 0; $i < count($this->fields); $i++) {
      if (empty($entry[$this->fields[$i]])) {
	$entry[$this->fields[$i]] = "";
      }
    }
    print $this->myfile("form", $entry);
  }

  function numEntries() {
    return count($this->entries);
  }

  function getEntry($i) {
    return $this->entries[$this->numEntries()-1-$i];
  }

  function getId($i) {
    return $this->numEntries()-1-$i;
  }

  function view($h = "header", $f = "footer", $b = "body") {
    global $HTTP_GET_VARS;

    $this->loadConfiguration();
    $this->loadBook();

    if (isset($HTTP_GET_VARS["start"]) && is_numeric($HTTP_GET_VARS["start"])) {
      $start = $HTTP_GET_VARS["start"];
    } else {
      $start = 0;
    }

    $vars = array( "previous" => "",
		   "next"     => "" );

    if ($start > 0) {
      $s2 = ($start-$this->pagelength >= 0) ? $start-$this->pagelength : 0;
      $vars["previous"] = $this->myfile("previous", array( "get" => "start=$s2" ));
    }
    if ($start+$this->pagelength < $this->numEntries()) {
      $s2 = $start+$this->pagelength;
      $vars["next"] = $this->myfile("next", array( "get" => "start=$s2" ));
    }

    print $this->myfile($h, $vars);
    $body = $this->myfile($b);
    for ($i = $start; $i < $start+$this->pagelength && $i < $this->numEntries(); $i++) {
      $entry = $this->deserialize($this->getEntry($i));
      $entry["id"] = "".$this->getId($i);
      print $this->setVars($body, $entry);
    }
    print $this->myfile($f, $vars);
  }

  function error($message) {
    print "<br>".nl2br($message)."<br>";
    exit;
  }
}

?>
 
Dieser „Code in einer Grafik“ wird allgemein als Captcha bezeichnet. Um soetwas in das bestehende Skript einzubinden, benötigst du zuerst ein Captcha-Skript.
Es gibt jedoch auch einfachere Möglichkeiten, sich vor unerwünschten Einträgen im Gästebuch zu schützen. Schaue dir einfach mal die Themen in der unten aufgeführten Liste der ähnlichen Themen an.
 
Also ich habe mich trotzdem für ein captcha entschieden.. Mein Problem besteht allerdings jetzt darin dass ich nicht weis wo an welcher stelle ich das einbauen soll. Bin leider auf dem Gebiet PHP nicht gerade gut unterwegs.. Fang gerade erst an C++ in der Schule zu lernen.
 
Wenn dir PHP eher fremd als vertraut ist, solltest du anfangs vielleicht eine etwas einfachere Lösung probieren.
Was ich noch vergessen hab: Um welche Art von Spam handelt es sich? Ist es automatischer Spam, der von Spam-Bots eingetragen wurde, oder ist es eher individueller Spam, der manuell eingetragen wurde?
 
Ist definitv automatisierter Spam. Hatte das selbe Problem schon mal auf einem Joomla CMS und die Einträge die da kamen sind die selben wie jetzt hier in meinem privaten GB. Ich mein ich kann mich in Php relativ gut einlesen. Aber um selbst zu schreiben fehlen mir dennoch die Kenntnisse.
 
Dann empfehle ich dir, ein Script zu suchen was deinen Ansprüchen genügt und nicht ein anderes anzupassen... Oder vielleicht im nicht-kommerziellen Job Forum zu fragen, ob es jemand für dich macht.
 
Eine sehr einfache Möglichkeit wäre, im Skript des Formulars einen zufälligen Schlüssel als Sitzungsvariable zu speichern und diesen Wert bei der Verarbeitung der Formulardaten zu prüfen und anschließend wieder zu löschen. Wird das Formularskript also nicht aufgerufen oder die Sitzungs-ID nicht mit übermittelt, wird der Eintrag nicht gemacht.
 
Puh... Da muss ich glaube ich passen. Versteh zwar was du damit meinst. Würde sagen ich fang erst mal damit an zu fragen wie man einen zufälligen Schlüssel im Formularskript erstelle?

Also ich stelle mir das ganze so vor:

Nachdem der zufällige Schlüssel erstellt wurde wird er als Sitzungs-ID an den verarbeitenten Teil des Gästebuches übergeben. Dieser muss nun als erste Bedingung überprüfen ob die Sitzungs-ID korrekt übermittelt wurde. Richtig? Das würde ich dann mit einer "if" realisieren, die als wahr Zweig den kompletten Inhalt der Datei hätte und als else Zweig eine Fehlermeldung.
 
Hier ein kleines Beispiel:
PHP:
<?php

	// Formular-Skript

	session_start();
	$uniqid = md5(uniqid(rand()));
	$_SESSION[$uniqid] = md5(rand());

	echo '<input type="hidden" name="uniqid" value="'.$uniqid.'">';
	echo '<input type="hidden" name="randid" value="'.$_SESSION[$uniqid].'">';

?>
PHP:
<?php

	// verarbeitendes Skript

	session_start();
	if( isset($_SESSION[$_POST['uniqid']]) && $_POST['randid']==$_SESSION[$_POST['uniqid']] ) {
		unset($_SESSION[$_POST['uniqid']]);
		// Authentifizeirung war erfolgreich
	}

?>
Wenn der Spam-Bot jedoch jedes Mal das Formular nach Formularelementen durchforstet, wird auch diese Variante nicht viel helfen, da der zufällige Schlüssel dort ebenfalls angegeben ist.
 
Status
Nicht offen für weitere Antworten.
Zurück