Php отдаем файлы эффективно

Отдаем файлы эффективно с помощью PHP

Метод хорош тем, что работает с коробки. Надо только написать свою функцию отправки файла (немного измененный пример из официальной документации):

function file_force_download($file) < if (file_exists($file)) < // сбрасываем буфер вывода PHP, чтобы избежать переполнения памяти выделенной под скрипт // если этого не сделать файл будет читаться в память полностью! if (ob_get_level()) < ob_end_clean(); >// заставляем браузер показать окно сохранения файла header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename=' . basename($file)); header('Content-Transfer-Encoding: binary'); header('Expires: 0'); header('Cache-Control: must-revalidate'); header('Pragma: public'); header('Content-Length: ' . filesize($file)); // читаем файл и отправляем его пользователю readfile($file); exit; > > 

Таким способом можно отправлять даже большие файлы, так как PHP будет читать файл и сразу отдавать его пользователю по частям. В документации четко сказано, что readfile() не должен создавать проблемы с памятью.

  • Скрипт ждет пока весь файл будет прочитан и отдан пользователю.
  • Файл читается в внутренний буфер функции readfile(), размер которого составляет 8кБ (спасибо 2fast4rabbit)

2. Читаем и отправляем файл вручную

Метод использует тот же Drupal при отправке файлов из приватной файловой системы (файлы недоступны напрямую по ссылкам):

function file_force_download($file) < if (file_exists($file)) < // сбрасываем буфер вывода PHP, чтобы избежать переполнения памяти выделенной под скрипт // если этого не сделать файл будет читаться в память полностью! if (ob_get_level()) < ob_end_clean(); >// заставляем браузер показать окно сохранения файла header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename=' . basename($file)); header('Content-Transfer-Encoding: binary'); header('Expires: 0'); header('Cache-Control: must-revalidate'); header('Pragma: public'); header('Content-Length: ' . filesize($file)); // читаем файл и отправляем его пользователю if ($fd = fopen($file, 'rb')) < while (!feof($fd)) < print fread($fd, 1024); >fclose($fd); > exit; > > 
  • Скрипт ждет пока весь файл будет прочитан и отдан пользователю.
  • Позволяет сэкономить память сервера

3. Используем модуль веб сервера

3a. Apache

Модуль XSendFile позволяет с помощью специального заголовка передать отправку файла самому Apache. Существуют версии по Unix и Windows, под версии 2.0.*, 2.2.* и 2.4.*

В настройках хоста нужно включить перехват заголовка с помощью директивы:

Читайте также:  Opera settings content javascript

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

Описание возможных опций на сайте разработчика: https://tn123.org/mod_xsendfile/

function file_force_download($file) < if (file_exists($file)) < header('X-SendFile: ' . realpath($file)); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename=' . basename($file)); exit; >> 
3b. Nginx

Nginx умеет отправлять файлы из коробки через специальный заголовок.

Для корректной работы нужно запретить доступ к папку напрямую через конфигурационный файл:

Пример отправки файла (файл должен находиться в директории /some/path/protected):

function file_force_download($file) < if (file_exists($file)) < header('X-Accel-Redirect: ' . $file); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename=' . basename($file)); exit; >> 

Больше информации на странице официальной документации

  • Скрипт завершается сразу после выполнения всех инструкций
  • Физически файл отправляется модулем самого веб сервера, а не PHP
  • Минимальное потребление памяти и ресурсов сервера
  • Максимальное быстродействие

Update: Хабраюзер ilyaplot дает дельный совет, что лучше слать не application/octet-stream , а реальный mime type файла. Например, это позволит браузеру подставить нужные программы в диалог сохранение файла.

Источник

Отдаем файлы эффективно с помощью PHP

Отдаем файлы эффективно с помощью PHP

Когда вообще нужно отдавать файлы через PHP? Например, когда нужно собрать какую-то статистику скачиваний файла или осуществить запрет на скачивание файлов, позволив скачивать по ссылке только один раз и ограниченной группе пользователей.

Допустим, чтобы скачать какой-то файл, мы отправляем пользователя не на прямую ссылку с расположением файла:

а на адрес скрипта, который отдает пользователю файл через PHP:

/files/download.php?file=$file_id

Где, в параметр file, для скрипта можно передавать идентификатор файла, который требуется скачать, после чего можно выстраивать различные проверки и выдавать пользователю файл для скачивания:

Header('location: /uploads/files/' . $file);

Сделать это можно несколькими способами, о которых речь пойдет ниже.

Функция readfile()

Этот метод будем применять в специально созданной функции. Такая функция поможет отправлять даже большие файлы, PHP будет отдавать файл пользователю по частям. Функция ждет, когда файл будет прочтен и отдан.

 /** * Отдача файла * Функция для отдачи файла через PHP * @param string $file путь к файлу на сервере * @return mixed */ function file_download($file) < if (file_exists($file)) < if (ob_get_level()) < ob_end_clean(); >header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename=' . basename($file)); header('Content-Transfer-Encoding: binary'); header('Expires: 0'); header('Cache-Control: must-revalidate'); header('Pragma: public'); header('Content-Length: ' . filesize($file)); readfile($file); return [ 'status' => 'success', 'message' => 'Файл успешно отдан' ]; >else < return [ 'status' =>'error', 'message' => 'Файл не найден' ]; > >

Чтение и отправка файла вручную

