2011-09-22 17 views
6

とzlibのフィルタを使用して、zlib.deflateフィルタはstream_socket_pair()によって生成されたソケットのペアを使用して動作していないようです。 2番目のソケットから読み取ることができるのは2バイトのzlibヘッダーだけです。それ以降はすべてNULLです。何らかの理由でソケットペア

例:

<?php 
list($in, $out) = stream_socket_pair(STREAM_PF_UNIX, 
            STREAM_SOCK_STREAM, 
            STREAM_IPPROTO_IP); 

$params = array('level' => 6, 'window' => 15, 'memory' => 9); 

stream_filter_append($in, 'zlib.deflate', STREAM_FILTER_WRITE, $params); 
stream_set_blocking($in, 0); 
stream_set_blocking($out, 0); 

fwrite($in, 'Some big long string.'); 
$compressed = fread($out, 1024); 
var_dump($compressed); 

fwrite($in, 'Some big long string, take two.'); 
$compressed = fread($out, 1024); 
var_dump($compressed); 

fwrite($in, 'Some big long string - third time is the charm?'); 
$compressed = fread($out, 1024); 
var_dump($compressed); 

出力:

string(2) "x�" 
string(0) "" 
string(0) "" 

私は、データが全体的に3つのすべての回をダンプされると、正しくstream_filter_append()への呼び出し、ストリームの書き込み/読み取り機能をコメントアウトした場合私がzlibでフィルタリングされたストリームをソケットのペアではなくファイルにすると、圧縮されたデータが正しく書き込まれます。したがって、両方の部品は正しくは別々に機能しますが、一緒には機能しません。これは私が報告しなければならないPHPバグですか、私の一部のエラーですか?

この質問はthis related questionに溶液から分岐しています。

答えて

2

the C source codeを見てみると、フィルタは常に圧縮された出力を生成する前に蓄積するデータの量をzlib's deflate() functionで決めることができます。 deflate()が何らかのデータを出力しないと(235行目を参照)、またはPSFS_FLAG_FLUSH_CLOSEフラグビットがセットされていないと(250行目)、デフレートフィルタは新しいデータバケットを作成しません。だからこそ、あなたが閉じるまであなたはヘッダバイトしか見ることができません。$in; deflate()への最初の呼び出しでは2つのヘッダーバイトが出力されるため、data->strm.avail_outは2であり、これらの2つのバイトが引き継がれる新しいバケットが作成されます。 fflush()が原因のzlibフィルタの既知の問題で動作しないことを

は注意してください。参照:Bug #48725 Support for flushing in zlib stream

残念ながら、これまでの素敵な回避策があるように表示されません。私はphp_user_filterを拡張してPHPでフィルターを作成し始めましたが、flags & PSFS_FLAG_FLUSH_CLOSEfilter()メソッドの4番目のパラメーター、一般的には$closingという名前のブール値の引数)かどうかだけ、php_user_filterがフラグビットを公開しないという問題に直面しました。 Bug#48725を修正するには、Cソースを自分で修正する必要があります。あるいは、書き直してください。

コードでいくつかの眉調達の問題があるようですので、個人的に私はそれを再作成を検討します:書き込み時にflagsは何だろう、なぜ、私は知らないので

  • status = deflate(&(data->strm), flags & PSFS_FLAG_FLUSH_CLOSE ? Z_FULL_FLUSH : (flags & PSFS_FLAG_FLUSH_INC ? Z_SYNC_FLUSH : Z_NO_FLUSH));は奇妙に思えますPSFS_FLAG_NORMAL以外。同時に&を書き込むことは可能ですか?いずれにしても、フラグの処理は、PSFS_FLAG_FLUSH_CLOSEがこのループの外側でどのように処理されるかのように、 "in"バケツ旅団を通じてwhileループの外側で実行する必要があります。
  • ライン221のmemcpyからdata->strm.next_inは、data->strm.avail_inがゼロでない可能性があるため、圧縮された出力は書き込みの一部のデータをスキップすることがあります。更新され、処理は、この時に再開されるすべての入力を処理することができない場合(出力バッファに十分なスペースがないので)、

    next_inavail_in:、例えば、zlibのマニュアルから、次のテキストを参照してください。次のコールのポイントはdeflate()です。

    つまり、avail_inはゼロではない可能性があります。

  • if行235、if (data->strm.avail_out < data->outbuf_len)の文は、おそらくif (data->strm.avail_out)またはおそらくif (data->strm.avail_out > 2)であるべきです。
  • *bytes_consumed = consumed;*bytes_consumed += consumed;ではない理由がわかりません。 http://www.php.net/manual/en/function.stream-filter-register.phpのストリームの例では、すべて+=を使用して$consumedを更新しています。

EDIT:*bytes_consumed = consumed;が正しいです。 The standard filter implementations allは+=ではなく=を使用して、size_tの値を5番目のパラメータで指すように更新します。また、PHP側の$consumed += ...size_text/standard/user_filters.cの行206および231を参照)の+=に有効に変換されても、NULLポインタまたはsize_tへのポインタを使用してネイティブフィルタ関数が呼び出され、5番目の引数が0に設定されます(main/streams/filter.cの行361および452を参照)。

