Salta ai contenuti

Query preparate

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

Questo e pericoloso:

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

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

Una query preparata separa la struttura della query dai valori.

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

:email e un placeholder, cioe un segnaposto. Il valore vero arriva dopo, in modo controllato.

<?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 non vengono incollati nella query.

Ogni volta che una query usa dati esterni, usa prepare ed execute con placeholder. E una delle abitudini piu 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 piu 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 perche 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 incollato $email nella stringa. Il valore deve entrare tramite placeholder.