Часто приходится сталкиваться с задачей отдать файл, не засвечивая место его хранения.
Допустим на сервере лежит файл, который нужно отдать пользователю и хранится он в storage/file.pdf.
Для решения задачи отдавать его браузеру посредством скрипта можно так:
header('Content-type: application/octet-stream');
header('Content-Length: '.filesize('storage/file.pdf'));
header('Content-Disposition: attachment; filename="My new file.pdf"');
readfile('storage/file.pdf');
Первый заголовок призывает браузер отнестить к файлу как к бинарным данным. Второй говорит браузеру сколько байт он должен получить. Третий — под каким именем сохранять.
Не стоит беспокоиться о том, что функция readfile() может создать проблемы с памятью при передаче файлов большого объема, т.к. отдает файлы небольшими частями.
Единственный недостаток данного метода — это то, что файл передается через сервер Apache. Конечно, если на сервере не установлен Nginx, то мы ничего не теряем.
Если же на сервере Nginx установлен, то правильнее воспользоваться другими заголовками:
header('X-Accel-Redirect: storage/file.pdf');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="My new file.pdf"');
exit();
Обратите внимание, что функция readfile() в этом случае не нужна, т.к. благодаря заголовку "X-Accel-Redirect" за передачу файла от сервера к клиенту теперь отвечает сам Nginx.