# PHP ja andmebaasid: PDO ja mysqli

> PHP ja andmebaasid selgitatud: PDO ja mysqli võrdlus, Prepared Statements, veakäsitlus alates PHP 8-st ning turvalised ligipääsuandmed käitamisel.

Allikas: https://phpsos.de/et/php/php-und-datenbanken/  
Seis: 25.10.2026  
Pakkuja: PHP SOS, PHP hädaabi ja serveri turvalisus. Kohene abi WhatsAppis: https://wa.me/491736494914?text=Tere%2C%20PHP%20SOS%2C%20vajame%20abi%20oma%20PHP-serveriga.%20Ettev%C3%B5te%3A%20%E2%80%A6%20Veebisait%3A%20%E2%80%A6

**Lühidalt:** PHP pöördub andmebaaside poole kahe levinud liidese kaudu: PDO (PHP Data Objects) töötab paljude andmebaasisüsteemidega ühtse liidese kaudu, mysqli on kohandatud MySQL-ile ja MariaDB-le. Mõlemaga kaitsevad Prepared Statements ehk kohatäitjatega päringud usaldusväärselt SQL-injektsiooni eest. Alates PHP 8.0-st (PDO) ja 8.1-st (mysqli) teatavad mõlemad vigadest vaikimisi erandina.

## Kuidas PHP andmebaasidega suhtleb

Peaaegu iga PHP rakendus salvestab oma sisu andmebaasi: lehed, tellimused, kasutajakontod, sätted. PHP skript loob selleks ühenduse, saadab päringu SQL-keeles ja töötleb tulemuse. Ligipääsuandmed asuvad enamasti seadistusfailis samas serveris.

Juhtkonna jaoks on see oluline, sest andmebaas sisaldab enamasti ettevõtte kõige väärtuslikumaid andmeid. Kes saab veebiserveris koodi käivitada, saab tavaliselt lugeda ka seadistusfaili ja nende ligipääsuandmetega andmebaasi poole pöörduda.

## PDO ja mysqli võrdluses

| Tunnus | PDO | mysqli |
|---|---|---|
| Andmebaasid | paljud, draiverite kaudu nagu `PDO_MYSQL`, `PDO_PGSQL`, `PDO_SQLITE`, `PDO_SQLSRV`, `PDO_OCI` | MySQL ja MariaDB |
| Kohatäited | nimelised (`:name`) ja positsioonilised (`?`) | positsioonilised (`?`) |
| Stiil | objektorienteeritud | objektorienteeritud ja protseduuriline |
| Vead erandina | vaikimisi alates PHP 8.0.0 | vaikimisi alates PHP 8.1.0 |
| Lühivorm parameetritega päringuteks | `prepare()` ja `execute()` massiiviga | `execute_query()` alates PHP 8.2.0 |

Praktikas otsustab sageli raamistik või CMS. Paljudel on oma andmebaasikiht, mis kasutab seespidiselt PDO-d või mysqli-d. Kes rakenduse üle võtab, saab lähtekoodist lihtsa otsinguga kindlaks teha, millist liidest kasutatakse ja kus päringud tekivad:

```bash
# Kus rakendus ühendusi loob, kus päringud tekivad?
grep -rn --include='*.php' -E 'new PDO|new mysqli|mysqli_connect|->query\(' /var/www/app/src | head -50
```

Leiukohad, kus on `->query(`, ei ole automaatselt ebaturvalised. Need väärivad siiski teist pilku, sest seal võivad väärtused sattuda otse SQL-teksti, selle asemel et need kohatäidete kaudu edasi anda. Just vanemad projektid segavad mõlemat stiili ja kontroll tasub end ära enne iga suuremat uuendust.

## Prepared Statements: kõige olulisem muster

Prepared Statement'i puhul saadetakse päring kohatäidetega andmebaasi ja väärtused antakse eraldi. PHP käsiraamatu järgi kaitseb see SQL-injektsiooni eest, kui kõik kasutaja sisestused jooksevad kohatäidete kaudu.

```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";
}
```

Sama mysqli-ga lühivormis, mis on olemas alates PHP 8.2-st:

```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";
}
```

