de.comp.lang.php.* FAQ

11.7. Wie kann ich aus einer Datenbanktabelle einen <select> erzeugen?

Keywords: select | Formular | LOV | option | Auswahlfeld | Liste | Menue | HTML

Antwort von Kristian Köhntopp

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.

Valid HTML 4.01! Valid CSS!

11.7. Wie kann ich aus einer Datenbanktabelle einen <select> erzeugen?
http://www.php-faq.de/q/q-formular-select.html
Archiv der de.comp.lang.php-FAQ Dies ist eine Archivseite von 2008 und wurde seitdem nicht geändert. Das dclp-FAQ-Team