Suchen
Inside Wiki
Nützliche Links
phpforum.de Tipp
 
phpforum.de bei Facebook
 
phpforum.de bei Twitter
 

Zurück   PHP Forum: phpforum.de > phpforum.de Wiki > phpforum.de Wiki

PHP Wiki Dieses Wiki sammelt Lösungen, zu Problemen, welche immer wieder im Forum auftauchen.

 
 
Artikel-Optionen Ansicht
  #1  

Standard Affenformular

 

Tutorials - Inhalte

 
Ein Formular, welches die vom Benutzer ausgefüllten Daten zur Überprüfung an sich selber schickt.

Affenformular


Affenformular? Was ist das?


Bei der Entwicklung einer Webapplikation kommt es häufig vor, dass die erstellte Software auf Benutzereingaben reagieren können soll bzw. muss. Es gibt viele Beispiele, die man an dieser Stelle nennen könnte, wie z.B. die Bestellung eines Artikels in einem Onlineshop, die Registrierung in einem Forum, das Schreiben einer Newsmeldungen auf einer Nachrichtenseite, und, und, und...

Technisch gesehen stellt dieser Vorgang eigentlich kein allzu großes Problem dar, doch es gibt einige Sachen, die man dabei beachten muss. Der Benutzer füllt ein (in HTML geschriebenes) Formular mit seinen gewünschten Daten aus, schickt dieses ab und wartet auf ein Ergebnis seiner Eingabe. Doch hier kommt es sehr häufig zu einem Problem: Der größte Fehler einer Anwendung sitzt meistens vor dem Computer, was bedeutet, dass alles, worauf ein Mensch Einfluss hat, von Natur aus fehleranfällig ist.

Wie sehen solche Fehler aus? Auch hier gibt es viele Beispiele: Der Benutzer hat vergessen, die gewünschte Zahlungsmethode seiner Bestellung anzugeben, der angegebene Benutzername ist bereits vergeben oder es wurde vergessen, einen passenden Newstitel anzugeben. Da dieses aber notwendige Angaben für einen sinnvollen Eintrag sind, müssen wir dafür sorgen, dass die Benutzereingaben korrekt und vollständig sind. Und genau hier kommt unser Affenformular ins Spiel:
Sobald der Benutzer seine gewünschten Daten in das Formular eingetippt hat, drückt er auf einen Button, um den Inhalt an die Software zu übermitteln. Hierbei sorgt der Entwickler nun dafür, dass das Formular diese Eingabe "an sich selber" schickt, worauf eine Überprüfung der Benutzeringabe durchgeführt wird. Hat der Benutzer etwas vergessen, oder z.B. bei der Telefonnummer seinen Vorname eingegeben, so soll er dieses doch bitte korrigieren und das Formular erneut absenden.

Der große Vorteil, dass das Formular die Eingabe an sich selber schickt ist nun, dass wir die vom Benutzer zuvor getätigte Benutzereingabe weiterhin zur Verfügung haben. Man kann also zunächst alle Daten auf Korrektheit und Vollständigkeit überprüfen und im Falle eines Fehlers auf diesen aufmerksam machen, ohne dass der Benutzer alle Daten neu ausfüllen muss, da wir die Formularfelder mit den bereits korrekt ausgefüllten Eingaben vorausfüllen können.

Um die Wortherkunft "Affenformular" nun zu erklären, zitiere ich nun einmal Wikipedia:
Zitat:
Die Bezeichnung Affenformular verweist darauf, dass selbst der millionenfache Aufruf des Formulars durch eine Million Affen nichts bewirken wird.
Dies besagt also nichts anderes, als dass man das Formular so oft absenden kann wie man möchte. Solange keine sinnvolle Eingabe getätigt wurde, werden die Daten erst garnicht weiterverarbeitet.

Ein Beispiel


Hier zeige ich nun ein Beispiel, wie man ein solches Affenformular prinzipiell aufbauen kann.
PHP Quellcode:
<?php
/*
 * Dafür sorgen, dass unabhängig von den aktuellen PHP-Einstellungen
 * alle auftretenden Fehler angezeigt werden
 */