Эта функция аналогична той, которая описана выше, но для чтения и отдали файла используются: fopen, feof, fread, fclose. Функция ждет когда файл будет прочитан и отдан, также позволяет экономить память.

 /** * Отдача файла * Функция для отдачи файла через PHP * @param string $file путь к файлу на сервере * @return mixed */ function file_download($file) < if (file_exists($file)) < if (ob_get_level()) < ob_end_clean(); >header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename=' . basename($file)); header('Content-Transfer-Encoding: binary'); header('Expires: 0'); header('Cache-Control: must-revalidate'); header('Pragma: public'); header('Content-Length: ' . filesize($file)); if ($fd = fopen($file, 'rb')) < while (!feof($fd)) < print fread($fd, 1024); >fclose($fd); > return [ 'status' => 'success', 'message' => 'Файл успешно отдан' ]; >else < return [ 'status' =>'error', 'message' => 'Файл не найден' ]; > >

Отдаем файл через сервер

Отдать файл можем не скриптом, через PHP, а с помощью Apache или Nginx. Отдача файла средствами сервера дает максимальное быстродействие, минимум потребляет памяти и ресурсов сервера.

Читайте также:  Test

Для Apache есть модуль XSendFile, который поможет с помощью специального заголовка сделать отправку файла Apache. В настройках хоста включитте директиву перехвата заголовка:

Функция для отправки файла будет следующей:

 /** * Отдача файла * Функция для отдачи файла через PHP * @param string $file путь к файлу на сервере * @return mixed */ function file_download($file) < if (file_exists($file)) < header('X-SendFile: ' . realpath($file)); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename=' . basename($file)); return [ 'status' =>'success', 'message' => 'Файл успешно отдан' ]; >else < return [ 'status' =>'error', 'message' => 'Файл не найден' ]; > >

Nginx умеет отправку файла из коробки, все что нужно, настроить конфиг, указав запрет на доступ к каталогу (my/path/protected/):

Функция отправки файла выглядит так:

 /** * Отдача файла * Функция для отдачи файла через PHP * @param string $file путь к файлу на сервере * @return mixed */ function file_download($file) < if (file_exists($file)) < header('X-Accel-Redirect: ' . $file); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename=' . basename($file)); return [ 'status' =>'success', 'message' => 'Файл успешно отдан' ]; >else < return [ 'status' =>'error', 'message' => 'Файл не найден' ]; > >

Источник

Отдаем файлы эффективно с помощью PHP

Отдаем файлы эффективно с помощью PHP

2012-09-19 в 14:53, admin , рубрики: Apache, php, Веб-разработка, настройка системы, метки: apache, PHP, настройка системы

Если Вам потребовалось отдавать файлы не напрямую веб сервером, а с помощью PHP (например для сбора статистики скачиваний), прошу под кат.

1. Используем readfile()

Метод хорош тем, что работает с коробки. Надо только написать свою функцию отправки файла (немного измененный пример из официальной документации):

function file_force_download($file) < if (file_exists($file)) < // сбрасываем буфер вывода PHP, чтобы избежать переполнения памяти выделенной под скрипт // если этого не сделать файл будет читаться в память полностью! if (ob_get_level()) < ob_end_clean(); >// заставляем браузер показать окно сохранения файла header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename=' . basename($file)); header('Content-Transfer-Encoding: binary'); header('Expires: 0'); header('Cache-Control: must-revalidate'); header('Pragma: public'); header('Content-Length: ' . filesize($file)); // читаем файл и отправляем его пользователю readfile($file); exit; > > 

Таким способом можно отправлять даже большие файлы, так как PHP будет читать файл и сразу отдавать его пользователю по частям. В документации четко сказано, что readfile() не должен создавать проблемы с памятью.

  • Скрипт ждет пока весь файл будет прочитан и отдан пользователю.
  • Файл читается в внутренний буфер функции readfile(), размер которого нигде не указан (может кто подскажет)
Читайте также:  Python csv dictreader headers

2. Читаем и отправляем файл вручную

Метод использует Drupal при отправке файлов из приватной файловой системы (файлы недоступны напрямую по ссылкам):

function file_force_download($file) < if (file_exists($file)) < // сбрасываем буфер вывода PHP, чтобы избежать переполнения памяти выделенной под скрипт // если этого не сделать файл будет читаться в память полностью! if (ob_get_level()) < ob_end_clean(); >// заставляем браузер показать окно сохранения файла header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename=' . basename($file)); header('Content-Transfer-Encoding: binary'); header('Expires: 0'); header('Cache-Control: must-revalidate'); header('Pragma: public'); header('Content-Length: ' . filesize($file)); // читаем файл и отправляем его пользователю if ($fd = fopen($file, 'rb')) < while (!feof($fd)) < print fread($fd, 1024); >fclose($fd); > exit; > > 
  • Скрипт ждет пока весь файл будет прочитан и отдан пользователю.
  • Позволяет сэкономить память сервера

3. Используем модуль Apache XSendFile

Модуль XSendFile позволяет с помощью специального заголовка передать отправку файла самому Apache. Существуют версии по Unix и Windows, под версии 2.0.*, 2.2.* и 2.4.*

В настройках хоста нужно включить перехват заголовка с помощью директивы:

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

Описание возможных опций на сайте разработчика: https://tn123.org/mod_xsendfile/

function file_force_download($file) < if (file_exists($file)) < header('X-SendFile: ' . realpath($file)); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename=' . basename($file)); exit; >> 
  • Скрипт завершается сразу после выполнения всех инструкций
  • Физически файл отправляется модулем самого Apache, а не PHP
  • Минимальное потребление памяти и ресурсов сервера
  • Максимальное быстродействие

Источник

Оцените статью