Kaks piiri peaksid arendajad teadma. Kohatäited ei tohi olla jutumärkides; `LIKE`-otsingute puhul kuuluvad kohatäitemärgid `%` edastatavasse väärtusesse. Ja kohatäited asendavad ainult väärtusi, mitte tabeli- ega veerunimesid. Kuidas selliseid erijuhte turvaliselt lahendada, näitab juhend [SQL-injektsiooni vältimine PHP-s](https://phpsos.de/et/ratgeber/sql-injection-php/).

## Veakäsitlus: erandid vaikivate vigade asemel

Varem töötasid mõlemad liidesed vaikimisi vaikselt: ebaõnnestunud päring tagastas `false` ja kes seda ei kontrollinud, töötas edasi tühjade andmetega. See on muutunud:

- **PDO:** Alates PHP 8.0.0-st on `PDO::ERRMODE_EXCEPTION` vaikeväärtus. Vead viskavad `PDOException`.
- **mysqli:** Alates PHP 8.1.0-st on veateatamine seatud väärtustele `MYSQLI_REPORT_ERROR` ja `MYSQLI_REPORT_STRICT`. Vead viskavad `mysqli_sql_exception`; varem oli teatamine välja lülitatud.

Turvalisuse jaoks tähendab see: erandid tuleb kinni püüda ja logida, kuid need ei tohi kunagi sattuda brauserisse koos SQL-teksti, tabelinimede või ligipääsuandmetega. Kuidas seda puhtalt eraldada, kirjeldab leht [Vead ja erandid PHP-s](https://phpsos.de/et/php/fehler-und-exceptions/).

## Ligipääsuandmed ja õigused õigesti anda

Andmebaas on kaitstud ainult nii hästi kui selle ligipääsuandmed. Need reeglid on end õigustanud:

1. **Oma kasutaja iga rakenduse jaoks:** Ärge kunagi kasutage veebisaidi jaoks andmebaasi administraatorit.
2. **Ainult vajalikud õigused:** Veebisait vajab enamasti lugemist, kirjutamist, muutmist ja kustutamist oma andmebaasis, kuid mitte õigusi teistele andmebaasidele ega serverifunktsioonidele.
3. **Kaugühendust ilma põhjuseta mitte:** Andmebaas peaks olema kättesaadav ainult veebiserverist, mitte internetist.
4. **Ligipääsuandmed väljaspool veebijuurt:** Seadistus- ja `.env` failid ei tohi olla URL-i kaudu kättesaadavad. Lisateavet artiklis [Ligipääsuandmete ja .env failide kaitsmine](https://phpsos.de/et/blog/env-dateien-schuetzen/).
5. **Krüpteeritud ühendus eraldi serverite korral:** Kui andmebaas asub teises arvutis, peaks ühendus olema krüpteeritud, et ligipääsuandmed ja sisu ei liiguks võrgus selgetekstina.
6. **Oma ligipääsud hoolduseks:** Andmete varundus, aruanded ja administraatorid saavad omad kasutajad. Nii saab logist jälgida, kes mida tegi, ja ühe ligipääsu saab sulgeda, veebisaiti segamata.

## Andmebaasid, PHP2Shell ja halvim stsenaarium

PHP2Shell ei puuduta andmebaasi ennast, vaid PHP interpretaatorit: CVE-2026-109618 ja CVE-2026-109619 võimaldavad kahjuliku koodi käivitamist ilma sisselogimiseta. Kui see õnnestub, töötab kood PHP protsessi õigustega ja saab seega tavaliselt lugeda andmebaasi ligipääsuandmetega seadistusfaili. Prepared Statements selle vastu ei aita, sest rünnak ei käi üldse SQL-päringu kaudu.

Kohustuslik on seetõttu uuendus versioonile PHP 8.5.12, 8.4.27, 8.3.36 või 8.2.35 ja kõigi PHP protsesside taaskäivitus. Kui on viiteid edukale rünnakule, kuuluvad juurde uued andmebaasi ligipääsuandmed, andmebaasi kontroll sissetoodud sisu suhtes ja teavitamiskohustuse hindamine IKÜM-i järgi. Siin on mõistlik struktureeritud [Incident Response](https://phpsos.de/et/leistungen/incident-response/).

> **Näpunäide:**
> Muutke andmebaasiparoole alles pärast serveri puhastamist. Seni kuni kahjulik kood töötab, saab see ka uued ligipääsuandmed uuesti välja lugeda.

## Kuidas PHP SOS konkreetselt aitab?

- Kontrollime, kuidas teie rakendus andmebaasi poole pöördub ning kas kasutajad, õigused ja võrgupääs vastavad miinimumile.
- Kontrollime, kas seadistus- ja ligipääsufailid asuvad väljaspool veebijuurt ega ole avalikult kättesaadavad.
- Pärast intsidenti uuendame ligipääsuandmed õiges järjekorras ja kontrollime andmebaasi sissetoodud koodi suhtes.
- Dokumenteerime tulemused nii, et andmekaitsespetsialistid ja kindlustajad saavad neid jälgida.


## Korduma kippuvad küsimused

**Kas peaksin kasutama PDO-d või mysqli-d?**  
Uute projektide jaoks on PDO enamasti paindlikum valik, sest see töötab paljude andmebaasidega sama liidese kaudu. mysqli on mõistlik, kui kasutate ainult MySQL-i või MariaDB-d ja vajate nende eriomadusi. Mõlemad on turvalised, kui Prepared Statements'i järjekindlalt kasutatakse.

**Kas PDO viskab vigade korral automaatselt erandeid?**  
Jah, alates PHP 8.0.0-st on PDO::ERRMODE_EXCEPTION vaikeväärtus. Varem oli see vaikne režiim, kus vigu sai pärida ainult funktsioonidega errorCode() ja errorInfo(). Vanemad rakendused seavad režiimi sageli ikka selgesõnaliselt.

**Kas kohatäited saavad asendada ka tabeli- või veerunimesid?**  
Ei. Kohatäited on ainult väärtuste jaoks. Tabeli- ja veerunimed, näiteks sorteerimiseks, tuleb enne päringusse panemist kontrollida lubatud nimede kindla nimekirja vastu.

**Kas pean pärast PHP2Shelli andmebaasi parooli muutma?**  
Uuendus üksi seda ei nõua. Kui on aga viiteid, et server oli kompromiteeritud, loetakse kõik seadistusfailides olevad ligipääsuandmed teadaolevaks. Siis tuleks need pärast puhastamist uuendada.

## Allikad

- [PHP käsiraamat: PDO Prepared Statements](https://www.php.net/manual/en/pdo.prepared-statements.php)
- [PHP käsiraamat: PDO veakäsitlus](https://www.php.net/manual/en/pdo.error-handling.php)
- [PHP käsiraamat: mysqli::execute_query](https://www.php.net/manual/en/mysqli.execute-query.php)
- [PHP käsiraamat: mysqli_driver::$report_mode](https://www.php.net/manual/en/mysqli-driver.report-mode.php)
