Скрипт для скачивания файла

Меня уже давно интересовал вопрос, как например, при клике по ссылке вида: http://servicefile/files/d58y1e предлагается скачать файл к примеру с названием test.zip. По такому принципу работают файлообменники. Оказалось все достаточно просто.  Сейчас я сделаю небольшое отступление.

Во времена статических web сайтов, у вебмастеров были весьма сильно связаны руки, не было возможности для реализации многих идей. Да и сайты кроме набора текста и пару картинок с баннерами, больше ничего из себя не представляли. Но времена изменились. И сейчас встретить в сети статический сайт становиться постепенно так же сложно, как раньше можно было бы встретить в сети сайт динамический. Но с появлением таких языков для веб программирования как PHP, ASP.NET и других,  интернет в большой степени словно “обогатился”. Соответственно появилось очень большое количество технических возможностей по созданию веб сайтов. Раньше все в больше мере ограничивалось HTML в связке с  JavaScript и редко с VBScript. Появились интернет магазины, электронные библиотеки, файлообменники, информационные порталы и другие, интересные и полезные веб ресурсы. Нет, конечно, они и раньше существовали, но это были не те магазины и порталы.  И вот у владельце таких ресурсов возникла задача, а как сделать так, чтобы при выдаче ссылки на загрузку того или иного файла, не выдать реальное его местоположение. К примеру, файл, ссылка на который была представлена выше, физически находиться на servicefile/www/files/ и имеет имя test.zip. Как же так? Наверняка спросите вы, а все гениально просто. Есть такой очень и очень хороший модуль mod_rewrite  который включается в стандартный дистрибутив Apache, но также необходим еще файл конфигурации веб-сервера Apache htaccess. Вот это все что нам необходимо. Ссылка вида: http://servicefile/files/d58y1e составлена в соответствии с концепцией mod_rewrite. Но как происходит нам выдача на загрузку файла test.zip, если мы видим на первый взгляд ссылку невразумительного вида. Вот это мы сейчас и разберем более подробно.

От слов к делу

Конечно, для таких целей нужно использовать базу данных. Но в примере, который я приведу, мы ограничимся массивом. Писать скрипт будем на PHP. Я не буду разбирать загрузку файлов на сервер. Об этом и без моего участия написано достаточно. А приведу лишь конкретные примеры. Для получения загруженного файла на сервер, нам необходимо работать с глобальной переменной $_FILES, которая в свою очередь является массивом. Вот какие поля у нее есть:

$_FILES[‘file’][‘name’] Оригинальное имя файла
$_FILES[‘file’][‘type’] Mime-тип файла
$_FILES[‘file’][‘size’] Размер файла в байтах
$_FILES[‘file’][‘tmp_name’] Временное имя файла на сервере.
$_FILES[‘file’][‘error’] Код ошибки

Возможные коды ошибок

0 UPLOAD_ERR_OK Ошибки нет
1 UPLOAD_ERR_INI_SIZE Размер файла превышает допустимый размер,  который задан директивой upload_max_filesize конфигурационного файла php.ini.
2 UPLOAD_ERR_FORM_SIZE Размер загружаемого файла превысил значение MAX_FILE_SIZE, указанное в HTML-форме.
3 UPLOAD_ERR_PARTIAL Загружаемый файл был получен только частично.
4 UPLOAD_ERR_NO_FILE Файл не был загружен.

Нам при обработке файла необходимо сохранить информацию из полей:

$_FILES['file']['name'] и $_FILES['file']['type'].

Далее нам необходимо создать файл конфигурации веб-сервера Apache htaccess. Со следующим содержанием:

#Директива RewriteEngine. Включает или выключает работу механизма преобразования.

RewriteEngine On

#Директива RewriteBase. Устанавливает базовый URL для преобразований в каталоге.

RewriteBase /# Ссылка на получение файла RewriteRule ^files/(.*)$ load.php?hash=$1 [L]

При отправке GET запроса вида: http://servicefile/files/d58y1e, происходит вот что. Сначала веб сервер Apache проверяет обязательно наличие файла htaccess в корне хоста. А именно в нашем случае в этом файле и находятся преобразования mod_rewrite, и если сервер находит соответствующее преобразование в этом модуле, то он перенаправляет запрос на соответствующий скрипт. В нашем случае, все происходит так: url который начинается с files/ далее идет набор произвольных символов. О чем свидетельствует выражение (.*). Набор произвольных символов идет до конца строки, т.е. до окончания url, все символы которые попадают под выражение (.*) – это наш hash, а именно “d58y1e”. В итоге скрипт load.php, получает значение параметра hash. Ниже приведен сам код скрипта:

<?php
// Путь до текущего каталога
define ( 'ROOT_DIR', dirname ( __FILE__ ) );

$files = array ();

$files['name'] = 'test.zip';
$files['type'] = 'application/zip';
$files['hash'] = 'd58y1e';

if (isset($_REQUEST['hash']) && $_REQUEST['hash'] != "";) {
	$hash = $_REQUEST['hash'];

	// Проверка на соответствие хеша
	if ($files['hash'] == $hash) {

		$fileName = ROOT_DIR . "/files/$files[name]";

		$zip = '';

		// Считываем нужный нам файл
		$f = fopen($fileName, 'rb');
		if ($f) {
			$zip = fread($f, filesize($fileName));
		}
		fclose($f);

		// Отправляем необработанные заголовки
		header ( "Expires: Mon, 1 Apr 1974 05:00:00 GMT" );
		header ( "Last-Modified: " . gmdate("D,d M YH:i:s") . " GMT" );
		header ( "Cache-Control: no-cache, must-revalidate" );
		header ( "Pragma: no-cache" );
		header ( "Content-type: $files[type]" );
		header ( "Content-Disposition: attachment; filename=$files[name]" );
		// Выводим содержимое файла
		print $zip;
	}
}
?>

Теперь при открытие ссылки http://servicefile/files/d58y1e в браузере, браузер предложит скачать файл test.zip.

Менеджер загрузки

Единственное что я был заметил, так это то, что если вы хотите таким образом выдать ссылку на загрузку *.exe файла, то он относиться к бинарному (двоичному типу файлов) и соответственно имеет media-тип – application/octet-stream. Поэтому некоторые браузеры в таком случае предлагают сохранять такие файлы с расширением *.html (многие сервисы отдают файлы *.exe файлы в расширении *.html). Конечно, расширение файла можно переименовать и все будет отлично, ну лучше сделать дополнительную проверку на расширение файла и если он является исполняемым файлом операционной системы windows (*.exe) то присвоить в качестве значения media-типа – application/zip. Вы можете скачать полный исходник.  Класс cURL прилагается.