PHP
HTML5
iOS

ドキュメントルート外の動画ファイルをvideoタグで公開する際の注意点(HTTP_RANGE)

More than 3 years have passed since last update.

ドキュメントルート外にある動画を再生させるとなると

readfile()やfile_get_contents(), fread()を使用してドキュメントルート外にある動画をはき出してくれるようなphpを用いれば良いがそれではうまく再生できない場合がある。



・safari

・mobile safari

・chrome



これら3つのブラウザはサーバー側がHTTP_RANGEに対応していなければならない。

Content-Range:bytes 0-99

たとえば、ブラウザがサーバーに対して0~99までをリクエストしてきたとする。

ドキュメントルート内にある動画ファイルを直接読み込む場合は自動でHTTP_RANGEに対応してくれるのだが、間にPHPをかませる場合はその処理を自前で用意してやる必要がある。


video.php

<?php

$filePath = "/var/www/hoge.mp4";
$fileSize = filesize( $filePath );
$contentLength = $fileSize;

$contentPointer = fopen($filePath, "rb");

// ブラウザがHTTP_RANGEを要求してきたかどうか
if ( empty($_SERVER["HTTP_RANGE"]) ) {
header("Accept-Ranges: bytes"); //HTTP_RANGEに対応してますよと返答
header("Content-Type: video/mp4");
header("Content-Length: " .$contentLength);
header("Etag: \"" .md5( $_SERVER["REQUEST_URI"] ) .$fileSize ."\"" );

} else if ( isset($_SERVER["HTTP_RANGE"]) ) {
// ex: bytes=10-29といった感じで要求してくるので、10と29に切り分ける
list($rangeOffset, $rangeLimit) = sscanf($_SERVER['HTTP_RANGE'], "bytes=%d-%d");

header("HTTP/1.1 206 Partial Content");
header("Accept-Ranges: bytes");
header("Content-Type: video/mp4");

// ex: 10-29/ファイル総サイズ を送るよと返答
$contentRange = sprintf("bytes %d-%d/%d", $rangeOffset, $rangeLimit, $fileSize);
header("Content-Range: " .$contentRange);

// ex: 10-29までを送るということは、 29 - 10 + 1で20バイト
$contentLength = $rangeLimit - $rangeOffset + 1;
// ex: 20バイト送るよと返答
header("Content-Length: " .$contentLength);

header("Etag: \"" .md5( $_SERVER["REQUEST_URI"] ) .$fileSize ."\"" );

// ex: ファイルポインタを10まで移動させる
fseek($contentPointer, $rangeOffset);

}

// ex: fseekでファイルポインタを10まで移動している。そこから20バイト読み込む
$buffer = fread($contentPointer, $contentLength);
// ex: 標準出力へ読み込んだ分をはき出す
echo $buffer;
fclose($contentPointer);
exit;