Gar nicht. Wenn das action= -Attribut eines Formulares ein PHP-Script ist, dann stehen die Variablen aus dem Formular und aus den Cookies automatisch als Elemente in einem von drei Arrays in PHP zur Verfügung: Je nach der Art der Übergabe stehen sie in $_GET , $_POST oder $_COOKIE bereit. Früher standen sie außerdem automatisch als globale Variablen bereit, aber dies ist ein Sicherheitsrisiko und seit PHP 4.2.x nicht mehr der Fall. Der Schalter register_globals kontrolliert dieses Verhalten und er steht seit PHP 4.2.x per Default auf off (siehe formular-register-globals ).
Wenn die Quelle der Daten nicht bekannt ist (z.B. wenn das Formular über GET oder POST aufgerufen werden darf), kann auch das Array $_REQUEST verwendet werden, das die Daten der drei Arrays, die externe Daten enthalten, vereint. Wenn gleichzeitig gleichnamige Variablen über unterschiedliche Methoden übergeben werden (z.B. GET-Variable und Cookie), werden sie in der unter variables_order angegebenen Reihenfolge berücksichtigt bzw. überschrieben.
Weil es sich bei diesen Arrays um superglobale Variablen handelt, sind sie in Funktionen automatisch sichtbar. Sie müssen nicht mit global() importiert werden.
Wenn GET-Variablen Zeichen enthalten bzw. zur Laufzeit enthalten können, die nicht im Klartext in URLs auftauchen dürfen (Umlaute, Leerzeichen, Prozentzeichen etc.), muss man die Variablen mit urlencode() codieren, bevor man sie an die URL anhängt. Um die Decodierung muss man sich im Normalfall nicht kümmern, das geschieht automatisch. Mit folgendem Script lassen sich mehrere Werte - übergeben als array(Variable => Wert) - bequem codieren:
<?php
function req_url($url, $para) {
$sep = "?";
if (! is_array($para))
return $url;
foreach ($para as $k => $v) {
$url .= sprintf("%s%s=%s",
$sep,
$k,
urlencode($v)
);
$sep = "&";
}
return $url;
}
$p = array(
"a" => "b",
"c" => "d"
);
$url = req_url("beispiel.php", $p);
?>
Klicke auf das <a href="php/php-faq/static/%26lt%3B%3Fphp%20print%20%24url%20%3F%26gt%3B.html">Beispiel</a>.
Wird das Formular mit POST übergeben, ist die Anzahl und Größe der Elemente möglicherweise begrenzt durch serverseitige Einstellungen (Apache: siehe LimitRequestBody und verwandte Direktiven).
Wird das Formular mit GET übergeben, ist die Anzahl der Variablen begrenzt durch die maximale Länge der URL, die der Browser und der Webserver verarbeiten können. Beim Browser ist dies vom Browser und der Browserversion abhängig. Beim Webserver ist das Limit unter Umständen konfigurierbar (Apache: siehe LimitRequestLine (8190) und verwandte Direktiven).
Im allgemeinen ist es besser, die Methode GET zu verwenden: Formulare sind leichter zu debuggen und der Anwender kann sich ein fertig ausgefülltes Formular mit Parametern in die Bookmarks oder einen Link legen - das ist bequem und ergonomisch.
Enthält das Formular Werte, die nicht in der URL angezeigt werden sollen und die ggf. nicht Bestandteil des Referer sein sollen und nicht in Proxy-Logs auftauchen sollen, dann ist die Verwendung von POST angezeigt. Dies ist zum Beispiel immer der Fall, wenn ein Eingabeelement Password verwendet wird.
Ebenfalls soll POST verwendet werden, wenn die Länge von Eingabeelementen nicht nach oben begrenzt ist, also immer dann, wenn ein TEXTAREA verwendet wird.
Schließlich ist die Verwendung von POST zwingend notwendig, wenn ein File-Upload durchgeführt werden soll, einmal wegen der prinzipiell unbegrenzten Länge, aber auch weil der notwendige ENCTYPE="multipart/form-data" nur mit POST zusammen funktioniert.
Normale Input-Felder eignen sich für einzeilige Eingaben von 1 bis ca. 100 Zeichen. In HTML werden sie als <input type="text" name="variable"/> definiert, wobei der Inhalt von name in PHP zum Namen der Variable wird, die die Eingabe des Benutzers enthält: $_REQUEST['variable'] .
Für eine Vorbelegung des Feldes gibt es das optionale Attribut value :
<input type="text" name="var"
value="<?php echo htmlspecialchars($_REQUEST['var']); ?>"/>
Da die Variable auch Anführungszeichen enthalten könnte (was das Ende des value-Feldes bedeuten würde), muss man sie durch htmlspecialchars() "entschärfen" lassen.
Formular-Felder werden von PHP immer als Variablen vom Typ string zur Verfügung gestellt - auch wenn das Feld "nichts", oder wenn es nur Zahlen enthält. Siehe hierzu auch: " formular-verarbeitung ".
Dieses Codebeispiel erzeugt für jede Zeile in der Textarea eine Ausgabe, die etwa so aussieht:
Der Inhalt von Zeile 0 ist: "Inhalt der ersten Zeile"
Zu beachten ist, dass die Zählung innerhalb des Arrays $line mit 0 beginnt. Der Code ist für PHP 4.1.0 oder höher geschrieben. Wenn eine älter Version von PHP verwendet wird, so ist $_SERVER["PHP_SELF"] durch $PHP_SELF und $_REQUEST["TA"] durch $TA oder $HTTP_POST_VARS["TA"] zu ersetzen.
<?php
echo '<form action="'.$_SERVER["PHP_SELF"].'" method="post">';
echo '<textarea name="TA" cols="50" rows="10">';
if (isset($_REQUEST["TA"])) {
echo $_REQUEST["TA"];
}
echo '</textarea>';
echo '<input type="submit" value="Prüfen...">';
echo '</form>';
if (isset($_REQUEST["TA"])) {
$lines = preg_split("/\r\n/", $_REQUEST["TA"]);
foreach ($lines as $key => $value){
echo 'Der Inhalt von Zeile '.$key.' ist: "'.$value.'"<br>';
}
}
?>
Zum Anzeigen des über eine Textarea eingegebenen Textes innerhalb eines HTML-Dokuments eignet sich die Funktion nl2br() (siehe string-html-umbruch ). Innerhalb des HTML-Tags <pre> ist dies jedoch nicht nötig.
Aus einer Datenbanktabelle mit einer List Of Values (LOV) soll eine Selectbox erzeugt werden:
<?php
/*
* lovselection - wandle eine Liste von Werten aus einer Datenbank
* in eine option-Liste in HTML.
*
* (benutzt PEAR::DB)
*
* von Kristian Köhntopp und Frank Wiegand
*
*/
function lovselection($dsn, $table, $field, $oldvalue) {
// Rueckgabestring
$ret = "";
// Datenbankverbindung aufbauen, Fehlerbehandlung
// ist hier nicht implementiert!
require_once 'DB.php';
$db = DB::connect($dsn);
// Daten auslesen
$query = sprintf("SELECT %s FROM %s",
$field,
$table
);
$res = $db->query($query);
while($row = $db->fetchRow()) {
if ($row[$field] == $oldvalue)
$selected = " selected='selected'";
else
$selected = "";
$ret .= sprintf("<option%s>%s</option>\n",
htmlspecialchars($selected),
$row[$field]
);
}
$db->disconnect();
return $ret;
}
/*
* is_validlov - überprüfe, ob ein gegebener Wert zu einer
* vorgegebenen Liste von Werten passt.
*
* von Kristian Köhntopp und Frank Wiegand
*
*/
function is_validlov($dsn, $table, $field, $value) {
require_once 'DB.php';
$db = DB::connect($dsn);
$query = sprintf("SELECT %s FROM %s WHERE %s = %s",
$field,
$table,
$field,
$db->quote($value) // Wert für die Abfrage maskieren
);
$res = $db->query($query);
if ($res->numRows() == 1) {
$db->disconnect();
return true;
} else {
$db->disconnect();
return false; // 0 or 2+ answers are a failure!
}
}
?>
<!-- Formularfragment -->
<select name="f_ortsnetz" size="1">
<?php echo lovselection("mysql://$user:$pass@$host/$db_name", "ortsnetze", "vorwahl", $ortsnetz) ?>
</select>
<!-- Auswertefragment -->
<?php
if (is_validlov("mysql://$user:$pass@$host/$db_name", "ortsnetze", "vorwahl", $_REQUEST['f_ortsnetz']))
$ortsnetz = $_REQUEST['f_ortsnetz']; // value is valid
else {
$error["ortsnetz"] = "Das angegebene Ortsnetz ist ungültig.";
$ortsnetz = ""; // clear session variable
}
?>
Die Funktion lovselection() generiert aus einer Tabelle von Werten in der Datenbank (eine sogenannte List Of Values, LOV) eine Reihe von Option-Tags. Man kann dann leicht den passenden Select-Container drumwickeln. lovselection() verwendet die Datenbank-Klasse DB aus dem PEAR , läuft also mit prinzipiell jeder SQL-Datenbank.
Wenn man einen solchen Select-Tag generiert, dann heißt das natürlich nicht, dass das so erzeugte Formular beim Submit ausschließlich Werte zurückliefert, die man dort zur Auswahl gestellt hat. Stattdessen kann jeder beliebige Wert zurück kommen.
Es ist also notwendig, dass man ein Prädikat erzeugt, das überprüft, ob der eingegangene Wert gültig ist. Dieses Prädikat ist is_validlov() : Die Funktion liefert true, wenn der gegebene Wert genau einmal in der angegebenen Tabelle vorkommt.
Im Beispiel kann mit der Variablen $_REQUEST['f_ortsnetz'] , die aus dem Formular kommt, nicht gearbeitet werden - sie kann potentiell ungültige Werte ("003432") enthalten oder sogar potentiell gefährliche Werte ("0431' or sp_clearall() or '0431", wobei sp_clearall() irgendeine Einbaufunktion oder Stored Procedure in einer Datenbank ist, die gefährliche Dinge mit der Datenbank macht).
Der Wert von $_REQUEST['f_ortsnetz'] kann nach $ortsnetz kopiert und gefahrlos verwendet werden genau dann und nur dann, wenn is_validlov() wahr ist, denn dann kommt der Inhalt von $_REQUEST['f_ortsnetz'] genau einmal in der angegebenen Tabelle vor und ist damit eine gültige und garantiert harmlose Auswahl.
Die Funktion is_validlov() selbst kann sich den Luxus nicht erlauben, mit harmlosen Werten zu arbeiten und muss daher so geschrieben sein, dass sie auch mit gefährlichen Inhalten in $value zurecht kommt. Um eine SQL-Injection auszuschließen, wird $value mit der quote -Methode entsprechend für die Abfrage präpariert.
Das Formular muss so aussehen:
<form action="script.php"> <select multiple="multiple" size="3" name="avar[]"> <option value="a">Eins</option> <option value="b">Zwei</option> <option value="c">Drei</option> <option value="d">Vier</option> <option value="e">Fuenf</option> <option value="f">Sechs</option> </select> <br /> <input type="submit" name="doit" value="Los!" /> </form>
Entscheidend ist, dass der Name der Variablen im <select>-Tag mit eckigen Klammern endet, damit ein Array erzeugt wird. Das Script script.php erhält nun diese Variable $_REQUEST['avar'] (bzw. vor PHP 4.1.0 als $HTTP_GET_VARS['avar'] ) als Array und kann die Werte dieses Arrays aufzählen.
In PHP3 können auf diese Weise nur eindimensionale Arrays erzeugt werden, in PHP4 sind auch mehrdimensionale Felder möglich. In jedem Fall kann nur die letzte Dimension unbestimmt sein.
Radio-Buttons verhalten sich analog zu Checkboxen (siehe formular-checkbox ), mit der Ausnahme, dass hier eine Mehrfachauswahl nicht möglich ist. Beim Erstellen des HTML-Codes sollte darauf geachtet werden, dass zusammengehörige Buttons den gleichen Namen haben müssen.
Mit dem folgenden Code lassen sich Radio-Buttons analog zu stil-normalform erstellen:
$elements = array(
array('name' => 'grün', 'value' => 'gr'),
array('name' => 'blau', 'value' => 'bl'),
array('name' => 'rot', 'value' => 'ro')
);
foreach ($elements as $element) {
printf('<input type="radio" name="farbe" value="%s" %s/> %s<br />',
$element['value'],
(isset($_REQUEST['farbe']) and $_REQUEST['farbe'] == $element['value']) ? 'checked="checked" ' : '',
$element['name']);
}
Wenn die Checkboxen nicht markiert sind, werden sie überhaupt nicht übermittelt. Andernfalls haben sie den im Attribut VALUE= angegebenen Wert. Man kann die Elemente auf die folgenden beiden Arten erzeugen:
# Fall 1: Verschiedene Namen, gleicher Wert <input type="checkbox" name="cbutton[1]" value="yes" /> <input type="checkbox" name="cbutton[2]" value="yes" /> # Fall 2: "Gleiche" Namen, verschiedene Werte <input type="checkbox" name="cbutton[]" value="1" /> <input type="checkbox" name="cbutton[]" value="2" />
Die Abfrage erfolgt in beiden Fällen mit
if (isset($_REQUEST['cbutton'])) {
reset($_REQUEST['cbutton']);
foreach ($_REQUEST['cbutton'] as $k => $v) {
print "$k $v\n";
}
} else {
print "alle cbutton schlafen schon.\n";
}
Im Fall 1 wertet man die $k aus, im Fall 2 die $v. Entscheidend ist auch hier, dass der Variablennamen bei mehr als einer Checkbox mit [] endet, damit in PHP ein Array zur Verfügung steht.
Ein Upload-Formular muss ein Input-Element enthalten, das den Typ file hat. Da Dateien in einem Upload prinzipiell beliebig groß werden können, muss die Übermittlung des Formulares mit der Methode POST erfolgen. Außerdem muss ein bestimmter ENCTYPE für das Formular angegeben werden. Ein solches Formular kann von Netscape Navigator ab Version 3 und von Microsoft Internet Explorer ab Version 4 verarbeitet werden.
<h1>Hallo</h1>
<form action="/submit.php" method="post"
enctype="multipart/form-data">
<input type="file" name="probe" />
<input type="submit" value="los" />
</form>
Das empfangende PHP-Script bekommt das Resultat des Datei-Uploads als assoziatives Array mit dem Namen $_FILES['probe'] (bzw. bei PHP 4.0.0 bis 4.0.6 $HTTP_POST_FILES['probe'] ) übermittelt, weil das Input-Element im Formular diesen Namen hat.
$_FILES['probe']['tmp_name']Diese Variable enthält den Namen der Datei in einem temporären Verzeichnis auf dem Server. Sie kann von dort mit einem move_uploaded_file() -Aufruf abgeholt werden. Das ist auch notwendig, da die Originaldatei am Ende des Scriptes automatisch gelöscht wird.
$_FILES['probe']['name']Diese Variable enthält den Namen der Datei auf dem System des Anwenders. Der genaue Dateiname mit evtl. vorhandenen Laufwerksbuchstaben, Pfadseparatoren und anderen Sonderzeichen ist betriebssystemabhängig und das empfangende Script sollte keine Annahmen hierüber machen.
$_FILES['probe']['size']Diese Variable enthält die Länge der Datei auf dem Server in Bytes.
$_FILES['probe']['type']Diese Variable enthält den MIME-Type der Datei, so wie er dem Server vom Browser übermittelt worden ist. Dieser Wert kann unter Umständen nicht richtig sein, je nach Einstellung des Browsers. Beim Ermitteln des Typs von hochgeladenen Grafiken sollte stattdessen die Funktion getimagesize() verwendet werden.
$_FILES['probe']['error']Diese Variable wurde mit PHP 4.2.0 eingeführt und enthält den Status des Dateiuploads. Die möglichen Werte und dazugehörige Konstanten in neueren PHP-Versionen sind im Handbuch aufgeführt.
Der Upload von Dateien wird durch die drei Konfigurationsparameter file_uploads , upload_tmp_dir und upload_max_filesize gesteuert. Außerdem relevant sind die drei Parameter memory_limit , post_max_size und max_execution_time . Der Pfad zu upload_tmp_dir muss absolut angegeben werden.
PHP legt die temporäre Datei in dem angegebenen Verzeichnis an und löscht sie am Ende des Scriptes wieder. Die Datei darf maximal die angegebene Größe haben. Ein Einstellen der Größenbegrenzung begrenzt jedoch nicht wirklich den Plattenplatz, der auf dem Server von PHP durch Fileupload verbraucht wird: Aus technischen Gründen muss PHP die Datei zunächst empfangen und kann sie erst dann verwerfen, wenn sie zu groß ist. Es kann auch mehr als eine Datei pro Formular hochgeladen werden (siehe formular-mehrfach-upload ).
Achtung:Das Kopieren der hochgeladenen Datei mit Hilfe von copy() und das Verwenden der alten, auf globalen Variablen beruhenden Version sollte wo möglich aus Sicherheitsgründen vermieden werden.
Vollständiges Beispiel:
<h1>Upload</h1>
<form
action="<?php echo $_SERVER['PHP_SELF']; ?>"
method="post"
enctype="multipart/form-data">
<input type="file" name="probe" />
<input type="submit" value="Los!" />
</form>
<hr />
<?php
if (isset($_FILES['probe']) and ! $_FILES['probe']['error']) {
// Alternativ: and $_FILES['probe']['size']
move_uploaded_file($_FILES['probe']['tmp_name'], "./newfile.txt");
printf("Die Datei %s steht jetzt als " .
"newfile.txt zur Verfügung.<br />\n",
$_FILES['probe']['name']);
printf("Sie ist %u Bytes groß und vom Typ %s.<br />\n",
$_FILES['probe']['size'], $_FILES['probe']['type']);
}
?>
Bei PHP3 muss über eine alternative Syntax auf die hochgelade Datei zugegriffen werden (siehe formular-upload-php3 ).
Das Auswählen mehrerer Dateien oder gar ganzer Verzeichnisse ist mit einem <input type="file"> -Feld nicht möglich. Auch das Vorgeben eines bestimmten Verzeichnisses oder vollständigen Pfades ist bei File-Input-Feldern unterbunden, sei es als Angabe value="path/to/file" oder per JavaScript. Warum? Aus Sicherheitsgründen! Wem wäre es schon recht, wenn auf einer x-beliebigen Internetseite sich ein (z.B. durch Layer verstecktes) Formular mit einem Feld <input type="file" value="c:\eigene dateien\*.*"> mittels JavaScript selbsttätig abschicken würde? Eben deshalb muss jede Datei, die verschickt werden soll, vom Anwender manuell und damit bewußt ausgewählt werden.
Mehrere Dateien lassen sich verschicken
mit mehreren <input type="file"> -Feldern - pro Datei eines (Tipp: [] an den Namen des Input-Feldes anhängen, um in PHP ein Array mit den Dateiinformationen zu erhalten)
als .zip - oder .tar -Datei
per FTP
mit einem eigenen Tool, das auf dem Rechner des Absenders installiert werden muss
per (Java-) Applet - hier gibt es mehrere kommerzielle oder kostenlose Lösungen, z.B.
Beim Verwenden der Array-Notierung in Zusammenhang mit mehreren Datei-Upload-Feldern ist die Zuweisung im $_FILES -Array nicht so, wie man es vermuten könnte. Beispiel:
<form
action="<?php echo $_SERVER['PHP_SELF']; ?>"
method="post"
enctype="multipart/form-data">
<input type="file" name="probe[test][]" />
<input type="file" name="probe[test][]" />
<input type="submit" />
</form>
<?php
if (isset($_FILES)) {
?><pre><?php print_r($_FILES); ?></pre><?php
}
?>
Der Name der ersten Datei z.B. findet sich in diesem Beispiel unter $_FILES['probe']['name']['test'][0] , der Fehlercode der zweiten Datei unter $_FILES['probe']['error']['test'][1] .
Ein Datei-Upload mittels HTML-Formular findet zwischen Browser und Webserver statt. Während der Upload im Gange ist, weiß PHP noch gar nichts davon. Erst wenn der Upload beendet ist, tritt PHP in Aktion und nimmt die Daten entgegen. Daraus folgt, dass es mit PHP/HTML/JavaScript-Mitteln (und seien sie noch so ausgefeilt) technisch unmöglich ist, den Benutzer über den tatsächlichen Fortschritt des Uploads zu informieren.
Am Sinnvollsten wäre eine Statusanzeige clientseitig, also als Browser-Feature, zu realisieren. Die derzeit erhältlichen Browser haben diese Funktion leider nicht implementiert.
In Formularen kann man statt eines SUBMIT auch ein IMAGE als Absendeknopf installieren. Dies sieht dann so aus:
<input type="image" src="meinbild.png" name="sub" />
Wenn der User das Bild anklickt, werden zwei Variablen mit den Namen sub.x und sub.y erzeugt, die die Koordinaten des Klicks relativ zur linken, oberen Ecke des Bildes beschreiben. Da Variablennamen in PHP keine Punkte enthalten dürfen, wandelt PHP die Punkte in Unterstriche um. Im Beispiel bekommt man die Variablen mit den Namen $_REQUEST['sub_x'] und $_REQUEST['sub_y'] übergeben (bzw. vor PHP 4.1.0 $HTTP_GET_VARS['sub_x'] , etc. oder $HTTP_POST_VARS['sub_x'] ).
Antwort von Johannes Frömter:Alternativ kann man an den Variablennamen eines <INPUT TYPE="image"> eckige Klammern [] anhängen; man erhält in PHP dann ein Array mit dem Namen des Buttons, das die Koordinaten des Klickpunktes enthält. Mehrere solcher Image-Buttons kann man als button[a][] , button[b][] usw. benennen und die Werte aus den Arrays $_REQUEST['button']['a'] , $_REQUEST['button']['b'] usw. auslesen. Ob ein bestimmter Button gedrückt wurde, überprüft man mit isset() : if (isset($_REQUEST['button']['b'])) (bzw. vor PHP 4.1.0 if (isset($HTTP_GET_VARS['button']['b'])) oder if (isset($HTTP_POST_VARS['button']['b'])) ).
Der Button muss einem Namen haben:
<input type="submit" name="submit" value="OK"/>
Dann ist bei einem Mausklick oder einem Tastendruck auf den Submit-Button eine Variable mit dem Namen des Buttons vorhanden:
if (isset($_REQUEST['submit'])) { ... }
// vor PHP 4.1.0 $HTTP_GET_VARS['submit'] oder $HTTP_POST_VARS['submit']
(Die Variable enthält den Text, der bei value angegeben wurde, oder den Standard-Text des Browsers für die Schaltfläche.)
Wurde das Formular dagegen per JavaScript oder durch Drücken der Eingabetaste im einzigen Texteingabefeld des Formulars abgeschickt, ist die Variable nicht vorhanden.
Man kann diese Abfrage sehr gut bei den sog. "Affenformularen" (Formulare, die sich selbst aufrufen, siehe " stil-normalform ") gebrauchen.
Es gibt verschiedene Möglichkeiten, in PHP zu unterscheiden, welcher Submit-Button in einem HTML-Formular betätigt wurde:
Haben die Buttons den gleichen Namen ( name="submit" ), kann man den value (gleichzeitig Beschriftungstext des Buttons) auswerten; die PHP-Variable heißt so wie der Button ( $_REQUEST['submit'] ).
Haben die Buttons unterschiedliche Namen, erhält man je nach betätigtem Button eine Variable mit anderem Namen registriert; mit isset() kann man prüfen, ob eine bestimmte Variable vorhanden ist, d.h. ob ein bestimmter Button angeklickt wurde.
Benennt man die Buttons in der Array-Schreibweise ( name="submit[0]" , zwischen den eckigen Klammern müssen eindeutige Werte stehen), erhält man in PHP ein Array mit genau einem Element; der Schlüssel (Key) dieses Elementes ist der aktivierte Button.
Im Script kann man dann z.B. unterschiedliche Anweisungsblöcke mit include() einbinden und somit ausführen.
Zunächst sollte man überlegen, ob man überhaupt einen Reset-Button braucht - bei Formularen mit nur einem Eingabefeld ist er eher witzlos, bei umfangreichen Formularen ist er dagegen umso ärgerlicher, wenn er aus Versehen betätigt wurde!
Bei einem HTML-Reset-Button ( <input type="reset"> ) setzt der Browser alle Eingabefelder auf den Anfangszustand zurück; da damit kein Request an den Server verbunden ist, kriegt PHP davon nichts mit. Möchte man einen Button realisieren, der Eingabeelemente mit vordefinierten Inhalten wirklich löscht, muss man einen Submit-Button nehmen:
<?php
if (isset($_REQUEST['loeschen'])) {
unset($_REQUEST['eingabe']);
}
?>
<form action="<?php echo $SERVER['PHP_SELF']; ?>" method="post">
<input type="text" name="eingabe"
value="<?php @print $_REQUEST['eingabe']; ?>"/>
<input type="submit" name="submit" value="Absenden"/>
<input type="reset" value="Reset"/>
<input type="submit" name="loeschen" value="Löschen"/>
</form>
Die Überprüfung von Formulareingaben ist in Hinblick auf die Sicherheit eines Skriptes ein nicht zu unterschätzender Faktor. Ausgangspunkt sollte meist das sogenannte Affenformular sein (siehe stil-normalform ).
Erkennen fehlender EingabenDie Länge einer Textfeldeingabe lässt sich mit der PHP-Funktion strlen() ermitteln. Leere Strings sind in PHP FALSE , d.h. durch eine Überprüfung auf Wahrheit ( if ($_REQUEST['textfeldname']) ) lässt sich feststellen, ob der Benutzer eine Eingabe gemacht hat.
Textfelder generellWenn ein Textfeld nur bestimmte Zeichen enthalten darf, ist es oft am einfachsten zu überprüfen, ob der übermittelte String Zeichen enthält, die nicht erlaubt sind (siehe auch regexp-bauelemente ):
if (preg_match('/[^0-9a-z_.-]/i', $_REQUEST['textfeldname']))
errmsg('Ungültige Zeichen im Textfeld.');
Um zu überprüfen, ob ein Textfeld eine Zahl enthält, eignet sich die Funktion is_numeric() . Diese Funktion akzeptiert allerdings auch Zeichen, die nicht Ziffern sind (z.B. -1.6e-12 ). Sollen nur Ziffern akzeptiert werden, helfen wieder Reguläre Ausdrücke:
if (preg_match('/\D/', $_REQUEST['textfeldname']))
errmsg('Ungültige Zeichen im Zahlenfeld.');
Zum Überprüfen einer URL reicht es meist aus, deren Anfang zu analysieren:
if (! preg_match('=(https?|ftp)://[a-z0-9]([a-z0-9-]*[a-z0-9])?\.[a-z0-9]=i', $_REQUEST['textfeldname']))
errmsg('Ungültige URL im Adressfeld.');
Diese Überprüfung soll nur ein Ansatz sein und lässt sich beliebig erweitern/verfeinern. Die tatsächliche Erreichbarkeit gewährleistet diese Vorgehensweise allerdings nicht. Mit Hilfe der Funktion fopen() lässt sich die momentante Erreichbarkeit einer URL feststellen.
E-Mail-AdressenDiese Frage wird unter mail-adresse-gueltig und mail-adresse-testen beantwortet.
Daten die ein Script aus Formularen übergeben bekommt, sollen meist in Datenbanken gespeichert werden. Dabei sollen in der Regel Dubletten vermieden werden. Diese können z.B. entstehen, wenn der User den URI neulädt, an den die Daten übergeben wurden oder wenn er bei Netscape-Browsern die Größe des Browserfensters ändert, was ebenfalls ein Neuladen bewirkt. Ein mögliches Verfahren zur Vermeidung solcher Dubletten wird in der Frage scripte-abstimmung beschrieben (Einsatz einer Challenge), ein anderes mögliches Verfahren ist ein Redirect per Location-Header nach der erfolgreichen Ausführung der gewünschten Aktionen (z.B. Speichern der Daten in einer Datenbank).
<?PHP
function formular_ausgeben($error = '')
{
$error = ($error=='')?'':'<font color="#DD0000">'.$error.'</font>';
return '<form action="script.php4" method="POST">
'.$error.'
Name: <input type="text" name="name" value="'.$_REQUEST['name'].'" />
<br />
<input type="submit" name="submit" value="OK" />
</form>';
}
function daten_speichern()
{
GLOBAL $db;
if(strlen($_REQUEST['name']) < 3)
{
return formular_ausgeben('Bitte Namen eingeben!<br>');
}
else
{
// Mit $db->escape_string() wird eine Funktion aufgerufen, die sicher stellt
// das möglicherweise in $_REQUEST['name'] enthaltene SQL-Fragmente nicht
// ausgeführt werden (siehe auch mysql_escape_string() ).
$db->query("INSERT INTO tabelle
SET name = '".$db->escape_string($_REQUEST['name'])."'");
if($db->affected_rows() == 1)
{
header('Location: http://domain.de/script.php4?d=bestaetigen');
return '<a href="http://domain.de/script.php4%3Fd%3Dbestaetigen">weiter</a>';
}
else
{
return formular_ausgeben('MySQL: '.$db->Error.'<br>');
}
}
}
function bestaetigung()
{
return 'Der Name wurde gespeichert.';
}
if($_REQUEST['submit'] == 'OK')
{
echo daten_speichern();
}
elseif($_REQUEST['d'] == 'bestaetigen')
{
echo bestaetigung();
}
else
{
echo formular_ausgeben();
}
?>
Ein Neuladen nach erfolgreichem Abspeichern der Daten führt hier nur zur erneuten Ausgabe der Bestätigung. Die Daten werden nicht erneut in die Datenbank geschrieben.
Die Symptome sind meist, dass die Seiten auf dem Webserver des Hosts tadellos funktionieren, aber bei dem nagelneu aufgesetzten Testserver die Formulareingaben einfach nicht mehr ankommen. Oft stolpern auch Neulinge darüber, wenn die Beispiele aus dem Lehrbuch nicht auf dem eigenen Testserver funktionieren.
Seit PHP 4.2.0 wurde register_globals in der php.ini per Default abgeschaltet. Die Option war dafür zuständig, dass ein Parameter an das Script automatisch in eine entsprechend genannte Variable kopiert wurde. Ein Angreifer hat damit jedoch die Möglichkeit, Variablen, die der Programmierer versehentlich uninitialisiert ließ, mit beliebigen Werten vorzubelegen.
Es gibt zwei Möglichkeiten, dieses Problem in den Griff zu kriegen.
Die gute Wahl ist, die PHP-Scripte entsprechend anzupassen. Das ist reine Fleißarbeit. Siehe auch Verwendung von Register Globals .
Die schlechte Wahl ist, register_globals wieder zu aktivieren. Da der Webauftritt damit wieder angreifbar ist, sollte man es höchstens als Notlösung betrachten, um den Webauftritt vorübergehend wieder online zu kriegen, bis man die Scripte umgestellt hat. Wenn man keine Rechte hat, um register_globals zu aktivieren, hilft die Funktion import_request_variables() weiter.