さて、前記事ではキャリアごとのダウンロード方法の特徴をつかむことができました。
今回はそれを元にスクリプトを修正します。
スクリプトの改良
docomoのサイトによると、RangeRequest(部分リクエスト)に対応するにはLast-Modified、Accept-Ranges、Content-Type、Content-Rangeの各ヘッダが必須となっています。
念のためですが、ApacheはE-Tagも吐き出しているのを確認したので、それも追加することにします。
auも部分リクエストに対応する必要がありますが、docomoの対応と同じだと思うので、docomoが出来ればauも一緒に対応できそうです。
If-Unmodified-Sinceヘッダに対する振る舞いは良く知らないので適当にあしらっておきました。
そんなわけで改良版のスクリプトは以下のような感じ。($file_path
, $mime_type
には本来キャリアごとの動画ファイルのパス、適切なMIMEタイプが入る)
// docomoやsoftbankの場合
$file_path = "/path/to/movie.3gp";
$mime_type = "video/3gpp";
$file_size = filesize($file_path);
if (($fp = fopen($file_path, "rb")) === false) {
header(" ", true, 404);
die;
}
$modified = gmdate("D, d M Y H:i:s", filemtime($file_path)) . " GMT";
$stats = stat($_SERVER['SCRIPT_FILENAME']);
$etag = sprintf('"%x-%x-%x"', $stats['ino'], $stats['size'], $stats['mtime']);
header("Last-Modified: " . $modified);
header("ETag: ".$etag);
header("Accept-Ranges: bytes");
// 更新日時の確認
$requests = apache_request_headers();
if (isset($requests["If-Unmodified-Since"]) && $requests["If-Unmodified-Since"] != $modified) {
header(" ", true, 412);
fclose($fp);
die;
}
// RangeRequest対応
if (!empty($requests["Range"])) {
list($range_begin, $range_end) = sscanf($requests["Range"], "bytes=%d-%d");
$content_length = $range_end - $range_begin + 1;
fseek($fp, $range_begin, SEEK_SET);
header("HTTP/1.1 206 Partial Content", true, 206);
header("Content-Range: bytes {$range_begin}-{$range_end}/{$file_size}");
} else {
$content_length = $file_size;
}
header("Content-Length: " . $content_length);
header("Content-Type: " . $mime_type);
// ファイル内容出力
echo fread($fp, $content_length);
flush();
fclose($fp);
結果
なんとかうまくいきました。3社とも無事にダウンロード&再生できています。
ちなみにPHPのデフォルト設定だと、レスポンスヘッダにPHPのバージョン情報が付加されてダウンロード不可になってしまうことがありますので、php.iniでexpose_phpをOffにします。
「expose_phpって何?それっておいしいの?」って方は下記リンクを参照ください。
まとめ
docomo
500KBまで → GETで一括取得
500KB以上 → 最初の受信でヘッダを解析し、後はRangeRequestで分割してダウンロードする。
au
最初にHEADでヘッダだけを取得した後にRangeRequestによる分割ダウンロードを行う。一回の要求サイズは126.5KB程度。
softbank
GETで一括取得。
今回の件は参考になったでしょうか。
コメント