error_reporting(E_ALL | E_STRICT);
ini_set('display_errors', 'On');


$err = '';    // Variable für die Fehlerausgabe
$success = '';  // Variable für die Ausgabe der Erfolgsmeldung

/*
 * Zunächst die Überprüfung der Benutzereingabe durchführen, d.h.
 * folgendes wird nur überprüft, falls der Button gedrückt und das
 * Formular somit abgesendet wurde
 */

if (isset($_POST['senden'])) {
 
    $eingabe = array(); // zum abspeichern überprüfter Benutzereingaben
    $error   = array(); // zum merken von fehlerhaften Benutzereingaben
   
    /*
     * Überprüfung eines Textfeldes: Wurde auch ein Name eingegeben?
    */

    if (isset($_POST['vorname']) && strlen(trim($_POST['vorname'])) && !is_array($_POST['vorname'])) {
        $eingabe['vorname'] = htmlspecialchars(trim($_POST['vorname']));
    } else {
        $error['vorname'] = 'Vorname';
    }
   
    /*
     * Überprüfung eines Textfeldes: Wurde auch eine Telefonnummer eingegeben?
     * Wir nehmen an, dass eine Telefonnummer nur aus Zahlen und min. 4 Ziffern besteht
    */

     if (isset($_POST['telefon']) && strlen(trim($_POST['telefon'])) > 4 && is_numeric($_POST['telefon'])) {
         $eingabe['telefon'] = trim($_POST['telefon']);
    } else {
         $error['telefon'] = 'Telefon';
    }
   
   
    /*
     * Überprüfung von Checkboxen
     * Kein Fehler generieren, wenn nichts ausgewählt wurde, da keine Pflichteingabe
    */

     if (isset($_POST['sprachen']) && is_array($_POST['sprachen']) && !empty($_POST['sprachen'])) {
     
         $erlaubte_sprachen = array('deutsch', 'englisch', 'spanisch', 'binaer'); // Erlaubte Eingaben
         
         $eingabe['sprachen'] = array();
         
         // Wurden auch nur erlaubte Sprachen angeklickt und das Formular somit nicht manipuliert?
         foreach ($_POST['sprachen'] AS $sprache) {
             if (in_array($sprache, $erlaubte_sprachen)) {
                 $eingabe['sprachen'][] = htmlspecialchars($sprache);
             } else {
                 $error['sprachen'] = 'Sprachen';
             }
         }        
    }
     
     /*
      * Bis hier sind nun alle Überprüfungen durchgeführt worden.
      * Wenn bis hier keine Fehler aufgetreten sind, dann waren die Eingaben korrekt und
      * können somit weiterverarbeitet werden. Wenn allerdings ein Fehler aufgetreten ist,
      * so wird der folgende Code nicht ausgeführt. Stattdessen wird ein Hinweis auf eine
      * fehlerhafte Eingabe ausgegeben und das Formular erneut angezeigt, da wir den
      * weiteren Ablauf des Scriptes nicht unterbrechen
     */

      if (empty($error)) {
         
          /*
           * Hier z.B. alle Daten in der Datenbank abspeichern und darauf hin
           * den Benutzer an eine andere Stelle weiterleiten.
           */

          $success =  'Alles Eingaben waren okay!';
         
          // Scriptablauf abbrechen, da alles wichtige erledigt ist
          exit();
      } else {

          /*
           * Das Fehler-Array wird in einen String umgewandelt
           * und dieser String für die Ausgabe gespeichert
          */

        $errors = implode(', ',$error);
   
          $err = 'Es sind Fehler aufgetreten: '.$errors;
      }
} // END if (isset($_POST['senden']))
?> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de" lang="de">
<head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
  <meta http-equiv="expires" content="0"/>
  <title>Affenformular</title>
