Actuele situatie: PHP2Shell. Twee kritieke PHP-kwetsbaarheden (CVSS 9.2) maken schadelijke code zonder inloggen mogelijk. Patches sinds 21-10-2026.Wat u nu moet doen →

PHP en databases: PDO en mysqli

PHP spreekt databases aan via PDO of mysqli. Hier ziet u de verschillen, veilige query's met prepared statements en wat na een serverincident met databasetoegang te doen is.

Stand 5 min. leestijdPHP-kennis

Kort gezegd: PHP benadert databases via twee wijdverbreide interfaces: PDO (PHP Data Objects) werkt met veel databasesystemen via een uniforme interface, mysqli is toegesneden op MySQL en MariaDB. Met beide beschermen prepared statements, dus query's met plaatsaanduidingen, betrouwbaar tegen SQL-injectie. Sinds PHP 8.0 (PDO) respectievelijk 8.1 (mysqli) melden beide fouten standaard als exception.

Hoe PHP met databases praat

Vrijwel elke PHP-toepassing slaat haar inhoud op in een database: pagina's, bestellingen, gebruikersaccounts, instellingen. Het PHP-script bouwt daarvoor een verbinding op, stuurt een query in de taal SQL en verwerkt het resultaat. De toegangsgegevens staan meestal in een configuratiebestand op dezelfde server.

Voor de directie is dat belangrijk, omdat de database meestal de waardevolste gegevens van het bedrijf bevat. Wie code op de webserver kan uitvoeren, kan in de regel ook het configuratiebestand lezen en met deze toegangsgegevens bij de database komen.

PDO en mysqli vergeleken

Kenmerk PDO mysqli
Databases veel, via stuurprogramma's als PDO_MYSQL, PDO_PGSQL, PDO_SQLITE, PDO_SQLSRV, PDO_OCI MySQL en MariaDB
Plaatsaanduidingen benoemd (:name) en positioneel (?) positioneel (?)
Stijl objectgeoriënteerd objectgeoriënteerd en procedureel
Fouten als exception standaard sinds PHP 8.0.0 standaard sinds PHP 8.1.0
Verkorte vorm voor query's met parameters prepare() en execute() met array execute_query() sinds PHP 8.2.0

In de praktijk beslist vaak het framework of CMS. Veel ervan brengen een eigen databaselaag mee, die intern PDO of mysqli gebruikt. Wie een toepassing overneemt, kan met een eenvoudige zoekopdracht in de broncode vaststellen welke interface wordt gebruikt en waar query's ontstaan:

# Waar bouwt de toepassing verbindingen op, waar ontstaan query's?
grep -rn --include='*.php' -E 'new PDO|new mysqli|mysqli_connect|->query\(' /var/www/app/src | head -50

Vindplaatsen met ->query( zijn niet automatisch onveilig. Ze verdienen echter een tweede blik, omdat daar waarden rechtstreeks in de SQL-tekst kunnen belanden in plaats van via plaatsaanduidingen te worden doorgegeven. Juist oudere projecten mengen beide stijlen, en de controle loont vóór elke grotere update.

Prepared statements: het belangrijkste patroon

Bij een prepared statement wordt de query met plaatsaanduidingen naar de database gestuurd en worden de waarden afzonderlijk doorgegeven. Volgens de PHP-handleiding beschermt dat tegen SQL-injectie, als alle gebruikersinvoer via plaatsaanduidingen loopt.

<?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";
}

Hetzelfde met mysqli in de verkorte vorm die er sinds PHP 8.2 is:

<?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";
}

Twee grenzen moeten ontwikkelaars kennen. Plaatsaanduidingen mogen niet tussen aanhalingstekens staan; bij LIKE-zoekopdrachten horen de jokertekens % in de doorgegeven waarde. En plaatsaanduidingen vervangen alleen waarden, geen tabel- of kolomnamen. Hoe men zulke bijzondere gevallen veilig oplost, toont de gids SQL-injectie in PHP voorkomen.

Foutafhandeling: exceptions in plaats van stille fouten

Vroeger werkten beide interfaces standaard stil: een mislukte query leverde false op, en wie dat niet controleerde, werkte met lege gegevens verder. Dat is veranderd:

  • PDO: Sinds PHP 8.0.0 is PDO::ERRMODE_EXCEPTION de standaard. Fouten gooien een PDOException.
  • mysqli: Sinds PHP 8.1.0 staat de foutrapportage op MYSQLI_REPORT_ERROR en MYSQLI_REPORT_STRICT. Fouten gooien een mysqli_sql_exception; daarvoor was de rapportage uitgeschakeld.

Voor de beveiliging betekent dit: exceptions moeten worden afgevangen en vastgelegd, maar mogen nooit met SQL-tekst, tabelnamen of toegangsgegevens in de browser belanden. Hoe men dat netjes scheidt, beschrijft de pagina Fouten en exceptions in PHP.

