Комментарии 59
А можно передать отправку файла чему-нибудь более заточенному для работы со статикой и медленными клиентами, например nginx:
header(«X-Accel-Redirect: ».$file);die;
header(«X-Accel-Redirect: ».$file);die;
+27
Метод эквивалентный третьему, но с nginx. Удивлен, что не увидел его в статье.
+6
Всегда использовал этот метод, т.к. веб сервер и предназначен для отдачи файлов клиенту.
Для каждой задачи должен использоваться подходящий инструмент.
А первые 2 метода я бы не публиковал. Вижу строчку, которая будет необоснованно кушать лишнюю память и не читаю код дальше.
Для каждой задачи должен использоваться подходящий инструмент.
А первые 2 метода я бы не публиковал. Вижу строчку, которая будет необоснованно кушать лишнюю память и не читаю код дальше.
0
Первые два метода не только плохи, но и легко кладут сервер на лопатки при средней нагрузке.
0
Я думаю есть проекты, где нет возможности ставить свои модули для Apache или тот же Nginx.
0
Не верю. Приведите примеры. Берем Apache и связываем с nginx. Апач обрабатывает динамику, nginx берет на себя статику.
Если хостинг не предоставляет необходимых инструментов, в топку такой хостинг.
Если хостинг не предоставляет необходимых инструментов, в топку такой хостинг.
0
Не нужна даже средняя нагрузка. Достаточно большого файла и 1-2 клиентов на медленном канале, соответственно с бешеным (иначе на плохом канале совсем не жизнь) download manager, качающим в несколько потоков.
0
А разве первые два метода не отдают файл постепенно? Мне кажется, несколько потоков тут никакого профита не дадут.
0
В том то и дело, что они отдают постепенно и пока не отдадут полностью процесс (поток) висит. А кол-во таких процессов ограничено настройками веб-сервера, т.е. если качать кол-во файлов равное кол-ву процессов, то сайт перестанет отвечать.
0
Подскажите, при этом методе работает докачка?
0
Кто-нибудь подскажет, как быть с IIS?
У меня файл лежит на диске с уникальным именем, но в момент отдачи клиенту имя файла меняется на вменяемое, поэтому приходится делать что-то, типа первого варианта. А хотелось бы обойтись без php. Это реально?
У меня файл лежит на диске с уникальным именем, но в момент отдачи клиенту имя файла меняется на вменяемое, поэтому приходится делать что-то, типа первого варианта. А хотелось бы обойтись без php. Это реально?
0
Вы можете указать любое имя, например:
Оно не должно совпадать с именем на сервере. Пользователю браузер должен показать именно
header('Content-Disposition: attachment; filename=FAKE_NAME.TXT');
Оно не должно совпадать с именем на сервере. Пользователю браузер должен показать именно
FAKE_NAME.TXT
+4
Это я знаю, хотелось как раз обойтись при отдаче файла БЕЗ PHP — каким-нибудь хитрым редиректом именно в IIS,
что-нибудь типа
header(«x_redirect:real_name,fake_name), чтобы после этого сработали какие-нибудь механизмы IIS или расширения и файл бы отдался штатными средствами, но с новым именем.
что-нибудь типа
header(«x_redirect:real_name,fake_name), чтобы после этого сработали какие-нибудь механизмы IIS или расширения и файл бы отдался штатными средствами, но с новым именем.
-1
В заголовке.
с помощью PHP
0
не ясно, за что минус человеку влепили. Явно вопрос был, об альтернативах XSendFile и X-Accel-Redirect под IIS.
Посмотрите здесь.
www.helicontech.com/ape/
Посмотрите здесь.
www.helicontech.com/ape/
0
А как быть с русскими символами вместо FAKE_NAME.TXT?
0
Можно попробовать отталкиваться от RFC2231 и заворачивать примерно так:
header("Content-Disposition: attachment; filename*=\"utf8'ru-ru'кириллический utf8 текст\"");
0
Пользователь remal рекомендует статью на stackoverflow
0
Последний метод хорош, но негодится, если нужно ограничить доступ к файлу (только для авторизованных пользователей). Как решение — нужно создавать симлинк на файл с произвольным именем и периодически подчищать симлинки
-7
Последний метод у меня как раз используется в системе, где все файлы приватные. Доступ к директории закрыт в
.htaccess
. Файлы отдаются PHP скриптом, который делает все проверки (в реальности у меня Drupal).+3
Извините, симлинки это тотальный капец, и главное зачем?
Сверху nginx, за ним любой сервер. Предположим, что все «файлы» просятся из папки /files/. Например /files/some-file.file.
В конфиге nginx'а говорим, что такие файлы нао спросить у backend'а по такому то пути. На беке, хоть средствами того же php, проверяем авторизацию пользователя, если все ок — выдаем заголовки с mime-type и т.п. и через x-accel-redirect выдаем на nginx реальное имя файла, вычисленное каким-то кастомным образом из some-file.file. Для таких файлов в ngixn делаем internal location. Если юзер не авторизован или еще что-то не так, выдаем backend'ом 403, 404 или что вам там нужно
Сверху nginx, за ним любой сервер. Предположим, что все «файлы» просятся из папки /files/. Например /files/some-file.file.
В конфиге nginx'а говорим, что такие файлы нао спросить у backend'а по такому то пути. На беке, хоть средствами того же php, проверяем авторизацию пользователя, если все ок — выдаем заголовки с mime-type и т.п. и через x-accel-redirect выдаем на nginx реальное имя файла, вычисленное каким-то кастомным образом из some-file.file. Для таких файлов в ngixn делаем internal location. Если юзер не авторизован или еще что-то не так, выдаем backend'ом 403, 404 или что вам там нужно
+1
В случае аудио или видеофайлов первый метод не подойдет, так как браузер запрашивают файлы по частям, передавая заголовок Range. Придется обрабатывать его вручную, как описано в статье, но проще воспользоваться заголовками X-Accel-Redirect / X-SendFile.
0
>>> Файл читается в внутренний буфер функции readfile(), размер которого нигде не указан (может кто подскажет)
Функция readfile использует внутреннию функцию php_stream_passthru для отправки файла в output буффер. Сама по себе функция php_stream_passthru это алиас на функцию _php_stream_passthru в коде которого есть декларация буффера размером 8192 символов. Это означает что файл читаеться и отправляеться порция по 8 кБ.
Пруф линки:
github.com/php/php-src/blob/master/ext/standard/file.c#L1345
github.com/php/php-src/blob/master/main/php_streams.h#L448
github.com/php/php-src/blob/master/main/streams/streams.c#L1378
Функция readfile использует внутреннию функцию php_stream_passthru для отправки файла в output буффер. Сама по себе функция php_stream_passthru это алиас на функцию _php_stream_passthru в коде которого есть декларация буффера размером 8192 символов. Это означает что файл читаеться и отправляеться порция по 8 кБ.
Пруф линки:
github.com/php/php-src/blob/master/ext/standard/file.c#L1345
github.com/php/php-src/blob/master/main/php_streams.h#L448
github.com/php/php-src/blob/master/main/streams/streams.c#L1378
+9
header('Content-Type: application/octet-stream');
0
А еще можно читать HTTP-RANGE и отдавать то, что запросил клиент, тогда получим докачку файлов.
+9
Допустим, мы скриптом отдаем картинку. В хэдере пишем Content-Type: image/jpeg, но не указываем сontent-disposition (не attachment). Браузер ее корректно отображает. Но при ручном сохранении картинка сохраняется под именем имя_скрипта.php. Как предложить корректное имя?
0
Можно сделать так:
Делаем новый обработчик пути в системе, например
Работать будет только с включенным
Для браузера путь картинки будет обычным, соответственно при сохранении будет показано имя файла.
Идея нагло подсмотрена в Drupal (обработка приватных файлов).
Делаем новый обработчик пути в системе, например
/file/private
. Далее все запросы к картинкам делаем через него в формате /file/private/path/inside/your/private/directory/picture.jpg
. Обработчик пути должен выдать картинку исходя из параметров переданных скрипту.Работать будет только с включенным
mod_rewrite
. Для браузера путь картинки будет обычным, соответственно при сохранении будет показано имя файла.
Идея нагло подсмотрена в Drupal (обработка приватных файлов).
+1
Кажется, таким поведением грешит только хром.
Я пользуюсь как раз решением, описанным в комментарии выше (расширение в урле).
От себя хочу добавить: в таком случае лучше ещё сделать и правильное имя файла, чтобы у сохраняющего не получились файлы типа picture(5).jpg
Я пользуюсь как раз решением, описанным в комментарии выше (расширение в урле).
От себя хочу добавить: в таком случае лучше ещё сделать и правильное имя файла, чтобы у сохраняющего не получились файлы типа picture(5).jpg
0
полные заголовки таких ответов бы привели что ли
0
// сбрасываем буфер вывода PHP, чтобы избежать переполнения памяти выделенной под скрипт // если этого не сделать файл будет читаться в память полностью! if (ob_get_level()) { ob_end_clean(); }
output buffering может быть вложенным, поэтому правильным вариантом будет такой:
while (ob_get_level()) {
ob_end_clean();
}
+8
Согласно заголовку: «Отдаем файлы эффективно с помощью PHP»
стоило бы провести хоть маленькое исследование на предмет эффективности.
стоило бы провести хоть маленькое исследование на предмет эффективности.
+7
первые два метода — это как отдавать НЕ ЭФФЕКТИВНО
так что тут проводить на эффективность нечего
так что тут проводить на эффективность нечего
0
мой опыт работы говорит тоже самое,
но! вдруг, автор знаетособое конфуособые настройки, чтобы эти методы нормально работали.
и поэтому тестирование хоть какой либо нагрузки, помогло бы автору, закончить статью. и написать реалии использования того или иного метода
но! вдруг, автор знает
и поэтому тестирование хоть какой либо нагрузки, помогло бы автору, закончить статью. и написать реалии использования того или иного метода
0
Третий метод должен был быть первым.
+1
В целом статья хорошая, все правильно расписано про заголовки, но файлы отдавать напрямую РНР — это Зло, нет — это даже очень Большое Зло! Так что первые два пункта, можно рассматривать только как пример того, как не надо делать.
Файлы отдавать надо напрямую с WEB сервера специальными модулями, если это не аналог рапидшара, в которой куча серверов на отдачу и сделана принудительная задержка на отдачу контента для бесплатных скачиваний.
Как в принципе и закачивать надо средствами WEB сервера а не РНР.
Разработано куча специальных модулей. Я с Апачем не работаю лет уже как пять, и кроме XSendFile — я не знаю, но для nginx есть модули: X-Accel-Redirect,
Для закачки надо использовать ngx_upload_module — на эту тему статьи были на Хабре
Файлы отдавать надо напрямую с WEB сервера специальными модулями, если это не аналог рапидшара, в которой куча серверов на отдачу и сделана принудительная задержка на отдачу контента для бесплатных скачиваний.
Как в принципе и закачивать надо средствами WEB сервера а не РНР.
Разработано куча специальных модулей. Я с Апачем не работаю лет уже как пять, и кроме XSendFile — я не знаю, но для nginx есть модули: X-Accel-Redirect,
Для закачки надо использовать ngx_upload_module — на эту тему статьи были на Хабре
+1
для создания защищенной зоны от скачивания есть модули accesskey wiki.nginx.org/HttpAccessKeyModule
отдача приватных файлов организуется с помощью этих двух модулей
отдача приватных файлов организуется с помощью этих двух модулей
+1
а что если мне нужно отдать юзеру файл не со своего сервера а с внешнего? + учесть вариант «докачки» файла?
и, важный момент, редирект на сам файл не считается =)
и, важный момент, редирект на сам файл не считается =)
0
НЛО прилетело и опубликовало эту надпись здесь
Не только с mod_proxy: redmine.lighttpd.net/projects/1/wiki/X-LIGHTTPD-send-file
+2
Еще, полезно было бы упомянуть про ETag и набор http-функций для избежания велосипедов, в частности эти:
http_cache_etag();
http_send_file();
http_cache_etag();
http_send_file();
+1
Первые два варианта полезны и даже очень, если нет web сервера вообще, а есть работа с клиентом на микроконтроллере, только переписать пришлось на С++.
0
Надо только отметить, что контент диспозишены и прочее надо отсылать не в составе страницы, а в ответе сервера.
0
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Отдаем файлы эффективно с помощью PHP