10

content-length ヘッダーを含めずにファイルを apache php サーバーにアップロードすることは可能ですか?

ファイルのアップロードとしてその場で作成しているファイルをストリーミングしようとしています。content-length ヘッダーを使用しないと、「501 メソッドが実装されていません」という Apache が表示されます。

$sock = fsockopen($host,80,$errno, $error);
fwrite($sock, "POST $resource HTTP/1.1\r\n" .
                     "Host: $host\r\n\r\n");
fwrite($sock,fread($readHandle,filesize($file)));

content-length を含めると、正常に動作します。

サーバーは php://input から読み取っています

4

1 に答える 1

19

HTTP 仕様によると、技術的に Content-Length ヘッダーを指定する必要はありません。RFC 2616 14.13から:

アプリケーションは、セクション 4.4 のルールで禁止されていない限り、このフィールドを使用してメッセージ本文の転送長を示す必要があります。

ただし、これはほとんどのサーバーにとって非常に標準的な要件であり、Content-Lengthヘッダーが欠落しているか正しく指定されていない場合、通常はエラー応答を返します。すべての意図と目的において、この場合のSHOULDはMUSTと同等です。

Content-Length問題は (特にキープアライブ接続の場合)、要求メッセージがヘッダーなしで実際にいつ終了するかをサーバーが認識できないことです。リクエスト エンティティ ボディをストリーミングする場合のもう 1 つのオプションは、Transfer-Encoding: chunkedヘッダーを送信し、エンティティ ボディのチャンクを一度に 1 つずつ手動で送信することです。

Content-Length要約すると、メッセージと共にエンティティ本体を送信したいが、ヘッダーを送信したくない場合、唯一の現実的なオプションは、チャンクされた HTTP メッセージを送信することです。これは基本的に、そのエンティティ本体をストリーミングしたいが、その長さが事前にわからない場合に必要です。

ストリーミング用に HTTP エンティティ本体をチャンク エンコードする方法 ...

Transfer-Encoding: chunkedRFC2616 Sec3.6.1で定められた制約に従って、HTTP メッセージのエンティティ ボディをエンコードしていることを意味します。このエンコード形式は、リクエストまたはレスポンスのいずれかに適用できます (どちらも HTTP メッセージです)。この形式は、エンティティ本体のサイズや、エンティティ本体がどうなるかを正確に知る前に、HTTP メッセージの送信をすぐに開始できるため、非常に便利です。実際、これはまさに PHP が透過的に行うことでechoあり、header('Content-Length: 42').

チャンク エンコーディングの詳細については説明しませんが (HTTP 仕様はそのためのものです)、リクエスト エンティティ ボディをストリーミングしたい場合は、次のようにする必要があります。

<?php

$sock = fsockopen($host,80,$errno, $error);
$readStream = fopen('/some/file/path.txt', 'r+');

fwrite($sock, "POST /somePath HTTP/1.1\r\n" .
              "Host: www.somehost.com\r\n" .
              "Transfer-Encoding: chunked\r\n\r\n");

while (!feof($readStream)) {
    $chunkData = fread($readStream, $chunkSize);
    $chunkLength = strlen($chunkData);
    $chunkData = dechex($chunkLength) . "\r\n$chunkData\r\n";

    fwrite($sock, $chunkData);
}

fwrite($sock, "0\r\n\r\n");
于 2012-08-28T20:58:19.387 に答える