Suchen
Inside Wiki
Nützliche Links




 
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 Arrays aus Formularfeldern

 

Inhalte

Arrays aus Formularfeldern



In den meisten Formularen wird nur ein einziger Datensatz aus der Datenbank bearbeitet. Hin und wieder möchte man aber mehrere Datensätze - oder gleich die ganze Tabelle - bearbeiten. Ein Beispiel dafür wäre ein administratives Interface, in dem man die Namen der registrierten Benutzer bearbeitet.

In PHP würde man für so etwas Arrays nehmen. Aber wie macht man das in HTML? HTML kennt natürlich keine Arrays. Man darf aber in den name-Attributen von Formularfeldern eckige Klammern verwenden! Damit kann man so tun, als würde man Arrays erzeugen. Und PHP spielt dabei mit. Beim Parsen der POST-Daten erkennt PHP die Klammern als Array-Notation und macht aus $_POST ein mehrdimensionales Array (ein Array von Arrays).

Muster Nr. 1: Arrays aus einzelnen Feldern



Bleiben wir beim Beispiel einer Benutzerverwaltung. Unsere Datenbanktabelle sieht so aus:

Code:
CREATE TABLE users (
    username VARCHAR(60) NOT NULL,
    id INT UNSIGNED AUTO_INCREMENT,
    PRIMARY KEY(id)
)


Und jetzt erzeugen wir ein Formular mit eckigen Klammern in den name-Attributen. Das Formularfeld benennen wir zweckmäßigerweise nach dem Tabellenfeld. Die IDs werden als Pseudo-Arrayschlüssel in die name-Attribute eingebaut und die Inhalte landen im value-Attribut:

PHP Quellcode:
$select = 'SELECT id, username FROM users';
$result = mysql_query($select) or die (mysql_error());

echo '<form action="" method="post">';
while ($row = mysql_fetch_assoc($result)) {
    echo '<input name="username[', $row['id'], ']" value="',
        htmlspecialchars($row['username']), '" type="text">';
}
echo '<input type="submit"></form>';


Unser Formular sähe nun in etwa so aus:

HTML Quellcode:
<form action="" method="post">
    <input name="username[1]" value="Erika Mustermann" type="text">
    <input name="username[2]" value="Otto Normalverbraucher" type="text">
    <input type="submit">
</form>


PHP interpretiert die ID in den Klammern als Arrayschlüssel und weist "username" ein Unterarray zu. Ein print_r($_POST); sähe anschliessend so aus:

Code:
Array
(
    [username] => Array
        (
            [1] => Erika Mustermann
            [2] => Otto Normalverbraucher
        )
)


Nun kann man $_POST['username'] verarbeiten, wie jedes andere Array auch:

(Das EVA Prinzip fordert, daß zunächst die Eingaben verarbeitet werden müssen und erst anschliessend das HTML erzeugt werden darf. Deshalb findet sich im Anschluß an die Verarbeitung von $_POST nochmal der Formularcode von oben.)

PHP Quellcode:
// Wie immer muss man alles gründlich prüfen. Keine Benutzerangabe ist
// jemals vertrauenswürdig. Alles muss getestet und/oder gefiltert werden.

// Ein einfaches isset reicht zum Testen von $_POST['username'] nicht.
// Zusätzlich muss man noch prüfen, ob es sich wirklich um ein Array handelt:
if (isset($_POST['username']) && is_array($_POST['username'])) {

    // Erstmal lesen wir jetzt die username-Felder in ein Array, denn wir
    // wollen unten in der eigentlichen Schleife kein SELECT durchführen.
    // SELECTs in Schleifen sind böse!!!
    $allUsernames = array();
    $select = 'SELECT id, username FROM users';
    $result = mysql_query($select) or die (mysql_error());
    while ($row = mysql_fetch_assoc($result)) {
        $allUsernames[$row['id']] = $row['username'];
    }

    // Jetzt können wir eine Schleife über $_POST['username'] laufen lassen.
    // Die id ist dabei der Schlüssel und der username der Wert:
    foreach ($_POST['username'] as $id => $username) {

        // Gibt es den Wert von $id in der Tabelle überhaupt?
        if (array_key_exists($id, $allUsernames)) {

            // Ist der username in der Tabelle anders, als der Wert im
            // Formular? Falls ja, ist ein UPDATE fällig:
            if ($allUsernames[$id] != $username) {
                $update = sprintf(
                    'UPDATE users SET username="%s" WHERE id=%u',
                    // hier beugen wir SQL-Injections vor:
                    mysql_real_escape_string($username), (int)$id
                );
                mysql_query($update) or die (mysql_error());
            }
        }
    }
}

// Hier ist die Formularausgabe von vorhin nochmal:

$select = 'SELECT id, username FROM users';
$result = mysql_query($select) or die (mysql_error());

