Пишем функцию скачки файлов (25кб!) (Рейтинг: +15)
Всем привет .
Если вы зашли прочитать эту статью, то наверняка задавались этим вопросом, либо вы просто хотите узнать что-то новое .
Поставим задачу: Написать функцию, которая будет отдавать файл частями и возможностью докачки файлов, в случае разрыва соединения.
Для решения задачи есть два способа решения: первый только отдает файл, соответственно она не является хорошим решением, но мы тоже его рассмотрим.
Начнем с простого способа. Пусть наш скрипт получает имя файла через какой-либо из параметров запроса. Это может быть реально набранный URL, а может быть и переписанный сервером при помощи mod_rewrite. Скрипт вызывает функцию file_download () с параметром $filename. Кроме прямой передачи в запросе $filename может также вычисляться на основе исходного идентификатора из запроса или дополняться путем в дереве папок сервера.
Самый легкий способ обработки запросов к скачиваемым файлам — это простое перенаправление на них.
Данный способ позволяет учитывать число закачек, но после перенаправления адрес файла становится доступным напрямую. Поэтому мы лишены возможности програмно контролировать как саму закачку файлов, так и скрыть их реальные адреса или взять их из папки, недоступной по протоколу HTTP.
Для этого потребуется усложнить нашу функцию закачки.
В своем скрипте (скачать) я использовал немного другую функцию:
---
Пишем комментарии, кто научился чему-то новому или просто понравилась статья
Добавил: iceman12
19.08.2010 / 14:47Если вы зашли прочитать эту статью, то наверняка задавались этим вопросом, либо вы просто хотите узнать что-то новое .
Поставим задачу: Написать функцию, которая будет отдавать файл частями и возможностью докачки файлов, в случае разрыва соединения.
Для решения задачи есть два способа решения: первый только отдает файл, соответственно она не является хорошим решением, но мы тоже его рассмотрим.
Начнем с простого способа. Пусть наш скрипт получает имя файла через какой-либо из параметров запроса. Это может быть реально набранный URL, а может быть и переписанный сервером при помощи mod_rewrite. Скрипт вызывает функцию file_download () с параметром $filename. Кроме прямой передачи в запросе $filename может также вычисляться на основе исходного идентификатора из запроса или дополняться путем в дереве папок сервера.
Самый легкий способ обработки запросов к скачиваемым файлам — это простое перенаправление на них.
<?php 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.
Для этого потребуется усложнить нашу функцию закачки.
<?php 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; ?>Теперь мы можем скрыть реальный адрес файла, взять его из папки, недоступной для браузеров и программ закачки. Недостатком данной функции является полная загрузка всего файла в память, что при больших его размерах может привести к ее переполнению. Чтобы избежать этой проблемы, можно считывать файл блоками небольшого размера.
<?php 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; } ?>
В своем скрипте (скачать) я использовал немного другую функцию:
<?php function downloadFile($filename, $name, $mimetype = 'application/octet-stream') { if (!file_exists($filename)) die('Файл не найден'); $from = $to = 0; $cr = null; if (isset($_SERVER['HTTP_RANGE'])) { $range = substr($_SERVER['HTTP_RANGE'], strpos($_SERVER['HTTP_RANGE'], '=') + 1); $from = strtok($range, '-'); $to = strtok('/'); if ($to > 0) ++$to; if ($to) $to -= $from; header('HTTP/1.1 206 Partial Content'); $cr = 'Content-Range: bytes ' . $from . '-' . (($to) ? ($to . '/' . $to + 1) : filesize($filename)); } else header('HTTP/1.1 200 Ok'); $etag = md5($filename); $etag = substr($etag, 0, 8) . '-' . substr($etag, 8, 7) . '-' . substr($etag, 15, 8); header('ETag: "' . $etag . '"'); header('Accept-Ranges: bytes'); header('Content-Length: ' . (filesize($filename) - $to + $from)); if ($cr) header($cr); header('Connection: close'); header('Content-Type: ' . $mimetype); header('Last-Modified: ' . gmdate('r', filemtime($filename))); $f = fopen($filename, 'r'); header('Content-Disposition: attachment; filename="' . $name . '";'); if ($from) fseek($f, $from, SEEK_SET); if (!isset($to) or empty($to)) { $size = filesize($filename) - $from; } else { $size = $to; } $downloaded = 0; while (!feof($f) and !connection_status() and ($downloaded < $size)) { echo fread($f, 512000); $downloaded += 512000; ob_flush(); flush(); } fclose($f); } ?>Но в принципе метод тот же
---
Пишем комментарии, кто научился чему-то новому или просто понравилась статья
Рейтинг:
+15
Просмотры: 3108Комментарии (14) »