Kort gezegd: Op een live website hoort display_errors = Off in de php.ini, samen met display_startup_errors = Off, log_errors = On en een foutenlog buiten de webroot. Daarnaast moeten CMS'en en frameworks in productiemodus draaien, anders tonen hun eigen foutpagina's de details. Vergrendeld met php_admin_flag en na elke update gecontroleerd, blijven fouten in het log in plaats van in de browser.
Wat één enkele foutmelding verraadt
Een waarschuwing bovenaan de pagina, een „Fatal error” in plaats van het besteloverzicht: zulke uitvoer ziet er onschuldig uit. Voor een aanvaller is het een plattegrond. Ze tonen volledige bestandspaden, namen van databases en tabellen, gebruikte bibliotheken en vaak de PHP-versie.
Juist in situaties als PHP2Shell, waarin massaal naar kwetsbare servers wordt gezocht, moet een server zo weinig mogelijk over zichzelf prijsgeven. Dat sluit geen kwetsbaarheid in de PHP-interpreter, maar bemoeilijkt elke vervolgstap na een inbraak en maakt gerichte aanvallen op uw applicatie lastiger.
Daar komt gegevensbescherming bij. Foutmeldingen kunnen delen van verzoeken bevatten, bijvoorbeeld e-mailadressen uit formulieren. Wat in de browser van een bezoeker verschijnt, valt niet meer onder uw controle.
De standaardwaarden zijn niet bedoeld voor productie
Velen gaan ervan uit dat PHP fouten uit zichzelf verbergt. De PHP-handleiding zegt iets anders: de ingebouwde standaardwaarde van display_errors is 1 en display_startup_errors is sinds PHP 8.0 eveneens standaard ingeschakeld. Pas het meegeleverde sjabloon php.ini-production zet beide op Off. De handleiding noemt display_errors uitdrukkelijk een ontwikkelfunctie die op systemen op internet nooit mag worden gebruikt.
Of uw server het productiesjabloon gebruikt, is niet vanzelfsprekend. Containerimages starten soms helemaal zonder php.ini, hostingpanelen stellen eigen waarden in en na een verhuizing wordt graag het ontwikkelsjabloon gekopieerd.
display_errors off: de instellingen in één oogopslag
De volgende waarden zijn zinvol voor productieservers. De constanten zoals E_ALL werken alleen in de php.ini; in de Apache-configuratie hebben ze volgens de PHP-handleiding geen betekenis en moeten ze als getal worden opgegeven.
| Instelling | Productie | Doel |
|---|---|---|
display_errors |
Off |
geen fouten in de browser |
display_startup_errors |
Off |
geen fouten bij het starten van PHP in de uitvoer |
log_errors |
On |
fouten naar het logboek schrijven |
error_log |
Pad buiten de webroot | eigen logbestand per website of pool |
error_reporting |
E_ALL |
alle fouten loggen, niet tonen |
html_errors |
Off |
platte tekst in plaats van HTML in logboeken |
zend.exception_ignore_args |
On |
geen functieargumenten in stacktraces |
fatal_error_backtraces |
0 tot de update (alleen PHP 8.5) |
overbruggingsmaatregel volgens php.net |
zend.exception_ignore_args is bijzonder waardevol. Zonder deze instelling kunnen stacktraces in logs en foutpagina's de argumenten van functieaanroepen bevatten, dus ook wachtwoorden of tokens die op dat moment werden verwerkt.
; php.ini van de web-SAPI
display_errors = Off
display_startup_errors = Off
log_errors = On
error_log = /var/log/php/website-fehler.log
error_reporting = E_ALL
html_errors = Off
zend.exception_ignore_args = On
; alleen PHP 8.5, overbruggingsmaatregel tot de update naar 8.5.12:
; fatal_error_backtraces = 0
In de FPM-pool vergrendelt u de belangrijkste waarden aanvullend, zodat geen applicatie ze via ini_set() weer inschakelt:
; bijv. /etc/php/8.3/fpm/pool.d/seite1.conf
php_admin_flag[display_errors] = off
php_admin_flag[display_startup_errors] = off
php_admin_flag[log_errors] = on
php_admin_value[error_log] = /var/log/php/seite1-fehler.log
Herstart daarna de betreffende PHP-service. Hoe het vergrendelen precies werkt, legt het artikel php_admin_value: instellingen tegen overschrijven vergrendelen uit. Een volledige basisconfiguratie vindt u onder php.ini veilig configureren.
De tweede schakelaar: debugmodus van de applicatie
PHP is maar de halve oplossing. Moderne frameworks vangen fouten zelf af en tonen eigen, vaak zeer uitgebreide foutpagina's. In debugmodus bevatten ze broncode-uittreksels, configuratiewaarden en soms omgevingsvariabelen. Deze pagina's verschijnen ook als display_errors in PHP is uitgeschakeld.
Controleer daarom voor elke applicatie de eigen schakelaar. Bij WordPress zijn dat WP_DEBUG en WP_DEBUG_DISPLAY in de wp-config.php, bij Laravel en Symfony APP_DEBUG en de omgeving in het .env-bestand, bij andere systemen de productiemodus volgens de documentatie van de fabrikant. Op een live systeem hoort de debugmodus blijvend uit; ook „even snel om te testen” is een risico.
Hoe fouten in de applicatie netjes worden afgehandeld in plaats van onderdrukt, beschrijft Fouten en exceptions in PHP.
Zo vindt u foutuitvoer voordat anderen dat doen
Eenmalig instellen volstaat niet. Foutuitvoer keert terug na updates, verhuizingen of paneelwijzigingen. Een korte controleprocedure helpt:
- De werkzame waarden in de webcontext controleren, niet alleen op de opdrachtregel, bijvoorbeeld met een kort neergezet en daarna meteen verwijderd controlebestand.
- De debugmodus van elke applicatie in haar configuratiebestand controleren.
- Uitgeleverde pagina's doorzoeken op typische foutteksten, zoals in het codeblok hieronder.
- In de zoekmachine met een
site:-zoekopdracht op uw domein zoeken naar termen als „Fatal error” of „Warning”. - Controleren of het foutenlog wordt beschreven en niet in de webroot staat.
# Uitgeleverde pagina's doorzoeken op PHP-foutteksten (alleen eigen domeinen)
for url in https://www.example.de/ https://www.example.de/kontakt/; do
curl -s "$url" | grep -E -o "(Fatal error|Warning|Notice|Deprecated|Stack trace)[^<]{0,80}" | head -3
done
# Wordt het foutenlog beschreven?
ls -l /var/log/php/
Fouten verbergen is geen vervanging voor ze verhelpen. Een log vol waarschuwingen wijst op onderhoudsbehoefte en na een inbraak is het vaak een belangrijk spoor. Wat u daarbij wel en niet logt, beschrijft Veilig loggen: fouten registreren zonder datalek.
Conclusie: stil in de browser, spraakzaam in het log
De regel voor productieservers is eenvoudig: fouten horen in het logboek, niet op de website. In de praktijk strandt ze op standaardwaarden die niet voor productie bedoeld zijn, op debugschakelaars in applicaties en op configuraties die na updates of verhuizingen terugvallen.
Wie display_errors en display_startup_errors uitschakelt, de waarden in de pool vergrendelt, de debugmodus van de applicatie controleert en het resultaat regelmatig toetst, dicht een van de meest voorkomende bronnen van onnodige informatieprijsgave. De inspanning is gering, de werking houdt stand zolang de controle onderdeel van elke update blijft.
Eén punt mag daarbij niet ondersneeuwen: het foutenlog is geen afvalbak. Wie het regelmatig leest, herkent foute updates, verouderde functies en soms ook de eerste sporen van een aanval, lang voordat klanten iets merken.
Hoe helpt PHP SOS concreet?
- Controleren: wij lezen de werkzame foutinstellingen per website en pool uit en doorzoeken uitgeleverde pagina's op foutuitvoer.
- Omschakelen: wij stellen PHP- en applicatie-instellingen in voor productiebedrijf en vergrendelen ze tegen overschrijven.
- Logboeken inrichten: foutenlogs staan buiten de webroot, worden geroteerd en zijn toegankelijk voor uw ontwikkelaars.
- Blijvend houden: in het security-onderhoudscontract controleren wij de instellingen na elke update opnieuw.
Veelgestelde vragen
Is display_errors in PHP niet standaard uitgeschakeld?
Niet automatisch. Volgens de PHP-handleiding is de ingebouwde standaardwaarde van display_errors 1. Pas het meegeleverde sjabloon php.ini-production zet Off. Of uw server dit sjabloon gebruikt, hangt af van distributie, paneel of containerimage en moet worden gecontroleerd.
Is display_errors = Off genoeg als WordPress of Laravel in debugmodus draaien?
Nee. Veel CMS'en en frameworks hebben eigen foutpagina's die los van PHP details kunnen tonen. Schakel daarom ook de debugmodus van de applicatie uit, bijvoorbeeld WP_DEBUG_DISPLAY bij WordPress of APP_DEBUG bij Laravel en Symfony.
Waar gaan fouten heen als ze niet meer worden getoond?
Met log_errors = On schrijft PHP ze naar het bestand dat error_log noemt, of naar het logboek van de betreffende uitvoeringsmodus, bijvoorbeeld het foutenlog van Apache of PHP-FPM. Het bestand moet buiten de webroot liggen en regelmatig worden geroteerd.
Wat heeft fatal_error_backtraces met PHP2Shell te maken?
De instelling bestaat vanaf PHP 8.5 en is standaard actief. php.net noemt fatal_error_backtraces=0 met aansluitende herstart als een van de overbruggingsmaatregelen voor PHP 8.5, zolang de update naar 8.5.12 nog niet is doorgevoerd. Ze vervangt de update niet.