echo '<form action="" method="post">';
while ($row = mysql_fetch_assoc($result)) {
    echo '<input name="username[', $row['id'], ']" value="',
        htmlspecialchars($row['username']), '" type="text">';
}
echo '<input type="submit"></form>';


Muster Nr. 2: Arrays aus ganzen Tabellen



Das ist alles schön und gut, so lange man nur ein einziges Feld im Formular unterbringen will, aber was, wenn es mehrere sind?

Nehmen wir an, die Tabelle sehe so aus:

Code:
CREATE TABLE users (
    frstname VARCHAR(60) NOT NULL,
    lastname VARCHAR(60) NOT NULL,
    id INT UNSIGNED AUTO_INCREMENT,
    PRIMARY KEY(id)
)


Wenn wir das vorige Muster einfach um ein zweites Feld erweitern, sieht unser $_POST Array so aus:

Code:
Array
(
    [frstname] => Array
        (
            [1] => Erika
            [2] => Otto
        )
    [lastname] => Array
        (
            [1] => Mustermann
            [2] => Normalverbraucher
        )
)


Wie man sieht, wird das Schema der Datenbanktabelle in $_POST umgestülpt. Die IDs sind nicht mehr der Schlüssel, sondern alle anderen Felder sind Schlüssel und die Zellinhalte sind aus dem Zusammenhang ihrer Zeile gerissen. Das lässt sich so zwar auch verarbeiten, aber es ist recht unintuitiv. Eleganter und einfacher wäre es, wenn $_POST die Tabelle wiederspiegeln würde.

Dazu müssen wir zunächst mal das Namensschema für unsere input-Elemente ändern. Bisher war es feld[id] und stattdessen nehmen wir jetzt tabelle[id][feld]. Auf den ersten Blick sieht das zwar komplizierter aus, aber $_POST bildet jetzt die Tabelle ab:

Code:
Array
(
    [users] => Array
        (
            [1] => Array
                (
                    [frstname] => Erika
                    [lastname] => Mustermann
                )

            [2] => Array
                (
                    [frstname] => Otto
                    [lastname] => Normalverbraucher
                )
        )
)


Und jetzt zum Code! So sieht unser neues Formular aus:

PHP Quellcode:
$select = 'SELECT id, frstname, lastname FROM users';
$result = mysql_query($select) or die (mysql_error());

echo '<form action="" method="post">';
while ($row = mysql_fetch_assoc($result)) {
    echo '<input name="users[', $row['id'], '][frstname]" value="',
        htmlspecialchars($row['frstname']), '" type="text">';
    echo '<input name="users[', $row['id'], '][lastname]" value="',
        htmlspecialchars($row['lastname']), '" type="text">';
}
echo '<input type="submit"></form>';


So in etwa würde die HTML-Ausgabe ausssehen:

HTML Quellcode:
<form action="" method="post">
  <input name="users[1][frstname]" value="Erika" type="text">
  <input name="users[1][lastname]" value="Mustermann" type="text">
  <input name="users[2][frstname]" value="Otto" type="text">
  <input name="users[2][lastname]" value="Normalverbraucher" type="text">
  <input type="submit">
</form>


Jetzt noch die Auswertung:

PHP Quellcode:
if (isset($_POST['users']) && is_array($_POST['users'])) {

    $table = array();
    $select = 'SELECT id, frstname, lastname FROM users';
    $result = mysql_query($select) or die (mysql_error());
    while ($row = mysql_fetch_assoc($result)) {
        $table[$row['id']] = array(
            frstname => $row['frstname'],
            lastname => $row['lastname']
        );
    }

    // die $id identifiziert die Tabellezeile und $row enthält die Zellen:
    foreach ($_POST['users'] as $id => $row) {
       
        // Kommt die $id überhaupt in der Tabelle vor? Ist $row
        // tatsächlich ein Array? Sind frstname und lastname gesetzt?
        if (array_key_exists($id, $table) && is_array($row) &&
            !empty($row['frstname']) && !empty($row['lastname']))
        {
            // Ist der frstname oder der lastname in der Tabelle anders,
            // als in $_POST? Falls ja, ist ein UPDATE fällig:
            if ($table[$id]['frstname'] != $row['frstname'] ||
                $table[$id]['lastname'] != $row['lastname'])
            {
                $update = sprintf(
                    'UPDATE users SET
                        frstname = "%s",
                        lastname = "%s"
                     WHERE id = %u'
,
                    mysql_real_escape_string($row['frstname']),
                    mysql_real_escape_string($row['lastname']),
                    (int)$id
                );
                mysql_query($update) or die (mysql_error());
            }
        }
    }
}

// Und hier nochmal die Formularausgabe:

$select = 'SELECT id, frstname, lastname FROM users';
$result = mysql_query($select) or die (mysql_error());

