Pe scurt: PHP accesează bazele de date prin două interfețe răspândite: PDO (PHP Data Objects) lucrează cu multe sisteme de baze de date printr-o interfață unitară, mysqli este croit pentru MySQL și MariaDB. Cu amândouă, Prepared Statements, adică interogări cu substituenți, protejează fiabil împotriva SQL injection. Din PHP 8.0 (PDO), respectiv 8.1 (mysqli), amândouă raportează implicit erorile ca excepții.
Cum comunică PHP cu bazele de date
Aproape orice aplicație PHP își stochează conținutul într-o bază de date: pagini, comenzi, conturi de utilizator, setări. Scriptul PHP stabilește pentru aceasta o conexiune, trimite o interogare în limbajul SQL și prelucrează rezultatul. Datele de acces se află de obicei într-un fișier de configurare de pe același server.
Pentru conducere este important, deoarece baza de date conține de obicei cele mai valoroase date ale companiei. Cine poate executa cod pe serverul web poate, de regulă, citi și fișierul de configurare și accesa baza de date cu aceste date de acces.
PDO și mysqli comparate
| Caracteristică | PDO | mysqli |
|---|---|---|
| Baze de date | multe, prin drivere precum PDO_MYSQL, PDO_PGSQL, PDO_SQLITE, PDO_SQLSRV, PDO_OCI |
MySQL și MariaDB |
| Substituenți | denumiți (:name) și pozițională (?) |
pozițională (?) |
| Stil | orientat pe obiecte | orientat pe obiecte și procedural |
| Erori ca excepție | implicit din PHP 8.0.0 | implicit din PHP 8.1.0 |
| Formă scurtă pentru interogări cu parametri | prepare() și execute() cu array |
execute_query() din PHP 8.2.0 |
În practică decide adesea framework-ul sau CMS-ul. Multe vin cu un strat propriu de baze de date, care folosește intern PDO sau mysqli. Cine preia o aplicație poate stabili printr-o căutare simplă în codul sursă ce interfață este folosită și unde apar interogările:
# Unde stabilește aplicația conexiuni, unde apar interogările?
grep -rn --include='*.php' -E 'new PDO|new mysqli|mysqli_connect|->query\(' /var/www/app/src | head -50
Locurile găsite cu ->query( nu sunt automat nesigure. Merită însă o a doua privire, pentru că acolo valorile pot ajunge direct în textul SQL, în loc să fie transmise prin substituenți. Mai ales proiectele mai vechi amestecă ambele stiluri, iar verificarea merită făcută înaintea oricărei actualizări mai mari.
Prepared Statements: modelul cel mai important
La un Prepared Statement, interogarea este trimisă bazei de date cu substituenți, iar valorile sunt transmise separat. Potrivit manualului PHP, aceasta protejează împotriva SQL injection dacă toate introducerile utilizatorului trec prin substituenți.
<?php
declare(strict_types=1);
$pdo = new PDO(
'mysql:host=localhost;dbname=shop;charset=utf8mb4',
$dbUser,
$dbPass,
[PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC]
);
$stmt = $pdo->prepare('SELECT id, name FROM kunden WHERE plz = :plz AND aktiv = :aktiv');
$stmt->execute(['plz' => $plz, 'aktiv' => 1]);
foreach ($stmt as $zeile) {
echo htmlspecialchars($zeile['name'], ENT_QUOTES, 'UTF-8'), "\n";
}
Același lucru cu mysqli, în forma scurtă care există din PHP 8.2:
<?php
$db = new mysqli('localhost', $dbUser, $dbPass, 'shop');
$ergebnis = $db->execute_query('SELECT id, name FROM kunden WHERE plz = ?', [$plz]);
foreach ($ergebnis as $zeile) {
echo htmlspecialchars($zeile['name'], ENT_QUOTES, 'UTF-8'), "\n";
}
Dezvoltatorii ar trebui să cunoască două limite. Substituenții nu trebuie puși între ghilimele; la căutările cu LIKE, caracterele joker % aparțin valorii transmise. Și substituenții înlocuiesc doar valori, nu nume de tabele sau de coloane. Cum se rezolvă sigur asemenea cazuri speciale arată ghidul Prevenirea SQL injection în PHP.
Tratarea erorilor: excepții în loc de erori silențioase
Înainte, ambele interfețe lucrau implicit silențios: o interogare eșuată returna false, iar cine nu verifica asta continua să lucreze cu date goale. Lucrurile s-au schimbat:
- PDO: Din PHP 8.0.0,
PDO::ERRMODE_EXCEPTIONeste valoarea implicită. Erorile aruncă oPDOException. - mysqli: Din PHP 8.1.0, raportarea erorilor este setată pe
MYSQLI_REPORT_ERRORșiMYSQLI_REPORT_STRICT. Erorile aruncă omysqli_sql_exception; înainte, raportarea era dezactivată.
Pentru securitate asta înseamnă: excepțiile trebuie interceptate și înregistrate în log, dar nu trebuie niciodată să ajungă în browser cu text SQL, nume de tabele sau date de acces. Cum se separă curat descrie pagina Erori și excepții în PHP.
Alocarea corectă a datelor de acces și a drepturilor
Baza de date este protejată doar cât sunt de bine protejate datele ei de acces. S-au dovedit utile aceste reguli:
- Utilizator propriu pentru fiecare aplicație: Nu folosiți niciodată administratorul bazei de date pentru site.
- Doar drepturile necesare: Un site are nevoie de obicei de citire, scriere, modificare și ștergere în propria bază de date, dar nu de drepturi asupra altor baze de date sau funcții ale serverului.
- Fără conexiune la distanță fără motiv: Baza de date ar trebui să fie accesibilă doar de la serverul web, nu din internet.
- Date de acces în afara webroot: Fișierele de configurare și
.envnu trebuie să poată fi accesate prin URL. Mai multe în articolul Protejarea datelor de acces și a fișierelor .env. - Conexiune criptată la servere separate: Dacă baza de date se află pe alt calculator, conexiunea ar trebui să fie criptată, pentru ca datele de acces și conținutul să nu circule în clar prin rețea.
- Accese proprii pentru mentenanță: Copiile de siguranță, analizele și administratorii primesc utilizatori proprii. Astfel se poate urmări în log cine ce a făcut și un acces poate fi blocat fără a deranja site-ul.
Baze de date, PHP2Shell și cazul critic
PHP2Shell nu privește baza de date însăși, ci interpretorul PHP: CVE-2026-109618 și CVE-2026-109619 permit executarea de cod malițios fără autentificare. Dacă reușește, codul rulează cu drepturile procesului PHP și poate astfel, de regulă, citi fișierul de configurare cu datele de acces la baza de date. Prepared Statements nu ajută împotriva acestui lucru, pentru că atacul nu trece deloc printr-o interogare SQL.
Obligatorie este de aceea actualizarea la PHP 8.5.12, 8.4.27, 8.3.36 sau 8.2.35 și repornirea tuturor proceselor PHP. Dacă există indicii ale unui atac reușit, fac parte din răspuns date noi de acces la baza de date, o verificare a bazei de date pentru conținut injectat și o evaluare a obligației de notificare conform RGPD. Aici este utilă o Incident Response structurată.
Schimbați parolele bazei de date abia după curățarea serverului. Cât timp rulează cod malițios, acesta poate citi din nou și noile date de acces.
Cum ajută PHP SOS concret?
- Verificăm cum accesează aplicația dumneavoastră baza de date și dacă utilizatorii, drepturile și accesul la rețea corespund minimului necesar.
- Controlăm dacă fișierele de configurare și de date de acces se află în afara webroot și nu sunt accesibile public.
- După un incident înnoim datele de acces în ordinea corectă și verificăm baza de date pentru cod injectat.
- Documentăm rezultatele astfel încât responsabilii cu protecția datelor și asigurătorii să le poată urmări.
Întrebări frecvente
Ar trebui să folosesc PDO sau mysqli?
Pentru proiecte noi, PDO este de obicei alegerea mai flexibilă, pentru că lucrează cu multe baze de date prin aceeași interfață. mysqli are sens dacă folosiți exclusiv MySQL sau MariaDB și aveți nevoie de funcțiile lor speciale. Ambele sunt sigure dacă Prepared Statements sunt folosite consecvent.
Aruncă PDO automat excepții la erori?
Da, din PHP 8.0.0, PDO::ERRMODE_EXCEPTION este valoarea implicită. Înainte era modul silențios, în care erorile puteau fi aflate doar prin errorCode() și errorInfo(). Aplicațiile mai vechi setează adesea încă explicit modul.
Pot substituenții să înlocuiască și nume de tabele sau de coloane?
Nu. Substituenții stau doar pentru valori. Numele de tabele și de coloane, de exemplu pentru o sortare, trebuie verificate față de o listă fixă de nume permise, înainte de a fi inserate în interogare.
Trebuie să schimb parola bazei de date după PHP2Shell?
Actualizarea singură nu o cere. Dacă există însă indicii că serverul a fost compromis, toate datele de acces din fișierele de configurare trebuie considerate cunoscute. Atunci ar trebui să le înnoiți după curățare.