</head>
<body>
<?php
// eveentuelle Fehler ausgeben
if(!empty($err)) echo $err;
// evtl. Erfolgsmeldung ausgeben
if(!empty($success)) echo $success;
?> 
  <form action="<?php echo htmlentities($_SERVER['PHP_SELF']); ?>" method="post">
    Vorname: <input type="text" name="vorname"<?php if(isset($eingabe['vorname'])) echo ' value="'.$eingabe['vorname'].'"'; ?> /><br />
    Telefonnummer: <input type="text" name="telefon"<?php if(isset($eingabe['telefon'])) echo ' value="'.$eingabe['telefon'].'"'; ?> /><br />
    Sprachen: Deutsch <input type="checkbox" name="sprachen[]" value="deutsch"<?php if(isset($eingabe['sprachen']) && in_array('deutsch', $eingabe['sprachen'])) echo ' checked="checked"'; ?> />
              Englisch <input type="checkbox" name="sprachen[]" value="englisch"<?php if(isset($eingabe['sprachen']) && in_array('englisch', $eingabe['sprachen'])) echo ' checked="checked"'; ?> />
              Spanisch <input type="checkbox" name="sprachen[]" value="spanisch"<?php if(isset($eingabe['sprachen']) && in_array('spanisch', $eingabe['sprachen'])) echo ' checked="checked"'; ?> />
              Binär <input type="checkbox" name="sprachen[]" value="binaer"<?php if(isset($eingabe['sprachen']) && in_array('binaer', $eingabe['sprachen'])) echo ' checked="checked"'; ?> />
    <input type="submit" name="senden" value="Und los!" />
  </form>
</body>
</html>


Natürlich könnte man einige Sachen noch zusätzlich in Funktionen Kapseln, wie z.B. die Überprüfung auf gültige Eingaben. Zudem sollte man generell dafür sorgen, dass das Markup sauber vom Scriptcode getrennt ist. Aus didaktischen Gründen, und um ein in sich geschlossenes Script zu erhalten, habe ich in diesem Beispiel allerdings alles in eine Datei verfasst.

In wie weit man die Benutzereingaben auf Korrektheit überprüft, muss man natürlich von Fall zu Fall abschätzen. Generell darf man Daten, die man von vornherein nicht kennt und auch nicht abschätzen kann, nie(!) vertrauen! Die Dummheit des Benutzers ist nämlich nicht der einzige Faktor, den man beachten muss. Es gibt auch Leute, die einem nicht das Beste wünschen oder welche, die einfach nur auf der Suche nach nicht entdeckten Sicherheitslücken sind. Deshalb sollte man seine Daten immer auf "Bösen Code" überprüfen, vor allem, wenn man mit Datenbanken arbeitet.

In diesem Beispiel sieht man nun, dass der Benutzer für den Vorname auf jeden Fall eine Folge an Zeichen eingeben muss, wobei ich nun von einer Mindestlänge von einem Zeichen ausgehe. Bei der Telefonnummer müssen mindestens 4 Zahlen eingegeben werden, um keinen Fehler zu kassieren.

Zum Testen kann man das Formular einfach mal ohne eine Benutzereingabe absenden. Es wird auffallen, dass direkt eine Fehlermeldung ausgegeben wird. Hat der Benutzer alles ausgefüllt und angeklickt, aber beispielsweise seine Telefonnummer vergessen, so werden die Felder mit den bereits korrekt eingegebenen Daten ausgefüllt, sodass der Benutzer nurnoch seine Telefonnummer ergänzen muss.

Auf verschiedene Formularelemente reagieren


