Salta ai contenuti
Manuale LogoManuale Logo

Query preparate

Quando una query contiene dati inseriti dall’utente, non devi inserirli direttamente nella stringa SQL.

Questo è pericoloso:

<?php
$sql = "SELECT * FROM utenti WHERE email = '$email'";

Se $email contiene testo malevolo, la query può cambiare significato. Questo rischio si chiama SQL injection.

Una query preparata separa la struttura della query dai suoi valori.

<?php
$sql = "SELECT * FROM utenti WHERE email = :email";
$stmt = $pdo->prepare($sql);
$stmt->execute(["email" => $email]);
$utente = $stmt->fetch();

:email è un placeholder, cioè un segnaposto. Il valore effettivo arriva dopo, separato dalla query.

<?php
$email = $_POST["email"] ?? "";
$stmt = $pdo->prepare("SELECT * FROM utenti WHERE email = :email");
$stmt->execute(["email" => $email]);
$utente = $stmt->fetch();
if ($utente) {
echo "Utente trovato";
}

fetch legge una riga. Se non ci sono risultati, restituisce false.

<?php
$stmt = $pdo->prepare(
"INSERT INTO utenti (nome, email) VALUES (:nome, :email)"
);
$stmt->execute([
"nome" => $nome,
"email" => $email,
]);

Anche qui i valori restano separati dalla query.

Ogni volta che una query usa dati esterni, usa prepare ed execute con placeholder. È una delle abitudini più importanti per scrivere PHP sicuro con i database.

Oltre ai placeholder con nome, puoi usare ?.

<?php
$stmt = $pdo->prepare("SELECT * FROM utenti WHERE email = ?");
$stmt->execute([$email]);

Funziona bene per query piccole. I placeholder con nome sono spesso più leggibili quando i valori sono molti.

Per una lista di risultati usa fetchAll.

<?php
$stmt = $pdo->prepare("SELECT * FROM prodotti WHERE prezzo < :massimo");
$stmt->execute(["massimo" => 20]);
$prodotti = $stmt->fetchAll();
foreach ($prodotti as $prodotto) {
echo $prodotto["nome"] . "\n";
}

La query resta sicura perché il valore 20 viene passato separatamente.

Errore comune: preparare e poi incollare lo stesso

Sezione intitolata “Errore comune: preparare e poi incollare lo stesso”

Questo non va bene:

<?php
$stmt = $pdo->prepare("SELECT * FROM utenti WHERE email = '$email'");

Anche se usi prepare, hai comunque inserito $email nella stringa. Il valore deve passare attraverso un placeholder.