Mit diesem 1 Byte Offset auf Strings bezogen, fehlt leider das 1. Zeichen, weil er ja den String um 1 Byte zu weit hinten anfängt zu interpretieren.
... wollt ich nur mal gesagt haben. :)
Da hatte ich einen Endian-Knoten im Hirn ;-) Du hast recht.
Um schreiben oder kommentieren zu können, benötigen Sie ein Benutzerkonto.
Sie haben schon ein Benutzerkonto? Melden Sie sich hier an.
Jetzt anmeldenHier können Sie ein neues Benutzerkonto erstellen.
Neues Benutzerkonto erstellen
Mit diesem 1 Byte Offset auf Strings bezogen, fehlt leider das 1. Zeichen, weil er ja den String um 1 Byte zu weit hinten anfängt zu interpretieren.
... wollt ich nur mal gesagt haben. :)
Da hatte ich einen Endian-Knoten im Hirn ;-) Du hast recht.
Sehr gut möglich. Aber evtl. könntest du ein var_dump für die ersten 10 Einträge hier reinbauen (gettext.php):
[...]
und das Ergebnis im Fehlerfall bereitstellen ?
Hab ich gemacht. Hier das Ergebnis:
array(1) { [1]=> int(-1794895138) } array(1) { [1]=> int(1577058304) } array(1) { [1]=> int(469762056) } array(1) { [1]=> int(201326592) } array(1) { [1]=> int(687865923) }
Zitat von codestyling
Ich hab noch einen, gerade im Labortest: Da es ja offensichtlich die Index Adressierung zu den Strings zermüllert (manchmal jedenfalls), wäre es eine Option, einen korrekten Index (ohne Absturz und ohne substr) zu haben, auch wenn dann die Beschriftungen evtl. um 1 Zeichen verschoben sind (1. fehlt, dafür 1. von nächsten hinten dran) und der Speed dem von vorher entspricht?
Ist zwar auch eine Krücke aber besser als keine Seite ausliefern. Und im Frontend sollte es deutlich weniger auffallen und wenn dann beim nächsten Reload ggf. weg sein.
Die Strings sind nicht vorne abgeschnitten und hinten verlängert, sondern vorne verlängert und hinten abgeschnitten, daher kann es sein (nicht nachgeguckt), dass eine 0 am Ende des vorherigen Strings dem Nachfolgestring gleich ein Ende macht. Ich habe das zum testen mal auf die Schnelle implementiert und es kam dann im Fehlerfall immer die englische Seite. Für mich ist das keine Lösung, denn der Fehler tritt ständig auf.
Vielleicht hab ich am Wochenende mal Zeit mir das genauer anzusehen und eine "echte" Lösung zu implementieren. Wahrscheinlich werde ich das .mo-File parsen und auf ewig große Strings verzichten.
Bei mir war das genauso. Wenn der Fehler aufgetreten ist, stimmte nach dem magick cookie nichts mehr, weil alles versetzt war. Revision sollte 0 sein, war es aber schon nicht, da noch ein Byte aus dem Cookie dabei war. Totals, originals und translations waren entsprechend vermurkst, da gerade die höherwertigen Bytes nicht 0 sondern vom nachfolgenden Doubleword stammten und damit die Zahlen jenseits von 16777216 lagen.
Codestyling, ich glaube, du hast wenig Chancen den Fehler bei dir zu finden, wenn das Problem bei dir nicht auftritt.
Wie ich schon sagte, die _pos-Werte fangen bei 0 an zu zählen, wenn du sie künstlich auf was anderes setzt, sind die Fehler klar und ähnlich. Das sollte aber bereits gleich am Anfang dazu führen, dass die Magic Cookies nicht gelesen werden können und gettext komplett aussteigt --> alles Englisch. Falls beim Cookie nicht ausgestiegen wird, dann stimmen die ausgelesenen Offsets für orginal und translation im .mo-File nicht mehr und das wiederum führt dazu, dass read() kein array liefert und die Fehlermeldung erscheint.
Bei mir stimmen die _pos-Werte bisher immer, damit lässt sich der Versatz jedenfalls nicht erklären. Zweimal substr() mit gleichen Parametern führt u.U. zu verschiedenen Ergebnissen.
Mein System ist übrigens Debian Etch i386. Wie es mit 64-Bit-OS aussieht, kann ich nicht sagen.
Selbst wenn man überprüft, ob substr() gerade mal den Versatz hat und ggf. nen Offset hinzuaddiert ist es nicht sicher, ob der Offset für alle folgenden substr() der Session gilt, das ist schonmal keine Lösung.
Noch was: Bei mir war es so, dass der Versatz erst beim Auslesen der .mo-Revision aufgetaucht ist. Wenn das zuverlässig sein sollte, könnte man bei $revision != 0 statt substr() my_substr() aufrufen. Sehr sehr unschön, aber eine Möglichkeit.
Ich hab das getestet. Bei allen Versuchen war _pos richtig. Das Verhalten von substr() war entweder richtig oder der ausgegebene String war eine Position zu weit vorne. Ich konnte das Verhalten fast zuverlässig ändern indem ich auf meiner phpBB-Installation eine Seite neu geladen habe. Das heißt natürlich nicht, dass _pos immer richtig sein muss. Ich habe _pos im richtigen Constructor auch mal initialisiert, aber das hat mein Problem nicht behoben.
Es könnte sein, dass substr() nur Äger macht, wenn der String lang ist und Apache schon eine Weile läuft. Da z.B. phpBB auch substr() verwendet und ich dort nie ein Problem hatte, gehe ich davon aus, dass die Stringlänge wichtig ist. Wenn ich den Apache neu starte, ist der Fehler für eine Weile (keine Ahnung, wie lange genau) weg.
[...] Denn wenn die _pos irgendwo in data steht, dann liest man Phantasiewerte für die Stringanzahlen aus, was den gleichen Effekt haben dürfte.
Das wird nicht passieren, siehe PHP: Variablen - Manual Der Default-Wert für Int ist 0, die Initialisierung spielt also keine Rolle. _pos wird immer richtig erhöht, nur liefert substr() leider nicht immer das, was man haben möchte. Ist wohl in der neuesten PHP-Version behoben.
Eine performante Lösung ist, die in WP nachimplementierte gettext-Funktion durch die entsprechende PHP-Funktion zu ersetzten - sofern vorhanden (s. PHP: Gettext - Manual ).
Ist mir auch aufgefallen. Allerdings macht das nichts, da $undefiniert += 1 == 1 ist und somit beim ersten read die Position initialisiert wird.
Das Problem bei mir war, dass substr sich manchmal um eine Stelle geirrt hat. Das hatte zur Folge, dass die readints bei load_table() ziemlichen Schrott geliefert haben (viel zu hohe Werte) und darauf hin versucht wurde, ein paar hunterttausend Strings einzulesen --> timeout.
Stelle gerade fest, dass mein Patch bei mir auch nicht richtig läuft, werde das jetzt mal ändern.
Update:
Wäh, dummer kleiner Fehler. Hier der aktuelle Patch:
class StringReader {
var $_pos;
var $_str;
function StringReader($str='') {
$this->_str = $str;
$this->_pos = 0;
}
function my_substr($in, $pos, $len) {
$out = "";
for ($i = $pos; $i < $pos + $len; $i++) {
$out .= $in[$i];
};
return $out;
}
function read($bytes) {
$data = $this->my_substr($this->_str, $this->_pos, $bytes);
$this->_pos += $bytes;
if (strlen($this->_str)<$this->_pos)
$this->_pos = strlen($this->_str);
return $data;
}
Alles anzeigen
Getestet und für nicht gut befunden. Diese Änderung zerschießt mir z.B. die Übersetzung des Simple Forums.
Schade. Was passiert genau?
Allerdings immer byteweise zu vergrößern, wäre ein Performance Problem, denn ein de_DE.mo enthält > 2000 Textpaare, von den int's mal ganz abgesehen !
Das ist wahr. Leider gehen einem die schnellen (weil intern auf memcpy basierend) Optionen aus, wenn so eine wichtige Funktion wie substr kaputt ist.
Hab jetzt nicht recherchiert, daher weiss ich nicht, warum das riesen File erstmal komplett in einen String gelesen wird und dann wieder alles aus dem String geholt wird. Wäre es nicht besser, direkt aus dem File zu lesen? Naja, schätze das wird wegen der Performance gerade nicht so gemacht...
So, hab auch mal ne Weile debugt, da mein Blog auch mit dem Fehler "Type V: not enough input, need 4, have 0 [...]" ausgestiegen ist. Das Problem trat erst nach einer Weile auf und hing davon ab, was auf meinen anderen Seiten los war (gleiche Installation). Für mich sieht es nach einem Fehler von substr() aus. Hier die Quick&Dirty-Korrektur:
In Datei wp-includes/streams.php:
Original:
class StringReader {
var $_pos;
var $_str;
function StringReader($str='') {
$this->_str = $str;
$this->_pos = 0;
}
function read($bytes) {
$data = substr($this->_str, $this->_pos, $bytes);
$this->_pos += $bytes;
if (strlen($this->_str)<$this->_pos)
$this->_pos = strlen($this->_str);
return $data;
}
function seekto($pos) {
$this->_pos = $pos;
if (strlen($this->_str)<$this->_pos)
$this->_pos = strlen($this->_str);
return $this->_pos;
}
Alles anzeigen
ändern in
class StringReader {
var $_pos;
var $_str;
function StringReader($str='') {
$this->_str = $str;
$this->_pos = 0;
}
function my_substr($in, $pos, $len) {
$out = "";
for ($i = $pos; $i <= $pos + $len; $i++) {
$out .= $in[$i];
};
return $out;
}
function read($bytes) {
$data = $this->my_substr($this->_str, $this->_pos, $bytes);
$this->_pos += $bytes;
if (strlen($this->_str)<$this->_pos)
$this->_pos = strlen($this->_str);
return $data;
}
function seekto($pos) {
$this->_pos = $pos;
if (strlen($this->_str)<$this->_pos)
$this->_pos = strlen($this->_str);
return $this->_pos;
}
Alles anzeigen
Bei mir läuft's damit bisher problemlos.