Jedes Formularelement stellt eine andere Funktionsweise dar, auf die man unterschiedlich reagieren kann. Hier ein kleiner Überblick, wie man mit den unterschiedlichen Elementen umgehen kann und im Fehlerfall auf sie reagiert:
  • Selectbox: Die Selectbox soll dem Benutzer ermöglichen, eine Auswahl aus einer vordefinierten Menge an Optionen zu treffen, worauf hin er entweder genau eine, oder im Fall einer Multiselectbox, auch mehrere Optionen auswählen kann. Da Multiselectboxen häufig eleganter durch Checkboxen darstellbar sind, um dem Benutzer etwa die Bedienung der STRG-Taste zu ersparen, beschreibe ich das Vorgehen nun anhand einer einfachen Selectbox, die ungefähr so aussehen könnte
    PHP Quellcode:
    <select name="heimatland">
      <option value="">Heimatland auswählen</option>
      <option value="de"<?php if(isset($eingabe['heimatland']) && $eingabe['heimatland'] == 'de') echo ' selected="selected"' ?>>Deutschland</option>
      <option value="ch"<?php if(isset($eingabe['heimatland']) && $eingabe['heimatland'] == 'ch') echo ' selected="selected"' ?>>Schweiz</option>
      <option value="at"<?php if(isset($eingabe['heimatland']) && $eingabe['heimatland'] == 'at') echo ' selected="selected"' ?>>Österreich</option>
    </select>

    Das bedeutet nun im Klartext, dass der Benutzer auf jedenfall ein Heimatland auswählen muss. Vergisst er, dieses anzugeben, so soll er dazu erneut aufgefordert werden, eine Auswahl zu treffen. Die Überprüfung könnte dann ungefähr so aussehen:
    PHP Quellcode:
    if (isset($_POST['heimatland']) && !is_array($_POST['heimatland']) && strlen(trim($_POST['heimatland']))) {
         
         $erlaubte_heimat = array('de', 'ch', 'at'); // Zur vorbeugung manipulierter Formulare
             
         if (in_array($_POST['heimatland'], $erlaubte_heimat)) {
             $eingabe['heimatland'] = htmlspecialchars(trim($_POST['heimatland']));
         } else {
             $error['heimatland'] = true;
         }
    } else {
         $error['heimatland'] = true;
    }

    Wir erwarten also eine einzelne Eingabe (kein Array), die unbedingt mit einem der zuvor definierten Werte de, ch oder at übereinstimmen muss. Wenn $_POST['heimatland'] einen anderen Wert beinhalten würde, könnte man direkt davon ausgehen, dass das Formular manipuliert wurde.
    Ist der Wert okay, aber es ist ein anderer Fehler im Formular aufgetreten, wie z.B. ein vergessener Vorname, so steht zumindest schonmal in $eingabe['heimatland'] der zuvor ausgewähle Wert, den wir nun durch selected="selected" vorauswählen können.
    Selectboxen werden auch sehr häufig mit Werten aus einer Datenbank gefüllt. Die Überprüfung der Variable sieht dabei ganz ähnlich aus, weshalb nun nur noch gezeigt wird, wie man die Vorauswahl bei vorher nicht bekannten value-Werten treffen kann, wobei nun davon ausgegangen wird, dass eine Tabelle existiert, wo alle Länder mit einer dazugehörigen ID existiert:
    PHP Quellcode:
    <?php
    $res = mysql_query("SELECT id, land FROM laender") or die(mysql_error());
    ?> 
    <select name="heimatland">
      <option value="">Heimatland auswählen</option>
      <?php
      while ($land = mysql_fetch_assoc($res)) {
          $sel = '';
          if (isset($eingabe['heimatland']) && $eingabe['heimatland'] == $land['id']) {
              $sel = ' selected="selected"';
          }
          echo '<option value="'.$land['id'].'"'.$sel.'>'.$land['land'].'</option>';
    }
    ?> 
    </select>

  • Radiobox: Eine Radiobox wird ähnlich wie eine Selectbox dazu verwendet, eine Auswahl an vordefinierten Eingaben zu treffen. Häufige Beispiele sind Ja/Nein-Fragen, die Frage nach dem Geschlecht oder vielem mehr... Es macht also nur Sinn, genau eine Aussage dieser Gruppe von Elementen zu treffen. Die Frage nach dem Geschlecht eines Benutzers könnte ungefähr so aussehen:
    PHP Quellcode:
    Ihr Geschlecht?<br />
    Sag ich nicht: <input type="radio" name="geschlecht" value="0"<?php if(!isset($eingabe['geschlecht']) || $eingabe['geschlecht'] == 0) echo ' checked="checked"'; ?> />
    männlich: <input type="radio" name="geschlecht" value="m"<?php if(isset($eingabe['geschlecht']) && $eingabe['geschlecht'] == 'm') echo ' checked="checked"'; ?> />
    weiblich: <input type="radio" name="geschlecht" value="w"<?php if(isset($eingabe['geschlecht']) && $eingabe['geschlecht'] == 'w') echo ' checked="checked"'; ?> />

    Falls das Formular noch nicht abgeschickt wurde, so soll die Auswahl "Sag ich nicht" vorausgewählt sein, ansonsten soll überprüft werden, welche Auswahl der Benutzer zuvor getroffen hatte, falls er durch einen anderen Fehler das Formular erneut angezeigt bekommt.
    Die mögliche Überprüfung des Geschlechtes könnte dann folgendem Code entsprechen:
    PHP Quellcode:
    if (isset($_POST['geschlecht']) && !is_array($_POST['geschlecht'])) {
                 
        $erlaubte_geschlechter = array('m', 'w', 0);
             
        if (in_array($_POST['geschlecht'], $erlaubte_geschlechter)) {
            $eingabe['geschlecht'] = $_POST['geschlecht'];
        } else {
            $error['geschlecht'] = true;
        }        
             
    } else {
        $error['geschlecht'] = true;
    }

    Falls der Wert des Geschlechtes einem anderen Wert als 0, m oder w entspricht, so kann man erneut davon ausgehen, dass der Benutzer das Formular verändert hat, was man mit einem Fehler quittieren sollte. Ob man diese Überprüfung nun vor notwendig hält, sei dahingestellt. Sicherer wäre es allemal, da die Variable somit nur einen Wert enthalten kann, den man vorher abschätzen kann.
    Sollte man einen anderen Weg einschlagen, so sollte man wenigstens dafür sorgen, dass der Inhalt vorher auf "Bösen Code" überprüft wird, d.h. am besten mit htmlspecialchars() bearbeiten, und sofern man mit einer Datenbank arbeitet, den Wert im Falle von MySQL mit mysql_real_escape_string() escapen.

