Решил поделиться с интернетом своими изысканиями
Задача: подменить имя файла при скачивании с сервера
На сайте имеется загрузчик файлов, который для удобства хранения переменовывает файлы в случайный набор букв и цифр, оставляя родным только расширение файла, типа вот так: 44srCfNgQPwWw60Wg3m5.doc
Так же в БД хранится заодно настоящее имя файла (которое можно изменять через админку). Файлы лежат в директории /files/2012/01/44srCfNgQPwWw60Wg3m5.doc
Просто и понятно.
Понятное дело, чтобы лишний раз не грузить сервер (без отдачи файла через php) мы будем отдавать файл напрямую (те тупо дадим ссылку на него), но в диалоге сохранения файла браузер выдаст сохранить как «44srCfNgQPwWw60Wg3m5.doc». Это некрасиво. Умные люди придумали такой заголовок: Content-Disposition: attachment; filename=»downloaded.pdf». Т.е. если бы мы отдавали файл через php, то мы бы просто обратились к нему через readfile и перед выплевыванием в браузер добавили бы в том числе такой заголовок и наш файл абракадабра имел бы человеческий вид.
А теперь я расскажу как это сделать средствами apache2 (уверен, нечто подобное можно сделать и для nginx, этим я озадачусь чуть позже, посколько nginx на тестовом сервере установлено не было на момент изыскания). Единственный минус данного способа в том, что мы должны еще передавать GET переменную name к скачиваемому файлу с нужным именем файла
Лезем в .htaccess и пишем там нечто подобное
RewriteEngine On RewriteBase / RewriteCond %{REQUEST_FILENAME} -f RewriteCond %{QUERY_STRING} name=(.*) RewriteRule ^files\/([0-9]{4})\/([0-9]{2})\/(.*)\.(.*)$ files/$1/$2/$3.$4 [L,E=NAME:"%1.$4"]SetEnvIf Request_URI "^\/files\/([0-9]{4})\/([0-9]{2})\/(.*)\.(.*)$" NAME="$3.$4" Header set "Content-Disposition" "attachment; filename=%{NAME}e"
Теперь объясняю:
RewriteCond %{REQUEST_FILENAME} -f RewriteCond %{QUERY_STRING} name=(.*)
проверяем на сущестование файла и переменной name в GET, если переменная name есть, то ее записываем в %1
RewriteRule ^files\/([0-9]{4})\/([0-9]{2})\/(.*)\.(.*)$ files/$1/$2/$3.$4 [L,E=NAME:"%1.$4"]
переписываем существующий файл в него же, но добавляем переменную окружения NAME, которая состоит из переменной name из GET запроса, точки и расширения файла ($4)
SetEnvIf Request_URI "^\/files\/([0-9]{4})\/([0-9]{2})\/(.*)\.(.*)$" NAME="$3.$4"
Проверяем есть ли переменная NAME (ведь если RewriteCond не выполнятся, то RewriteRule не сработает и переменная окружения NAME создана не будет) и если переменной нету, то устанавливаем ее, пройдясь регуляркой по request_uri в котором есть «нечеловеческое» представление файла.
Header set "Content-Disposition" "attachment; filename=%{NAME}e"
Перед отдачей файла еще отдаем заголовок, в котором устанавливаем имя файла и берем его из переменной окружения NAME.
Итого получается:
/files/2012/01/44srCfNgQPwWw60Wg3m5.doc —> выплюнет на скачивание «44srCfNgQPwWw60Wg3m5.doc»
/files/2012/01/44srCfNgQPwWw60Wg3m5.doc?name=Очень%20важный%20документ —> выплюнет на скачивание «Очень важный документ.doc»
3 часа у меня ушло эти 7 строчек.
Спасибо за внимание