Toegangsgegevens en rechten juist toewijzen

De database is maar zo goed beschermd als haar toegangsgegevens. Deze regels hebben zich bewezen:

  1. Eigen gebruiker per toepassing: Gebruik nooit de beheerder van de database voor de website.
  2. Alleen noodzakelijke rechten: Een website heeft meestal lezen, schrijven, wijzigen en verwijderen in haar eigen database nodig, maar geen rechten op andere databases of serverfuncties.
  3. Geen verbinding op afstand zonder reden: De database moet alleen vanaf de webserver bereikbaar zijn, niet vanaf het internet.
  4. Toegangsgegevens buiten de webroot: Configuratie- en .env-bestanden mogen niet via URL opvraagbaar zijn. Meer daarover in het artikel Toegangsgegevens en .env-bestanden beschermen.
  5. Versleutelde verbinding bij gescheiden servers: Staat de database op een andere machine, dan moet de verbinding versleuteld lopen, zodat toegangsgegevens en inhoud niet in klare tekst over het netwerk gaan.
  6. Eigen toegangen voor onderhoud: Back-up, analyses en beheerders krijgen eigen gebruikers. Zo is in het log na te gaan wie wat heeft gedaan, en kan een toegang worden geblokkeerd zonder de website te verstoren.

Databases, PHP2Shell en de noodsituatie

PHP2Shell raakt niet de database zelf, maar de PHP-interpreter: CVE-2026-109618 en CVE-2026-109619 maken het uitvoeren van schadelijke code zonder aanmelding mogelijk. Lukt dat, dan draait de code met de rechten van het PHP-proces en kan daarmee in de regel het configuratiebestand met de databasetoegangsgegevens lezen. Prepared statements helpen daartegen niet, omdat de aanval helemaal niet via een SQL-query loopt.

Verplicht is daarom de update naar PHP 8.5.12, 8.4.27, 8.3.36 of 8.2.35 en de herstart van alle PHP-processen. Zijn er aanwijzingen voor een geslaagde aanval, dan horen nieuwe databasetoegangsgegevens, een controle van de database op ingebrachte inhoud en een beoordeling van de meldplicht op grond van de AVG erbij. Een gestructureerde incident response is hier zinvol.

Tip

Wijzig databasewachtwoorden pas na de opschoning van de server. Zolang schadelijke code draait, kan die ook nieuwe toegangsgegevens weer uitlezen.

Hoe helpt PHP SOS concreet?

  • Wij controleren hoe uw toepassing de database benadert en of gebruikers, rechten en netwerktoegang het minimum benaderen.
  • Wij controleren of configuratie- en toegangsbestanden buiten de webroot staan en niet openbaar bereikbaar zijn.
  • Na een incident vernieuwen wij de toegangsgegevens in de juiste volgorde en controleren de database op ingebrachte code.
  • Wij documenteren de resultaten zo dat functionarissen voor gegevensbescherming en verzekeraars ze kunnen nalopen.

Veelgestelde vragen

Moet ik PDO of mysqli gebruiken?

Voor nieuwe projecten is PDO meestal de flexibelere keuze, omdat het met veel databases via dezelfde interface werkt. mysqli is zinvol als u uitsluitend MySQL of MariaDB gebruikt en hun speciale functies nodig hebt. Beide zijn veilig als prepared statements consequent worden gebruikt.

Gooit PDO bij fouten automatisch exceptions?

Ja, sinds PHP 8.0.0 is PDO::ERRMODE_EXCEPTION de standaard. Daarvoor gold de stille modus, waarin fouten alleen via errorCode() en errorInfo() op te vragen waren. Oudere toepassingen stellen de modus vaak nog uitdrukkelijk in.

Kunnen plaatsaanduidingen ook tabel- of kolomnamen vervangen?

Nee. Plaatsaanduidingen staan alleen voor waarden. Tabel- en kolomnamen, bijvoorbeeld voor een sortering, moeten tegen een vaste lijst van toegestane namen worden gecontroleerd voordat ze in de query worden gezet.

Moet ik na PHP2Shell het databasewachtwoord wijzigen?

De update alleen vereist dat niet. Zijn er echter aanwijzingen dat de server gecompromitteerd was, dan gelden alle toegangsgegevens in configuratiebestanden als bekend. Dan moet u ze na de opschoning vernieuwen.

Bronnen

Direct contact

Elk uur telt. Schrijf ons nu.

Beschrijf kort het systeem, de PHP-versie en wat u opmerkt. Wij nemen contact op, brengen de situatie in kaart en werken op afstand tot het incident is afgerond en gedocumenteerd.

Directe hulp