Реализация возможности скачивания директорий пользователями сайта

от автора

Есть небольшой закрытый сайт, на котором выкладывается музыка альбомами и пользователи сайта имеют возможность эти альбомы слушать прямиком из браузера. На сервере альбомы хранятся в виде директорий, внутри которых хранятся сами музыкальные композиции, которые по требованию плеера отдаются nginx-ом.
Все было хорошо, пока пользователи не захотели скачивать понравившиеся альбомы целиком на свои компьютеры.

Под катом раскажу как мы реализовали это.

Первое решение, которое приходит в голову — создавать архив каждого альбома и отдавать его пользователю.
Главная причина по которой мы отказались от этого варианта: у нас много музыки и создание архива для каждого альбома означает, что количество дискового пространства нужно умножить на два — пока мы себе этого позволить не можем.

Нам показалось, что идеально было бы формировать архив альбома по запросу и на лету. Если при создании архива отключить сжатие, то накладные расходы должны быть небольшими, ну и сами расходы для нас не особо критичны — на данный момент у нас большой запас по процессорному времени и оперативной памяти, в отличие от постоянного хранилища.

Поиск модуля для nginx, или каких-то других готовых решений, результата не дал — будем реализовывать сами — задача не сложная.

Для архивации будем использовать стандартную программу zip, без сжатия и данные не будем писать в файл, а направим сразу в stdout. Для такой цели логичнее было бы использовать tar, но у нас обычные пользователи и для многих будет загадкой что делать с tar или tar.gz архивом.

Теперь нам надо как-то передать сжатые данные nginx-у, который отдаст их пользователю.
Для этих целей на шелле был написан простенький cgi-скрипт:

#!/bin/bash  # Корневая директория, от нее будут идти пути в архиве и внутри нее хранятся все альбомы homeDir="/storage/media/audio"  # Имя скачиваемой директории передается в строке запроса, строку запроса надо декодировать downloadDir=$(echo $QUERY_STRING | sed -f urldecode.sed)  # Переходим в корневую директорию pushd "$homeDir" > /dev/null  # Если директория существует - на лету упаковываем ее в zip без сжатия и возвращаем в качестве тела ответа if [ -d $downloadDir ]  && [ ! -z $downloadDir ] then     echo "Content-Type: application/octet-stream"     echo "Content-Disposition: attachment; filename=$downloadDir.zip"     echo ""     /usr/bin/zip -r -0 - "$downloadDir" else     echo "Status: 404 Not Found"     echo "Content-Type: text/html"     echo ""     echo "<h1>404 File not found!</h1>" fi  # Возвращаемся в начальную директорию popd > /dev/null 

Скрипт прост, думаю дополнительно его комментировать будет излишне.

Так как имя директории приходит url-кодированное, мы его раскодируем, для этого используем sed и небольшой скрипт для него, скрипт берем здесь и кладём рядом с нашим cgi-скриптом.

Все знают, что nginx поддерживает FastCGI и не поддерживает CGI, чтобы наш скрипт все таки работал будем использовать Fcgiwrap.

Ставим:

apt-get install fcgiwrap

И конфигурируем:

# support for cgi scripts (require fcgiwrap) location ~ \.cgi$ {     gzip off;     try_files $uri =404;       # pass scripts to fcgiwrap     fastcgi_pass unix:/var/run/fcgiwrap.socket;          # Используем стандартные параметры     include /etc/nginx/fastcgi_params;     fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;     fastcgi_ignore_client_abort off; } 

Перезапускаем nginx и можно пользоваться: /download.cgi? имя_директории_для скачивания

ссылка на оригинал статьи http://habrahabr.ru/post/194904/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *