|
|
|
|
|
|
Всякое |
Скачивание файлов в PHPМногие ресурсы используют файловые хранилища. Кроме возможностей загрузки и хранения файлов, бывает необходимо организовать их скачивание. Одно дело когда файлы лежат в открытом доступе, но и тогда может потребоваться передача файла через PHP. Например, администратору ресурса может быть нужна информация о количестве скачиваний. Для файлов большого объема до сих пор требуется возможность докачки, что пожалуй и является самым трудным моментом для серверных скриптов. Посмотрим как можно организовать работу скрипта на PHP, который позволяет реализовать все вышеуказанные возможности. Начнем с простого способа. Пусть наш скрипт получает имя файла через какой-либо из параметров запроса. Это может быть реально набранный URL, а может быть и переписанный сервером при помощи mod_rewrite. Скрипт вызывает функцию file_download() с параметром $filename. Кроме прямой передачи в запросе $filename может также вычисляться на основе исходного идентификатора из запроса или дополняться путем в дереве папок сервера. Самый легкий способ обработки запросов к скачиваемым файлам - это простое перенаправление на них. function file_download($filename) { // Проверяем существование файла if (file_exists($filename)) { // Здесь пишем код, который будет обрабатывать каждую загрузку файла. // Перенаправляем клиента на файл. header('Location: ' . $filename); } else { // Если файл не найден, сообщаем клиенту об этом через заголовки HTTP header($_SERVER["SERVER_PROTOCOL"] . ' 404 Not Found'); header('Status: 404 Not Found'); } // Прерываем дальнейшее выполнение скрипта, чтобы не отправлять мусор в ответе клиенту exit; } Данный способ позволяет учитывать число закачек, но после перенаправления адрес файла становится доступным напрямую. Поэтому мы лишены возможности програмно контролировать как саму закачку файлов, так и скрыть их реальные адреса или взять их из папки, недоступной по протоколу HTTP. Для этого потребуется усложнить нашу функцию закачки. function file_download($filename, $mimetype='application/octet-stream') { if (file_exists($filename)) { // Отправляем требуемые заголовки header($_SERVER["SERVER_PROTOCOL"] . ' 200 OK'); // Тип содержимого. Может быть взят из заголовков полученных от клиента // при закачке файла на сервер. Может быть получен при помощи расширения PHP Fileinfo. header('Content-Type: ' . $mimetype); // Дата последней модификации файла header('Last-Modified: ' . gmdate('r', filemtime($filename))); // Отправляем уникальный идентификатор документа, // значение которого меняется при его изменении. // В нижеприведенном коде вычисление этого заголовка производится так же, // как и в программном обеспечении сервера Apache header('ETag: ' . sprintf('%x-%x-%x', fileinode($filename), filesize($filename), filemtime($filename))); // Размер файла header('Content-Length: ' . (filesize($filename))); header('Connection: close'); // Имя файла, как он будет сохранен в браузере или в программе закачки. // Без этого заголовка будет использоваться базовое имя скрипта PHP. // Но этот заголовок не нужен, если вы используете mod_rewrite для // перенаправления запросов к серверу на PHP-скрипт header('Content-Disposition: attachment; filename="' . basename($filename) . '";'); // Отдаем содержимое файла echo file_get_contents($filename); } else { header($_SERVER["SERVER_PROTOCOL"] . ' 404 Not Found'); header('Status: 404 Not Found'); } exit; } Теперь мы можем скрыть реальный адрес файла, взять его из папки, недоступной для браузеров и программ закачки. Недостатком данной функции является полная загрузка всего файла в память, что при больших его размерах может привести к ее переполнению. Чтобы избежать этой проблемы, можно считывать файл блоками небольшого размера. function file_download($filename, $mimetype='application/octet-stream') { if (file_exists($filename)) { header($_SERVER["SERVER_PROTOCOL"] . ' 200 OK'); header('Content-Type: ' . $mimetype); header('Last-Modified: ' . gmdate('r', filemtime($filename))); header('ETag: ' . sprintf('%x-%x-%x', fileinode($filename), filesize($filename), filemtime($filename))); header('Content-Length: ' . (filesize($filename))); header('Connection: close'); header('Content-Disposition: attachment; filename="' . basename($filename) . '";'); // Открываем искомый файл $f=fopen($filename, 'r'); while(!feof($f)) { // Читаем килобайтный блок, отдаем его в вывод и сбрасываем в буфер echo fread($f, 1024); flush(); } // Закрываем файл fclose($f); } else { header($_SERVER["SERVER_PROTOCOL"] . ' 404 Not Found'); header('Status: 404 Not Found'); } exit; } Продолжение следует... |
|
Direqtor Home Page by ASIADATA. |
|
Отправить комментарий