Наши заметки о MODx
В этом разделе мы будем собирать небольшую копилку секретов по работе с системой управления контентом сайта (CMS) MODx. Эти заметки ни в коем случае не претендуют на лавры документации. На нашем сайте тема MODx вообще занимает небольшой уголок, и эти материалы мы размещаем только потому, что по роду основной работы нам приходится оказывать техническую поддержку нескольким десяткам организаций, использующих наши прототипы сайтов. В то же время кое-что может пригодиться и другим людям.
Мы не претендуем на изложение "истины в последней инстанции". Наверняка в этих заметках гуру MODx найдут неточности и ошибки. Мы будем очень благодарны, если на это нам укажут в комментариях.
В заметках мы стараемся не просто сразу приводить готовое правильное решение, но и показываем, как мы набивали шишки в процессе поиска.

Как организовать Download с сайта


Без скачивания файлов не может обойтись, пожалуй, ни один сайт. Мы - не исключение. Монстров закачек, наподобие DownloadEngine рассматривать не будем, попробуем обойтись средствами MODX.

Какая же нам нужна система для скачивания файлов с нашего сайта:

1. Загрузка файлов на сайт нас не интересует особо - позволять делать это посетителям мы не собираемся.

2. Для скачиваемых файлов должна быть возможность русского названия, какой-то аннотации, указания размеров файла.

3. Должна быть скрыта прямая ссылка на файл - иначе мы бы просто давали линк в любом месте.

4. Конечно нужен счетчик закачек.

5. Требуется ограничение доступа к скачиванию всяких праздношатающихся.

Что же мы имеем на эту тему в репозитории MODx? А не особенно чего имеем. Есть ранее знакомые нам FileDownload сниппет с плагином и более свежий сниппет FileDownloadPE. Вот с него и начнем.

Сниппет FileDownloadPE

Это не простой FileDownload, это PE - то есть Pirate Edition! Круто! Наверное. "Будем посмотреть".

В общем, всё работает, файл скачивается, счетчик добавляется.  Только такая маленькая деталь - скачанный архив не открывается, испорчен. Это, видимо связано с MIME-types.В параметре TV указано правильно - application/zip, а в момент скачивания определяется неправильно - application/octet-stream.

Кроме того, к файлу прицепляется расширение .html. Автор рекомендует отключить для сайта суффиксы URL. Это нам просто никак не подходит.

В общем, от  FileDownloadPE мы решили отказаться. "Такой хоккей нам не нужен!".

Сниппет-плагин FileDownload

  Эта "сладкая парочка" работает по другому принципу.

FileDownloadPlugin скрывает настоящие имена файлов, загружаемых с сайта. Он использует TV-параметр FileDownloadFolder, в котором указыватся папка с файлами.

Ссылка на файл получается в виде http://cadx2009/ru_files.html/ru_source_explorer_2.0.zip

Вообще-то это неправильно - такого файла действительно нет, но по этой ссылке можно загрузить файл.
А нам это надо?

Но нужно получше разобраться с настройками. Скорее всего это учтено.

Сниппет FileDownload автоматически отображает файлы в заданной папке

FileDownloadPlugin поддерживает:

  • Скачивание файлов из каталога, заданного  TV-параметром  FileDownloadFolder.
  • Привилегий для работы с документами - файл нельзя скачать, если WEB- пользователь не имеет к нему доступа.
  • Скачивание больших файлов без тайтм-аутов при малом использовании памяти.
  • Частичную загрузку по  HTTP/206
  • Докачку после разрывов соединений.
  • Интеграцию со сниппетом FileDownload.
Установка


1) Создать новый  TV FileDownloadFolder с типом ввода text.

2) Создать плагин FileDownloadPlugin.

3) Вставить код плагина.

3) Отметить событие  OnWebPagePrerender.

4) Сохранить плагин.


  Нужно ещё настроить в .htaccess  правило:

RewriteRule ^([^/]*)/?(.*)$ index.php?q=$1&d=$2 [L,QSA]


А то, что было предусмотрено в MODx, закомментировать:

#RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]


Еще можно поэкспериментировать с настройками блока памяти (мы этого делать не стали) в коде плагина:

define('FILE_DOWNLOAD_BLOCK_SIZE', 256 * 1024);
define('FILE_DOWNLOAD_VARIABLE', 'FileDownloadFolder');

Дальше надо браться за сниппет.


Сниппет FileDownload

Установка сниппета
  1. Создать папку assets/shippets/filedownload.
  2. Скопировать файлы filedownload.class.inc.php, data.db.class.inc.php, и filecount.txt  в эту папку.
  3. Создать новый сниппет  FileDownload.
  4. Скопировать код из FileDownloadSnippet2.5.php в код сниппета.
  5. При использовании FileDownloadPlugin (а мы его уже установили) записать в конфигурацию плагина (этого мы ещё не делали):

