W3docs

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
ParametroDescrizione
$connectionUn link restituito da mysqli_connect(). La funzione ne ha bisogno per conoscere il charset della connessione.
$stringLa 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.

Esercitazione

Pratica
Cosa fa la funzione PHP mysql_real_escape_string?
Cosa fa la funzione PHP mysql_real_escape_string?
Was this page helpful?