Tabellen- und Spaltennamen können in PDO NICHT durch Parameter ersetzt werden.
In diesem Fall möchten Sie die Daten einfach manuell filtern und bereinigen. Eine Möglichkeit, dies zu tun, besteht darin, Kurzparameter an die Funktion zu übergeben, die die Abfrage dynamisch ausführt, und dann mithilfe einer switch()
Anweisung eine weiße Liste gültiger Werte zu erstellen, die für den Tabellennamen oder den Spaltennamen verwendet werden sollen. Auf diese Weise wird keine Benutzereingabe direkt in die Abfrage eingegeben. Also zum Beispiel:
function buildQuery( $get_var )
{
switch($get_var)
{
case 1:
$tbl = 'users';
break;
}
$sql = "SELECT * FROM $tbl";
}
Indem Sie keinen Standardfall belassen oder einen Standardfall verwenden, der eine Fehlermeldung zurückgibt, stellen Sie sicher, dass nur Werte verwendet werden, die Sie verwenden möchten.
array('u'=>'users', 't'=>'table', 'n'=>'nonsensitive_data')
default
. Wenn dieses Muster verwenden, sollten Sie entweder einen Ihrer beschriftencase
s alsdefault
, oder fügen Sie eine explizite Fehlerfall wiedefault: throw new InvalidArgumentException;
if ( in_array( $tbl, ['users','products',...] ) { $sql = "SELECT * FROM $tbl"; }
. Danke für die Idee.mysql_real_escape_string()
. Vielleicht kann ich es hier sagen, ohne dass jemandUm zu verstehen, warum das Binden eines Tabellen- (oder Spalten-) Namens nicht funktioniert, müssen Sie verstehen, wie die Platzhalter in vorbereiteten Anweisungen funktionieren: Sie werden nicht einfach durch (entsprechend maskierte) Zeichenfolgen ersetzt und die resultierende SQL ausgeführt. Stattdessen erstellt ein DBMS, das aufgefordert wird, eine Anweisung "vorzubereiten", einen vollständigen Abfrageplan für die Ausführung dieser Abfrage, einschließlich der verwendeten Tabellen und Indizes, die unabhängig davon, wie Sie die Platzhalter ausfüllen, identisch sind.
Der Plan für
SELECT name FROM my_table WHERE id = :value
ist derselbe, den Sie ersetzen:value
, aber der scheinbar ähnliche PlanSELECT name FROM :table WHERE id = :value
kann nicht geplant werden, da das DBMS keine Ahnung hat, aus welcher Tabelle Sie tatsächlich auswählen werden.Dies kann oder sollte auch keine Abstraktionsbibliothek wie PDO umgehen, da dies die beiden Hauptziele vorbereiteter Anweisungen zunichte machen würde: 1) Damit die Datenbank im Voraus entscheiden kann, wie eine Abfrage ausgeführt wird, und diese verwenden kann mehrmals planen; und 2) um Sicherheitsprobleme zu verhindern, indem die Logik der Abfrage von der Variableneingabe getrennt wird.
quelle
TOP
/LIMIT
/OFFSET
-Klauseln an, sodass dies als Feature etwas fehl am Platz wäre.Ich sehe, dass dies ein alter Beitrag ist, aber ich fand ihn nützlich und dachte, ich würde eine Lösung teilen, die der von @kzqai vorgeschlagenen ähnelt:
Ich habe eine Funktion, die zwei Parameter empfängt wie ...
Im Inneren überprüfe ich anhand von Arrays, die ich eingerichtet habe, um sicherzustellen, dass nur Tabellen und Spalten mit "gesegneten" Tabellen zugänglich sind:
Dann sieht die PHP-Prüfung vor dem Ausführen von PDO wie folgt aus ...
quelle
$pdo->query($sql)
Die Verwendung der ersteren ist von Natur aus nicht sicherer als die der letzteren. Sie müssen die Eingabe bereinigen, unabhängig davon, ob sie Teil eines Parameterarrays oder einer einfachen Variablen ist. Ich sehe also nichts Falsches daran, das letztere Formular mit zu verwenden
$table
, vorausgesetzt, Sie stellen sicher, dass der Inhalt von$table
sicher ist (Alphanum plus Unterstriche?), Bevor Sie es verwenden.quelle
(Späte Antwort, konsultieren Sie meine Randnotiz).
Die gleiche Regel gilt beim Versuch, eine "Datenbank" zu erstellen.
Sie können keine vorbereitete Anweisung zum Binden einer Datenbank verwenden.
Dh:
wird nicht funktionieren. Verwenden Sie stattdessen eine Sicherheitsliste.
Randnotiz: Ich habe diese Antwort hinzugefügt (als Community-Wiki), weil sie häufig zum Schließen von Fragen verwendet wurde, bei denen einige Personen ähnliche Fragen stellten, als sie versuchten, eine Datenbank und keine Tabelle und / oder Spalte zu binden .
quelle
Ein Teil von mir fragt sich, ob Sie so einfach Ihre eigene Desinfektionsfunktion bereitstellen könnten:
Ich habe nicht wirklich darüber nachgedacht, aber es scheint, als würde alles entfernt, außer Zeichen und Unterstrichen.
quelle
MyLongTableName
gespeichert. Beispiel : Es ist leicht, richtig zu lesen. Wenn Sie jedoch den gespeicherten Namen überprüfen, ist dies (wahrscheinlich)MYLONGTABLENAME
nicht sehr lesbar und daherMY_LONG_TABLE_NAME
besser lesbar.Select * From $table
. Eine Whitelist oder eine strikte Musterübereinstimmung (z. B. "Namen, die mit report_ beginnen, gefolgt von nur 1 bis 3 Ziffern") sind hier wirklich wichtig.Was die Hauptfrage in diesem Thread betrifft, haben die anderen Beiträge deutlich gemacht, warum wir bei der Vorbereitung von Anweisungen keine Werte an Spaltennamen binden können. Hier ist eine Lösung:
Das Obige ist nur ein Beispiel, daher funktioniert Kopieren-> Einfügen natürlich nicht. Passen Sie es an Ihre Bedürfnisse an. Dies bietet möglicherweise keine 100% ige Sicherheit, ermöglicht jedoch eine gewisse Kontrolle über die Spaltennamen, wenn diese als dynamische Zeichenfolgen "eingehen" und auf Benutzerseite geändert werden können. Darüber hinaus ist es nicht erforderlich, ein Array mit den Namen und Typen Ihrer Tabellenspalten zu erstellen, da diese aus dem Informationsschema extrahiert werden.
quelle