PHP readfile возвращает файл нулевой длины

Это странно.

У меня есть скрипт, который отправляет локальные zip-файлы пользователю через браузер. Скрипт работает нормально до сих пор без каких-либо проблем. Сегодня мой коллега сообщил мне, что скрипт отправляет файлы нулевой длины.

Немного справочной информации:

  • Настройки сервера не были изменены до того, как скрипт дал сбой
  • Протестированы разные браузеры (то же самое в Chrome/Firefox)
  • Предыдущие zip-файлы (которые раньше работали нормально) также имеют нулевую длину.
  • Скрипт находит файлы на сервере
  • Размер файла (при отображении для отладки) правильный
  • Попытка настроить параметры сервера и сценарий, как рекомендуется здесь, безуспешно.

ОБНОВЛЕНИЯ:

  • is_readable() возвращает 1
  • размеры файлов могут варьироваться от 5 МБ до 100 МБ (не конкретно)
  • $zip_file содержит путь к файлу
  • $zip_name содержит имя почтового индекса
  • файл действительно нулевой длины (открытый в текстовом редакторе, он не содержит ни одного байта)
  • error_reporting это On (E_ALL) ничего не показывает
  • без заголовков браузер правильно отображает «источник» zip
  • Safari говорит: «0 байт? не может декодировать необработанные данные' первый полезный(?) симптом

Фрагмент вопроса:

if (file_exists($zip_file)) {
    header('Content-type: application/zip');
    header('Content-disposition: filename="' . $zip_name . '"');
    header("Content-length: " . filesize($zip_file));
    readfile($zip_file);
    exit();
}

Как я могу отладить это легко?

Заранее спасибо, Фабрик


person fabrik    schedule 21.03.2011    source источник
comment
Глупый вопрос: файл существует?   -  person Thom Wiggers    schedule 21.03.2011
comment
вы можете использовать is_readable() вместо file_exists(). is_readable проверяет, существует ли файл и доступен ли он для чтения.   -  person JohnP    schedule 21.03.2011
comment
Являются ли они нулевой длины или очень малой длины? В последнем случае они могут содержать сообщение об ошибке PHP. Просто скачайте файл и откройте его в текстовом редакторе.   -  person Unicron    schedule 21.03.2011
comment
@TGOD Пожалуйста, внимательно прочитайте мой вопрос: скрипт находит файлы на сервере   -  person fabrik    schedule 21.03.2011
comment
@JohnP, @Unicron только что обновил мой вопрос в ответ на ваши советы. Спасибо.   -  person fabrik    schedule 21.03.2011
comment
@fabrik: хорошо, но мы не можем видеть остальную часть кода, не так ли? Может был баг, который позволял проскальзывать несуществующий файл или что-то в этом роде.   -  person Thom Wiggers    schedule 21.03.2011
comment
В чем разница между $zip_file и $zip_name?   -  person Thom Wiggers    schedule 21.03.2011
comment
@TGOD, когда я печатаю некоторую отладочную информацию внутри if, она печатается хорошо. Файл найден, размер правильный, но результирующий файл имеет нулевую длину.   -  person fabrik    schedule 21.03.2011
comment
@fabrik это действительно буквально нулевая длина? Отчеты об ошибках включены?   -  person Unicron    schedule 21.03.2011
comment
Что происходит, когда вы получаете содержимое файла, сохраняете его в переменной и просто выводите без заголовков? Он что-нибудь распечатывает?   -  person JohnP    schedule 21.03.2011
comment
@JohnP стомегабайтная переменная?   -  person fabrik    schedule 21.03.2011
comment
@fabrik, ой! пропустил размер файла! Глядя на примечания к записи вручную: php.net/manual/en/function .readfile.php вы можете попробовать очистить буфер или переключиться на фрагментированный метод   -  person JohnP    schedule 21.03.2011
comment
@JohnP Нет проблем :) Также, как я указал в своем вопросе, я безуспешно пытался использовать буферизацию вывода :(   -  person fabrik    schedule 21.03.2011
comment
@fabrik проверяет, прошел ли первый фрагмент. Вы можете запустить Xdebug на Eclipse, чтобы увидеть, в чем именно проблема.   -  person JohnP    schedule 21.03.2011
comment
@JohnP, отображающий файл непосредственно в окне браузера, работает «отлично». Кажется, что-то происходит с заголовками?   -  person fabrik    schedule 21.03.2011


Ответы (4)


http://www.php.net/manual/en/function.readfile.php#102137< /а> :

Следует отметить, что в примере:

header('Content-Length: ' . filesize($file));

$file действительно должен быть полным путем к файлу. В противном случае длина содержимого не всегда будет установлена, что часто приводит к ужасной проблеме «0-байтового файла».

person Thom Wiggers    schedule 21.03.2011
comment
Спасибо за подсказку, но если я повторяю размер файла, он дает мне правильное значение. - person fabrik; 21.03.2011
comment
не имеет значения, когда браузер начинает получать файл, единственный способ узнать его полный размер — через заголовки. - person RobertPitt; 21.03.2011
comment
@ Роберт, я имею в виду эхо для отладки. - person fabrik; 21.03.2011
comment
Удалите header('Content-Length: ' . filesize($file)); для отладки. - person powtac; 21.03.2011
comment
о, Том, ты спас мой день. Большинство проблем с 0 байтами, обнаруженных в вопросах SO, связаны с тем, что люди ошибочно устанавливают размер файла ($ файл), а $ файл - это просто дескриптор. ЗДЕСЬ $file должен быть полным путем к файлу. Я установил его как этот заголовок (Content-Length: .filesize ($ filePath)); и это сработало сразу. - person webblover; 16.01.2014

Я думаю, что самая большая проблема здесь заключается в том, как вы отправляете файл, пробовали ли вы отправлять его в кусках:

if (file_exists($zip_file))
{
    header('Content-type: application/zip');
    header('Content-disposition: filename="' . $zip_name . '"');
    header("Content-length: " . filesize($zip_file));

    $resource = fopen($zip_file,'r');
    while(!feof($resource))
    {
         $chunk = fread($resource,4096);
         //....
         echo $chunk;
    }

    exit();
}
person RobertPitt    schedule 21.03.2011
comment
Спасибо за подсказку, но мне это никак не помогло. Кстати, когда все будет хорошо, я реализую ваше решение. +1 - person fabrik; 21.03.2011

Попробуйте добавить attachment; и используйте другой браузер.

header('Content-disposition: attachment; filename="' . $zip_name . '"');
person powtac    schedule 21.03.2011
comment
Посмотрите мой собственный ответ. Это была полностью моя вина, извините. stackoverflow.com/questions/ 5375143/ - person fabrik; 21.03.2011

Моя. Хромой. Ошибка. Извините за всех.

Просто подправил код неделю назад и добавил:

if (substr_count($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip')) {
    ob_start('ob_gzhandler');
} else {
    ob_start();
}

Что вызвало эту аномалию. :(

person fabrik    schedule 21.03.2011
comment
Что вы сделали, чтобы решить эту проблему? Вы только что удалили обратный вызов ob_gzhandler? - person acme; 07.03.2013