Сценарий обслуживания файлов PHP: ненадежные загрузки? - PullRequest
2 голосов
/ 11 апреля 2010

Этот пост начинался как вопрос о 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% пользователей это работает как есть (хотя я нахожу это раздражающим сейчас, когда не сообщается ни о каком размере файла и, таким образом, невозможно рассчитать оценку времени загрузки).

Ответы [ 3 ]

2 голосов
/ 11 апреля 2010

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

Обычно вы включаете его:

ob_start("ob_gzhandler");

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

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

2 голосов
/ 11 апреля 2010
Content-Encoding: gzip

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

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

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

0 голосов
/ 11 апреля 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);
} 

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...