readfile を使用して、クライアントがサーバー経由でファイルをダウンロードできるようにします。そのため、 readfile('external-url') から受け取ったデータをクライアントに直接出力します。
ここで、readfile() によって引き起こされるトラフィックを特定したいと考えています。
readfile の戻り値で判断できますが、クライアントがダウンロードを終了した場合のみです。そうしないと、スクリプトは動作を停止し、readfile() の戻り値は 0 になります。
最初にこのコードを試しました:
//outputs download headers
//creating $stream_context with request headers for the external download server
$traffic = readfile($url, false, $stream_context);
//save traffic...
クライアントがダウンロードを停止したときに、トラフィックの保存が呼び出されませんでした。
次に、トラフィックを節約するためのグローバル変数として $traffic を含む register_shutdown_function() でシャットダウン関数を登録しました。これで、トラフィック ファイルが作成されましたが、使用されたトラフィックは 0 でした。
サーバーログなどにアクセスできません。php と htaccess しか使えません。
私が現在使用している 1 つの回避策は、ファイルへの要求を開始し、ファイル サイズを解析して、完全なファイル サイズをクライアント トラフィックに追加することです。次に、readfile() でダウンロードを開始します。クライアントがダウンロードを停止すると、ファイル全体をダウンロードしたかのように処理されます。
3 番目の方法は、curl とその CURLOPT_WRITEFUNCTION 設定です。しかし、これはサーバーのオーバーヘッドが大きすぎて、私がやりたいこと、つまり実際のトラフィックを節約することとは関係ありません。
ファイルをダウンロードする前にクライアント トラフィックを保存することには、別の問題もあります。ダウンロードの再開とチャンク ダウンロード (ダウンロードを高速化するために 1 つのファイルへの複数の接続) をサポートしたいのです。これでも機能しますが、問題はトラフィックのカウントです! チャンクの場合、HTTP-RANGE ヘッダーを解析して要求されたファイルの部分を特定し、これをトラフィックとして保存できますが、再開についてはどうでしょうか。
では、世の中に解決策はあるのでしょうか?
私はまだデータベースを使用しておらず、htaccess -logininformation を含むファイルのみを使用してクライアントを識別し、各クライアントの使用済みトラフィックを Web スペースの個別のファイルに保存しています。
これも私のコードです:
//$download = array(url, filesize, filename) got it whith a separate curl request to the external file
$downloadHeader = CreateDownloadHeaders($download, $_hoster->AcceptRanges());
$requestOptions = array(
'http'=>array(
'method' => 'GET',
'header' => CreateRequestHeaders($download['filesize'], $_hoster->AcceptRanges())
)
);
$requestOptions['http']['header'] = array_merge($requestOptions['http']['header'], $_hoster->GetAdditionalHeaders());
//Output download headers for our client
foreach($downloadHeader as $header) {
header($header);
}
register_shutdown_function('SaveTraffic', $username, $givenUrl, $download['filename'], $download['filesize']);
//SaveTraffic($username, $givenUrl, $download['filename'], $download['filesize']);
$context = stream_context_create($requestOptions);
$traffic = readfile($download['url'], false, $context);
そして今、機能:
function CreateDownloadHeaders($download, $acceptRanges) {
//IE workaround for downloads
$type = (isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'],'MSIE')) ? 'force-download' : 'octet-stream';
$headers = array(
'Content-Type: application/' . $type,
'Content-Disposition: attachment; filename="'.$download['filename'].'"',
'Content-Length: '.$download['filesize'],
'Content-Transfer-Encoding: Binary',
'Expires: 0',
'Cache-Control: must-revalidate, post-check=0, pre-check=0',
'Pragma: public',
'Connection: close'
);
$headers = AddDownloadRangeHeaders($headers, $acceptRanges, $download['filesize']);
return $headers;
}
function CreateRequestHeaders($filesize, $acceptRanges) {
$headers = array();
$headers = AddRequestRangeHeaders($headers, $acceptRanges, $filesize);
$headers[] = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; de; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13';
$headers[] = 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8';
$headers[] = 'Accept-Language: de, en-gb;q=0.9, en;q=0.8';
$headers[] = 'Accept-Encoding: gzip, deflate';
$headers[] = 'Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7';
$headers[] = 'Cache-Control: no-cache';
$headers[] = 'Pragma: no-cache';
$headers[] = 'Connection: close';
return $headers;
}
function AddDownloadRangeHeaders($headers, $acceptRanges, $filesize) {
if($acceptRanges !== true) {
$headers[] = 'Accept-Ranges: none';
}
elseif(isset($_SERVER['HTTP_RANGE'])) {
preg_match('/bytes([[:space:]])?=([[:space:]])?(\d+)?-(\d+)?/', $_SERVER['HTTP_RANGE'], $matches);
$start = intval($matches[3]);
$stop = intval($matches[4]);
if($stop == 0) {
$stop = $filesize;
}
$headers[] = 'HTTP/1.1 206 Partial Content';
$headers[] = 'Accept-Ranges: bytes';
$headers[] = 'Content-Range: bytes ' . $start . '-' . $stop . '/' . $filesize;
$newSize = $stop - $start + 1;
$key = array_search('Content-Length: '.$filesize, $headers);
$headers[$key] = 'Content-Length: '.$newSize;
}
return $headers;
}
function AddRequestRangeHeaders($headers, $acceptRanges, $filesize) {
if($acceptRanges === true && isset($_SERVER['HTTP_RANGE'])) {
preg_match('/bytes([[:space:]])?=([[:space:]])?(\d+)?-(\d+)?/', $_SERVER['HTTP_RANGE'], $matches);
$start = intval($matches[3]);
$stop = intval($matches[4]);
if($stop == 0) {
$stop = $filesize;
}
$headers[] = 'Range: bytes='.$start.'-'.$stop;
}
return $headers;
}