Fehler signalisieren


Nun ist es sehr oft erwünscht, dem Benutzer anzuzeigen, welche seiner Eingabe(n) falsch war(en). Dies könnte man z.B. dadurch realisieren, indem man das Feld, in welchem sich eine falsche Eingabe befunden hat, einfach mit einem roten Rahmen (gestyled mit CSS) verpasst, oder man einfach daneben einen Text a'la "Telefonnummer ungültig" anzeigt. Sofern man den oberen Teil dieses Artikels schon gelesen und verstanden hat, so hat man eigentlich schon das meiste erledigt:

Bei der Überprüfung der Benutzereingabe haben wir für jedes Feld, in dem sich eine fehlerhafte Eingabe befindet, einen Eintrag mit dem Namen des Inputfeldes als Index im $error-Array erstellt, und diesen mit dem Wert true belegt. Für eine fehlerhafte Rufnummer könnte dies, wie oben bereits beschrieben, ungefähr so aussehen:
PHP Quellcode:
if (isset($_POST['telefon']) && strlen(trim($_POST['telefon'])) > 4 && is_numeric($_POST['telefon'])) {
     $eingabe['telefon'] = trim($_POST['telefon']);
} else {
     $error['telefon'] = true; // Hier den Fehlereintrag erstellen
}