&countDownloads=Count Downloads;list;yes,no;yes &useDbCount=Store Count Where;list;db,file;db

Теперь мы можем вставлять сниппет в разные страницы. Для каждого документа, в котором вызывается сниппет FileDownload, нужно уcтановить значение TV  FileDownloadFolder. Это будет указанием плагину - какую папку обрабатывать. В FileDownloadFolder вписывается путь от корня сайта, например assets/files/rucad.

Вот теперь можно вызывать сниппет. Разумеется, он имеет множество параметров, настройкой которых можно добиться нужного эффекта.

 

Простейший вызов

  При самом простом вызове:

[ !FileDownload? &getFolder=`assets/snippets/filedownload`! ]

мы получим примерно такой результат:

Результат простого вызова FD

Здесь мы видим простой список файлов. Форма отображения достаточно корявая (английские заголовки, формат даты, отсутствие комментариев, счетчика загрузок).  Теперь придётся заняться настройкой с помощью параметров. 

Параметры сниппета FileDownload

 

Что отображать

Главный параметр - это &getFolder. Он задает каталог, показываемый сниппетом. Может быть и список каталогов, разделенных запятыми. В этом параметре не надо задавать концевые слэши! Но если мы используем сниппет совместно с плагином, то &getFolder задавать не надо - папка будет взята из TV FileDownloadFolder. Так мы и будем делать в дальнейшем.

Если задать в &getFolder список каталогов, да еще &groupByDirectory=`1`, то на одной странице будут показаны файлы, сгруппированные по каталогам. Вот так:

  Группировка по каталогам

Группировка по каталогам

Но при этом должен быть пустым параметр TV FileDownloadFolder, а это означает потерю защиты файла от скачивания. Оно нам надо - такая группировка?

Если задать параметр &browseDirectories=`1`  при заданном   TV FileDownloadFolder, то будут отображаться подкаталоги:

Отображение подкаталогов

Отображение подкаталогов

В подкаталоги можно заходить и просматривать их содержимое:

Просмотр подкаталога

Просмотр подкаталога

Такой вариант вполне может применяться. Недостатком является то, что отображаются настоящие имена каталогов и им нельзя присвоить понятное русскоязычное описание. Иногда это может быть существенным препятствием, а иногда его можно обойти если, например, для какого-то архива задать имена подкаталогов в виде лет - 2008, 2007.

Если не задавать параметр  &browseDirectories=`1`, то будет отображаться только каталог, заданный в   TV FileDownloadFolder:

Просмотр одного каталога

Просмотр одного каталога

  Параметр  &browseDirectories=`1` должен именно отсутствовать, а не быть установленным &browseDirectories=`0` - в этом случае всё равно выводятся папки.

Для того, чтобы отображались файлы только с некоторыми расширениями, используется параметр &showExt. Можно задать список допустимых расширений, например &showExt=`zip,exe,pdf`. А можно использовать альтернативный вариант - &hideExt.

Внешний вид

Как именно отображать файлы - задается кучей шаблонов. Показанные примеры значительно отличаются от первоначального. Достигнуто это использованием нескольких параметров.

Параметр &tplList=`dnl_list` задаёт имя чанка, в котором описан шаблон вывода (иначе принимается по умолчанию зашитый в код). Пример используемог нами чанка:

<table border="0" cellpadding="5" style="width:95%">
<tr ><td colspan="5"><strong>Дорожка: </strong></td></tr>
<tr>
<th colspan="2">Файл</th>
<th width="10%">Скачан</th>
<th width="15%">Размер</th>
<th width="10%">Дата</th></tr>
<!-- Fd:Splitter -->
<!-- This is the parent template -->
<tr >
<td colspan="5">
<a href="" alt="Выше"  title="На уровень выше"><img src=""/></a>
</td>
</tr>
<!-- Fd:Splitter -->
<!-- This is the folder template -->
<tr >
<td><img src=""/></td>
<td colspan="4"><a href=""></a></td>
</tr>
<!-- Fd:Splitter -->
<!-- This is the file template -->
<tr >
<td><img src=""/></td>
<td>
<a href=""   title="Скачать файл"><br /></a>

