Сценарий обслуживания файлов PHP: ненадежные загрузки?

Этот пост начался с вопроса о ServerFault (https://serverfault.com/questions/131156/user-receiving-partial-downloads), но я определил, что виноват наш php-скрипт. Поэтому я задаю обновленный вопрос о том, что, по моему мнению, является реальной проблемой.

Я использую php-скрипт для проверки разрешений, а затем предоставляю файл для загрузки пользователям моего сайта. В большинстве случаев это работает, но недавно у одного пользователя возникли проблемы с большими загрузками. Он получает только ~ 80% загрузок для файлов размером> 100 МБ. Кроме того, все загрузки из этого скрипта не сообщают размер файла. Кроме того, тесты показали, что один и тот же пользователь МОЖЕТ надежно загрузить каждый из отказавших файлов, если ему дана прямая ссылка (в этот момент указывается размер файла).

Вот соответствующий фрагмент кода, который мы используем для обслуживания файла:

header("Content-type:$contenttype");
$len = filesize($filename);
header("Content-Length: $len");
header("Content-Disposition: attachment; filename=".$title.".".$ext);
readfile($filename);

Обратите внимание, что $ contenttype, $ filename, $ title и $ ext установлены правильно до того, как мы сюда попали. Они были проверены трижды. Ни одна из них не является проблемой. Кроме того, $ len предоставляет правильный размер файла.

Изучая эту проблему, я наткнулся на это сообщение: Заголовок Content-Length всегда равен нулю

Похоже, я столкнулся с той же проблемой. Когда я использую сценарий, я получаю фрагментированную кодировку для файла, и размер не задан для длины содержимого. Я предполагаю, что что-то идет не так с большими загрузками, из-за чего он получает кусок нулевой длины перед концом файла.

Вот как выглядят заголовки для прямого запроса:

http://www.grinderschool.com/videos/zfff5061b65ae00e8b21/KillsAids021.wmv

GET /videos/zfff5061b65ae00e8b21/KillsAids021.wmv HTTP/1.1
Host: www.grinderschool.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://www.grinderschool.com/phpBB3/viewtopic.php?f=14&p=29468
Cookie: style_cookie=printonly; phpbb3_7c544_u=2; phpbb3_7c544_k=44b832912e5f887d; phpbb3_7c544_sid=e8852df42e08cc1b2250300c2897f78f; __utma=174624884.2719561324781918700.1251850714.1270986325.1270989003.575; __utmz=174624884.1264524375.411.12.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=low%20stakes%20poker%20videos; phpbb3_cmviy_k=; phpbb3_cmviy_u=2; phpbb3_cmviy_sid=d8df5c0943863004ca40ef9c392d371d; __utmb=174624884.4.10.1270989003; __utmc=174624884
Pragma: no-cache
Cache-Control: no-cache

HTTP/1.1 200 OK
Date: Sun, 11 Apr 2010 12:57:41 GMT
Server: Apache/2.2.14 (Unix) mod_ssl/2.2.14 OpenSSL/0.9.8l DAV/2 mod_auth_passthrough/2.1 FrontPage/5.0.2.2635
Last-Modified: Sun, 04 Apr 2010 12:51:06 GMT
Etag: "eb42d6-7d9b843-48368aa6dc280"
Accept-Ranges: bytes
Content-Length: 131708995
Keep-Alive: timeout=10, max=30
Connection: Keep-Alive
Content-Type: video/x-ms-wmv

А вот как они выглядят для запроса, на который ответил мой скрипт:

http://www.grinderschool.com/download_video_test.php?t=KillsAids021&format=wmv

GET /download_video_test.php?t=KillsAids021&format=wmv HTTP/1.1
Host: www.grinderschool.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Cookie: style_cookie=printonly; phpbb3_7c544_u=2; phpbb3_7c544_k=44b832912e5f887d; phpbb3_7c544_sid=e8852df42e08cc1b2250300c2897f78f; __utma=174624884.2719561324781918700.1251850714.1270986325.1270989003.575; __utmz=174624884.1264524375.411.12.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=low%20stakes%20poker%20videos; phpbb3_cmviy_k=; phpbb3_cmviy_u=2; phpbb3_cmviy_sid=d8df5c0943863004ca40ef9c392d371d; __utmb=174624884.4.10.1270989003; __utmc=174624884

HTTP/1.1 200 OK
Date: Sun, 11 Apr 2010 12:58:02 GMT
Server: Apache/2.2.14 (Unix) mod_ssl/2.2.14 OpenSSL/0.9.8l DAV/2 mod_auth_passthrough/2.1 FrontPage/5.0.2.2635
X-Powered-By: PHP/5.2.11
Content-Disposition: attachment; filename=KillsAids021.wmv
Vary: Accept-Encoding
Content-Encoding: gzip
Keep-Alive: timeout=10, max=30
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: video/x-ms-wmv

Итак, вопрос в том ... что я могу сделать, чтобы загрузка из скрипта работала правильно? Опять же, для 99% пользователей он работает как есть (хотя меня сейчас раздражает то, что размер файла не сообщается и, следовательно, невозможно вычислить оценку времени загрузки).


person Jeffrey Blake    schedule 11.04.2010    source источник


Ответы (3)


Это ваше сжатие GZIP. Когда вы указываете длину контента, но включаете сжатие, все сводится к нулю. Со мной такое случалось несколько раз: попробуйте выключить это в своем скрипте.

Обычно вы включаете его с помощью:

ob_start("ob_gzhandler");

... так что просто закомментируйте эту строку. Если этого нет в вашем коде, скорее всего, параметр есть либо в вашем файле php.ini, либо в вашем apache.conf / conf.d.

Надеюсь это поможет!

person mattbasta    schedule 11.04.2010
comment
Этой строки нет в коде, поэтому я копаюсь в php.ini. Если вы случайно знаете, что мне нужно искать, это будет весьма кстати! - person Jeffrey Blake; 11.04.2010
comment
Попробуйте найти это: zlib_output_compression. Он должен быть выключен. - person mattbasta; 11.04.2010
comment
Моя ошибка: zlib.output_compression = Off и zlib.output_handler = Off - person mattbasta; 11.04.2010
comment
zlib.output_compression уже отключен. Другое значение было закомментировано по умолчанию, и я читал, что его следует использовать только при включенном output_compression. - person Jeffrey Blake; 11.04.2010
comment
Я пошел дальше и начал копаться в других местах конфигурации apache. В конце концов, я обнаружил параметр, который можно добавить в .htaccess для указанного каталога, чтобы предотвратить сжатие и на стороне apache: SetEnvIfNoCase Request_URI \ .php $ no-gzip dont-var - person Jeffrey Blake; 11.04.2010

Content-Encoding: gzip

Хм. Предположительно, zlib.output_compression PHP является делая это. (Не похоже на mod_deflate Apache.)

Попробуйте выключить его и посмотреть, не вызывает ли это принудительное кодирование фрагментов. Вы не хотите сжимать загрузку файлов такого типа, как WMV, которые уже сильно сжаты.

Однако фрагментированное кодирование объясняет только отсутствие отчета о размере. Загрузка все еще должна работать. Возможно ли, что у вас истекло время ожидания (например, PHP set_time_limit или Apache Тайм-аут)?

person bobince    schedule 11.04.2010
comment
Я согласен, что эти двое, вероятно, связаны. Я пытаюсь выяснить причину. zlib.output_compression уже отключен в php.ini - person Jeffrey Blake; 11.04.2010

Если это сценарий, то пробовали ли вы использовать заменяющую функцию для функции readfile (), которая читает и выводит по частям? Причина этого может заключаться в том, что где-то достигнут предел памяти, и он не работает.

Из http://php.net/manual/en/function.readfile.php:

function readfile_chunked ($filename) {
  $chunksize = 1*(1024*1024); // how many bytes per chunk
  $buffer = '';
  $handle = fopen($filename, 'rb');
  if ($handle === false) {
    return false;
  }
  while (!feof($handle)) {
    $buffer = fread($handle, $chunksize);
    print $buffer;
  }
  return fclose($handle);
} 

Кроме того, старайтесь как можно чаще сбрасывать выходные данные.

person zaf    schedule 11.04.2010