real_escape_string
Scopri la funzione mysqli_real_escape_string() in PHP per evitare caratteri speciali nelle stringhe usate nelle query SQL e prevenire SQL injection.
La funzione mysqli_real_escape_string() esegue l'escape dei caratteri speciali in una stringa in modo che possa essere inserita in sicurezza in una query SQL. Questa pagina spiega cosa fa la funzione, la sua sintassi e il valore restituito, il problema del charset che la può rendere inefficace, la funzione deprecata mysql_real_escape_string() che ha sostituito, e perché le istruzioni preparate sono oggi la scelta migliore.
Cosa fa mysqli_real_escape_string()
Quando si costruisce una query SQL concatenando direttamente l'input dell'utente nella stringa della query, un valore come O'Reilly chiude la stringa citata anzitempo e il resto viene interpretato come SQL. Un attaccante può sfruttare questo per leggere, modificare o cancellare dati — un attacco di SQL injection.
mysqli_real_escape_string() lo previene aggiungendo backslash davanti ai caratteri che hanno un significato speciale all'interno di un letterale stringa MySQL: la virgoletta singola ', la virgoletta doppia ", il backslash \, il byte NUL, il newline \n, il ritorno a capo \r e Ctrl+Z. Dopo l'escape, il valore può essere incorporato in sicurezza tra virgolette in una query.
È "real" perché consulta il set di caratteri della connessione, eseguendo l'escape correttamente anche per le codifiche multi-byte — qualcosa che la più vecchia addslashes() non può fare.
Sintassi
mysqli_real_escape_string(mysqli $connection, string $string): string| Parametro | Descrizione |
|---|---|
$connection | Un link restituito da mysqli_connect(). La funzione ne ha bisogno per conoscere il charset della connessione. |
$string | La stringa di cui eseguire l'escape. |
Restituisce la stringa con l'escape applicato. Si noti che non aggiunge le virgolette di contorno — è necessario scrivere '$escaped' nella query manualmente.
In stile orientato agli oggetti, si chiama come metodo: $mysqli->real_escape_string($string).
Come si usa
<?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);
?>Qui ci connettiamo con mysqli_connect(), definiamo $name con una virgoletta singola e applichiamo l'escape. Il valore con escape John O\'Reilly si inserisce in sicurezza nel segnaposto '$name', quindi l'INSERT viene eseguito senza errori di sintassi e senza aprire una falla di injection. Vedi Inserire dati in MySQL per il flusso completo di inserimento.
Prima impostare il charset
mysqli_real_escape_string() esegue l'escape correttamente solo se la connessione conosce il suo set di caratteri. Chiamare sempre mysqli_set_charset() subito dopo la connessione:
mysqli_set_charset($con, 'utf8mb4');Omettere questo passaggio con certe codifiche (in particolare GBK) lascia aperto un vettore di injection multi-byte in cui il backslash di escape viene "assorbito" da una sequenza multi-byte. Impostare il charset sulla connessione — non solo nella query — chiude quella falla.
Cosa non protegge
L'escape rende un valore sicuro all'interno di un letterale stringa tra virgolette. Non rende i valori sicuri nei punti in cui non si possono usare le virgolette — nomi di tabelle e colonne, numeri LIMIT o parole chiave. Non eseguire mai l'escape di un identificatore per inserirlo in una query; validarlo invece contro una lista di valori consentiti.
// 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()
La vecchia mysql_real_escape_string() (senza i) apparteneva all'estensione originale mysql_*, che è stata rimossa in PHP 7. Usare la versione mysqli_* — o PDO — su qualsiasi PHP moderno. Se viene chiamata senza una connessione attiva apre silenziosamente una connessione predefinita ed emette un avviso, il che è un altro motivo per cui è stata ritirata.
Preferire le istruzioni preparate
L'escape funziona, ma richiede di non dimenticare mai un singolo valore. Le istruzioni preparate sono più sicure perché il template della query e i dati viaggiano separatamente, quindi l'input dell'utente non può mai modificare la struttura della query:
<?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);
?>Usare mysqli_real_escape_string() quando si deve necessariamente costruire SQL dinamico a mano; ricorrere a mysqli_prepare() in tutti gli altri casi. Per una panoramica dell'estensione, vedere PHP MySQLi.
Conclusione
mysqli_real_escape_string() esegue l'escape dei caratteri speciali che altrimenti interromperebbero — o verrebbero sfruttati in — un letterale stringa SQL. Impostare prima il charset della connessione, ricordare che non fa nulla per gli identificatori, e preferire le istruzioni preparate ogni volta che è possibile.