Majoritatea bazelor de date performante suportă conceptul de prepared statements. Ce sunt acestea? Pot fi considerate un fel de şabloane compilate pentru SQL care pot fi rulate şi care pot fi particularizate folosind ca parametri diverse variabile. Prepared statements oferă două mari beneficii:
1. Interogarea trebuie parcursă (sau pregătită - prepared) o singură dată, dar poate fi executată de mai multe ori folosind aceiaşi sau alţi parametri. La pregătirea interogării, baza de date va analiza, compila şi optimiza propriul plan pentru executarea interogării. Pentru interogări complexe, acest proces poate dura destul de mult, astfel încetinind aplicaţia în cazul în care se repetă aceeaşi interogare de mai multe ori, folosind parametri diferiţi. Utilizând prepared statement se evită repetarea ciclului analiză/compilare/optimizare. Pe scurt, prepared statements foloseşte mai puţine resurse, deci rulează mai repede.
2. Parametrii pentru prepared statements nu trebuie să fie între ghilimele; driverul face acest lucru. Dacă aplicaţia foloseşte doar prepared statements, atunci nu pot interveni injecţii SQL. (Dar dacă se folosesc în alte părţi interogări fără prepared statements, există riscul injecţiilor SQL). Prepared statements sunt atât de utile încât PDO le emulează pentru drivere care nu le suportă. Astfel se poate folosi aceeaşi informaţie de acces la baza de date.
Inserări repetate folosind prepared statements
Acest exemplu realizează o interogare INSERT prin înlocuirea parametrilor name şi value în placeholders.
<?php
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);
// inserarea unui rand
$name = 'one';
$value = 1;
$stmt->execute();
// inserarea altui rand cu valori diferite
$name = 'two';
$value = 2;
$stmt->execute();
?>
Inserări repetate folosind prepared statements
Acest exemplu realizează o interogare INSERT prin înlocuirea parametrilor name şi value în poziţiile ? din placeholders.
<?php
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (?, ?)");
$stmt->bindParam(1, $name);
$stmt->bindParam(2, $value);
// inserarea unui rand
$name = 'one';
$value = 1;
$stmt->execute();
// inserarea altui rand cu valori diferite
$name = 'two';
$value = 2;
$stmt->execute();
?>
Culegerea datelor folosind prepared statements
Aceste exemplu culege date în funcţie de valoarea unei chei obţinută dintr-un formular. Valoarea introdusă de utilizator este pusă automat între ghilimele, deci nu sunt riscuri de atac cu injecţii SQL. Există păreri care contrazic invulnerabilitatea PDO.
<?php
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name = ?");
if ($stmt->execute(array($_GET['name']))) {
while ($row = $stmt->fetch()) {
print_r($row);
}
}
?>
Unele drivere pot suporta parametri bind pentru afişare date. Parametrii pentru ieşire sunt folosiţi de obicei din procedurile stocate - stored procedures. Parametrii de ieşire sunt puţin mai complecşi faţă de parametrii de intrare. Dacă valoarea întoarsă este mai mare decât mărimea sugerată, apare o eroare.
Apelarea unei proceduri stocate cu un parametru de ieşire
<?php
$stmt = $dbh->prepare("CALL sp_returns_string(?)");
$stmt->bindParam(1, $return_value, PDO::PARAM_STR, 4000);
// apelarea procedurii stocate stored procedure
$stmt->execute();
print "Procedura intoarsa $return_value\n";
?>
Pot fi specificaţi parametrii care conţin valori de intrare şi ieşire. Sintaxa este similară cu parametrii de ieşire. În exemplul următor, textul 'hello' este trecut într-o procedură stored procedure, şi când este întors, este înlocuit cu valoarea din procedură.
Apelarea unei proceduri stocate cu parametri de input/output
<?php
$stmt = $dbh->prepare("CALL sp_takes_string_returns_string(?)");
$value = 'hello';
$stmt->bindParam(1, $value, PDO::PARAM_STR|PDO::PARAM_INPUT_OUTPUT, 4000);
// apelare stored procedure
$stmt->execute();
print "Procedura intoarsa $value\n";
?>
Folosirea incorectă a unui placeholder (substituent)
<?php
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name LIKE '%?%'");
$stmt->execute(array($_GET['name']));
// placeholder trebuie folosit în locul întregii valori
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name LIKE ?");
$stmt->execute(array("%$_GET[name]%"));
?>