Компонент источник файлов Dropbox для MODX Revolution

Для реализации одного проекта возникла необходимость использовать какое-либо облачное хранилище. Суть заключается в том, что есть несколько распределенных сотрудников, каждый из которых использует специальную программу, результатом деятельности которой являются обособленные XML-файлы. Данные этих файлов необходимы для того, чтобы сформировать отчетность на сайте, где пользователи могли бы скачать доступную им информацию. Проблема в том, что сотрудники работают на своих локальных машинах и как бы с интернетом не взаимодействуют (то есть не используется какой-то единый сервер или типа того). И вот я решил задействовать Dropbox, типа настрою каждому пользователю свою папочку, куда и будут синхронизироваться их файлы, а на стороне сайта по крону буду все забирать с дропбокса и использовать для формирования отчетности. Под катом расскажу, что из этого получилось. Вообще, изначально я думал, что все будет гораздо проще, так как довольно давно уже натыкался на готовый компонент, который устанавливает в MODX источник файлов, взаимодействующий с Dropbox, но когда я его установил, получил только кучу фатальных ошибок. Компонент разрабатывался в 2012-ом году, и то ли использовал старое Dropbox PHP SDK, то ли вообще что-то самописное было, но в любом случае оно уже совсем не работало. В итоге было понятно, что все придется переписывать. Примеров особых я не нашел в сети, но дропбокс радует довольно добротной документацией здесь и здесь. В итоге я взял имеющийся в пакете объект источника файлов за основу, залил последнюю версию PHP SDK (сейчас это 1.1.4) и допилил до состояния, когда через админку сайта можно было управлять файлами в дропбоксе.

0a418df8f4064f98ae656f6507d9ed76.jpg

На этом завершилась разработка пакета dropbox-2.0.0-beta. Но покоя не давала мысль, что нет у меня еще возможности получать от дропбокса данные изменений. Просто насколько я понимаю, мне придется иметь дело с десятками тысяч документов в итоге, и не могу же я каждый раз просто перебором проходиться по папкам и сверять ревизии уже на стороне сайта (к слову, за раз дропбокс методом Client: getMetadataWithChildren ($path) возвращает не более 2000 записей, хотя в методе указано 25000). Поковыряв доки, добрался до метода Client: getDelta ($cursor = null, $pathPrefix = null). Это как раз то, что нам нужно, так как передав в него известный курсор, можно получить информацию о изменениях с момента его создания. Но вот здесь небольшая неприятность: как получить последний курсор? Дело в том, что если дропбокс-аккаунт давно уже существует, в нем за всю историю может накопиться куча изменений, и простым перебором курсоров можно очень долго добираться до актуального. Что интересно, такого метода нет в PHP SDK, хотя в самом API для этого есть метод. Ну да ладно, если в ядре есть метод, то не долго допилить свой класс клиента, чтобы умел получать эту информацию. Теперь можно зафиксировать для себя отправную точку и следить за изменениями без всяких переборов. Когда я все это получил, для меня стало очевидно, что эти данные удобно было бы хранить в базе данных, а некоторые профильные методы дропбокс-клиента вынести в специфические сущности. Далее просто покажу несколько примеров использования того, что получилось.

Конечно же прежде чем что-то делать, надо зарегистрировать свое Dropbox-приложение (разумеется, вы должны быть зарегистрированы в Dropbox).Подробно Для этого идем на страничку www.dropbox.com/developers/apps и жмем Create app (Кстати, название приложения должно быть уникальное для всего Dropbox-а (так как есть возможность публиковать публичные приложения, так что лучше указывать домен сайта или типа того, ибо названия типа myApp и т.п. заняты и дропбокс не даст сохранить)). Типов создаваемых приложений два Drop-ins app и Dropbox API app, мы будем создавать второй.a86ae621b6c84d7e995d7752e199c9ea.jpgЗдесь сразу же подробней рассмотрим шаг 3.Can your app be limited to its own folder? Если выбрать «My app only needs access to files it creates.», то для приложения будет создана собственная папка, куда и будет доступ у приложения. У меня это папка Приложения/[AppName]. То есть папка Приложения — это системная для всех приложений, а далее для каждого приложения создается своя папка.А если выбрать «My app needs access to files already on Dropbox.», то приложение получит доступ к корневой папке и далее список доступных файлов будет ограничиваться только выбранными типами файлов. То есть если вы выбираете этот пункт, то появляется новый шаг What type of files does your app need access to? и там вы можете выбрать или «All file types» (то есть все файлы) или «Specific file types» и указать какие типы файлов доступны.5aab0464b7524a24889de89d21a0f686.jpg

После того, как мы нажали «Create App», приложение будет создано и нам открывается страница настроек приложения. На ней мы кроме всего прочего найдем App key и App secret, но они нам пока не понадобятся, их использование мы рассмотрим позже. А пока нас интересует Access token. Сгенерируем его и скопипастим куда-нибудь в недоступное место. Повторно его не получится увидеть. Правда можно сгенерировать новый токен, и что интересно — работать будут и предшествующие. Я сгенерил три токена и все они работают, при чем я не могу увидеть список используемых токенов и отменить не нужные, могу только удалить все приложение. Катца не секурно немного, но это скорее фича нежели бага.2fff8e5c140549d5b0fd77fae93f3583.jpg

После установки пакета Dropbox в системе появляется новый тип источников файлов — Dropbox. Создаем медиасурс с этим типом.Подробно 8ecba34f0bec43698c8ec9c22d7ea2c2.jpge4c4507e81f74e7992a7f7d6f0d8314e.jpg

