WCF 2: Zugriff auf die Datenbank – Teil 2

  • WCF 2

Achtung: Diese Seite ist nur noch Teil eines Archivs und wird in Zukunft entfernt.

Nach einer etwas längeren Pause geht es nun mit der Tutorial-Reihe weiter.

Wie schon im letzten Tutorial meinerseits angekündigt, wird dieses Tutorial nun auf die direkte Nutzung von SQL-Abfragen in Form von vorbereiteten Anweisungen (Prepared Statements) für die Datenbank eingegangen.
Diese Form von SQL-Abfragen hat den entscheidenden Vorteil, dass sogenannte SQL-Injections (Einschleusung von nicht gewollten Inhalten) effektiv verhindert werden, da keine Parameterwerte direkt übergeben werden, sondern in Form von Platzhaltern in den Abfragen stehen.

Um zu verdeutlichen, einmal folgende Abfrage im direkten Vergleich:

SQL-Abfrage

  1. SELECT email
  2. FROM wcf1_user
  3. WHERE userID = 456;

SQL-Abfrage

  1. SELECT email
  2. FROM wcf1_user
  3. WHERE userID = ?;
Durch die Verwendung der Variante 1 war es in WoltLab Community Framework 1.x (WCF 1) grundsätzlich notwendig, dass die Parameterwerte vor Ausführung der Abfragen mit PHP-Methoden validiert wurden. Dadurch hat man im WCF1 an den Stellen, wo Abfragen ausgeführt werden sollten, Quellcodezeilen wie folgt vorgefunden:

PHP-Quellcode

  1. $sql = "SELECT *
  2. FROM wcf".WCF_N. "_user
  3. WHERE username = ".escapeString($this->username);
Oder:

PHP-Quellcode

  1. $sql = "SELECT *
  2. FROM wcf".WCF_N. "_user
  3. WHERE userID = ".intval($this->userID);
Die Erstellung von Abfragen, welche escapeString() oderintval() beinhalten, fällt komplett weg, da jeder Parameterwert durch ein Fragezeichen in der Abfrage ersetzt wird. intval() wird natürlich noch bei der Validierung von Integer-Werten verwendet, wie es beispielsweise bei Formulareingaben der Fall ist.

Bei den Platzhaltern kümmert sich der Datenbanktreiber um die entsprechende Validierung, nachdem die einzelnen Werte bei der Ausführung des vorbereiteten Statements übergeben wurden.

Doch wie werden diese Abfragen mit den Fragezeichen nun über das Framework an die Datenbank gesendet?

Die Interaktion mit dem im Hintergrund laufenden Datenbanksystem geschieht grundsätzlich erst mal über einen Aufruf von WCF::getDB() welches das aktuelle Datenbankobjekt (PDO) zurückliefert.
Anschließend wollen wir, dass der Datenbanktreiber die eigene SQL-Abfrage, welche in der Variable $sql steht (siehe oben), vorbereitet. Dazu muss die Funktion prepareStatement() mit der übergebenden Abfrage aufgerufen werden und das zurückgelieferte Statement gespeichert werden, da dieses wiederum noch ausgeführt werden muss.

PHP-Quellcode

  1. $statement = WCF::getDB()->prepareStatement($sql);
Um das Vorhaben zu verdeutlichen, bereiten wir die Anfangs genannte SQL-Abfrage vor:

PHP-Quellcode

  1. $sql = "SELECT email
  2. FROM wcf".WCF_N. "_user
  3. WHERE userID = ?";
  4. $statement = WCF::getDB()->prepareStatement($sql);
Dadurch, dass dem Datenbanktreiber schließlich die Struktur der Tabelle wcf1_user bekannt ist, kann dieser ableiten, dass das Attribut userID unter anderem vom Typ INT(10) ist und somit sicherstellen, dass die Abfrage an dieser Stelle nur einen Wert in Form eines Integer haben kann/sollte. Ihr bekommt durch das Ausführen der Methode prepareStatement() übrigens eine Instanz der Klasse wcf\system\database\statement\PreparedStatement zurück.

So weit, so gut, aber wie kann man mit der vorbereiteten Abfrage nun die E-Mail-Adresse des Benutzers mit der ID 456 auslesen?
Dazu liefert die Klasse PreparedStatement die Methode execute(), welche als Übergabeparameter optional eine Liste von Parametern in Form eines (mehr-)dimensionalen Arrays akzeptiert.
Würden wir nun die vorbereitete Abfrage mit der benannten Methode und dem Übergabeparameter 456 einmal ausführen, sähe der Quellcode folgendermaßen aus:

PHP-Quellcode

  1. $statement->execute(array(456));
Um das Ergebnis der Abfrage in Empfang zu nehmen, führen wir nun die Methode fetchArray() aus und speichern die Rückgabe in einer weiteren Variable.

PHP-Quellcode

  1. $row = $statement->fetchArray();

Über $row['email'] hätte ich nun Zugriff auf die E-Mail-Adresse des Benutzers mit der ID 456, sollte dieser in der Datenbank existieren. Damit man keinen „Undefined index: …”-Fehler bekommt, sollte der Benutzer in der Datenbank nicht existieren, ist es angebracht, vorher eine Prüfung durchzuführen, welche im Gesamtkontext folgendermaßen aussehen kann:

PHP-Quellcode

  1. $sql = "SELECT userID
  2. FROM wcf".WCF_N."_user
  3. WHERE userID = ?";
  4. $statement = WCF::getDB()->prepareStatement($sql);
  5. $statement->execute(array(456));
  6. $row = $statement->fetchArray();
  7. if ($row !== false) {
  8. // Abfrage brachte ein Ergebnis
  9. $userID = $row['userID'];
  10. }
Ich hoffe, dass ich euch mithilfe dieses Tutorials mit der direkten Interaktion mit der Datenbank über die Möglichkeiten des Community Frameworks vertraut machen konnte. Sollte Fragen vorhanden sein, so bitte ich euch, ein Thema im Forum zu erstellen, da die Kommentarfunktion für ausführliche Hilfestellung leider ungeeignet ist.

Im nächsten Tutorial wird euch die Nutzung des „PreparedConditionBuilder” erklärt, womit ihr ganz einfach WHERE- bzw. OR-Klauseln erstellen könnt und damit Datenbankabfragen noch einfacher gestaltet werden können.

Teil 11: Inhalt mit jQuery dynamisch manupulieren
Über den Autor
Keine Angabe

927 mal gelesen

Kommentare 2

  • FragenÜberFragen -

    Könntest du ein Tutorial zur Datenbank schreiben, indem du wie in dem PlugIn examplePage alles von 0 - 100 machst?

    Ich kapiere einfach nicht wie ich die WCF-Klassen einbinde, wann ich eine neue Klasse machen muss und Co.

  • Fabii -

    Im letzten Abschnitt steht "PreparedConditionBuilder" anstatt korrekterweise "PreparedStatementConditionBuilder" ;)