Уже неоднократно сталкивался с задачей выведения пользователю на скачивание файлов, залитых в качестве свойств инфоблока... И если это самое свойство ставить с типом "Файл" то битрикс автоматически данному файлу присваивал уникальное имя, конфликта файлов в системе не возникало, но вот выдавать этот файл было крайне проблематично.
До недавнего времени вместо свойства "Файл" ставил другое - "Привязка к файлу на сервере" и тогда по ИД файла вытягивалось его имя, файл выдавался на скачивание и все было просто замечательно.
Но, в один прекрасный момент, возникла задача и необходимость более профессионального подхода к данному вопросу и вот решил сделать полноценный механизм по закачке/скачке файлов.
Итак, сама задача:
Пользователь сайта через компонент добавления нового элемента ИБ добавляет свой элемент. Одним из свойств элемента является поле "Файл" с типом "Файл". Дальше этот элемент через вывод списка новостей выводим другим пользователям. Файл должен быть доступен для скачивания с тем именем, с которым его заливали, а не с той "кракозяброй", с которой он хранится на сервере.
Решение:
Заливка файла проходит нормально, обычным образом, поэтому на ней останавливаться не буду.
Вывод элементов происходит с помощью стандартного компонента news.list. При выводе элементов, когда добираемся до свойства с файлом, получаем всего-лишь ИД файла и ничего больше.
Т.к. у меня таких файлов могло быть несколько, то данный блок получился такой:
Тут мы делаем перебор по всем файлам, добавленным в данное свойство элемента. Получаем файл по его ИД. Для отображения пользователю нормального, читабельного имени, получаем имя, с которым данный файл был загружен на сервер:
$arFile["ORIGINAL_NAME"]
Дальше выводим ссылку пользователю на скачивание файла:
Скачивание файла не напрямую, а через другой вспомогательный файл со скриптом, было сделано сначала просто потому, что пользователю файл при сохранении выдавал все-таки не то имя, которое мы отображаем, а то, с которым он хранится на сервере и с этим надо было как-то бороться. Вот и пришел к решению, что нужно создать доп. файл, в котором будет определяться нужное имя файла. Этому скрипту передаем ИД файла, который нужно скачать...
Скрипт начинается со строки, в которой мы проверяем указан ли вообще ИД файла:
<? if(isset($_GET['file'])){
Дальше мы снова получаем оригинальное имя файла и транслитерируем его. В Данной транслитерации учтены символы русского и украинского языка. Кому нужны еще какие-то символы - добавляйте.
Для того, чтобы построить нужную нам схему html-файла, которая будет нам выдавать файл на скачивание, нужно указать соответствующие head-функции. Все данные для этих функций можно выбрать из свойств файла. Что в принципе и было сделано...
Битриксовая функция получения пути файла выдает путь не физический (где файл лежит на сервере), а путь относительно корня сайта. поэтому к пути нужно добавить где сайт лежит физически на сервере.
Теперь построчно самый важный кусок всего скрипта:
Имя файла, которое будет выдано пользователю при сохранении:
Тип файла - нужен в основном для того, чтобы браузер понимал, что делать с этим файлом:
header("Content-Type: $c_Type");
Непосредственное чтение файла:
readfile($file);
Уже после реализации, осознал несколько преимуществ такого скачивания.
Во-первых, это конечно же транслитерация названия файла. Она является достаточно важным моментом данной реализации, т.к. не все браузеры нормально реагируют на кириллицу.
Во-вторых, пользователь никак не может получить прямую ссылку на файл. И если внутри скрипта поставить доп. проверку на то, а может ли текущий пользователь скачивать этот файл, то воспользоваться прямой ссылкой без авторизации на сайте уже будет очень проблематично...
Update 2015-08-04: Рекомендую файл-обработчик скачивания начинать не с
Vadim Dumbravanu обнаружил уязвимость в приведенном скрипте, рекомендую ознакомиться с выводами по уязвимости и принять свое собственное решение, что с этим делать. У меня, к сожалению или счастью, нет проектов, на которых есть необходимость в данном скрипте, но, возможно, кому-то будет полезно.
Итак! Скрипт содержит критическую уязвимость, поэтому в приведенном виде не может быть использован в конечных проектах. Описание уязвимости:
1) перебором ID можно выкачать все загруженные файлы - а вы не можете знать, какие из них защищены по доступу 2) можно указать путь к файлу - т.к. к целому значению параметр не приводится, то скачается любой произвольный файл, включая dbconn.php с паролем к БД К сожалению, этот уязвимый скрипт уже разошелся по ряду проектов. Если Вы лично имеете отношение к таким проектам, рекомендую срочно внести правки, либо удалить этот скрипт на них.
Могу порекомендовать: 1) Передавать не только ID картинки, но и ID элемента инфоблока и проверять, что в этом элементе есть эта картинка 2) все параметры приводить к целому.
разобрался - у Вас в скрипте перед выводом заголовков подключается шапка сайта и скачиваемый файл портится у Вас require($_SERVER["DOCUMENT_ROOT"]."/bitrix/header.php"); а надо require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");
Egorenkov Alexey, ааа. да, действительно забыл... Когда делал этот скрипт был еще очень слаб в тонкостях подключения ядра:) благодарю за найденную ошибку.... Сейчас переношу потихоньку все свои наработки на свой сайт и заодно вычитываю все, что писал и вношу корректировки:)
Группы на сайте создаются не только сотрудниками «1С-Битрикс», но и партнерами компании. Поэтому мнения участников групп могут не совпадать с позицией компании «1С-Битрикс».