Vor geraumer Zeit begegnete ich immer wieder einer nervigen Fehlermeldung:
Warning: unpack() [function.unpack]: Type V: not enough input,
need 4, have 0 in /***/wp-includes/gettext.php on line 85
Hierbei handelt es sich um PHP-Dateien einer WordPress-Installation (Version 2.2.3 DE und Version 2.3 DE). Unter Unix ist GNU gettext eine weit verbreitete Bibliothek. Sie macht im Grunde nichts anderes, als einen übergebenen “originalen” String (in der Regel ein englischer Text) in einen entsprechenden String einer anderen Sprache zu übersetzen. Das Mapping zwischen diesen Strings befindet sich in so genannten MO-Dateien (z.B. “de_DE.mo”). Auch WordPress setzt solche Dateien für die Übersetzung ein.
(Gelöst mit WordPress 2.6.1 — Details weiter unten…)
PHP könnte direkt mit gettext-Support kompiliert werden. Dadurch stünden entsprechende Funktionen direkt zur Verfügung. Doch würde solch ein Programm nicht auf einem Rechner ohne entsprechende Unterstützung laufen. Aus diesem Grund wurde in WordPress das Projekt PHP gettext integriert. Die Implementierung liegt in den Dateien “gettext.php” und “streams.php” im “wp-includes”-Verzeichnis. WordPress erhält dadurch die Fähigkeit diese MO-Dateien einzulesen. Doch genau hier entstanden ab und zu Probleme.
Betrachtung des Problems
Die oben dargestellte Fehlermeldung kam bei mir sporadisch. Und ich kenne die Fehlerstelle genau. Sie befindet sich in der Datei “streams.php” in der Klasse StringReader
. Und dort in der Funktion read($bytes)
. Hier lieferte die Zeile $data = substr($this->_str, $this->_pos, $bytes);
nicht immer den richtigen Teilstring zurück. Manchmal war der Inhalt genau um ein Byte verschoben. Dadurch wurden in der Datei “gettext.php” in der Funktion gettext_reader(…) Strukturinformationen einer MO-Datei falsch interpretiert, was wiederum dazu führte, dass Mengenangaben komplett falsch eingelesen wurden. In solch einem Fehlerfall wurde die seekto()
Funktion mit einem großen negativen Wert aufgerufen, was dazu führte, dass der Stream-Positionszeiger an das Ende der Daten gesetzt wurde. Dadurch lieferte jeder weitere Aufruf der Lesemethode einen Leerstring zurück. Und genau solch ein Leerstring wurde der Methode unpack()
in der Datei “gettext.php” in der Zeile 85 übergeben, was zu der oben besagten Meldung führte.
Es ist zwar nicht wirklich eine Lösung, doch hatte ich die oben benannte Codezeile temporär mit folgenden Kommandos ausgetauscht:
Alter Code:
$data = substr($this->_str, $this->_pos, $bytes);
Neuer Code, der immer den richtigen Teilstring ermittelt:
$data = ""; for ($i=0; $i<$bytes; $i++) { $data .= $this->_str[$this->_pos+$i]; };
Gibt man hier noch eine Meldung aus, sobald die beiden ermittelten Teilstrings unterschiedlich sind, dann merkte man, dass diese gleichzeitig mit dem hier beschriebenen Fehler auftauchte. Verglich man die Inhalte, sah man, dass bei einer Startposition > 0 der Teilstring aus substr()
um ein Zeichen/Byte verschoben war. Statt z.B. den Inhalt von Index 4–7 zu ermitteln, lieferte diese Methode dann die Zeichen 5–8. Wohl bemerkt, dies aber nur sehr sporadisch!
Eigentlich eine fatale Sache, wenn ein regulärer PHP-Befehl Probleme verursacht. Dieser Befehl, der Teile aus gegebenen Texten extrahiert, kommt in WordPress häufiger zum Einsatz. Am sichtbarsten ist er in Kombination mit der Datei “gettext.php”, da hier ein Fehler geworfen wird. Aber mir ist ebenfalls aufgefallen, dass es auch Probleme mit dem Abspeichern geschriebener Inhalte gab. Hier kam es vor, dass an Stellen eingebundener Steuercodes (Links, Code-Tags) Teile des Inhaltes verschwanden. Man bemerkte die Fehlersituation, da der berühmte gettext-Fehler auftrat. Aus diesem Grund ließ ich die oben beschriebenen neuen Codezeilen auch nicht in meiner Installation. Mir sind mit diesem Code schon Inhalte verschwunden, ohne dass ich dies sofort bemerkte.
Lösungswege
Auf jeden Fall musste die Problemursache an einer Server-Konfiguration oder –Komponente liegen. Ich verwalte noch eine weitere WordPress-Webseite und dort bekam ich noch keine Fehler. Zu erwähnen ist auch, das beide Seiten beim gleichen Provider gehostet werden, die gleiche PHP-Version installiert war und inzwischen bei beiden WordPress in der Version 2.3 vorlag.
Meine temporäre Lösung bestand darin, dass ich auf meiner Seite die originale englische Version von WordPress installierte. Somit trat der Fehler seltener auf, da eine Sprachdatei weniger eingelesen werden musste. Er verschwand aber nicht komplett, weil noch PlugIns mit Sprachdateien installiert waren. Dies machte sich dann aber eher im Admin-Bereich, vor allem beim Speichern der Beiträge bemerkbar.
Dank dem schnellen und motivierten Support meines Providers All-Inkl.de dachten wir zuerst, dass wir den Fehler eindämmen konnten. Der erste Versuch bestand darin, den ZEND-Optimizer zu installieren und weitere PHP-Parameter an den Parametern des Servers meiner anderen WordPress-Präsenz anzupassen. Leider ohne dem gewünschten Ergebnis. Ein Update der PHP-Installation von der Version 5.2.3 auf 5.2.4, sowie die Aktualisierung der Apache-Installation von der Version 2.2.4 auf 2.2.6 ließen den nervigen Fehler dann kurzzeitig doch verschwinden. Vermutlich besitzt substr()
in PHP 5.2.3 nicht die erhoffte Stabilität.
Update 24.10.07:
Das Problem tritt seit heute leider wieder auf! Womöglich lag es doch nicht an der alten PHP-Version. Ich verfolge das weiter…
Update 30.10.07:
Das ist schade, aber auch das Update auf WordPress 2.3.1 DE brachte nicht den erhofften Erfolg. Wir sind leider so langsam am Ende mit dem Suchen, auch mit der Geduld. Der nächste Schritt besteht wohl darin, meinen Webspace innerhalb meines Providers auf einen anderen Server zu verschieben. Zur Zeit habe ich die Datei “/wp-includes/languages/de_DE.mo” entfernt, damit der Fehler nicht mehr so häufig auftritt.
Update 03.11.07:
Mein Provider All-Inkl hat nun meine Webseite auf einen anderen Server installiert. Seit dem scheint die Webseite ohne Probleme zu funktionieren. Schade ist nur, dass wir nun nicht genau wissen, welche Server-Einstellung / Hardware-Kombination hier wohl Probleme mit der Funktion substr()
aus PHP 5 verursacht.
Update:
Der Fehler taucht wieder auf…
Update 15.11.07:
Heute wurde PHP 5.2.5 auf dem Webserver installiert. Laut All-Inkl bin ich der Erste, der diese Installation testen darf. Ich laufe nun auch wieder auf der originalen deutschen Version. Bis jetzt sind mir noch keine Probleme begegnet. Die Zeit wird zeigen, ob das die Lösung war…
Update 26.02.08:
Im Kommentar Nr. 48 berichtet Niko_K, dass das Problem wohl durch nicht übereinstimmende Spracheinstellungen zwischen der WordPress-Configuration und dem Linux-System (Variable LANG) auftritt. Danke!
Ich vermute stark, dass PHP-String-Funktionen wie das substr()
wohl abhängig von den Systemeinstellungen sind und somit mit den richtigen Daten befüttert werden müssen.
Update 25.04.08:
Im Kommentar Nr. 60 berichtet Kretzschmar darüber, dass der Fehler unter PHP 4 nicht mehr auftaucht. Die Umstellung von PHP 5 auf PHP 4 kann beim Provider All-Inkl wohl selbst vorgenommen werden.
Ubdate 24.06.08:
Der Bug ist inzwischen schon bei WordPress registriert (Bug 5599 — danke an Codestyler für den Hinweis). Hier wird aktuell eine Alternative zu substr()
eingesetzt. Diese Lösung ist eleganter als die oben beschriebene. Leider ist die korrigierte Stelle nicht die einzige mit dem Befehl substr()
, weswegen man trotzdem ein Fehlverhalten bzw. Datenverlust in der Anwendung erwarten kann.
Update 15.08.08:
Endlich! WordPress 2.6.1 liefert nun ein Bugfix zu diesem Problem. Der Fehler tritt auf, sobald man in der php.ini
den Eintrag mbstring.func_overload
auf einen anderen Wert als 0 stellt. Meist erlauben die Provider es, diesen Wert für die eigene Web-Präsenz zu ändern. Ein Bug im Apache-Modul mod_php
sorgt allerdings bei dieser Art der Umstellung dafür, dass sie für alle V‑Hosts des Servers gilt! Sobald also ein User des gleichen V‑Hosts an dieser Einstellung dreht, erscheinen bei den anderen WordPress-Präsenzen auf dem Server wohl diese Fehler, zumindes bis eine andere Präsenz diesen Wert wieder auf 0 stellt. Näheres hierzu unter code-styling.de.
Native Lösung
Es lief einige Tage gut, nun sind seit heute (06.11.2007) alle WordPress-Seiten auf dem neuen Server wohl auch betroffen…
Im deutschsprachigen WordPress-Forum bin ich nun auf eine weitere Lösung gestoßen: Einsatz des originalen gettext() Kommandos. Diese Lösung kann leider nur dann angewendet werden, wenn gettext auf dem entsprechenden Server installiert ist. Ein Blick in die PHP-Info liefert hierzu Informationen:
GetText Support enabled
Worin besteht die Lösung? In der WordPress-Datei /wp-includes/l10n.php wird die WordPress-Version von gettext() aufgerufen. Der Code wird nun so geändert, dass die installierte Funktion gettext() anstelle der problematischen gettext-Vertretung aufgerufen wird. Dazu muss die Sprachdatei /wp-includes/languages/de_DE.mo zu wordpress.mo umbenannt und in ein neues Verzeichnis kopiert werden. Der Name des Verzeichnisses ist abhängig von der eingestellten Codierung in der Datei wp-config.php:
Eine Sprachdefinition define (‘WPLANG’, ‘de_DE.UTF‑8’); benötigt das Verzeichnis wp-includes/locale/de_DE.UTF‑8/LC_MESSAGES/.
Lautet die Sprachdefinition define (‘WPLANG’, ‘de_DE’); muss das Verzeichnis den Namen wp-includes/locale/de_DE/LC_MESSAGES/ tragen.
Wenn man will, kann man in der Datei wp-settings.php die Zeilen
include_once(ABSPATH . WPINC . ‘/gettext.php’);
include_once(ABSPATH . WPINC . '/streams.php');
auskommentieren und die Dateien gettext.php und streams.php löschen.
Damit die Umstellung schnell vollzogen werden kann, hab ich für WordPress 2.3.1 Deutsch ein kleines ZIP-File mit allen nötigen Änderungen erstellt:
Native_gettext_WordPress_2.3.1.zip
ACHTUNG:
hier bitte auf die richtige Codierung achten, damit beim Posten keine Inhalte verloren gehen. Am Besten vorher ein Backup der Datenbank anlegen. Wenn eine andere WordPress-Version unterstützt werden soll, dann einfach die Sprachdateien aus dem ZIP-File entsprechend der obigen Anleitung selbst generieren.
Und nicht vergessen: somit ist das Anzeige-Problem gelöst, der Fehler taucht nicht mehr auf, aber es gibt noch viele andere substr()-Aufrufe, welche schief laufen können. Auffällig ist dabei Datenverlust an den Steuer-Tags aus der Code-Ansicht.
OKT