echo '<form action="" method="post">';
while ($row = mysql_fetch_assoc($result)) {
    echo '<input name="users[', $row['id'], '][frstname]" value="',
        htmlspecialchars($row['frstname']), '" type="text">';
    echo '<input name="users[', $row['id'], '][lastname]" value="',
        htmlspecialchars($row['lastname']), '" type="text">';
}
echo '<input type="submit"></form>';


Muster Nr. 3: Arrays aus Checkboxen



Und wie ist das bei Checkboxen? Im Gegensatz zu anderen input-Elementen werden Name und Wert einer Checkbox nur an PHP geschickt, wenn die Checkbox angekreuzt wurde. Wenn neben den Checkboxen noch andere Felder im Formular sind, kann man zwar das vorige Muster benutzen, aber was, wenn das Formular nur aus Checkboxen besteht?

Ein Formular mit dem man Datensätze löschen kann, wäre ein Beispiel:

PHP Quellcode:
$select = 'SELECT id, frstname, lastname FROM users';
$result = mysql_query($select) or die (mysql_error());

echo '<form action="" method="post">';
while ($row = mysql_fetch_assoc($result)) {
    echo htmlspecialchars($row['frstname']), ' ';
    echo htmlspecialchars($row['lastname']), ' ';
    echo '<input name="row[]" value="', $row['id'], '" type="checkbox">';
}
echo '<input value="Lösche die ausgewählten Zeilen" type="submit">';
echo '</form>';


Die eckigen Klammern im Namen sind hier leer gelassen worden. Auch hier denkt PHP mit. Es vergibt einfach fortlaufende Schlüssel an die Felder. Das ist analog zu der Schreibweise, die in PHP selbst verwendet wird, um Elemente an ein Array anzuhängen:

PHP Quellcode:
$a = array();
$a[] = 1; $a[] = 2;
// $a ist jetzt gleich array(1,2)


Nehmen wir an der Benutzer habe das zweite und das vierte Feld angekreuzt, dann sieht $_POST so aus:

Code:
Array
(
    [row] => Array
        (
            [0] => 2
            [1] => 4
        )
)


Und so wertet man diese Variante aus:

PHP Quellcode:
if (isset($_POST['row']) && is_array($_POST['row'])) {
    foreach ($_POST['row'] as $id) {
        $delete = sprintf(
            'DELETE FROM users WHERE id = %u',
            (int)$id
        );
        mysql_query($delete) or die (mysql_error());
    }
}

// die Formularausgabe:

$select = 'SELECT id, frstname, lastname FROM users';
$result = mysql_query($select) or die (mysql_error());

echo '<form action="" method="post">';
while ($row = mysql_fetch_assoc($result)) {
    echo htmlspecialchars($row['frstname']), ' ';
    echo htmlspecialchars($row['lastname']), ' ';
    echo '<input name="row[]" value="', $row['id'], '" type="checkbox">';
}
echo '<input value="Lösche die ausgewählten Zeilen" type="submit">';
echo '</form>';


Eine kleine Nachbemerkung zu GET



Alle hier verwendeten Formulare verwenden POST. Theoretisch funktionieren diese Muster genau so gut mit GET. Aber besonders empfehlenswert ist das nicht, denn streng genommen sind eckige Klammern in URLs nicht erlaubt. Die meisten Browser erlauben sie zwar trotzdem, aber zwischengeschaltete Instanzen wie Gateways und Proxies sind vielleicht nicht so tolerant. Dann werden die Klammern in %5B und %5D umgewandelt. PHP ist es egal, ob die Klammern in Rohform oder urlenkodiert sind. Sie werden so oder so korrekt verarbeitet. Aber die URL sieht natürlich auf einmal ziemlich hässlich aus. Mehr noch: Sicherheitsbewusste User könnten diese "komischen" Zeichen in der URL als Warnsignal verstehen und abbrechen. Und wenn man solche "komischen" URLs irgendwo postet - in einem Forum z.B. - durchlaufen sie vielleicht irgendwelche Filter, die die eckigen Klammern rausschmeissen oder durch etwas noch komischeres ersetzen. Am Besten nutzt man diese Muster also nur bei POST.


Mitwirkende: pecos
Erstellt von pecos, 29.04.2010 am 00:18
Zuletzt bearbeitet von pecos, 29.04.2010 am 14:57
0 Kommentare , 8124 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
Deaktivieren von Formularfeldern losah PHP 2 03.04.2006 11:39
Auslesen auf Formularfeldern... boo PHP 1 01.11.2005 00:38
Problem mit Quotes und Formularfeldern r.kretzer PHP 6 01.04.2005 04:11
Daten aus Csv in Formularfeldern pivo PHP 3 27.03.2004 15:57
if abfrage aus formularfeldern lance PHP 2 03.11.2003 19:43


Alle Zeitangaben in WEZ +2. Es ist jetzt 13:09 Uhr.


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