Matthias: nur letzte value von Checkbox wird übergeben :(

Hallo ! :)

Ich habe mit PHP & HTML ein Formular erstellt, welches unter anderem ein paar Checkboxen enthält. Die Eingaben im Formular werte ich dann in einem anderen Script aus, um damit mysql Abfragen/Inserts zu machen. Alle Eingaben bekomme ich auch korrekt auf "der anderen Seite" an, ausser der value für die checkboxen ...

Ich habe in der Variable dann immer nur den Wert der als letzte angekreuzten Checkbox stehen?!

Wenn ich mir den Quelltext der Formularseite anschaue, haben auch alle Checkboxen den korrekten Wert als Value drinstehen und alle den selben Namen.

Hier mal ein Stück Code:

print "<td class="item_form_l">Usable by : </td>\n";
    print "<td><input type="checkbox" name="USABLE" value="All" checked>All<br>\n";

$QUERY    = "SELECT class FROM help_class order by class";
    $RESULT   = mysql_query($QUERY)
        or die($TEXT["sql_query_fail"]);
    $NUM_ROWS = mysql_num_rows($RESULT);

$COUNTER = 0;
    while ($COUNTER < $NUM_ROWS) {
        while ($ROW = mysql_fetch_array ($RESULT)) {
            print "<input type="checkbox" name="USABLE" value="$ROW[$COUNTER]">$ROW[$COUNTER]<br>\n";
        }

$COUNTER++;
    }

print "</td>\n";

In das Zieldokument habe ich dann mal als Test (damit ich nur ne Bildschirmausgabe bekomme und nicht immer sql Abfragen) folgenden Abbruch eingebaut:

print "USABLE BY : $USABLE"
   and die($TEXT["sql_query_fail"]);

Auf jeden Fall steht in $USABLE immer nur der Wert der "untersten" Checkbox drin. Also gehe ich mal davon aus, dass diese die anderen values überschrieben hat??

Was mache ich falsch?

