適切なタイトルが思い浮かばなかったもので、何だか分かり辛い物になってしまいました。
どこか、HTTPサーバーから何か読み込む時に、取り敢えずヘッダーまで読み込んでおいて、その内容に応じて続きを読むかどうか、読むとしたらどういう読み方をするか(ファイルに保存するか標準出力などに出すかSAXやMessagePackとしてパースするか、単にやめるかなど)選びたかったりします。しますよね。するんです。
Guzzleを使うとそれが割と簡単にできるようになります。
↓で、ヘッダーまで読んでその続きがいらないと判断したら、while
ループに入らずにclose()
してしまえばいいです。
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Guzzle\Http;
use Guzzle\Stream;
use Guzzle\Parser\Message;
$client = new Http\Client('http://example.net');
$request = $client->get();
$factory = new Stream\PhpStreamRequestFactory();
$stream = $factory->fromRequest($request);
print_r($stream->getWrapperData());
$header = implode("\r\n", $stream->getWrapperData()) . "\r\n\r\n";
$parser = new Message\MessageParser;
$message = $parser->parseResponse($header);
print_r($message);
$buff = '';
while (!$stream->feof()) {
$c = $stream->read(1);
file_put_contents('php://stderr', $stream->ftell() . ":${c}". PHP_EOL);
$buff .= $c;
sleep(1);
}
$stream->close();
$stream->detachStream();
var_dump(strlen($buff) == $message['headers']['Content-Length']);
$ lsof | grep php | grep curl; ps | grep php
あたりをしながら見ていると、「一旦全部読み込んで、擬似的にストリームとして読み直している」のではなくて、ちゃんと「接続先から一バイトずつ読んでいる」(一バイトかは分からないけどずっと接続をキープしている)ことが分かります。
↑の例は一バイトずつだから、日本語文字みたいなマルチバイト文字を読んでいる時は別にその為の処理を入れる必要があることに注意してくださいね。
なお、都合でPHP5.3を使わなくちゃいけなくて、Guzzleの(古いバージョンである)3を評価していましたけど、そういう制約がないなら現行のバージョン4を使ったほうがいいと思います。結構使いやすそう。