</td>
<td align="right"></td>
<td align="right"></td>
<td align="right"></td>
</tr>
<!-- Fd:Splitter -->
<!-- This is the delete link template -->
<a href="">Удалить</a>
<!-- Fd:Splitter -->
<!-- This is the template used when &groupByDirectory=`1` -->
<tr >
<td colspan="5"><strong></strong></td>
</tr>
<!-- Fd:Splitter -->
<!-- This is the footer template -->
</table>
 

  В этот шаблон мы ввели дополнительную колонку Скачан, задали размеры колонок. В шаблоне используются плейсхолдеры наподобие [ +fd.class+ ]. Во время работы сниппета на их места подставляются текущие значения. Пытливые люди могут сравнить код шаблона с кодом, выдаваемым браузеру. В приведенном шаблоне вроде бы одна таблица, но она состоит из нескольких секций. Не все секции показываются одновременно и обязательно! Это зависит от сочетания аргументов. Используются такие шаблоны:

  1. Header - Показывается вверху. Когда используется &browseDirectories=`1`, показывает текущий путь, используя плейсхолдеры: [ +fd.path+ ], [ +fd.class+ ]
  2. Parent - Используется для ссылки на родительскую папку. Использует плейсхолдеры как в шаблоне  File, исключая  fd.delete и fd.filenumber.
  3. Folder - Используется для отображения папок. Использует плейсхолдеры как в шаблоне  File, исключая  fd.delete.
  4. File - Используется для отображения файлов с помощью плейсхолдеров : [ +fd.filename+ ], [ +fd.extension+ ], [ +fd.path+ ], [ +fd.size+ ], [ +fd.sizetext+ ], [ +fd.type+ ], [ +fd.date+ ], [ +fd.description+ ], [ +fd.image+ ], [ +fd.delete+ ], [ +fd.count+ ], [ +fd.link+ ], [ +fd.class+ ], [ +fd.filenumber+ ]
  5. Delete  - Это шаблон ссылки на удаление файла, вставляемый в  [ +fd.delete+ ] если пользователь имеет соответствующие права.  Использует плейсходер: [ +fd.deletelink+ ]. Мы его убрали от греха подальше.
  6. Group By - Шаблон, используемый для нескольких дорожек при действии &groupByDirectory=`1`. Использует плейсхолдеры : [ +fd.directory+ ],[ +fd.class+ ]
  7. Footer - Показывается в конце.
    Описания файлов

На рисунках видны длинные русские описания файлов. Они создаются в чанке, имя которого задано параметром &chkDesc=`dnl_rucad`. В чанке dnl_rucad записаны, в определенном формате, имена и описания файлов:

assets/files/rucad/doc|Документация||
assets/files/rucad/doc/ru_install.pdf|Руководство по установке||
assets/files/rucad/ruSourceExplorerR4.zip|Обозреватель исходных текстов. Версия 4||
assets/files/rucad/ru_air_heater.zip|Поверочный расчет воздухонагревателей||
assets/files/rucad/rudwgpreview_vcl.zip|Компонент Delphi для предварительного просмотра DWG-файлов||
assets/files/rucad/wlx_rudwgpreview_1_1.zip|Плагин к Total Commander для предварительного просмотра DWG-файлов ||
assets/files/rucad/dnl|Старые версии||
assets/files/rucad/dnl/ru_source_explorer_2.0.zip|Обозреватель исходных текстов. Версия 2 ||

  Такой чанк надо делать для каждого каталога, указанного в TV. Обратите внимание - имена файлов задаются от корня сайта. К сожалению, на имена каталогов комментарии не распространяются (мы их оставили специально для примера).

Иконки файлов

В наших примерах слева у папок и файлов отображаются свои иконки, причем для каждого типа файла - своя.  Достигается это использованием параметров  &imgLocat=`assets/templates/yaml/images` и
&imgTypes=`download_img`. Параметр &imgLocat задает каталог, в котором хранятся файлы иконок, а &imgTypes - чанк, в котором описаны типы файлов и соответсвующие им иконки. Место вывода иконок задано в шаблоне местом расположения плейсхолдера fd.image. Пример чанка download_img:

jpg=jpg.gif,
gif=gif.gif,
pdf=pdf.gif,
doc=doc.gif,
dll=dll.gif,
exe=exe.gif,
txt=txt.gif,
lsp=lsp.gif,
zip=zip.gif,
xml=xml.gif,
folder=folderopened.gif,
parent=folderup.gif,
default=default.gif

  Сортировка файлов

Задается параметрами &userSort=`date` и &sortOrder=`asc`. В &useSort можно задать

filename | extension | path | size | sizetext | type | date | description | count

а в &sortOrder - asc или desc.

Замечания.
1. При заданном &browseDirectories=`1`сортировка не выполняется как надо.
2. Для сортировки можно задать список полей, например &userSort=`date,extension`. Однако при этом будут рядом выводиться файлы с одинаковыми расширениями, отсортированными по дате, а потом с другими расширениями. Добиться, например, чтобы вверху были самые последние файлы с любыми расширениями, будет сложно - если не применять искусственной нумерации.

