PCRE – der Stackspeicher Fresser

28. Juli 2011 Besucher gesamt: 1009

Als erstes möchte ich euch mitteilen, dass ich mich sehr freue diesen Beitrag zu schreiben. Die letzten drei Monate war ich in Elternzeit und bin nicht zum Schreiben geschweige zum Programmieren gekommen. Es war aber eine sehr schöne Zeit für mich und die Familie. Nach dieser langen Programmier-Abstinenz wollte ich eine neue LAMP Entwicklungsumgebung Installieren. Kurz darauf habe ich einen in den Jahren gekommenen Laptop platt gemacht und eine neue Version von Ubuntu installiert. Das ging ganz schnell und einfach. Danach habe ich mittels „aptitude“, eine Erweiterung der Paketverwaltung APT welche auf allen Debian-basierten Systemen zum Einsatz komm, einen Apache2 Server, eine MySQL Datenbank, PHP, PEAR und PHPUnit installiert. Um das ganze zu testen habe ich ein im PHP5 erstelltes Projekt in der neuen LAMP Umgebung kopiert und die PHPUnit Tests gestartet. Alles lief recht schnell und ohne Probleme. Die Tests waren erfolgreich. Nun bin ich auch neugierig geworden und habe ein etwas älteres Projekt, das von PHP4 auf PHP5 umgeschrieben habe, ausprobiert. Hier handelt es sich um eine Schnittstelle die sehr viele Text-Dateien verarbeitet um den Inhalt anschließend in der Datenbank zu importiert. So, ab hier fangen die Probleme an.

Kurz nach dem ich den Test gestartet habe, meldete sich PHP mit einem PCRE Rekursionslimit-Fehler. Das Rekursionslimit sei 128 und darf nicht überschritten werden. Nach einer kurzen Recherche im Internet, habe ich erfahren, dass seit PHP5.2.0 zwei neue Einstellungen „pcre.recursion_limit“ und „pcre.backtrack_limit“ eingeführt worden sind. Diese sollen PHP vor komplexe oder fehlerhafte reguläre Ausdrücke schützen. Da sie zu viel Stackspeicher benötigen und PHP zum Absturz bringen können.

Lösungsansatz 1:
Da es sich hier um eine Einstellungen im PHP handelt, können diese direkt in der php.ini oder gleich mit ini_set() auf einen höheren Wert gesetzt werden. Die php.ini lässt man besser in Ruhe, denn der Standartwert von hunderttausend ist ganz gut gewählt. Dafür sollten man besser darauf achten, keine Stackspeicher-Fresser zu programmieren. Eventuell nach Alternativen suchen oder native PHP String-Funktionen kombinieren. Nun, zurück zum Thema. Je nach dem, ist es auch möglich den Wert auch auf zehn Millionen zu setzen, aber nicht bevor man sich mit dem Teamkollegen oder Administrator konsultiert hat. Man sollte eben nicht den ganzen Speicher für PCRE Operationen reservieren.

ini_set('pcre.recursion_limit',10000000);
ini_set('pcre.backtrack_limit',10000000);

Lösungsansatz 2:
Ich gebe es zu, der erste Lösungsansatz war nicht der beste. Wenn man die Einstellungen zur Scriptlaufzeit ändert, riskiert man dadurch einen PHP Absturz, wenn der reguläre Ausdruck doch zu viel Speicher verbraucht. Eleganter ist es, wenn man es durch eine Fehlerprüfung absichert. Ganz besonders wenn man mit komplexen regulären Ausdrücken arbeitet oder reguläre Ausdrücke auf große Datenmengen anwendet. Der Abbruch im Script passiert also wenn ein regulärer Ausdruck das gesetzte Limit überschreitet. PHP liefert keine Fehlermeldung indem Fall, und der reguläre Ausdruck liefert NULL als Ergebnis. Dabei muss man unmittelbar nach der PCRE-Funktion mittels preg_last_error() prüfen, welcher Fehler aufgetreten ist. Dabei wird ein integer-Wert zurück geliefert. Die Werte sind ebenfalls als PHP-Konstanten vertreten.

< ?php

preg_match('/(?:\D+|<\d+>)*[!?]/', '...big text....');

if (preg_last_error() == PREG_BACKTRACK_LIMIT_ERROR
	|| preg_last_error() == PREG_RECURSION_LIMIT_ERROR)
{
    throw new Exception('Regular Expression limit was exhausted!');
}

?>

Im den oberen Beispiel, wirft PHP eine Exception wenn der Speicher-Limit erreicht ist. So kann man besser den Fehler abfangen um entsprechend reagieren. Das Problem und die Folgefehler wurden somit behoben.

¬ geschrieben von gjerokrsteski in PHP Tricks und Tipps  ¬ Erzähl´s weiter Twitter  | Mr. Wong  | Delicious  | Del.icio.us  | Google  | Facebook

«

» 

4 Kommentare zu 'PCRE – der Stackspeicher Fresser'

  1. Oliver sagte am 28. Juli 2011 um 17:35 Uhr:

    Deine Zeichenkodierung im Artikel scheint ISO8859-15, aber die Seite ist als UTF8 deklariert, was in kaputten Umlauten endet. Ich glaube XP f

  2. Oliver sagte am 28. Juli 2011 um 17:37 Uhr:

    Ok, Kommentare funktionieren auch nicht mit Umlauten. :-)

  3. Gjero Krsteski sagte am 29. Juli 2011 um 07:23 Uhr:

    @Oliver:
    Der Grund für die Falsche Darstellung der Zeichen ist der WP-Cache. Wenn der abgelaufen ist, schafft er es nicht immer die Seite neu dynamisch zu laden. Du musst dein Browser-Cache leeren und die Seite neu laden. Wenn ich mal Zeit habe, schaue ich mir das WP-Cache Plugin genauer an.

  4. Oliver sagte am 31. Juli 2011 um 00:19 Uhr:

    Ich habe gar keinen Browsercache. :-)

    Aber normal ist das nicht, weil ich hab es ausprobiert, auf ISO funktionieren die Umlaute und die waren auch nur im Artikel selbst falsch.

Hinterlasse einen Kommentar

*Codebeispiele können im CODE-Tag angegeben werden.

Powered by Wordpress • Abonniere den RSS Feed