2016-12-25 1 views
1

Ich schrieb eine kleine WebSocket-Bibliothek eine Weile zurück, und fand Hinzufügen von gzip Unterstützung überraschend einfach. Ich habe damals nicht ganz realisiert, dass die Funktionen eigentlich nur PHP 7 waren und ich nun meinen WebSocket Server in PHP 5 Umgebungen betreiben könnte.Binäre Interoperabilität zwischen gzdecode() und inflate_add()

Mein Problem ist, deflate_add() produziert Ausgabe, die sich geringfügig von gzdeflate() unterscheidet - um ein Zeichen im Testfall unten.

Der deflate_add()/inflate_add() basierte Ansatz funktioniert perfekt in-Browser, so die Ausgabe von gzdeflate() die falschen ist. Ich vermute, gzdeflate()/gzinflate() verwenden zlib mit verschiedenen zugrunde liegenden Optionen - etwas im Zusammenhang mit Stream-Status, vielleicht? - und das lässt alles auseinander fallen.

Letztendlich möchte ich wissen, ob ich PHP 5-Ära-Zlib-Funktionen überzeugen kann, "korrekte" deflationierte Daten auszugeben.


Vor allem die deflate_init()/deflate_add() basierten Ansatz, den ich auf PHP 7 verwendet:

$data = "ABC"; 

$ctx = deflate_init(ZLIB_ENCODING_RAW); 

// unfortunately I can't find the gigantic blog post with example code 
// that I learned from :(, but it contained the Ruby equivalent of the 
// the substr() below. I blinked at it a bit but apparently this is how 
// it's done. 
$deflated = substr(deflate_add($ctx, $data, ZLIB_SYNC_FLUSH), 0, -4); 

// $deflated is now "rtr\6\0" 

$ictx = inflate_init(ZLIB_ENCODING_RAW); 

$data2 = inflate_add($ictx, $deflated, ZLIB_NO_FLUSH); 

// $data2 is now "ABC" 

Hier ist was passiert, wenn ich gzdeflate()/gzinflate() verwenden passiert:

$data = "ABC"; 

$deflated = gzdeflate($data, 9, ZLIB_ENCODING_RAW); 

// $deflated is now "str\6\0" 

$output = gzinflate($deflated); 

// $output is now "ABC" 

Der Versuch, gzinflate() erzeugt die Ausgabe von inflate_add() einen data error. Als ein TL; DR:

print gzinflate("rtr\6\0")."\n"; // will bomb out 

print gzinflate("str\6\0")."\n"; // prints "ABC" 

Antwort

0

Was Sie richtig anrufen, ist falsch, und was Sie falsch nennen, ist richtig.

Mit deflate_add erstellen Sie absichtlich einen nicht abgeschlossenen, d. H. Ungültigen Deflate-Stream. Warum, ich habe keine Ahnung. (Offensichtlich auch nicht, da dies von einem "gigantischen Blogbeitrag" stammt, den Sie nicht finden können.) Dies geschieht mit der ZLIB_SYNC_FLUSH, die den aktuellen Deflate-Block vervollständigt und einen leeren gespeicherten Block anfügt. Die substr(,,-4) entfernt den größten Teil dieses leeren gespeicherten Blocks am Ende, so dass Sie einen unvollständigen, ungültigen Inflate-Stream erhalten, der vorzeitig in der Mitte eines gespeicherten Blocks endet.

gzdeflate auf der anderen Seite erstellt einen ordnungsgemäß beendeten Deflate-Stream, wobei ein einzelner Deflate-Block als letzter Block markiert wird. Der einzige Unterschied zwischen den beiden Strömen ist das erste (niedrigstwertige) Bit, das eine 1 ist, um den letzten Block zu markieren.

Sie sagen nicht, wie der ordnungsgemäß beendete Deflate-Stream "verursacht, dass alles auseinander fällt". In jedem Fall können Sie einen ordnungsgemäß terminierten Deflate-Stream mit deflate_add erstellen, indem Sie ZLIB_FINISH anstelle von ZLIB_SYNC_FLUSH verwenden und auf substr verzichten.

Es gibt keine Möglichkeit, einen ungültigen Deflate-Stream mit gzdeflate zu machen, wenn Sie das fragen. Sie können nicht nur das erste Bit ändern, da bei einem größeren String der letzte Block möglicherweise nicht der erste ist.