Помнится, я искренне не понимал всю прелесть nginx. Ну подумаешь, веб-сервер — эка невидаль, у него даже аналога .htaccess нет и не известно, каким образом производить настройку сервера под свои нужды. Понимание пришло сильно позже — энджин, поставленный фронтэндом перед apache и настроенный на раздачу статики, способен в разы снизить общую нагрузку. Более того, с помощью специального заголовка можно делегировать задачу раздачи больших файлов из php. Но об этом я узнал позже. На тот момент я по старинке отдавал файлики средствами php.
Тут-то и возникла данная проблема. При отдаче файла в буфер (а на сервере, как помним, крутится связка nginx ↔ apache ↔ php) — не обязательно функцией readfile()
, можно и посредством echo file_get_contents();
или каким-то другим способом, некоторые файлы скачивались битыми (точнее даже, отдавалась лишь их часть, хотя из php данные уходили полностью).
Дальнейшие раскопки показали, что как только превышен определённый размер файла, он перестаёт «отдаваться» целиком.
Всему виной оказалась настройка сжатия gzip/deflate.
Мораль: нет нужды жать данные на уровне php ↔ apache, nginx сам прекрасно справится с этим. Но вот навредить при промежуточном пережатии очень даже можно.
Однако, как я уже отписал ранее, из php даже не нужно отдавать файлы. Гораздо выгоднее делегировать эту задачу энджину. Делается всё предельно просто: заместо того, чтобы выводить файл в буфер, просто пишем:
header('X-Accel-Redirect: ' . $fn_for_nginx);
где $fn_for_nginx — путь к файлу, который, в случае с apache, пришлось бы отдавать функцией readfile().
Однако тут есть один момент: в зависимости от настроек, путь может быть необходимо указывать от корня сайта, а не абсолютный путь операционной системы. Долго бился, пока не удосужился внимательно посмотреть логи и прочитать пути.
днём интернета
шоколадкой для работы мозга
коробочкой ароматного чая для бодрости
продлением хостинга на +1 месяц