Я запускаю PHP-FPM 5.6 и Nginx 1.7.6.
Я обслуживаю фильмы Matroska/Mp4, используя файл PHP. Код: этот:
<?php
register_shutdown_function( 'shutdown' );
$request = 'movie.mp4';
header( 'X-Accel-Buffering: no' ); //avoid nginx buffering.
header( 'Content-type: video/mp4' );
if ( file_exists( $request ) )
{
$fp = @fopen( $request, 'rb' );
$size = filesize( $request ); // File size
$length = $size; // Content length
$start = 0; // Start byte
$end = $size - 1; // End byte
header( "Accept-Ranges: 0-$length" );
if ( isset( $_SERVER['HTTP_RANGE'] ) )
{
$c_start = $start;
$c_end = $end;
list( , $range ) = explode( '=', $_SERVER['HTTP_RANGE'], 2 );
if ( strpos( $range, ',' ) !== false )
{
header( 'HTTP/1.1 416 Requested Range Not Satisfiable' );
header( "Content-Range: bytes $start-$end/$size" );
exit;
}
if ( $range == '-' )
{
$c_start = $size - substr( $range, 1 );
}
else
{
$range = explode( '-', $range );
$c_start = $range[0];
$c_end = ( isset( $range[1] ) && is_numeric( $range[1] ) ) ? $range[1] : $size;
}
$c_end = ( $c_end > $end ) ? $end : $c_end;
if ( $c_start > $c_end || $c_start > $size - 1 || $c_end >= $size )
{
header( 'HTTP/1.1 416 Requested Range Not Satisfiable' );
header( "Content-Range: bytes $start-$end/$size" );
exit;
}
$start = $c_start;
$end = $c_end;
$length = $end - $start + 1;
fseek( $fp, $start );
header( 'HTTP/1.1 206 Partial Content' );
}
header( "Content-Range: bytes $start-$end/$size" );
header( "Content-Length: " . $length );
ob_end_flush();
$buffer = 1024 * 8;
while ( ! feof( $fp ) && ClientConnected() && ( $p = ftell( $fp ) ) <= $end )
{
$response = stream_get_line( $fp, $buffer );
echo $response;
}
fclose( $fp );
}
function ClientConnected()
{
if ( connection_status() != CONNECTION_NORMAL || connection_aborted() )
{
return false;
}
return true;
}
function shutdown()
{
//main cause of problems is that line
//posix_kill( getmypid(), 9 );
}
Вы заметите, что вышеупомянутый скрипт поддерживает диапазоны Accept, чтобы пользователь мог искать фильм ! Эта функция работает отлично, а также сам фильм. Я могу посмотреть фильм с моего плеера, обратившись к нему без каких-либо проблем.
Проблема заключается в функции выключения. Вы можете спросить, почему я хочу использовать posix_kill и убить php pid.
У пользователя есть возможность выбрать несколько фильмов для просмотра в моем приложении. Пользователь имеет LIMIT для подключений, которые могут быть открыты на моем сервере. Это означает, что если у пользователя есть 1 доступный слот для подключения к серверу, он сможет открыть только один фильм одновременно.
По этой причине скажем, что пользователь в данный момент смотрит фильм, и он хочет, чтобы ZAP (изменить) текущий фильм на другой.
Он не сможет этого сделать, потому что старое соединение не закончится быстро, и pid останется открытым еще на несколько секунд.
Если мы раскомментируем строку //posix_kill вышеуказанного кода, пользователь не сможет увидеть какой-либо фильм вообще, потому что почему-то функция posix_kill переопределяет все вышеперечисленные заголовки, а nginx/php не отправляет заголовки, которые у меня есть в файле,
Однако, если я DISABLE HTTP SEEK и включите posix_kill, как описано, пользователь сможет смотреть фильмы, но он не сможет найти. Это происходит потому, что, когда у нас есть заголовок Accept-Ranges, игроки делают несколько запросов к фильму, прежде чем открывать его.
Так, например, игрок будет делать 2-3 запроса к этому файлу PHP, чтобы понять и идентифицировать поиск. Posix_kill, однако, быстро убьет эти pids, и игрок не сможет принять правильные заголовки.
Таким образом, нам нужно решение, которое сделает PID соединения на сервере мгновенно удаляться, когда пользователь закроет соединение, но останется поддержкой поиска.
PS. Вышеприведенный код с включенным posix_kill работает ОТЛИЧНО в режиме потокового вещания, поскольку мы не стремимся, чтобы игрок сделал только один запрос.
Надеюсь, ты меня понял
Если у вас нет проблемы с безопасностью. Тогда используйте mp4-модуль nginx. Он работает как псевдо-потоковая передача для mp4. После этого вам не нужен php, чтобы искать фильм на любой части. Сам Nginx.
Я решил проблему с fastcgi_finish_request();
Из руководства PHP:
Эта функция удаляет все данные ответа клиенту и завершает запрос. Это позволяет выполнять трудоемкие задачи, не оставляя открытое соединение с клиентом.
Моя функция останова:
function shutdown()
{
fastcgi_finish_request();
posix_kill( getmypid(), 9 );
}