Когда создали источник файлов, открываем его для редактирования и указываем Access Token приложения.692fc1379acb4542a54e4e9152694e0d.jpg

Если все ОК, то после сохранения источник файлов должен показывать содержимое вашего дропбокса (см. первую картинку вверху). Первое, что я сделал в обновленной версии пакета — это вынес возможность получить Dropbox-клиент в отдельный метод медиасурса. Получить его можно, к примеру, вот так: $source_id = 27; // ID вашего источника файлов $source = $modx→getObject ('modMediaSource', $source_id); $client = $source→getClient (); Это удобно тем, что можно иметь сколько угодно медиасурсов и на заморачиваться с их настройками, при этом каждый медиасурс будет работать со своей дропбокс-папкой.

Получаем информацию о содержимом директорий $source_id = 27; // ID вашего источника файлов $source = $modx→getObject ('modMediaSource', $source_id); $client = $source→getClient (); $result = $client→getMetadataWithChildren ('/'); print_r ($result); Результат Array ( [hash] => cfcf0b65c94cff03c32390b3c30a5812 [thumb_exists] => [bytes] => 0 [path] => / [is_dir] => 1 [icon] => folder [root] => dropbox [contents] => Array ( [0] => Array ( [rev] => 115ce031c0d71 [thumb_exists] => 1 [path] => /315a73ec24 — копия.jpg [is_dir] => [client_mtime] => Fri, 05 Dec 2014 23:12:30 +0000 [icon] => page_white_picture [bytes] => 258713 [modified] => Mon, 08 Dec 2014 02:45:31 +0000 [size] => 252.6 KB [root] => dropbox [mime_type] => image/jpeg [revision] => 71118 )

[1] => Array ( [rev] => 102d6031c0d71 [thumb_exists] => 1 [path] => /315a73ec24.jpg [is_dir] => [client_mtime] => Fri, 05 Dec 2014 23:12:30 +0000 [icon] => page_white_picture [bytes] => 258713 [modified] => Sat, 06 Dec 2014 21:21:20 +0000 [size] => 252.6 KB [root] => dropbox [mime_type] => image/jpeg [revision] => 66262 )

)

[size] => 0 bytes ) Получаем содержимое файла $source_id = 27; // ID вашего источника файлов $source = $modx→getObject ('modMediaSource', $source_id); $content = $source→getContent ('/315a73ec24.jpg'); Или так $source_id = 27; // ID вашего источника файлов $entry = $modx→newObject ('DropboxEntry', array ( «source_id» => $source_id, «path» => '/315a73ec24.jpg', )); $content = $entry→getContent (); // Или $entry→get ('content'); Или так $source_id = 27; // ID вашего источника файлов $source = $modx→getObject ('modMediaSource', $source_id); $entry = $modx→newObject ('DropboxEntry', array ( «path» => '/315a73ec24.jpg', )); $entry→Source = $source; $content = $entry→getContent (); // Или $entry→get ('content'); Или так (если запись уже в БД) $entry = $modx→getObject ('DropboxEntry', array ( «path» => '/315a73ec24.jpg', )); $content = $entry→getContent (); // Или $entry→get ('content'); Отслеживаем изменения в разделах Здесь необходимы два этапа:1. Получаем актуальный курсор для раздела и сохраняем его в БД Вообще сохранять не обязательно его, но ведь так удобней, никуда не пропадет. $source_id = 27; // ID вашего источника файлов $cursor = $modx→newObject ('DropboxCursor', array ( «source_id» => $source_id, «path» => '/', )); if ($result = $cursor→getLast ()){ $cursor→fromArray ($result); $cursor→save (); } 2. Запрашиваем изменения. $cursor= $modx→getObject ('DropboxCursor', array ( «path» => '/', )); $result = $entry→getDelta (); print_r ($result); Ответ Array ( [has_more] => [cursor] => AAE3sefSDffe3SiOcfkaMd7vyzjQvjxngkI1gkJGLvBQplsNUhF9tx5Okb7epnGufIziuDWjyG16sWaxjRcnt-XjT-jBD_8fDW89enF7OO3AHBjsZz9vHTBJenmeCdLUgO0f-EqRJYigzELD0rzD3hFNn-YGfDQaxUOs0bHd2F5qND3J6HX-HwOqOLWQfcbuMZMNHN1_UGN2VODIbaPzBbML0rap_B6ibV03JQxtiGHZtxwjP-mSw8drigK3yJtvqyR3XdzHP5uVsyrD8gkyGk1J9dOTLdzFRA-woImCg1Iwc9XA7l1XsZGCRvDYpXjg [entries] => Array ( )

[reset] => ) Если будут изменения, то вы их увидите в массиве entries. Ревизии файлов $entry = $modx→getObject ('DropboxEntry', array ( «path» => '/315a73ec24.jpg', )); $result = $entry→getRevisions (); И можно восстановить нужную версию файла. $entry = $modx→getObject ('DropboxEntry', array ( «path» => '/315a73ec24.jpg', )); $result = $entry→restoreFile ('102d6031c0d71'); В общем, если покопать официальную документацию, можно много чего на базе этого сделать. А вообще есть желание разработать под MODX компонент файлового менеджера, который умел бы обмениваться файлами между различными типами медиасурсов, но пока на это нет времени/ресурсов.

Скачать пакет можно с оффрепозитория modx.comПроект на гитхабе: github.com/Fi1osof/modx-Dropbox

И напоследок небольшая заметка об одной коварной проблемке, с которой столкнулся во время разработки компонента.

© Habrahabr.ru