За последние 24 часа нас посетили 17769 программистов и 1718 роботов. Сейчас ищут 962 программиста ...

Chrome и Яндекс.Браузер не отдают HTTP_RANGE

Тема в разделе "Прочие вопросы по PHP", создана пользователем Dion, 9 июн 2015.

  1. Dion

    Dion Новичок

    С нами с:
    8 июн 2015
    Сообщения:
    4
    Симпатии:
    0
    Добрый день!
    Отдача файлов пользователям осуществляется через PHP-скрипт. Реализована "докачка" файлов по наличию у клиента HTTP_RANGE.
    Однако HTTP_RANGE отдают только браузеры: Opera и Firefox, Chrome и Яндекс.Браузер повторные запросы на возобновление загрузки отдают без HTTP_RANGE, соответственно загрузка файла начинается заново. Chrome вообще дублирует зачем-то загрузку, оставляя недокаченную старую.
    Вероятно я делаю что-то не так. Может быть браузеру изначально нужно отдать какие-то специфические заголовки, о том что сервер поддерживает докачку файлов?
    Код (PHP):
    1. $file = './files/' . 'Zhizn.posle.ludei.(01.serija.iz.10).Tela.chto.my.ostavili.2009.XviD.TVRip.avi';
    2. $mime = 'video/x-msvideo';
    3.  
    4. if (file_exists($file)) {
    5.     set_time_limit(0); // Неограниченное время выполнение скрипта (для длительных загрузок)
    6.     
    7.     ob_end_clean(); // Отключаем буферизацию вывода
    8.  
    9.     $fd = fopen($file, 'rb'); // Открываем файл для чтения
    10.     
    11.     $file_size = filesize($file); // Определяем размер файла
    12.     
    13.     $range = 0;
    14.  
    15.     // Если докачка
    16.     if(isset($_SERVER['HTTP_RANGE']))
    17.     {   
    18.         $range = str_replace('bytes=', '', $_SERVER['HTTP_RANGE']);
    19.         $range = str_replace('-', '', $range); // Убираем лишнее "-"
    20.         header('Status: 206 Partial Content'); // Частичные данные
    21.         fseek($fd, $range); // Устанавливаем смещение в читаемом файле               
    22.     }
    23.     else
    24.     {
    25.         header('Status: 200 Ok'); // OK
    26.     }
    27.     
    28.     // HTTP-заголовки
    29.     //header('Content-Description: File Transfer');
    30.     header('Content-Type: ' . $mime);
    31.     header('Content-Disposition: attachment; filename=' . basename($file));
    32.     //header('Content-Transfer-Encoding: binary');
    33.     //header('Expires: 0'); 
    34.     //header('Cache-Control: must-revalidate');
    35.     //header('Pragma: public');
    36.     header('Accept-Ranges: bytes'); // Указываем, что система счисления - байты
    37.     header('Content-Length: ' . ($file_size - $range));
    38.     header('Content-Range: bytes ' . $range . '-' . $file_size . '/' . $file_size);
    39.     
    40.     // читаем файл и отправляем его пользователю
    41.     while (!feof($fd))
    42.     {
    43.         print fread($fd, 1024); // Вывод
    44.     }
    45.         
    46.     fclose($fd);
    47.     exit;
    48. }
    49. else
    50. {
    51.     echo 'Файл не найден!';
    52. }
    53.  
    P.S: Web-сервер IIS 7.5

    PHP, JavaScript, SQL и другой код пишите внутри тегов
    Код ( (Unknown Language)):
    1. [b]php][/b]Тут код[b][/[/b][b]code][/b][/color]
     
  2. runcore

    runcore Старожил

    С нами с:
    12 окт 2012
    Сообщения:
    3.625
    Симпатии:
    158
    а с чего это лишнее? '-' может означать диапазон, или байты отсчитанные с конца.
    плюс запросы может содержать диапазон. от сих до сих.
    в общем что браузер запросил то и нужно отдавать.
    запросы могут быть:
    Код (Text):
    1.  
    2. bytes=0-499
    3. bytes=500-999
    4. bytes=-500
    5. bytes=9500-
    6. bytes=0-0,-1
    7. bytes=500-600,601-999
    как видно, могут запрашиваться даже несколько диапазонов. это все нужно корректно парсить и отдавать. иначе браузер видит что вы ему фигню какуюто шлете. плюет. и пытается запросить опять все сначала)

    хотите сделать нормальную докачку читайте документацию по http_RANGE. если лень - отдавайте файлы nginx-ом, например. он докачку может.
     
  3. Dion

    Dion Новичок

    С нами с:
    8 июн 2015
    Сообщения:
    4
    Симпатии:
    0
    runcore, я знаком с положением о диапазоне(ах) значения Range. На данный момент пока не реализовано. Безусловно будет, но проблема в другом.
    При первичной отдаче клиенту файла, всё идёт замечательно, Браузеру пока не нужны никакие диапазоны - он скачивает файл целиком с 0 по размер файла.
    Но, если файл был скачен не до конца, по каким-то причинам загрузка была прервана - скажем половину скачал, а половину нет. Браузер же должен отдать web-серверу этот диапазон. Правильно? С какого по какой качать...
    В HTTP-заголовке от клиента это выглядит вот так:
    Код (Text):
    1. [Range] => bytes=129450409-
    и такие браузера как Opera и Firefox успешно предоставляют это значение.
    А вот Google Chrome и Яндекс.Браузер - НЕТ!!! (не дают они его!) Файл загружен наполовину, а они не говорят об этом. Почему? Я вот этого не понимаю.
    Откуда сервер знает, что сейчас ему нужно отдать диапазон, если сам клиент об этом молчит?

    С удовольствием сделал бы всё это на Nginx или Apache, но заказчик настаивает на IIS - хозяин барин.
     
  4. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.771
    Адрес:
    :сердА
    Потому что это экспериментальная функция. Включается в скрытых настройках. По дефолту неактивна. Телятся с ней, потому что она может представлять дыру в безопасности.

    Соль в том, что файлик мы качаем с бита по бит. Без предварительной передачи хэша. Можно, в теории, сделать страничку, которая под видом закачки православного файла, устроит прерывание и, при повторном запросе, "докачает" тебе зловреда, к примеру. Проверка, является ли докачанный файл тем, что ты начинал качать, не проводится никак. ЯндексБраузер - это тот же хром, но с перерисованными формочками.
     
  5. Dion

    Dion Новичок

    С нами с:
    8 июн 2015
    Сообщения:
    4
    Симпатии:
    0
    Fell-x27, логично!

    В общем, провёл несложный эксперимент.
    Яндекс.браузер докачивал файлы которые отдавались напрямую web-сервером. Но отданные скриптом - нет!
    Я решил сравнить HTTP-заголовки, которые отдаёт сервер при прямой загрузке, и то что отдаю скриптом я.
    Вот что из этого получилось.

    Прямая ссылка сервера:
    Код (Text):
    1. HTTP/1.1 200 OK
    2. Content-Length: 524918784
    3. Content-Type: video/x-msvideo
    4. Last-Modified: Fri, 16 Jul 2010 20:43:38 GMT
    5. Accept-Ranges: bytes
    6. ETag: "624f98912725cb1:0"
    7. Server: Microsoft-IIS/7.5
    8. Date: Wed, 10 Jun 2015 13:30:24 GMT
    Ссылка отданная моим скриптом
    Код (Text):
    1. HTTP/1.1 200 Ok
    2. Content-Length: 524918784
    3. Content-Type: video/x-msvideo
    4. Content-Range: bytes 0-524918784/524918784
    5. Accept-Ranges: bytes
    6. Server: Microsoft-IIS/7.5
    7. X-Powered-By: PHP/5.6.9
    8. Content-Disposition: attachment; filename=Zhizn.posle.ludei.(01.serija.iz.10).Tela.chto.my.ostavili.2009.XviD.TVRip.avi
    9. Date: Wed, 10 Jun 2015 13:31:08 GMT
    Первое что мне бросилось в глаза, заголовок: Last-Modified (дата-время изменения файла)
    Что в общем-то кажется логичным, Яндекс.Браузер молодец, он проверят когда файл был изменён. К такому случаю, когда например файл на сервере был изменён. Вдруг пока пользователь качал файл, его уже изменили на сервере, поэтому он сравнивает дату.

    Добавил заголовок Last-Modified к скрипту и Яндекс.Браузер стал предоставлять Range-параметр!!! ^^

    Но с Хромом, дела обстоят иначе. Данный браузер не докачивает даже прямые ссылки. Что как выяснилось является известной проблемой у него. Если Хром перезапустить, то он уже не продолжит загрузку с места обрыва. Думаю дело в том, что когда браузер закрывается, он автоматически удаляет за собой части недокаченных файлов (наверное так) "сборка мусора"!
     
  6. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.771
    Адрес:
    :сердА
    Да, у всех свои недостатки. В хроме это решается расширениями, к слову.