Stručně: PHP přistupuje k databázím přes dvě rozšířená rozhraní: PDO (PHP Data Objects) pracuje s mnoha databázovými systémy přes jednotné rozhraní, mysqli je přizpůsobeno MySQL a MariaDB. U obou spolehlivě chrání před SQL injection prepared statements, tedy dotazy se zástupnými symboly. Od PHP 8.0 (PDO) resp. 8.1 (mysqli) hlásí obě rozhraní chyby standardně jako výjimku.
Jak PHP komunikuje s databázemi
Téměř každá aplikace PHP ukládá svůj obsah do databáze: stránky, objednávky, uživatelské účty, nastavení. Skript PHP k tomu naváže spojení, pošle dotaz v jazyce SQL a zpracuje výsledek. Přístupové údaje bývají uloženy v konfiguračním souboru na stejném serveru.
Pro vedení firmy je to důležité, protože databáze obsahuje většinou nejcennější data podniku. Kdo může na webovém serveru spustit kód, může zpravidla přečíst i konfigurační soubor a těmito přístupovými údaji se dostat do databáze.
PDO a mysqli v porovnání
| Vlastnost | PDO | mysqli |
|---|---|---|
| Databáze | mnoho, přes ovladače jako PDO_MYSQL, PDO_PGSQL, PDO_SQLITE, PDO_SQLSRV, PDO_OCI |
MySQL a MariaDB |
| Zástupné symboly | pojmenované (:name) i poziční (?) |
poziční (?) |
| Styl | objektově orientovaný | objektově orientovaný i procedurální |
| Chyby jako výjimka | výchozí od PHP 8.0.0 | výchozí od PHP 8.1.0 |
| Zkrácený zápis dotazů s parametry | prepare() a execute() s polem |
execute_query() od PHP 8.2.0 |
V praxi často rozhoduje framework nebo CMS. Mnohé přinášejí vlastní databázovou vrstvu, která interně používá PDO nebo mysqli. Kdo aplikaci přebírá, může jednoduchým hledáním ve zdrojovém kódu zjistit, které rozhraní se používá a kde dotazy vznikají:
# Kde aplikace navazuje spojení, kde vznikají dotazy?
grep -rn --include='*.php' -E 'new PDO|new mysqli|mysqli_connect|->query\(' /var/www/app/src | head -50
Nálezy s ->query( nejsou automaticky nebezpečné. Zaslouží si ale druhý pohled, protože tam se hodnoty mohou dostat přímo do textu SQL místo předání přes zástupné symboly. Právě starší projekty míchají oba styly a kontrola se vyplatí před každou větší aktualizací.
Prepared statements: nejdůležitější vzor
U prepared statement se dotaz pošle databázi se zástupnými symboly a hodnoty se předají odděleně. Podle příručky PHP to chrání před SQL injection, pokud všechny vstupy uživatele procházejí přes zástupné symboly.
<?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";
}
Totéž s mysqli ve zkráceném zápisu, který existuje od 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";
}
Vývojáři by měli znát dvě hranice. Zástupné symboly nesmějí stát v uvozovkách; u vyhledávání pomocí LIKE patří zástupné znaky % do předávané hodnoty. A zástupné symboly nahrazují jen hodnoty, nikoli názvy tabulek nebo sloupců. Jak takové zvláštní případy bezpečně řešit, ukazuje průvodce Prevence SQL injection v PHP.
Zpracování chyb: výjimky místo tichých chyb
Dříve obě rozhraní standardně pracovala tiše: neúspěšný dotaz vrátil false a kdo to nezkontroloval, pokračoval s prázdnými daty. To se změnilo:
- PDO: Od PHP 8.0.0 je výchozí
PDO::ERRMODE_EXCEPTION. Chyby vyvolajíPDOException. - mysqli: Od PHP 8.1.0 je hlášení chyb nastaveno na
MYSQLI_REPORT_ERRORaMYSQLI_REPORT_STRICT. Chyby vyvolajímysqli_sql_exception; dříve bylo hlášení vypnuto.
Pro bezpečnost to znamená: výjimky je třeba zachytávat a zaznamenávat, nikdy však nesmějí skončit v prohlížeči s textem SQL, názvy tabulek nebo přístupovými údaji. Jak to čistě oddělit, popisuje stránka Chyby a výjimky v PHP.
Správně přidělovat přístupové údaje a oprávnění
Databáze je chráněna jen tak dobře jako její přístupové údaje. Osvědčila se tato pravidla:
- Vlastní uživatel pro každou aplikaci: Nikdy nepoužívat pro web administrátora databáze.
- Jen nutná oprávnění: Web většinou potřebuje čtení, zápis, změny a mazání ve své vlastní databázi, ale žádná oprávnění k jiným databázím nebo funkcím serveru.
- Žádné vzdálené spojení bez důvodu: Databáze by měla být dostupná jen z webového serveru, nikoli z internetu.
- Přístupové údaje mimo webroot: Konfigurační soubory a soubory
.envnesmějí být dostupné přes URL. Více v článku Ochrana přístupových údajů a souborů .env. - Šifrované spojení při oddělených serverech: Pokud je databáze na jiném počítači, mělo by spojení probíhat šifrovaně, aby přístupové údaje a obsah nešly sítí v otevřeném textu.
- Vlastní přístupy pro údržbu: Zálohování, vyhodnocení a správci dostanou vlastní uživatele. V logu pak lze dohledat, kdo co udělal, a přístup lze zablokovat, aniž by to rušilo web.
Databáze, PHP2Shell a krizový případ
PHP2Shell se netýká samotné databáze, ale interpretu PHP: CVE-2026-109618 a CVE-2026-109619 umožňují spuštění škodlivého kódu bez přihlášení. Pokud se to podaří, kód běží s oprávněními procesu PHP a může tak zpravidla přečíst konfigurační soubor s přístupovými údaji k databázi. Prepared statements proti tomu nepomáhají, protože útok vůbec neprobíhá přes dotaz SQL.
Povinná je proto aktualizace na PHP 8.5.12, 8.4.27, 8.3.36 nebo 8.2.35 a restart všech procesů PHP. Pokud existují náznaky úspěšného útoku, patří k postupu nové přístupové údaje k databázi, kontrola databáze na vložený obsah a posouzení oznamovací povinnosti podle GDPR. Zde je vhodná strukturovaná reakce na incident.
Hesla k databázi měňte až po vyčištění serveru. Dokud běží škodlivý kód, může nové přístupové údaje opět přečíst.
Jak konkrétně pomáhá PHP SOS?
- Zkontrolujeme, jak vaše aplikace přistupuje k databázi, a zda uživatelé, oprávnění a síťový přístup odpovídají nezbytnému minimu.
- Ověříme, zda konfigurační soubory a soubory s přístupovými údaji leží mimo webroot a nejsou veřejně dostupné.
- Po incidentu obnovíme přístupové údaje ve správném pořadí a zkontrolujeme databázi na vložený kód.
- Výsledky zdokumentujeme tak, aby je pověřenci pro ochranu osobních údajů a pojišťovny mohli dohledat.
Časté dotazy
Mám používat PDO, nebo mysqli?
Pro nové projekty je PDO většinou flexibilnější volba, protože pracuje s mnoha databázemi přes stejné rozhraní. mysqli dává smysl, pokud používáte výhradně MySQL nebo MariaDB a potřebujete jejich zvláštní funkce. Obě jsou bezpečná, pokud se důsledně používají prepared statements.
Vyhazuje PDO při chybách automaticky výjimky?
Ano, od PHP 8.0.0 je výchozí PDO::ERRMODE_EXCEPTION. Dříve platil tichý režim, ve kterém bylo možné chyby zjistit jen přes errorCode() a errorInfo(). Starší aplikace tento režim často nastavují výslovně.
Mohou zástupné symboly nahrazovat i názvy tabulek nebo sloupců?
Ne. Zástupné symboly stojí jen za hodnoty. Názvy tabulek a sloupců, například pro řazení, je třeba před vložením do dotazu ověřit proti pevnému seznamu povolených názvů.
Musím po PHP2Shell změnit heslo k databázi?
Samotná aktualizace to nevyžaduje. Pokud ale existují náznaky, že byl server kompromitován, považují se všechny přístupové údaje v konfiguračních souborech za známé. Pak byste je měli po vyčištění obnovit.