Falls der Benutzer nun eine falsche Rufnummer angegeben hat, so können wir ihn folgendermaßen darauf aufmerksam machen, indem wir das Inputfeld etwas erweitern:
PHP Quellcode:
Telefonnummer: <input type="text" name="telefon"<?php if(isset($eingabe['telefon'])) echo ' value="'.$eingabe['telefon'].'"'; ?><?php if(isset($error['telefon')) echo ' class="error"';?> />


Sofern nun also unsere Überprüfung einen Fehler für die Telefonnummer erstellt, wird das Inputfeld mit dem Attribut class="error" erweitert. Falls wir nun per CSS eine Klasse "error" erstellen, so können wir über diese das Aussehen eines fehlerhaften Inputfeldes definieren. Man könnte das ganze natürlich auch textuell erstellen, was ungefähr gleich abläuft:
PHP Quellcode:
Telefonnummer: <input type="text" name="telefon"<?php if(isset($eingabe['telefon'])) echo ' value="'.$eingabe['telefon'].'"'; ?> /><?php if(isset($error['telefon')) echo '<span class="error">Du hast ne ungültige Rufnummer eingegeben!</span>';?>


Möglichkeiten für das action-Attribut


Es stellt sich natürlich die Frage, wohin genau man das Formular senden muss, um ein Affenformular zu erhalten. Anschaulich ist das natürlich klar: An sich selber! Doch dies kann man auf unterschiedliche Art und Weise erledigen, die sich in gewisser Hinsicht ein wenig unterscheiden.
  • Feste Angabe des Dateinamen: Dies bedeutet, dass man in dem action-Attribut einfach den Namen der Datei angibt, in der sich das Formular selber befindet. Heisst unsere Datei beispielsweise form.php, so sähe unser action-Attribut folgendermaßen aus:
    PHP Quellcode:
    <form action="form.php" method="post">
    Diese Methode hat allerdings den Nachteil, dass falls sich der Name der Datei aus irgendeinem Grund ändern sollte, man diesen auch im Script selber ändern muss. Dies hat natürlich einen extra Aufwand zur Folge, welchen man natürlich vergessen kann, der aber auch Zeitaufwendig bei einer Vielzahl an Änderungen werden kann.

  • Den Dateiname dynamisch ermitteln: In dem Superglobalen Array $_SERVER steht unter dem Index PHP_SELF bei jedem Aufruf der Pfad und Name des momentan verwendeten Scriptes. Da der erfahrene Benutzer aber auch eine Möglichkeit hat, diesen Wert zu beeinflussen, sollte man den Inhalt auf jeden Fall escapen, um auch vor XSS-Attacken geschützt zu sein. (Für nähere Details, schaue man hier). SCRIPT_NAME ist weniger anfällig für solche Probleme.
    Unser Formularkopf sähe somit ungefähr so aus:
    PHP Quellcode:
    <form action="<?php echo htmlentities($_SERVER['SCRIPT_NAME']); ?>" method="post">

  • Ein leeres action-Attribut:
    PHP Quellcode:
    <form action="" method="post">

Quellen


http://de.wikipedia.org/wiki/Affenformular
http://blog.phpdoc.info/archives/13-guid.html

Tutorials
  Nächstes Kapitel »

Mitwirkende: Bernd456, daN-the-man, combie
Erstellt von daN-the-man, 04.02.2008 am 16:25
Zuletzt bearbeitet von Bernd456, 24.12.2009 am 13:01
8 Kommentare , 49820 Betrachtungen

Dieser Text steht unter der GNU-Lizenz für freie Dokumentation


 

Lesezeichen

Artikel-Optionen
Ansicht

Forumregeln
Es ist Ihnen nicht erlaubt, neue Themen zu verfassen.
Es ist Ihnen nicht erlaubt, auf Beiträge zu antworten.
Es ist Ihnen nicht erlaubt, Anhänge hochzuladen.
Es ist Ihnen nicht erlaubt, Ihre Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.

Gehe zu
Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
Affenformular value löschen blaustreetballer PHP 3 12.01.2008 13:54
Problem / Hilfe mit PHP Affenformular tafkat PHP 1 08.03.2007 09:32
Affenformular Maddi1986 PHP 2 09.12.2006 20:13
ACHTUNG: Affenformular mit Comboboxen Nick_Taylor PHP 16 22.10.2006 11:44
Affenformular & refresh Trax482 PHP 1 28.03.2006 16:50


Alle Zeitangaben in WEZ +2. Es ist jetzt 20:59 Uhr.


Powered by vBulletin® Version 3.8.8 (Deutsch)
Copyright ©2000 - 2016, Jelsoft Enterprises Ltd.
Powered by NuWiki v1.3 RC1 Copyright ©2006-2007, NuHit, LLC