+0

ありがとうございます。私はRubyで同じプロジェクトを実装し、Zlib :: deflate()への第2引数として 'Zlib :: SYNC_FLUSH'を渡す必要がありました。私はこれが書き込みであると仮定し、書き込み後すぐにフラッシュします。 'PSFS_FLAG_FLUSH_INC'フラグがセットされている場合、PHPは' Z_SYNC_FLUSH'のみを使用していますが、あなたが言ったように、フラグビットは公開されていないようです。 – FtDRbwLXw6

1

あなたはデータが読み取りから来る前にそれをフラッシュするために、書き込み後のストリームをクローズする必要があります。生成

list($in, $out) = stream_socket_pair(STREAM_PF_UNIX, 
            STREAM_SOCK_STREAM, 
            STREAM_IPPROTO_IP); 

$params = array('level' => 6, 'window' => 15, 'memory' => 9); 

stream_filter_append($out, 'zlib.deflate', STREAM_FILTER_WRITE, $params); 
stream_set_blocking($out, 0); 
stream_set_blocking($in, 0); 

fwrite($out, 'Some big long string.'); 
fclose($out); 
$compressed = fread($in, 1024); 
echo "Compressed:" . bin2hex($compressed) . "<br>\n"; 


list($in, $out) = stream_socket_pair(STREAM_PF_UNIX, 
            STREAM_SOCK_STREAM, 
            STREAM_IPPROTO_IP); 

$params = array('level' => 6, 'window' => 15, 'memory' => 9); 

stream_filter_append($out, 'zlib.deflate', STREAM_FILTER_WRITE, $params); 
stream_set_blocking($out, 0); 
stream_set_blocking($in, 0); 


fwrite($out, 'Some big long string, take two.'); 
fclose($out); 
$compressed = fread($in, 1024); 
echo "Compressed:" . bin2hex($compressed) . "<br>\n"; 

list($in, $out) = stream_socket_pair(STREAM_PF_UNIX, 
            STREAM_SOCK_STREAM, 
            STREAM_IPPROTO_IP); 

$params = array('level' => 6, 'window' => 15, 'memory' => 9); 

stream_filter_append($out, 'zlib.deflate', STREAM_FILTER_WRITE, $params); 
stream_set_blocking($out, 0); 
stream_set_blocking($in, 0); 

fwrite($out, 'Some big long string - third time is the charm?'); 
fclose($out); 
$compressed = fread($in, 1024); 
echo "Compressed:" . bin2hex($compressed) . "<br>\n"; 

: 圧縮:圧縮789c0bcecf4d5548ca4c57c8c9cf4b57282e29cacc4bd70300532b079c は:圧縮 789c0bcecf4d5548ca4c57c8c9cf4b57282e29cacc4bd7512849cc4e552829cfd70300b1b50b07:789c0bcecf4d5548ca4c57c8c9cf4b57282e29ca0452ba0a25199945290a259940c9cc62202f55213923b128d71e008e4c108c

はまた、私は私を混乱に$に書き込むので、うちで$を切り替えて$。

+0

返信いただきありがとうございますが、この解決策は実現可能なものではありません。書き込みのたびにソケットを開閉するためのオーバヘッドは、それ自体では禁止されますが、書き込みが終わるたびにzlibフィルタも破棄され、実装が中断されます。 zlibフィルタを使用するポイントは、連続した書き込みが同じフィルタを使用するためです。確かに閉鎖せずにフラッシュする方法があるはずですか?私は 'fflush()'を前に試しました。 **編集:**より明確にするためには、一度だけ送信されることを意図しているので、すべての書き込みをヘッダーに送信すると実装が中断されます。 – FtDRbwLXw6

3

私はPHPのソースコードに取り組み、修正を見つけました。

私は

.... 
for ($i = 0 ; $i < 3 ; $i++) { 
    fwrite($s[0], ...); 
    fread($s[1], ...); 
    fflush($s[0], ...); 
    fread($s[1], ...); 
    } 

ループの中にコードをトレースしていたし、新しいデータがbackets_in旅団に存在していないので、私はdeflate機能がZ_SYNC_FLUSHフラグセットで呼び出されることはありませんことを発見し、何が起こるか理解します。

私の修正が過度

if (flags & PSFS_FLAG_FLUSH_CLOSE) { 

管理FLUSH_INC延びる(PSFS_FLAG_FLUSH_INCフラグがANDない反復をデフレート関数場合に実行されていない設定されている)を管理することである。

if (flags & PSFS_FLAG_FLUSH_CLOSE || (flags & PSFS_FLAG_FLUSH_INC && to_be_flushed)) { 

This downloadable patchのためのものであるがdebian squeeze PHPのバージョンですが、現在のgitバージョンのファイルはそれに近いので、修正を移植することを想定しています(数行)。

副作用が発生した場合は、私に連絡してください。