Parameter an eine MySQL-Query übergeben
5. Oktober 2008 | 01:56:54
Es gibt zwei verschiedene Wege, wie man mittels PHP Parameter an eine MySQL-Query übergeben kann.
Der erste Weg gestaltet sich im Prinzip wie folgt:
Der zweite Ansatz gibt den Parametern eine Reihen- bzw. Rangfolge (auch als argument-numbering bezeichnet):
Die Parameter kann man dann z.B. mittels folgender Methode übergeben:
Dabei sollte man die Reihenfolge genau beachten. Im oberen Beispiel 2 übergeben wir zwei verschiedene Parameter (einen ganzzahligen Wert und eine Zeichenkette) an die Positionen '1$' und '2$'. Falsch wäre es nun, wenn man die Position der Zeichenkette z.B. auf '3$' festlegen würde:
Warum sollte man den Ansatz aus Beispiel 2 eigentlich nutzen? Er sieht nicht nur komplexer aus als der Ansatz in Beispiel 1, er ist dazu auch noch um ein paar Zeichen länger. Was ist also der Vorteil?
Als Beispiel möchte ich meine Artikel-Suche nennen, denn hier nutze ich diesen Ansatz und erspare mir damit einige Zeilen zusätzlichen Code.
Wie man in Beispiel 4 sieht, muss man den Suchbegriff dreimal übergeben (je einen für jeden Platzhalter).
Mittels argument-numbering muss man dies nicht, hier reicht die Übergabe eines Arguments:
Nun ist meine Suchfunktion aber doch etwas komplexer als hier dargestellt. Es werden z.B. einige Bedingungen geprüft - z.B. ob Volltextsuche, Suche innerhalb der Kommentare, Suche über allen Kategorien usw. markiert wurde. Die Ergebnisse der Auswertung der Bedingungen haben natürlich Einfuß auf den Query-Formatstring, den man letztlich ausführen möchte. Das Problem war nun, dass ich nicht mehr alle Argumente einfach so durchnummerieren durfte. Folgendes einfachte Beispiel soll dies deutlich machen:
Welche Nummer soll ich den beiden unteren markierten Zeilen geben? Dies ist nicht ohne weiteres zu lösen, denn es ist nicht gesagt, dass immer über allen Jahren und in allen Kategorien gesucht werden soll. Beides ist möglich, oder keines von beiden oder jeweils eines von beiden. Eine feste Nummerierung kann man hier nicht anwenden.
Zur Lösung des Problems verwende ich eine Variable, die entsprechend hochgezählt wird:
Der erste Weg gestaltet sich im Prinzip wie folgt:
/* Beispiel 1 */
$query = "SELECT * FROM table WHERE (column1 = '%u') AND (column2 LIKE '%%%s%%');";Der zweite Ansatz gibt den Parametern eine Reihen- bzw. Rangfolge (auch als argument-numbering bezeichnet):
/* Beispiel 2 */
$query = "SELECT * FROM table WHERE (column1 = '%1\$u') AND
(column2 LIKE '%%%2\$s%%');";Die Parameter kann man dann z.B. mittels folgender Methode übergeben:
$res = $db->query( $query, array(10, "Hallo"));Dabei sollte man die Reihenfolge genau beachten. Im oberen Beispiel 2 übergeben wir zwei verschiedene Parameter (einen ganzzahligen Wert und eine Zeichenkette) an die Positionen '1$' und '2$'. Falsch wäre es nun, wenn man die Position der Zeichenkette z.B. auf '3$' festlegen würde:
/* Beispiel 3 - !!FEHLER IM FORMATSTRING!! */
$query = "SELECT * FROM table WHERE (column1 = '%1\$u') AND
(column2 LIKE '%%%3\$s%%');";Warum sollte man den Ansatz aus Beispiel 2 eigentlich nutzen? Er sieht nicht nur komplexer aus als der Ansatz in Beispiel 1, er ist dazu auch noch um ein paar Zeichen länger. Was ist also der Vorteil?
Als Beispiel möchte ich meine Artikel-Suche nennen, denn hier nutze ich diesen Ansatz und erspare mir damit einige Zeilen zusätzlichen Code.
Beispiel Artikel-Suche
Gibt man im Suchfeld dieser Seite einen Begriff, so wird eine Query gebaut, die (vereinfacht gesagt) in der Artikel-Tabelle die Spalten 'a_titel' (der Titel das Artikels), 'a_tags' (dem Artikel zugeordnete Tags) sowie 'a_inhalt' (den Artikelinhalt) nach dem eingegebenen Begriff durchsucht. Würde ich den ersten Ansatz nutzen, so hätte ich eine Query, die in etwa wie folgt aussieht:/* Beispiel 4 */
// der Query-Formatstring
$query = "SELECT * FROM table WHERE (a_titel LIKE '%%%s%%') OR
(a_tags LIKE '%%%s%%') OR
(a_inhalt LIKE '%%%s%%');";
// Formatstring und drei Parameter übergeben sowie die Query ausführen
$res = $db->query( $query, array( $suchbegriff, $suchbegriff, $suchbegriff ));
Wie man in Beispiel 4 sieht, muss man den Suchbegriff dreimal übergeben (je einen für jeden Platzhalter).
Mittels argument-numbering muss man dies nicht, hier reicht die Übergabe eines Arguments:
/* Beispiel 5 */
// der Query-Formatstring
$query = "SELECT * FROM table WHERE (a_titel LIKE '%%%1\$s%%') OR
(a_tags LIKE '%%%1\$s%%') OR
(a_inhalt LIKE '%%%1\$s%%');";
// Formatstring und einen Parameter übergeben sowie die Query ausführen
$res = $db->query( $query, array( $suchbegriff ));
Nun ist meine Suchfunktion aber doch etwas komplexer als hier dargestellt. Es werden z.B. einige Bedingungen geprüft - z.B. ob Volltextsuche, Suche innerhalb der Kommentare, Suche über allen Kategorien usw. markiert wurde. Die Ergebnisse der Auswertung der Bedingungen haben natürlich Einfuß auf den Query-Formatstring, den man letztlich ausführen möchte. Das Problem war nun, dass ich nicht mehr alle Argumente einfach so durchnummerieren durfte. Folgendes einfachte Beispiel soll dies deutlich machen:
/* Beispiel 6 */
query .= "SELECT ..., SUBSTRING(a_inhalt, 1, %1\$u) AS vorschau FROM t_artikel ... ";
if( $volltext_suche == true )
{
$query .= "WHERE (MATCH (a_title) AGAINST ('%2\$s' IN BOOLEAN MODE)";
...
}
else
{
$query .= "WHERE ((a_titel LIKE '%%%2\$s%%') OR (a_tags LIKE '%%%2\$s%%')";
...
}
if($suche_in_allen_jahren == false)
{
$query .= "AND YEAR(a_datum) = '%?\$s' ..."; // <-- welche Nummer?
}
if($suche_in_allen_kategorien == false)
{
$query .= "AND (a_kategorie_id = '%?\$u') ..."; // <-- welche Nummer?
}
Welche Nummer soll ich den beiden unteren markierten Zeilen geben? Dies ist nicht ohne weiteres zu lösen, denn es ist nicht gesagt, dass immer über allen Jahren und in allen Kategorien gesucht werden soll. Beides ist möglich, oder keines von beiden oder jeweils eines von beiden. Eine feste Nummerierung kann man hier nicht anwenden.
Zur Lösung des Problems verwende ich eine Variable, die entsprechend hochgezählt wird:
/* Beispiel 7 */
$i = 1
query .= "SELECT ..., SUBSTRING(a_inhalt, 1, %" . $i++ . "\$u) ...";
// ---> i = 2
if( $volltext_suche == true )
{
$query .= "WHERE (MATCH (a_title) AGAINST ('" . $i . "\$s' IN BOOLEAN MODE)";
...
}
else
{
$query .= "WHERE ((a_titel LIKE '%%%" . $i . "\$s%%') OR
(a_tags LIKE '%%%" . $i . "\$s%%')";
...
}
$i++;
// ---> i = 3
if($suche_in_allen_jahren == false)
{
$query .= "AND YEAR(a_datum) = '%" . $i++ . "\$s' ...";
}
// ---> i = 3 oder i = 4
if($suche_in_allen_kategorien == false)
{
$query .= "AND (a_kategorie_id = '%" . $i . "\$u') ...";
}


du müsstest hierbei noch erwähnen, wie die Methode DB::query() überhaupt funktioniert, also, wie sie die Werte des übergebenen Arrays in den Query integriert.
z.B. die Verwendung von
Aber warum schiebst du die ganzen Werte in ein zusätzliches Array? Du kannst sie doch direkt übergeben, denn so sparst du dir das Anlegen des Arrays und das Wiederauslesen der Werte aus dem Array.
cu cornfelt