real_escape_string
Erläuterung der Funktion mysqli_real_escape_string() in PHP: Syntax, Zeichensatz-Hinweis, Unterschied zu mysql_* und warum Prepared Statements besser sind.
Die Funktion mysqli_real_escape_string() maskiert Sonderzeichen in einem String, sodass er sicher in eine SQL-Abfrage eingefügt werden kann. Diese Seite erklärt, was die Funktion tut, ihre Syntax und ihren Rückgabewert, den Zeichensatz-Fallstrick, das veraltete mysql_real_escape_string(), das sie ersetzt, und warum Prepared Statements heute die bessere Wahl sind.
Was mysqli_real_escape_string() macht
Wenn Sie eine SQL-Abfrage durch direktes Verketten von Benutzereingaben in den Abfrage-String erstellen, beendet ein Wert wie O'Reilly den zitierten String vorzeitig, und der Rest wird als SQL interpretiert. Ein Angreifer kann dies ausnutzen, um Daten zu lesen, zu ändern oder zu löschen — ein SQL-Injection-Angriff.
mysqli_real_escape_string() verhindert dies, indem vor den Zeichen, die innerhalb eines MySQL-String-Literals eine besondere Bedeutung haben, Backslashes eingefügt werden: einfaches Anführungszeichen ', doppeltes Anführungszeichen ", Backslash \, NUL-Byte, Zeilenumbruch \n, Wagenrücklauf \r und Strg+Z. Nach der Maskierung ist der Wert sicher zwischen Anführungszeichen in eine Abfrage einzubetten.
Er heißt „real", weil er den Zeichensatz der Verbindung berücksichtigt und daher auch bei Multi-Byte-Kodierungen korrekt maskiert — etwas, das das ältere addslashes() nicht kann.
Syntax
mysqli_real_escape_string(mysqli $connection, string $string): string| Parameter | Beschreibung |
|---|---|
$connection | Ein von mysqli_connect() zurückgegebener Link. Die Funktion benötigt ihn, um den Zeichensatz der Verbindung zu kennen. |
$string | Der zu maskierende String. |
Die Funktion gibt den maskierten String zurück. Beachten Sie, dass sie die umgebenden Anführungszeichen nicht hinzufügt — Sie müssen '$escaped' in der Abfrage selbst schreiben.
Im objektorientierten Stil rufen Sie sie als Methode auf: $mysqli->real_escape_string($string).
Verwendung
<?php
$con = mysqli_connect('localhost', 'username', 'password', 'database');
if (!$con) {
exit('Could not connect: ' . mysqli_error($con));
}
// Set charset to prevent multi-byte character vulnerabilities
mysqli_set_charset($con, 'utf8mb4');
$name = "John O'Reilly";
$name = mysqli_real_escape_string($con, $name);
$sql = "INSERT INTO customers (name) VALUES ('$name')";
if (!mysqli_query($con, $sql)) {
exit('Error: ' . mysqli_error($con));
}
echo '1 record added';
mysqli_close($con);
?>Hier stellen wir mit mysqli_connect() eine Verbindung her, definieren $name mit einem einfachen Anführungszeichen und maskieren es. Der maskierte Wert John O\'Reilly wird sicher in den '$name'-Platzhalter eingefügt, sodass das INSERT ohne Syntaxfehler und ohne eine Injection-Lücke ausgeführt wird. Unter Daten in MySQL einfügen finden Sie den vollständigen Insert-Ablauf.
Zeichensatz zuerst setzen
mysqli_real_escape_string() maskiert nur dann korrekt, wenn die Verbindung ihren Zeichensatz kennt. Rufen Sie mysqli_set_charset() immer direkt nach dem Verbindungsaufbau auf:
mysqli_set_charset($con, 'utf8mb4');Wird dieser Schritt bei bestimmten Kodierungen (insbesondere GBK) übersprungen, entsteht ein Multi-Byte-Injection-Vektor, bei dem der maskierende Backslash von einer Multi-Byte-Sequenz „aufgefressen" wird. Das Setzen des Zeichensatzes auf der Verbindung — nicht nur in der Abfrage — schließt diese Lücke.
Was die Funktion nicht schützt
Das Maskieren macht einen Wert innerhalb eines zitierten String-Literals sicher. Es macht Werte nicht sicher an Stellen, an denen keine Anführungszeichen verwendet werden können — Tabellen- und Spaltennamen, LIMIT-Zahlen oder Schlüsselwörter. Maskieren Sie niemals einen Bezeichner und fügen Sie ihn in eine Abfrage ein; validieren Sie ihn stattdessen anhand einer Erlaubnisliste.
// WRONG — escaping does nothing useful for an identifier
$column = mysqli_real_escape_string($con, $_GET['sort']);
$sql = "SELECT * FROM users ORDER BY $column"; // still injectable
// RIGHT — allow-list
$allowed = ['name', 'email', 'created_at'];
$column = in_array($_GET['sort'], $allowed, true) ? $_GET['sort'] : 'name';mysql_real_escape_string() vs mysqli_real_escape_string()
Das alte mysql_real_escape_string() (ohne i) gehörte zur ursprünglichen mysql_*-Erweiterung, die in PHP 7 entfernt wurde. Verwenden Sie die mysqli_*-Version — oder PDO — auf jedem modernen PHP. Wenn Sie sie ohne eine aktive Verbindung aufrufen, öffnet sie stillschweigend eine Standard-Verbindung und gibt eine Warnung aus, was ein weiterer Grund für ihre Abschaffung war.
Prepared Statements bevorzugen
Maskieren funktioniert, setzt aber voraus, dass Sie nie einen einzigen Wert vergessen. Prepared Statements sind sicherer, weil das Abfrage-Template und die Daten getrennt übertragen werden, sodass Benutzereingaben die Struktur der Abfrage niemals verändern können:
<?php
$con = mysqli_connect('localhost', 'username', 'password', 'database');
mysqli_set_charset($con, 'utf8mb4');
$stmt = mysqli_prepare($con, 'INSERT INTO customers (name) VALUES (?)');
mysqli_stmt_bind_param($stmt, 's', $name);
$name = "John O'Reilly"; // no manual escaping needed
mysqli_stmt_execute($stmt);
echo '1 record added';
mysqli_close($con);
?>Verwenden Sie mysqli_real_escape_string(), wenn Sie wirklich dynamisches SQL manuell aufbauen müssen; greifen Sie ansonsten auf mysqli_prepare() zurück. Eine Übersicht der Erweiterung finden Sie unter PHP MySQLi.
Fazit
mysqli_real_escape_string() maskiert die Sonderzeichen, die andernfalls ein SQL-String-Literal beschädigen oder ausgenutzt werden könnten. Setzen Sie zuerst den Verbindungs-Zeichensatz, denken Sie daran, dass die Funktion für Bezeichner nichts bewirkt, und bevorzugen Sie wo immer möglich Prepared Statements.