Besten Dank, Matthias

  1. Hallo.

    nach meiner Erfahrung mag PHP solche Konstrukte bei der Ausgabe nicht: $ROW[$COUNTER]

    Über print "blabla".$ROW[$COUNTER]."blablub<br>"; sollte es klappen.

    Grüße aus Würzburg
    Julian

  2. Huhu

    probier es mal mit

    <input type="checkbox" name="USABLE[]">

    Viele Grüße

    lulu

  3. Aloha!

    Ich habe mit PHP & HTML ein Formular erstellt, welches unter anderem ein paar Checkboxen enthält. Die Eingaben im Formular werte ich dann in einem anderen Script aus, um damit mysql Abfragen/Inserts zu machen. Alle Eingaben bekomme ich auch korrekt auf "der anderen Seite" an, ausser der value für die checkboxen ...

    Ein typischer Fehler... Aber ich gehe einfach mal deinen Code durch, denn der läßt auch zu wünschen übrig.

    Hier mal ein Stück Code:

    print "<td class="item_form_l">Usable by : </td>\n";
        print "<td><input type="checkbox" name="USABLE" value="All" checked>All<br>\n";

    $QUERY    = "SELECT class FROM help_class order by class";
        $RESULT   = mysql_query($QUERY)
            or die($TEXT["sql_query_fail"]);

    Bis hierhin alles gut.

    $NUM_ROWS = mysql_num_rows($RESULT);

    Sowas braucht man eigentlich ganz selten mal.

    $COUNTER = 0;
        while ($COUNTER < $NUM_ROWS) {
            while ($ROW = mysql_fetch_array ($RESULT)) {

    Das erscheint mir irgendwie heftigst doppelt gemoppelt und kräftigst fehlerhaft!

    Was passiert? Du setzt $counter auf Null und beginnst eine WHILE-Schleife, welche solange läuft, bis $counter gleich $num_rows ist (an dieser Stelle der gutgemeinte Tipp: Variablennamen immer in Kleinbuchstaben - ist übersichtlicher).

    Dann startest du eine weitere Schleife, die solange aus der Datenbank liest, bis es nichts mehr zu lesen gibt. Die Inhalte der Datenbank werden als Checkbox ausgegeben, wobei immer das nullte Datenbankfeld verwendet wird - da es kein weiteres Datenbankfeld gibt, ist das in Ordnung.

    Wenn die Datenbank ausgelesen ist, wird der Counter erhöht, und die äußere Schleife beginnt von vorn.

    Da die innere Schleife die Datenbank bereits vollkommen ausgelesen hat, wird die innere Schleife nicht noch einmal begonnen, sonder _übersprungen_.

    Folglich zählt der Counter erneut um eins hoch, die äußere Schleife beginnt von vorn, die innere Schleife wird wieder übersprungen, der Counter zählt... solange, bis der Wert von $num_rows erreicht ist.

    Das ist definitiv nicht, was du willst. Das Skript macht nur _zufällig_ das, was du willst: Alle Felder der Datenbank auslesen und jeweils als Checkbox ausgeben.

    Nimm nur die innere Schleife und lass den Mist außenrum mit mysql_num_rows() weg.

    Die Schleife while ($row = mysql_fetch_array(...)) liest solange eine Zeile der Datenbank ein und macht etwas damit, solange es noch Daten gibt, andernfalls wird die Schleife verlassen. Den Counter benötigst du absolut nicht. Nimm einen konstanten Wert (sehr empfehlenswert ist, nicht einen numerischen Index zu verwenden, sondern den Hash-Namen: $ROW['class'] (class heißt die selektierte Datenbankspalte). Dann bleibt dein Code auch dann gültig, wenn du aus irgendwelchen Gründen etwas an der Datenbankabfrage änderst, beispielsweise noch ein zweites Feld abfragst - und dabei die Reihenfolge der Felder änderst.

    print "<input type="checkbox" name="USABLE" value="$ROW[$COUNTER]">$ROW[$COUNTER]<br>\n";
            }

    $COUNTER++;
        }

    print "</td>\n";

    In das Zieldokument habe ich dann mal als Test (damit ich nur ne Bildschirmausgabe bekomme und nicht immer sql Abfragen) folgenden Abbruch eingebaut:

    print "USABLE BY : $USABLE"
       and die($TEXT["sql_query_fail"]);

    Hier ist die nächste böse Falle: Du verläßt dich auf das eingeschaltete "register_globals", was eine recht teuflische Erfindung von PHP ist. Damit kann man nämlich schwach geschriebene Skripte prima knacken und Unheil anrichten. PHP hat für diese Art der Parameterverarbeitung ziemlich viele Prügel bezogen, weil es unsichere Programmierung extrem erleichtert.

    Was ist besser? PHP stellt dir zwei Arrays zur Verfügung, die Benutereingaben enthalten: $_GET und $_POST. In älteren PHP-Versionen heißen sie $HTTP_GET_VARS und $HTTP_POST_VARS.

    Wenn du ein GET-Formular oder URL-Parameter hast, stehen diese Daten in den GET-Variablen, hast du ein POST-Formular, stehen sie in den POST-Variablen.

    Außerdem musst du noch einen Trick anwenden, der in PHP notwendig ist, um solche mehrfach anfallenden Variablen übertragen zu können: Der Name in HTML muss auf "[]" enden, also in diesem Fall name="USABLE[]".

    Bezogen auf dein Beispiel kriegst du dann folgendes Ergebnis:
    $_GET['USABLE'] oder $_POST['USABLE'] (bzw. die langen Variablennamen) enthalten alle Checkboxen-Werte. Wie das? Ganz einfach, indem diese Variable ein Array ist. Wenn du mit var_dump($_GET['USABLE']); mal nachprüfst (bzw. bei umfangreichen Formularen einfach mal mit phpinfo(INFO_VARIABLES);), dann siehst du, welchen Variablentyp und welchen Inhalt die Variable hat.

    Mit anderen Worten:
    Du greifst auf die einzelnen Checkboxwerte mit $_GET['USABLE'][0] (statt 0 jeder weitere Index) zu.

    Warum sind "register_globals" jetzt aber böse? Naja, auf diese Weise kann dir ein Angreifer beliebige Variablen unterjubeln. Es ist ja nicht verpflichtet, nur die URL-Parameter zu benutzen, die du vorgesehen hast. Insbesondere hat er, wenn du z.B. ein POST-Formular hat, aber nicht $_POST auswertest, die leichte Möglichkeit, auch mit URL-Parametern dein Skript mit Daten zu füttern. Mögliche Konsequenz: Er schickt dir Mailbomben, indem er, anstatt mit POST das Formular zu schicken, was Mausklicks erfordert, einfach ständig das Auswerteskript mit URL-Parametern neu lädt. Opera bietet z.B. solche Möglichkeiten an, im Sekundentakt Seiten neu zu laden. Nach einer Minute hast du 60 Mails.

    Noch schlimmer: Wenn du Variablen im Skript vor ihrer ersten Verwendung nicht in jedem Fall initialisierst, kann der Angreifer diesen Variablen Anfangswerte mitgeben, die den Programmablauf beeinflussen können.

    Sicherheit gewinnst du, wenn register_globals auf off gesetzt wird - und der Zugriff auf $_GET und $_POST (außerdem gibts noch $_COOKIES, $_SERVER, $_ENV und $_FILES) stellt sicher, dass du wirklich nur die POST-Werte verarbeitest - eben weil das reguläre Formular nur POST schicken kann, kein GET. Besser ist das.

    - Sven Rautenberg

    1. Hallo zusammen,

      vielen Dank (besonders Sven für die sehr ausführlichen Erklärungen) für Eure Hilfe. Ich werde dann gleich mal testen ... :)

      Das mit der doppelten while Schleife hat mir auch nicht gefallen, aber anders habe ich keine Ergebnisse bekommen :(
      Das lag aber, wie es aussieht, an meiner fehlerhaften Programmierung also jagte wohl ein Folgefehler den anderen ;)

      Wenn noch was nicht klappt, poste ich nochmal ...

      Beste Grüsse, Matthias