# PHP și bazele de date: PDO și mysqli

> PHP și bazele de date explicat: PDO și mysqli comparate, Prepared Statements, tratarea erorilor din PHP 8 și date de acces sigure în exploatare.

Sursa: https://phpsos.de/ro/php/php-und-datenbanken/  
Stadiu: 25.10.2026  
Furnizor: PHP SOS, Asistență de urgență PHP și securitatea serverelor. Ajutor imediat pe WhatsApp: https://wa.me/491736494914?text=Bun%C4%83%20ziua%2C%20PHP%20SOS%2C%20avem%20nevoie%20de%20ajutor%20cu%20serverul%20nostru%20PHP.%20Firma%3A%20%E2%80%A6%20Site%3A%20%E2%80%A6

**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:

```bash
# 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
<?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
<?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](https://phpsos.de/ro/ratgeber/sql-injection-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_EXCEPTION` este valoarea implicită. Erorile aruncă o `PDOException`.
- **mysqli:** Din PHP 8.1.0, raportarea erorilor este setată pe `MYSQLI_REPORT_ERROR` și `MYSQLI_REPORT_STRICT`. Erorile aruncă o `mysqli_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](https://phpsos.de/ro/php/fehler-und-exceptions/).

## 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:

1. **Utilizator propriu pentru fiecare aplicație:** Nu folosiți niciodată administratorul bazei de date pentru site.
2. **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.
3. **Fără conexiune la distanță fără motiv:** Baza de date ar trebui să fie accesibilă doar de la serverul web, nu din internet.
4. **Date de acces în afara webroot:** Fișierele de configurare și `.env` nu trebuie să poată fi accesate prin URL. Mai multe în articolul [Protejarea datelor de acces și a fișierelor .env](https://phpsos.de/ro/blog/env-dateien-schuetzen/).
5. **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.
6. **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](https://phpsos.de/ro/leistungen/incident-response/) structurată.

> **Sfat:**
> 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.

## Surse

- [Manualul PHP: PDO Prepared Statements](https://www.php.net/manual/en/pdo.prepared-statements.php)
- [Manualul PHP: tratarea erorilor în PDO](https://www.php.net/manual/en/pdo.error-handling.php)
- [Manualul PHP: mysqli::execute_query](https://www.php.net/manual/en/mysqli.execute-query.php)
- [Manualul PHP: mysqli_driver::$report_mode](https://www.php.net/manual/en/mysqli-driver.report-mode.php)
