DateMalformedStringException unter PHP 8.5
Ein Bericht zur Fehlersuche in WordPress Multisite – und wie sich ein PHP-Fatal-Error im Plugin Event Organiser beheben lässt.
Nach einer Aktualisierung der Serverumgebung auf PHP 8.5 fiel auf einer WordPress-Multisite ein ungewöhnlicher Fehler auf: Die Website funktionierte weitgehend normal, aber sobald ein Besucher die WordPress-Suchfunktion verwendete, erschien nur noch die Meldung:
Auf deiner Website ist ein kritischer Fehler aufgetreten.
Die Startseite, einzelne Beiträge und Unterseiten waren weiterhin erreichbar. Auch andere Websites innerhalb der Multisite funktionierten problemlos – sogar mit der Suchfunktion.
Der Fehler ließ sich zuverlässig durch einen Suchaufruf reproduzieren:
https://www.beispiel.de/?s=suchbegriff
Nach einer Analyse stellte sich heraus, dass weder das WordPress-Theme noch die Suchvorlage verantwortlich war. Die Ursache lag im Plugin Event Organiser, genauer gesagt in der Verarbeitung von Datumsangaben innerhalb der Suchergebnisse. In diesem Artikel beschreibe ich die Fehlersuche, die eigentliche Ursache und eine mögliche Lösung.
Ausgangssituation
Die betroffene Installation hatte folgende technische Eigenschaften:
| Komponente | Umgebung |
|---|---|
| CMS | WordPress Multisite |
| WordPress | Aktuelle Version zum Zeitpunkt der Fehlersuche |
| PHP | 8.5.12 |
| Theme | Twenty Twenty-Four |
| Editor | Gutenberg / Full Site Editing |
| Veranstaltungsverwaltung | Event Organiser 3.12.10 |
| Suchfunktion | WordPress-Standardsuche |
| Server | Linux mit Apache und PHP-FPM |
Die Website verwendete eine individuell angepasste Suchvorlage im Full Site Editor. Darin befand sich unter anderem ein Query-Loop-Block, der die Ergebnisse der aktuellen WordPress-Suchanfrage übernahm. Da der Fehler ausschließlich bei Suchanfragen auftrat, lag zunächst die Vermutung nahe, dass die Suchvorlage oder ein Gutenberg-Block dafür verantwortlich sein könnte. Diese Vermutung bestätigte sich jedoch nicht.
Fehlerprotokollierung in WordPress aktivieren
Der wichtigste Schritt bei der Fehlersuche war die Aktivierung des WordPress-Debug-Logs. Dazu wurden in der Datei wp-config.php folgende Einstellungen verwendet:
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
@ini_set( 'display_errors', 0 );
Die Einstellungen müssen vor der Zeile stehen, mit der WordPress die Bearbeitung der Konfiguration beendet.
Wichtig: Bereits vorhandene Definitionen sollten angepasst und nicht doppelt eingetragen werden.
Durch diese Konfiguration schreibt WordPress PHP-Fehler standardmäßig in:
wp-content/debug.log
Gleichzeitig werden die Fehlermeldungen nicht öffentlich auf der Website angezeigt. Bei produktiven Websites sollte das Debugging nur vorübergehend aktiviert und der Zugriff auf die Logdatei geschützt werden.
Den Fehler reproduzieren
Nach der Aktivierung wurde die Suche erneut aufgerufen:
https://www.beispiel.de/?s=suchbegriff
Anschließend ließ sich die Logdatei über SSH untersuchen:
tail -n 100 wp-content/debug.log
Jetzt wurde die eigentliche Ursache sichtbar.
Die entscheidende Fehlermeldung
Im Debug-Log fand sich ein PHP-Fatal-Error:
PHP Fatal error: Uncaught DateMalformedStringException:
Failed to parse time string ( ) at position 0 ( ):
Empty string
Die Fehlermeldung verwies auf:
wp-content/plugins/event-organiser/
includes/event-organiser-archives.php:632
Damit war die Suche nach der Ursache deutlich eingegrenzt. Der Fehler entstand bei der Verarbeitung eines Datumswertes durch die PHP-Klasse DateTime. Vereinfacht gesagt versuchte das Plugin, aus einer leeren Zeichenkette ein gültiges Datum zu erzeugen. Das funktioniert nicht:
$date = new DateTime( ' ' );
Die Zeichenkette enthält lediglich ein Leerzeichen und damit keine verwertbare Datumsinformation. PHP löst deshalb eine DateMalformedStringException aus. Wird diese Ausnahme nicht abgefangen, bricht die Verarbeitung mit einem Fatal Error ab.
Warum trat der Fehler ausgerechnet bei der WordPress-Suche auf?
Hier wurde es interessant. Das Plugin Event Organiser erweitert WordPress um einen eigenen Beitragstyp für Veranstaltungen. Dieser Beitragstyp heißt:
event
Da Veranstaltungen grundsätzlich auch über die WordPress-Suche gefunden werden können, tauchten entsprechende Beiträge innerhalb der Suchergebnisse auf.
Das Plugin verwendet außerdem einen Filter:
add_filter(
'the_posts',
'_eventorganiser_update_event_dates_cache',
10,
2
);
Dieser Filter wird während der Verarbeitung von WordPress-Abfrageergebnissen ausgeführt. Die betreffende Funktion ist dafür zuständig, Datumsinformationen von Veranstaltungen für die weitere Verarbeitung beziehungsweise Zwischenspeicherung bereitzustellen. Bei unserer Fehlersuche zeigte sich allerdings, dass innerhalb der betroffenen Suchanfrage nicht alle benötigten Datumsinformationen vorhanden waren.
Besonders relevant waren die Felder:
StartDate
StartTime
EndDate
FinishTime
Aus diesen Werten erstellt das Plugin DateTime-Objekte. Fehlen notwendige Angaben, kann genau der beobachtete Fehler entstehen.
Ein wichtiger Unterschied
Eine Veranstaltung ohne Datumsinformationen im Abfrageergebnis ist nicht zwangsläufig eine Veranstaltung mit fehlerhaften Daten in der Datenbank.
Das wurde in diesem Fall besonders deutlich.
Den betroffenen Beitrag identifizieren
Um herauszufinden, welche Suchergebnisse den Fehler auslösten, wurde die Funktion vorübergehend um Debug-Ausgaben ergänzt. Während der Verarbeitung wurden die Beitrags-ID, der Beitragstyp und die verfügbaren Datumswerte protokolliert. Die anonymisierte Ausgabe sah sinngemäß so aus:
EO DEBUG:
ID=12075
TYPE=event
START=NULL
END=NULL
Ein weiteres Suchergebnis zeigte:
EO DEBUG:
ID=1425
TYPE=page
START=NULL
END=NULL
Damit wurde ein wichtiger Punkt sichtbar: Die Suchergebnisse enthielten nicht nur Veranstaltungen, sondern auch gewöhnliche WordPress-Seiten. Bei normalen Seiten sind Veranstaltungsdaten selbstverständlich nicht vorhanden. Auch bei mindestens einem Veranstaltungsbeitrag fehlten die erwarteten Datumsfelder im verarbeiteten Ergebnisobjekt. Das erklärte, weshalb die Funktion nicht einfach davon ausgehen durfte, dass jedes verarbeitete Objekt vollständig nutzbare Veranstaltungsdaten besitzt.
Kontrolle der Veranstaltungsdatenbank
Zunächst bestand der Verdacht, dass eine Veranstaltung falsch gespeichert worden war. Deshalb wurde der betroffene Beitrag im WordPress-Backend kontrolliert. Dort waren die Veranstaltungsdaten korrekt hinterlegt. Anschließend folgte eine direkte Datenbankprüfung. Event Organiser verwendet für Veranstaltungstermine eine eigene Tabelle. Bei einer Multisite besitzt diese einen standortspezifischen Tabellenpräfix.
In einer anonymisierten Beispielinstallation könnte die Tabelle so heißen:
wp_7_eo_events
Eine entsprechende SQL-Abfrage lautet:
SELECT
event_id,
post_id,
StartDate,
EndDate,
StartTime,
FinishTime,
event_occurrence
FROM wp_7_eo_events
WHERE post_id = 12075;
Wichtig: Das Tabellenpräfix und die Beitrags-ID müssen an die eigene Installation angepasst werden.
Das Ergebnis zeigte gültige Datumswerte, beispielsweise:
StartDate: 2027-02-08
EndDate: 2027-02-08
StartTime: 00:00:00
FinishTime: 23:59:00
event_occurrence: 0
Die Veranstaltung war also korrekt gespeichert. Trotzdem standen die Datumsfelder im betroffenen Abfrageergebnis nicht zur Verfügung. Damit war klar: Es wäre falsch gewesen, die Veranstaltung zu löschen oder ihre Daten auf Verdacht zu verändern.
Das Problem lag in der fehlenden Absicherung der Datenverarbeitung, nicht nachweislich in einem beschädigten Datenbankeintrag.
Die problematische Stelle im Event-Organiser-Plugin
Die betreffende Funktion befindet sich in:
wp-content/plugins/event-organiser/
includes/event-organiser-archives.php
Sie heißt:
_eventorganiser_update_event_dates_cache()
In der untersuchten Plugin-Version wurden dort Datumsobjekte sinngemäß folgendermaßen erzeugt:
$cached_event[$event->occurrence_id] = array(
'start' => new DateTime(
$event->StartDate . ' ' . $event->StartTime,
$tz
),
'end' => new DateTime(
$event->EndDate . ' ' . $event->FinishTime,
$tz
),
);
Dieser Code funktioniert, solange die Daten vollständig und gültig sind. Problematisch wird es, wenn beispielsweise StartDate und StartTime leer sind. Dann entsteht aus ihrer Verkettung möglicherweise lediglich ein Leerzeichen:
' ' . ''
Der anschließende Aufruf von new DateTime() schlägt fehl. In unserem Fall führte das zum Abbruch der gesamten WordPress-Suche.
Lösung: Beitragstyp und Datumswerte überprüfen
Eine robuste Verarbeitung sollte vor dem Erstellen von DateTime-Objekten mehrere Dinge sicherstellen:
- Der aktuelle Datensatz gehört tatsächlich zu einer Veranstaltung.
- Die notwendigen Datumsfelder sind vorhanden.
- Die Datumswerte lassen sich erfolgreich verarbeiten.
- Fehlerhafte Datensätze bringen nicht die gesamte Suchanfrage zum Absturz.
Dafür wurde die betroffene Funktion vorsichtig erweitert.
Schritt 1: Andere Beitragstypen überspringen
Innerhalb der Schleife, die Suchergebnisse beziehungsweise Veranstaltungen verarbeitet, lässt sich zunächst der Beitragstyp überprüfen:
if (
! isset( $event->post_type ) ||
'event' !== $event->post_type
) {
continue;
}
Damit werden gewöhnliche WordPress-Seiten und Beiträge nicht wie Veranstaltungen behandelt.
Schritt 2: Fehlende Datumswerte erkennen
Zusätzlich werden die notwendigen Datumsfelder kontrolliert:
if (
empty( $event->StartDate ) ||
empty( $event->EndDate )
) {
continue;
}
Fehlen die erforderlichen Daten, wird der betreffende Datensatz übersprungen.
Andere Suchergebnisse können weiterhin verarbeitet werden.
Schritt 3: Ausnahmen beim Erstellen von DateTime abfangen
Auch vorhandene Datumsfelder können ungültige Werte enthalten.
Daher empfiehlt sich zusätzlich eine Ausnahmebehandlung:
try {
$start = new DateTime(
trim( $event->StartDate . ' ' . $event->StartTime ),
$tz
);
$end = new DateTime(
trim( $event->EndDate . ' ' . $event->FinishTime ),
$tz
);
} catch ( \Exception $e ) {
error_log(
'Event Organiser: Invalid date for event ID '
. $id
. ' - '
. $e->getMessage()
);
continue;
}
Damit wird verhindert, dass eine nicht verarbeitbare Datumsangabe unmittelbar zum Abbruch der gesamten Suchfunktion führt.
Beispiel für die abgesicherte Datumsverarbeitung
Der folgende Code zeigt das Prinzip der Korrektur. Er ist kein vollständiger Ersatz für die Funktion, sondern muss an der entsprechenden Stelle innerhalb der bestehenden Verarbeitung eingefügt werden.
Die Variablen $event, $cached_event, $tz und $id stammen aus dem umgebenden Plugin-Code.
// Nur Veranstaltungen verarbeiten.
if (
! isset( $event->post_type ) ||
'event' !== $event->post_type
) {
continue;
}
// Fehlende Datumsangaben abfangen.
if (
empty( $event->StartDate ) ||
empty( $event->EndDate )
) {
continue;
}
try {
// Beginn der Veranstaltung.
$start = new DateTime(
trim(
$event->StartDate . ' ' . $event->StartTime
),
$tz
);
// Ende der Veranstaltung.
$end = new DateTime(
trim(
$event->EndDate . ' ' . $event->FinishTime
),
$tz
);
// Nur gueltige Daten zwischenspeichern.
$cached_event[$event->occurrence_id] = array(
'start' => $start,
'end' => $end,
);
wp_cache_set(
'eventorganiser_occurrences_' . $id,
$cached_event
);
} catch ( \Exception $e ) {
error_log(
'Event Organiser: Invalid date for event ID '
. $id
. ' - '
. $e->getMessage()
);
continue;
}
Achtung bei der Übernahme
Dieser Beispielcode setzt voraus, dass $event tatsächlich ein Objekt mit einem post_type-Feld ist und die umgebende Funktion die gezeigten Variablen bereitstellt. Das muss in der konkret installierten Plugin-Version überprüft werden. Andernfalls könnte die zusätzliche Typprüfung gültige Daten unbeabsichtigt überspringen. Die eigentliche Korrektur sollte möglichst direkt in der vorhandenen Funktion erfolgen, ohne deren übrige Logik zu verändern. Vor Änderungen an Plugin-Dateien empfiehlt sich außerdem ein vollständiges Backup oder – noch besser – ein Test in einer Staging-Umgebung.
Ergebnis: Die WordPress-Suche funktioniert wieder
Nach der Anpassung wurde die WordPress-Suchfunktion erneut getestet. Das Ergebnis war eindeutig:
Der kritische Fehler trat nicht mehr auf.
Die Suche zeigte wieder reguläre WordPress-Inhalte an, darunter:
- Beiträge,
- Seiten,
- Veranstaltungen.
Auch Suchanfragen, die zuvor zuverlässig zum Fatal Error geführt hatten, funktionierten wieder. Die ursprüngliche Veranstaltung musste weder gelöscht noch neu gespeichert werden. Ihre Datenbankeinträge blieben unverändert. Die Korrektur bestand ausschließlich darin, die Verarbeitung fehlender beziehungsweise ungeeigneter Datumswerte abzusichern.
Warum PHP 8.5 bei der Fehlersuche eine Rolle spielte
Der Fehler wurde unter PHP 8.5.12 beobachtet. Die Fehlermeldung DateMalformedStringException stammt aus der PHP-Datumsverarbeitung. Dabei ist eine wichtige Unterscheidung erforderlich:
Das Problem ist nicht grundsätzlich auf PHP 8.5 beschränkt.
Die Ausnahme DateMalformedStringException wurde bereits mit PHP 8.3 eingeführt. In älteren PHP-Versionen konnte sich die Fehlerbehandlung anders verhalten. Die grundsätzliche Schwachstelle bleibt jedoch dieselbe: Einer Datumsfunktion werden unzureichend geprüfte Eingabewerte übergeben. PHP 8.5 war in unserem Fall also die verwendete Laufzeitumgebung, nicht die nachgewiesene alleinige Ursache.
Warum nicht einfach das Theme wechseln?
Während der Fehlersuche wurde zunächst auch die Suchvorlage des Themes Twenty Twenty-Four betrachtet. Die Website verwendete den WordPress-Site-Editor mit individuell angepassten Template-Teilen und einem Query Loop. Da die Fehlermeldung jedoch eindeutig auf eine PHP-Funktion innerhalb von Event Organiser verwies, gab es keinen belastbaren Hinweis darauf, dass das Theme die eigentliche Ursache war. Ein Theme-Wechsel hätte den Fehler möglicherweise verdeckt oder die betroffene Abfrage verändert, aber nicht notwendigerweise behoben.
Das ist eine wichtige Erkenntnis für die WordPress-Fehlersuche:
Nicht jede Fehlermeldung, die beim Anzeigen einer bestimmten Vorlage auftritt, wird durch diese Vorlage verursacht.
Entscheidend ist der PHP-Stacktrace.
Achtung: Plugin-Updates können die Korrektur überschreiben
Die beschriebene Änderung wurde direkt in einer Plugin-Datei vorgenommen. Das war als kurzfristige Fehlerbehebung erfolgreich, hat aber einen wesentlichen Nachteil:
Beim nächsten Update von Event Organiser kann die Änderung verloren gehen.
Deshalb sollten Administratoren nach einer solchen Anpassung:
- die geänderte Datei beziehungsweise den Patch separat sichern,
- die verwendete Plugin-Version dokumentieren,
- nach Plugin-Updates die betroffene Funktion kontrollieren,
- den Fehler möglichst an die Plugin-Entwickler melden,
- prüfen, ob eine neuere Plugin-Version die Ursache bereits behebt.
Ein direkter Eingriff in Plugin-Dateien sollte keine unbemerkte Dauerlösung bleiben. Für einen dauerhaft wartbaren Betrieb ist eine Korrektur im offiziellen Plugin-Code vorzuziehen.
Nach der Fehlerbehebung: Debugging wieder deaktivieren
Nach erfolgreicher Kontrolle sollte das zusätzliche Debugging in der produktiven WordPress-Installation wieder deaktiviert werden.
In der wp-config.php beispielsweise:
define( 'WP_DEBUG', false );
define( 'WP_DEBUG_LOG', false );
define( 'WP_DEBUG_DISPLAY', false );
Auch hier gilt: Bereits vorhandene Definitionen anpassen und nicht doppelt eintragen. Die während der Untersuchung entstandene debug.log sollte anschließend überprüft, gegebenenfalls archiviert und sicher entfernt werden. Debug-Dateien können sensible technische Informationen enthalten und sollten nicht öffentlich zugänglich sein.
Learnings..
Ein kritischer Fehler in der WordPress-Suche kann ganz unterschiedliche Ursachen haben. In dem Fall war zunächst unklar, ob das Problem durch das Theme, Gutenberg, den Query Loop oder die Multisite-Konfiguration verursacht wurde.
Erst der Blick in das PHP-Debug-Log brachte Klarheit:
DateMalformedStringException:
Failed to parse time string ( ):
Empty string
Der Fehler entstand innerhalb der Datumsverarbeitung des Plugins Event Organiser.
Die weitere Untersuchung zeigte, dass einzelne Objekte in den Suchergebnissen nicht die erwarteten Datumsfelder enthielten – obwohl zumindest eine betroffene Veranstaltung korrekt in der Datenbank gespeichert war.
Durch eine zusätzliche Prüfung des Beitragstyps und der erforderlichen Datumsfelder sowie eine Ausnahmebehandlung bei DateTime ließ sich die Suche wiederherstellen.
Die wichtigste Erkenntnis:
Nicht vorschnell Beiträge löschen, Themes wechseln oder Datenbanken verändern. Stattdessen sollte man den Fehler reproduzieren, das PHP-Log auswerten, den Stacktrace verfolgen und anschließend gezielt die tatsächlich betroffene Stelle absichern. In unserem Fall reichte eine kleine Änderung in der Verarbeitung der Veranstaltungsdaten, um die WordPress-Suche wieder funktionsfähig zu machen.
Links
Weiterer dokumentierter Fall mit derselben Ausnahme und einer vergleichbaren Absicherung der Datumsverarbeitung: https://wordpress.org/support/topic/getting-fatal-error-when-vesting-all-events-page-in-the-backend