Стили

Для изменения внешнего вида списка файлов могут использоваться стили CSS. При желании можно задать стиль для какого-то элемента списка (из числа доступных) или определить стиль с именем по умолчанию. Задать стиль, с именем, отличающимся от имени стиля по умолчанию можно с помощью параметров.

&altCSS (по умолчанию fd-alt)  - класс нечетных строк.

&firstFolderCss  - класс для первой папки

&lastFolderCss  - класс для последней папки папки

&firstFieCss  - класс для первого файла

&lastFileCss  - класс для последнего файла

&folderCSS (по умолчанию fd-folder)  - класс для папок

&fileCSS (по умолчанию fd-file)  - класс для файлов

&parentCSS (по умолчанию fd-parent)  - класс для родительской папки

&directoryCSS (по умолчанию fd-directory)  - класс для каталога при выводе из нескольких папок

&pathCSS (по умолчанию fd-path)  - класс для строки с дорожкой при обзоре каталогов

&extCSS (по умолчанию 0) -  при установке в 1 позволяет использовать собственные классы для каждого расширения файлов. Например, для exe-файлов  будет использоваться класс fd-exe, а для pdf-файлов класс fd-pdf.

Таким образом, разумно манипулируя аргументами, можно добиться любого отображения файлов:

Вариант отображения

Вариант отображения


Настройки языка


Сообщения, выдаваемые сниппетом, можно задать в виде аргументов &delSuccess&delError, &dirOpenError, &notaDir, &noDownload. Это неплохо для многоязычных файлов, но мы один язык используем. Зачем нам передавать столько аргументов при каждом вызове? Мы просто переведём эти жалкие строчки в коде сниппета в файле filedownload.class.inc.php (не забывая, что его надо сохранить в кодировке UTF-8 без BOM).

Однако иногда мы можем и переопределить в параметре текст сообщения, например:

&noDownload=`Скачивать этот файл имеют право только зарегистрированные пользователи системы ruCAD`

для конкретного случая может быть более подходящим. Такое сообщение имеет смысл, если задан аргумент

&downloadGroups=`Admins,SiteAdmins,ruCAD` 

Здесь задан перечень групп WEB-пользователей, имеющих право скачивать файлы.

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

 

К сожалению, полная защита от скачивания не обеспечивается. Если сохранена ссылка на файл в виде, например,

http://cadx2009/ru_files.html/wlx_rudwgpreview_1_1.zip

  то по этой ссылке можно будет скачать файл, не заходя на страницу. Сниппет сработает и выдаст файл. Впрочем, ещё надо разобраться - нет ли каких-то настроек на эту тему.

 

 

 

17-02-2009 16:56:32



    Содержание раздела «Скачивание файлов»:
Комментарии любых посетителей

Написать комментарий


 
Matrix
Комментарий
Счётчик не работает
Реплика №4: 11.03.2011, 21:05:15
Есть небольшая проблема и не одна.
1. При использовании FileDownloadFolder скачивается содержимое страницы с именем файла а не сам файл.
2. Счётчик скачиваний никак не хочет работать.
3. При использовании RewriteRule ^([^/]*)/?(.*)$ index.php?q=$1&d=$2 [L,QSA] в .htaccess страница со скачиваемым файлом не открывается, выдаётся ошибка что "сервер перенаправляет запрос на этот адрес таким образом, что он никогда не завершится"

1-й вопос не обязателен, пусть скачивается по прямой ссылке.
а вот остальные хотелось бы понять почему не работают
ShaggyDoc
Комментарий
Можно ли как-то это избежать и считать только действит
Реплика №3: 24.10.2009, 08:07:27
Так кнопка Отменить будет нажата в браузере, уже после того, как сайт отдал файл. Естественно, теперь уже сайту неизвестно, как посетитель поступил с файлом. Щелчок на скачивание увеличивает счетчик, предотвратить это невозможно.
Виктор
Комментарий
FileDownload
Реплика №2: 23.10.2009, 21:26:00
Согласен, спасибо, использовал при разработке сайта. НО - есть вопрос - если я отказываюсь (нажимаю на кнопку "отменить"), то всё равно счётчик скачиваний увеличивается на единицу.....
И, находясь на странице, нажимать скачать-отменить, а счётчик будет расти.....
Можно ли как-то это избежать и считать только действительно качаемые ?
Anonymous
Комментарий
Re: Как организовать Download с сайта
Реплика №1: 13.05.2009, 17:10:23
Классная статья. давно искал информацию про FileDownload. автору большое спасибо