Я использую 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 (изменить) текущий фильм на другой.
Он не сможет этого сделать, потому что старое соединение не будет быстро разорвано, а пид будет оставаться открытым еще несколько секунд.
Если мы раскомментируем строку // posix_kill вышеуказанного кода пользователя не сможет увидеть ни одного фильма вообще потому, что каким-то образом функция posix_kill переопределяет все вышеперечисленные заголовки, а nginx / php не отправляет заголовки, которые у меня есть в файле.
Однако, если я отключу HTTP SEEK и включу posix_kill, как объяснено, пользователь сможет смотреть фильмы, НО он не сможет искать . Это происходит потому, что когда у нас есть заголовок Accept-Ranges, игроки делают несколько запросов к фильму перед его открытием.
Так, например, игрок сделает 2-3 запроса к этому файлу PHP, чтобы понять и идентифицировать поиск. Однако Posix_kill быстро убьет эти пиды, и игрок не сможет получить правильные заголовки.
Итак, мы хотим, чтобы решение, которое сделало бы мгновенный сброс PID соединения на сервере, когда пользователь закрывает соединение, но остается поддержкой поиска.
PS. Приведенный выше код с включенным posix_kill работает ОТЛИЧНО при потоковой трансляции, так как у нас нет поиска, поэтому игрок сделает только один запрос.
Надеюсь, что вы меня понимаете
Спасибо
Если у вас нет проблем с безопасностью. Чем использовать mp4 модуль nginx. Это работает как псевдопоток для mp4. После этого вам не нужно php искать фильм в любой части. Nginx Гендель сам.
Я решил проблему с fastcgi_finish_request ();
Из руководства по PHP:
Эта функция сбрасывает все данные ответа клиенту и завершает
запрос. Это позволяет выполнять трудоемкие задачи без
оставив соединение с клиентом открытым.
Моя функция выключения стала такой:
function shutdown()
{
fastcgi_finish_request();
posix_kill( getmypid(), 9 );
}