Die Regeln zur Hinzufügung einer PHP-Variablen in eine MySQL-Anweisung sind einfach und klar:
1. Verwenden Sie vorbereitete Anweisungen
Diese Regel deckt 99% der Abfragen und Ihre Abfrage im Besonderen ab. Jede Variable, die ein SQL-Datenliteral repräsentiert, (oder einfacher ausgedrückt - eine SQL-Zeichenfolge oder eine Zahl) MUSS über eine vorbereitete Anweisung hinzugefügt werden. Keine Ausnahmen. Ein konstanter Wert kann so eingefügt werden.
Dieser Ansatz beinhaltet vier grundlegende Schritte
- ersetzen Sie in Ihrer SQL-Anweisung alle Variablen durch Platzhalter
- vorbereiten Sie die resultierende Abfrage
- binden Sie Variablen an die Platzhalter
- führen Sie die Abfrage aus
Und so wird es mit allen populären PHP-Datenbanktreibern gemacht:
Hinzufügen von Datenliteralen mit mysqli
Ab PHP 8.2 können Sie die gesamte Vorbereitungs-/Bindungs-/Ausführungsfolge in einem Aufruf durchführen:
$type = 'testing';
$reporter = "John O'Hara";
$sql = "INSERT INTO contents (type,reporter,description) VALUES ('whatever',?,?)";
$mysqli->execute_query($sql, [$reporter, $description]);
Wenn Ihre PHP-Version alt ist, dann muss Vorbereiten/Binden/Ausführen explizit gemacht werden:
$type = 'testing';
$reporter = "John O'Hara";
$sql = "INSERT INTO contents (type,reporter,description) VALUES ('whatever',?,?)";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param("ss", $reporter, $description);
$stmt->execute();
Der Code ist etwas kompliziert, aber eine ausführliche Erklärung aller dieser Operatoren finden Sie in meinem Artikel Wie man eine INSERT-Abfrage mit Mysqli ausführt, sowie eine Lösung, die den Prozess erheblich erleichtert.
Für eine SELECT-Abfrage können Sie dieselbe Methode wie oben verwenden:
$reporter = "John O'Hara";
$result = $mysqli->execute_query("SELECT * FROM users WHERE name=?", [$reporter]);
$row = $result->fetch_assoc(); // oder while (...)
Aber wieder, wenn Ihre PHP-Version alt ist, müssen Sie den Vorbereitungs-/Bindungs-/Ausführungsprozess durchlaufen und auch einen Aufruf der get_result()
-Methode hinzufügen, um ein vertrautes mysqli_result
zu erhalten, aus dem Sie die Daten auf übliche Weise abrufen können:
$reporter = "John O'Hara";
$stmt = $mysqli->prepare("SELECT * FROM users WHERE name=?");
$stmt->bind_param("s", $reporter);
$stmt->execute();
$result = $stmt->get_result();
$row = $result->fetch_assoc(); // oder while (...)
Hinzufügen von Datenliteralen mit PDO
$type = 'testing';
$reporter = "John O'Hara";
$sql = "INSERT INTO contents (type,reporter,description) VALUES ('whatever',?,?)";
$stmt = $pdo->prepare($sql);
$stmt->execute([$reporter, $description]);
In PDO können Bindungs- und Ausführungsteile kombiniert werden, was sehr praktisch ist. PDO unterstützt auch benannte Platzhalter, die einige als äußerst praktisch empfinden.
2. Verwenden Sie White-Listen-Filterung
Jeder andere Abfrageteil, wie SQL-Schlüsselwort, Tabelle oder Feldname oder Operator, muss durch eine White-Liste gefiltert werden.
Manchmal müssen wir eine Variable hinzufügen, die einen anderen Teil einer Abfrage darstellt, wie ein Schlüsselwort oder einen Bezeichner (einen Datenbank-, Tabellen- oder Feldnamen). Es ist ein seltener Fall, aber es ist besser, vorbereitet zu sein.
In diesem Fall muss Ihre Variable gegen eine Liste von Werten explizit geprüft werden, die in Ihrem Skript festgelegt sind. Dies wird in meinem anderen Artikel erklärt, Hinzufügen eines Feldnamens in die ORDER BY-Klausel basierend auf der Wahl des Benutzers:
Leider hat PDO keinen Platzhalter für Bezeichner (Tabellen- und Feldnamen), daher muss ein Entwickler sie manuell filtern. Ein solcher Filter wird oft als "White-Liste" bezeichnet (wo wir nur erlaubte Werte auflisten) im Gegensatz zu einer "Black-Liste", wo wir nicht erlaubte Werte auflisten.
Also müssen wir alle möglichen Varianten im PHP-Code explizit auflisten und dann daraus auswählen.
Hier ist ein Beispiel:
$orderby = $_GET['orderby'] ?: "name"; // setze den Standardwert
$allowed = ["name","price","qty"]; // die White-Liste erlaubter Feldnamen
$key = array_search($orderby, $allowed, true); // prüfen, ob wir einen solchen Namen haben
if ($key === false) {
throw new InvalidArgumentException("Ungültiger Feldname");
}
Der gleiche Ansatz sollte auch für die Richtung verwendet werden,
$direction = $_GET['direction'] ?: "ASC";
$allowed = ["ASC","DESC"];
$key = array_search($direction, $allowed, true);
if ($key === false) {
throw new InvalidArgumentException("Ungültige ORDER BY-Richtung");
}
Nach einem solchen Code können sowohl die Variablen $direction
als auch $orderby
sicher in die SQL-Abfrage eingefügt werden, da sie entweder einem der erlaubten Varianten entsprechen oder ein Fehler geworfen wird.
Zum Schluss muss noch erwähnt werden, dass Bezeichner auch entsprechend der spezifischen Datenbankensyntax formatiert werden müssen. Für MySQL sollten es backtick
-Zeichen um den Bezeichner sein. Die endgültige Abfragezeichenfolge für unser Beispiel des ORDER BY würde also sein
$query = "SELECT * FROM `table` ORDER BY `$orderby` $direction";
15 Stimmen
WICHTIG: Das direkte Einfügen von Variablen in Ihren SQL-Befehl ist eine Hauptursache von SQL Injection Attacken