Your IP : 216.73.216.163


Current Path : /home/user/web/pansionat-v-yaroslavle.ru/public_html/331ab/
Upload File :
Current File : /home/user/web/pansionat-v-yaroslavle.ru/public_html/331ab/clouds.tar

lang/ru/install/index.php000064400000000660150241560060011402 0ustar00<?
$MESS["CLO_MODULE_NAME"] = "Облачные хранилища";
$MESS["CLO_MODULE_DESCRIPTION"] = "Модуль поддержки облачных хранилищ файлов.";
$MESS["CLO_INSTALL_TITLE"] = "Установка модуля поддержки облачных хранилищ";
$MESS["CLO_UNINSTALL_TITLE"] = "Деинсталляция модуля поддержки облачных хранилищ";
?>lang/ru/install/step1.php000064400000000165150241560060011327 0ustar00<?
$MESS["CLO_INSTALL"] = "Установка модуля поддержки облачных хранилищ.";
?>lang/ru/classes/general/storage_service_clodo.php000064400000000360150241560060016240 0ustar00<?
$MESS["CLO_STORAGE_CLODO_EDIT_USER"] = "Имя пользователя (API user)";
$MESS["CLO_STORAGE_CLODO_EDIT_KEY"] = "Ключ доступа (API key)";
$MESS["CLO_STORAGE_CLODO_EDIT_HOST"] = "Имя сервера (API host)";
?>lang/ru/classes/general/storage_upload.php000064400000000151150241560060014702 0ustar00<?
$MESS["CLO_STORAGE_UPLOAD_ERROR"] = "Ошибка загрузки части файла: #errno#";
?>lang/ru/classes/general/storage_service_s3.php000064400000001765150241560060015477 0ustar00<?
$MESS["CLO_STORAGE_S3_XML_PARSE_ERROR"] = "нераспознанный ответ службы (ошибка ##errno#)";
$MESS["CLO_STORAGE_S3_XML_ERROR"] = "ошибка службы: #errmsg#";
$MESS["CLO_STORAGE_S3_EMPTY_ACCESS_KEY"] = "Не задан ключ доступа.";
$MESS["CLO_STORAGE_S3_EMPTY_SECRET_KEY"] = "Не задан секретный ключ.";
$MESS["CLO_STORAGE_S3_EDIT_ACCESS_KEY"] = "Ключ доступа";
$MESS["CLO_STORAGE_S3_EDIT_SECRET_KEY"] = "Секретный ключ";
$MESS["CLO_STORAGE_S3_EDIT_HELP"] = "Для начала использования необходимо зарегистрироваться в <a href=\"http://aws.amazon.com/s3/\">Amazon</a> и активировать доступ к S3. Ключ доступа и секретный ключ к нему можно получить на странице <a href=\"https://aws-portal.amazon.com/gp/aws/developer/account/index.html?ie=UTF8&action=access-key\">Security Credentials</a>.";
?>lang/ru/classes/general/storage_service_openstack.php000064400000001442150241560060017131 0ustar00<?
$MESS["CLO_STORAGE_OPENSTACK_EMPTY_HOST"] = "Не задано имя сервера.";
$MESS["CLO_STORAGE_OPENSTACK_EMPTY_USER"] = "Не задано имя пользователя.";
$MESS["CLO_STORAGE_OPENSTACK_EMPTY_KEY"] = "Не задан ключ доступа.";
$MESS["CLO_STORAGE_OPENSTACK_ERROR_GET_TOKEN"] = "Ошибка авторизации. Проверьте правильность введенных настроек.";
$MESS["CLO_STORAGE_OPENSTACK_EDIT_USER"] = "Имя пользователя (API user)";
$MESS["CLO_STORAGE_OPENSTACK_EDIT_KEY"] = "Ключ доступа (API key)";
$MESS["CLO_STORAGE_OPENSTACK_EDIT_HOST"] = "Имя сервера (API host)";
$MESS["CLO_STORAGE_OPENSTACK_FORCE_HTTP"] = "Всегда использовать протокол http";
?>lang/ru/classes/general/storage_service_google.php000064400000002317150241560060016420 0ustar00<?
$MESS["CLO_STORAGE_GOOGLE_XML_PARSE_ERROR"] = "нераспознанный ответ службы (ошибка ##errno#)";
$MESS["CLO_STORAGE_GOOGLE_XML_ERROR"] = "ошибка службы: #errmsg#";
$MESS["CLO_STORAGE_GOOGLE_EMPTY_ACCESS_KEY"] = "Не задан ключ доступа.";
$MESS["CLO_STORAGE_GOOGLE_EMPTY_SECRET_KEY"] = "Не задан секретный ключ.";
$MESS["CLO_STORAGE_GOOGLE_EMPTY_PROJECT_ID"] = "Не задан идентификатор проекта.";
$MESS["CLO_STORAGE_GOOGLE_EDIT_PROJECT_ID"] = "Идентификатор проекта";
$MESS["CLO_STORAGE_GOOGLE_EDIT_ACCESS_KEY"] = "Ключ доступа";
$MESS["CLO_STORAGE_GOOGLE_EDIT_SECRET_KEY"] = "Секретный ключ";
$MESS["CLO_STORAGE_GOOGLE_EDIT_HELP"] = "Для начала использования необходимо активировать <a href=\"https://cloud.google.com/storage/docs/signup\">Google Storage for Developers</a>. Далее в <a href=\"https://code.google.com/apis/console#:storage\">консоли управления API Google</a> необходимо активировать совместимый доступ (Legacy Access) и включить биллинг.";
?>lang/ru/classes/general/storage_service_selectel.php000064400000000371150241560060016742 0ustar00<?
$MESS["CLO_STORAGE_SELECTEL_EDIT_USER"] = "Имя пользователя (API user)";
$MESS["CLO_STORAGE_SELECTEL_EDIT_KEY"] = "Ключ доступа (API key)";
$MESS["CLO_STORAGE_SELECTEL_EDIT_HOST"] = "Имя сервера (API host)";
?>lang/ru/classes/general/storage.php000064400000001013150241560060013334 0ustar00<?
$MESS["CLO_STORAGE_MENU"] = "Облачные хранилища";
$MESS["CLO_STORAGE_TITLE"] = "Просмотр и управление файлами в облачных хранилищах";
$MESS["CLO_STORAGE_UPLOAD_MENU"] = "Переместить в облако";
$MESS["CLO_STORAGE_UPLOAD_CONF"] = "Вы уверены, что хотите выгрузить файл в облачное хранилище?";
$MESS["CLO_404_ON_MOVED_FILE"] = "404 ошибка после перемещения файла";
?>lang/ru/classes/general/security_service_s3.php000064400000000312150241560060015665 0ustar00<?
$MESS["CLO_SECSERV_S3_XML_PARSE_ERROR"] = "нераспознанный ответ службы (ошибка ##errno#)";
$MESS["CLO_SECSERV_S3_XML_ERROR"] = "ошибка службы: #errmsg#";
?>lang/ru/classes/general/storage_bucket.php000064400000004321150241560060014676 0ustar00<?
$MESS["CLO_STORAGE_WRONG_SERVICE"] = "Задана неверная служба контейнера.";
$MESS["CLO_STORAGE_EMPTY_BUCKET"] = "Не задан идентификатор контейнера.";
$MESS["CLO_STORAGE_BAD_BUCKET_NAME"] = "Идентификатор контейнера содержит недопустимые символы (разрешены символы латиницы в нижнем регистре, цифры и знак: \"-\").";
$MESS["CLO_STORAGE_WRONG_BUCKET_NAME_LENGTH"] = "Длина идентификатора контейнера должна быть не менее 2-х символов и не более 64-х.";
$MESS["CLO_STORAGE_WRONG_BUCKET_NAME_LENGTH2"] = "Длина компонента идентификатора контейнера (подстрока между точками) должна быть не менее 2-х символов и не более 64-х.";
$MESS["CLO_STORAGE_BAD_BUCKET_NAME2"] = "Идентификатор контейнера должен начинаться и заканчиваться на букву или цифру.";
$MESS["CLO_STORAGE_BAD_BUCKET_NAME3"] = "Рядом с символом точки могут быть только буквы или цифры.";
$MESS["CLO_STORAGE_BUCKET_ALREADY_EXISTS"] = "Контейнер с таким идентификатором уже существует в облачном хранилище. Уникальность имени проверяется по всем пользователям облачного хранилища.";
$MESS["CLO_STORAGE_DB_DELETE_ERROR"] = "Контейнер в облаке удален, но произошла ошибка удаления описания контейнера из базы данных.";
$MESS["CLO_STORAGE_CLOUD_DELETE_ERROR"] = "Ошибка удаления контейнера: #error_msg#.";
$MESS["CLO_STORAGE_CLOUD_BUCKET_NOT_EMPTY"] = "Ошибка удаления контейнера: в контейнере есть файлы.";
$MESS["CLO_STORAGE_UNKNOWN_SERVICE"] = "неизвестная служба";
$MESS["CLO_STORAGE_CLOUD_ADD_ERROR"] = "Ошибка добавления контейнера: #error_msg#.";
?>lang/ru/admin/task_description.php000064400000001424150241560060013261 0ustar00<?
$MESS["TASK_NAME_CLOUDS_DENIED"]="Доступ закрыт";
$MESS["TASK_NAME_CLOUDS_BROWSE"]="Выбор файлов";
$MESS["TASK_NAME_CLOUDS_UPLOAD"]="Перемещение файлов";
$MESS["TASK_NAME_CLOUDS_FULL_ACCESS"]="Полный административный доступ";
$MESS["TASK_DESC_CLOUDS_DENIED"]="Доступ к модулю запрещен";
$MESS["TASK_DESC_CLOUDS_BROWSE"]="Просмотр содержимого облачных хранилищ";
$MESS["TASK_DESC_CLOUDS_UPLOAD"]="Перемещение файлов в облачные хранилища из структуры сайта и выгрузка новых";
$MESS["TASK_DESC_CLOUDS_FULL_ACCESS"]="Разрешен полный доступ, включая настройки.";
?>lang/ru/admin/menu.php000064400000000241150241560060010654 0ustar00<?
$MESS["CLO_MENU_ITEM"] = "Облачные хранилища";
$MESS["CLO_MENU_TITLE"] = "Управление облачными хранилищами";
?>lang/ru/admin/clouds_storage_list.php000064400000005661150241560060013773 0ustar00<?
$MESS["CLO_STORAGE_LIST_ADD"] = "Добавить";
$MESS["CLO_STORAGE_LIST_ADD_TITLE"] = "Добавить новое подключение к облачному хранилищу";
$MESS["CLO_STORAGE_LIST_ID"] = "ID";
$MESS["CLO_STORAGE_LIST_ACTIVE"] = "Активность";
$MESS["CLO_STORAGE_LIST_MODE"] = "Режим";
$MESS["CLO_STORAGE_LIST_READ_ONLY"] = "Чтение";
$MESS["CLO_STORAGE_LIST_READ_WRITE"] = "Чтение/Запись";
$MESS["CLO_STORAGE_LIST_SORT"] = "Сортировка";
$MESS["CLO_STORAGE_LIST_SERVICE"] = "Сервис";
$MESS["CLO_STORAGE_LIST_BUCKET"] = "Контейнер";
$MESS["CLO_STORAGE_LIST_FILE_COUNT"] = "Файлов";
$MESS["CLO_STORAGE_LIST_FILE_SIZE"] = "Объем";
$MESS["CLO_STORAGE_LIST_EDIT"] = "Изменить";
$MESS["CLO_STORAGE_LIST_MOVE_FILE_ERROR"] = "Ошибка перемещения файла в облачное хранилище";
$MESS["CLO_STORAGE_LIST_START_MOVE_FILES"] = "Переместить файлы в облачное хранилище";
$MESS["CLO_STORAGE_LIST_CONT_MOVE_FILES"] = "Продолжить перемещение файлов в облачное хранилище";
$MESS["CLO_STORAGE_LIST_MOVE_LOCAL"] = "Вернуть файлы из облачного хранилища";
$MESS["CLO_STORAGE_LIST_MOVE_LOCAL_CONF"] = "Вы уверены, что хотите вернуть файлы из облачного хранилища на диски сервера?";
$MESS["CLO_STORAGE_LIST_DEACTIVATE"] = "Деактивировать";
$MESS["CLO_STORAGE_LIST_DEACTIVATE_CONF"] = "Деактивировать подключение к облачному хранилищу?";
$MESS["CLO_STORAGE_LIST_ACTIVATE"] = "Активировать";
$MESS["CLO_STORAGE_LIST_DELETE"] = "Удалить";
$MESS["CLO_STORAGE_LIST_DELETE_CONF"] = "Удалить подключение к облачному хранилищу?";
$MESS["CLO_STORAGE_LIST_CANNOT_DELETE"] = "Ошибка удаления: #error_msg#.";
$MESS["CLO_STORAGE_LIST_TITLE"] = "Облачные хранилища";
$MESS["CLO_STORAGE_LIST_MOVE_IN_PROGRESS"] = "Идет перенос файлов в облачное хранилище.";
$MESS["CLO_STORAGE_LIST_MOVE_DONE"] = "Перенос файлов в облачное хранилище завершен.";
$MESS["CLO_STORAGE_LIST_MOVE_PROGRESS"] = "
Всего обработано <b>#total#</b> файлов.<br>
Из них перемещено <b>#moved# (#bytes#)</b> и пропущено <b>#skiped#</b>.
";
$MESS["CLO_STORAGE_LIST_STOP"] = "Остановить";
$MESS["CLO_STORAGE_LIST_DOWNLOAD_IN_PROGRESS"] = "Идет выгрузка файлов из облачного хранилища.";
$MESS["CLO_STORAGE_LIST_DOWNLOAD_PROGRESS"] = "
Осталось выгрузить <b>#remain# (#bytes#)</b>.
";
$MESS["CLO_STORAGE_LIST_DOWNLOAD_DONE"] = "Возврат файлов из облачного хранилища завершен.";
?>lang/ru/admin/clouds_file_list.php000064400000003400150241560060013233 0ustar00<?
$MESS["CLO_STORAGE_FILE_NAME"] = "Название";
$MESS["CLO_STORAGE_FILE_SIZE"] = "Размер";
$MESS["CLO_STORAGE_FILE_DELETE"] = "Удалить";
$MESS["CLO_STORAGE_FILE_DELETE_CONF"] = "Удалить файл без возможности восстановления?";
$MESS["CLO_STORAGE_FILE_SHOW_DIR_SIZE"] = "Размеры каталогов";
$MESS["CLO_STORAGE_FILE_SHOW_DIR_SIZE_TITLE"] = "Показать размеры каталогов с учетом вложенности";
$MESS["CLO_STORAGE_FILE_LIST_ERROR"] = "Ошибка получения списка файлов";
$MESS["CLO_STORAGE_FILE_UPLOAD_ERROR"] = "Ошибка выгрузки файла:";
$MESS["CLO_STORAGE_FILE_EXISTS_ERROR"] = "Файл с таким именем уже загружен в облачное хранилище.";
$MESS["CLO_STORAGE_FILE_OPEN_ERROR"] = "Ошибка открытия файла для чтения.";
$MESS["CLO_STORAGE_FILE_UNKNOWN_ERROR"] = "Неизвестная ошибка с кодом [#CODE#].";
$MESS["CLO_STORAGE_FILE_UPLOAD_IN_PROGRESS"] = "Идет выгрузка файла:";
$MESS["CLO_STORAGE_FILE_UPLOAD_DONE"] = "Выгрузка файла завершена:";
$MESS["CLO_STORAGE_FILE_UPLOAD_PROGRESS"] = "
Выгружено: <b>#bytes#</b> из <b>#file_size#</b>.
";
$MESS["CLO_STORAGE_FILE_STOP"] = "Остановить";
$MESS["CLO_STORAGE_FILE_UPLOAD"] = "Новый файл";
$MESS["CLO_STORAGE_FILE_UPLOAD_TITLE"] = "Выгрузить новый файл в облачное хранилище.";
$MESS["CLO_STORAGE_FILE_UPLOAD_BTN"] = "Выгрузить";
$MESS["CLO_STORAGE_FILE_CANCEL_BTN"] = "Отмена";
$MESS["CLO_STORAGE_FILE_UPLOAD_INPUT"] = "Файл";
$MESS["CLO_STORAGE_FILE_PATH_INPUT"] = "Путь";
?>lang/ru/admin/clouds_storage_edit.php000064400000006161150241560060013741 0ustar00<?
$MESS["CLO_STORAGE_EDIT_TAB"] = "Подключение";
$MESS["CLO_STORAGE_EDIT_TAB_TITLE"] = "Настройка параметров подключения и использования облачного хранилища";
$MESS["CLO_STORAGE_EDIT_TAB2"] = "Правила";
$MESS["CLO_STORAGE_EDIT_TAB2_TITLE"] = "Настройка правил для отбора файлов в облачное хранилище";
$MESS["CLO_STORAGE_EDIT_EDIT_TITLE"] = "Редактирование подключения к облачному хранилищу";
$MESS["CLO_STORAGE_EDIT_ADD_TITLE"] = "Новое подключение к облачному хранилищу";
$MESS["CLO_STORAGE_EDIT_MENU_LIST"] = "Список";
$MESS["CLO_STORAGE_EDIT_MENU_LIST_TITLE"] = "Список подключений к облачным хранилищам";
$MESS["CLO_STORAGE_EDIT_ID"] = "ID";
$MESS["CLO_STORAGE_EDIT_ACTIVE"] = "Активность";
$MESS["CLO_STORAGE_EDIT_SORT"] = "Сортировка";
$MESS["CLO_STORAGE_EDIT_SERVICE_ID"] = "Провайдер";
$MESS["CLO_STORAGE_EDIT_LOCATION"] = "Регион";
$MESS["CLO_STORAGE_EDIT_BUCKET"] = "Контейнер";
$MESS["CLO_STORAGE_EDIT_READ_ONLY"] = "Только для чтения";
$MESS["CLO_STORAGE_EDIT_CNAME"] = "Каноническое имя домена (<a href=\"http://en.wikipedia.org/wiki/CNAME_record\">CNAME</a>)";
$MESS["CLO_STORAGE_EDIT_MODULE"] = "Список модулей";
$MESS["CLO_STORAGE_EDIT_EXTENSIONS"] = "Список расширений";
$MESS["CLO_STORAGE_EDIT_SIZE"] = "Список размеров";
$MESS["CLO_STORAGE_EDIT_ADD_FILE_RULE"] = "Добавить новое правило";
$MESS["CLO_STORAGE_EDIT_SAVE_ERROR"] = "Ошибка сохранения подключения к облачному хранилищу";
$MESS["CLO_STORAGE_EDIT_RULES_NOTE"] = "Для того чтобы правило сработало, файл должен удовлетворять всем трем условиям хотя бы одного правила.";
$MESS["CLO_STORAGE_EDIT_RULES_NOTE1"] = "Список идентификаторов модулей. Например: iblock, advertising. Если не задан, то под действие правила подпадают файлы любых модулей.";
$MESS["CLO_STORAGE_EDIT_RULES_NOTE2"] = "Список расширений файлов для хранения в облачном хранилище. Например: gif, png, jpeg, jpg. Если не задан, то под действие правила подпадают файлы с любым расширением. Список является нечувствительным к регистру.";
$MESS["CLO_STORAGE_EDIT_RULES_NOTE3"] = "Список размеров файлов. Допустимо использовать суффиксы, такие как: K, M или G. Так же возможно задавать диапазоны размеров. Например: 1K-1M, 2.3M-. Если не задан, то под действие правила подпадают файлы любого размера.";
?>lang/ru/admin/operation_description.php000064400000000544150241560060014321 0ustar00<?
$MESS["OP_NAME_CLOUDS_BROWSE"] = "Просмотр содержимого облачных хранилищ";
$MESS["OP_NAME_CLOUDS_UPLOAD"] = "Загрузка новых файлов и выгрузка существующих";
$MESS["OP_NAME_CLOUDS_CONFIG"] = "Настройка подключений к облачным хранилищам";
?>lang/ru/admin/clouds_file_search.php000064400000001034150241560060013526 0ustar00<?
$MESS["CLO_STORAGE_SEARCH_TITLE"] = "Выбор файла из облачного хранилища";
$MESS["CLO_STORAGE_SEARCH_BUCKET"] = "Облачное хранилище";
$MESS["CLO_STORAGE_SEARCH_CHOOSE_BUCKET"] = "Выберите облачное хранилище";
$MESS["CLO_STORAGE_SEARCH_PATH"] = "Путь";
$MESS["CLO_STORAGE_SEARCH_NAME"] = "Название";
$MESS["CLO_STORAGE_SEARCH_SIZE"] = "Размер";
$MESS["CLO_STORAGE_SEARCH_LIST_ERROR"] = "Ошибка получения списка файлов";
?>lang/ru/options.php000064400000000257150241560060010322 0ustar00<?
$MESS["CLO_OPTIONS_LOG_404_ERRORS"] = "Записывать 404 ошибки на перемещенных в облака файлах в журнал событий:";
?>lang/en/install/index.php000064400000000377150241560060011363 0ustar00<?
$MESS["CLO_MODULE_NAME"] = "Cloud Storages";
$MESS["CLO_MODULE_DESCRIPTION"] = "Supports cloud file storages.";
$MESS["CLO_INSTALL_TITLE"] = "Cloud Storages Module Installation";
$MESS["CLO_UNINSTALL_TITLE"] = "Cloud Storages Module Uninstallation";
?>lang/en/install/step1.php000064400000000103150241560060011273 0ustar00<?
$MESS["CLO_INSTALL"] = "Cloud Storages module installation.";
?>lang/en/classes/general/storage_service_clodo.php000064400000000303150241560060016211 0ustar00<?
$MESS["CLO_STORAGE_CLODO_EDIT_USER"] = "User name (API user)";
$MESS["CLO_STORAGE_CLODO_EDIT_KEY"] = "Access key (API key)";
$MESS["CLO_STORAGE_CLODO_EDIT_HOST"] = "Server name (API host)";
?>lang/en/classes/general/storage_upload.php000064400000000120150241560060014652 0ustar00<?
$MESS["CLO_STORAGE_UPLOAD_ERROR"] = "Error uploading file chunk: #errno#";
?>lang/en/classes/general/storage_service_s3.php000064400000001415150241560060015443 0ustar00<?
$MESS["CLO_STORAGE_S3_XML_PARSE_ERROR"] = "unrecognized service response (error ##errno#)";
$MESS["CLO_STORAGE_S3_XML_ERROR"] = "service error: #errmsg#";
$MESS["CLO_STORAGE_S3_EMPTY_ACCESS_KEY"] = "The access key is not specified.";
$MESS["CLO_STORAGE_S3_EMPTY_SECRET_KEY"] = "The secret key is not specified.";
$MESS["CLO_STORAGE_S3_EDIT_ACCESS_KEY"] = "Access Key";
$MESS["CLO_STORAGE_S3_EDIT_SECRET_KEY"] = "Secret Key";
$MESS["CLO_STORAGE_S3_EDIT_HELP"] = "Before you start using this service, you have to register with <a href=\"http://aws.amazon.com/s3/\">Amazon</a> and activate S3 access. The access and secret keys can be obtained at <a href=\"https://aws-portal.amazon.com/gp/aws/developer/account/index.html?ie=UTF8&action=access-key\">Security Credentials</a>.";
?>lang/en/classes/general/storage_service_openstack.php000064400000001141150241560060017101 0ustar00<?
$MESS["CLO_STORAGE_OPENSTACK_EMPTY_HOST"] = "The server name is now specified.";
$MESS["CLO_STORAGE_OPENSTACK_EMPTY_USER"] = "The user name is not specified.";
$MESS["CLO_STORAGE_OPENSTACK_EMPTY_KEY"] = "The access key is not specified.";
$MESS["CLO_STORAGE_OPENSTACK_ERROR_GET_TOKEN"] = "Authorization error. Please check the settings.";
$MESS["CLO_STORAGE_OPENSTACK_EDIT_USER"] = "User name (API user)";
$MESS["CLO_STORAGE_OPENSTACK_EDIT_KEY"] = "Access key (API key)";
$MESS["CLO_STORAGE_OPENSTACK_EDIT_HOST"] = "Server name (API host)";
$MESS["CLO_STORAGE_OPENSTACK_FORCE_HTTP"] = "Always use HTTP";
?>lang/en/classes/general/storage_service_google.php000064400000001637150241560060016400 0ustar00<?
$MESS["CLO_STORAGE_GOOGLE_XML_PARSE_ERROR"] = "unrecognized service response (error ##errno#)";
$MESS["CLO_STORAGE_GOOGLE_XML_ERROR"] = "service error: #errmsg#";
$MESS["CLO_STORAGE_GOOGLE_EMPTY_ACCESS_KEY"] = "The access key is not specified.";
$MESS["CLO_STORAGE_GOOGLE_EMPTY_SECRET_KEY"] = "The secret key is not specified.";
$MESS["CLO_STORAGE_GOOGLE_EMPTY_PROJECT_ID"] = "The project ID is not specified.";
$MESS["CLO_STORAGE_GOOGLE_EDIT_PROJECT_ID"] = "Project ID";
$MESS["CLO_STORAGE_GOOGLE_EDIT_ACCESS_KEY"] = "Access Key";
$MESS["CLO_STORAGE_GOOGLE_EDIT_SECRET_KEY"] = "Secret Key";
$MESS["CLO_STORAGE_GOOGLE_EDIT_HELP"] = "Before you start using this service, you have to activate <a href=\"https://cloud.google.com/storage/docs/signup\">Google Storage for Developers</a>. Then, use <a href=\"https://code.google.com/apis/console#:storage\">API Google console</a> to activate Legacy Access and enable billing.";
?>lang/en/classes/general/storage_service_selectel.php000064400000000314150241560060016713 0ustar00<?
$MESS["CLO_STORAGE_SELECTEL_EDIT_USER"] = "User name (API user)";
$MESS["CLO_STORAGE_SELECTEL_EDIT_KEY"] = "Access key (API key)";
$MESS["CLO_STORAGE_SELECTEL_EDIT_HOST"] = "Server name (API host)";
?>lang/en/classes/general/storage.php000064400000000545150241560060013321 0ustar00<?
$MESS["CLO_STORAGE_MENU"] = "Cloud Storage";
$MESS["CLO_STORAGE_TITLE"] = "View and manage files in cloud storages";
$MESS["CLO_STORAGE_UPLOAD_MENU"] = "Move to cloud storage";
$MESS["CLO_STORAGE_UPLOAD_CONF"] = "Are you sure you want to upload the file to cloud storage?";
$MESS["CLO_404_ON_MOVED_FILE"] = "Error 404 occurred while moving the file.";
?>lang/en/classes/general/security_service_s3.php000064400000000240150241560060015641 0ustar00<?
$MESS["CLO_SECSERV_S3_XML_PARSE_ERROR"] = "unrecognized service response (error ##errno#)";
$MESS["CLO_SECSERV_S3_XML_ERROR"] = "service error: #errmsg#";
?>lang/en/classes/general/storage_bucket.php000064400000002604150241560060014654 0ustar00<?
$MESS["CLO_STORAGE_WRONG_SERVICE"] = "Wrong bucket service.";
$MESS["CLO_STORAGE_EMPTY_BUCKET"] = "The bucket ID is missing.";
$MESS["CLO_STORAGE_BAD_BUCKET_NAME"] = "The bucket ID contains invalid characters (use only lowercase Latin letters, digits and dashes \"-\").";
$MESS["CLO_STORAGE_WRONG_BUCKET_NAME_LENGTH"] = "A valid bucket ID must contain from 2 to 64 characters.";
$MESS["CLO_STORAGE_WRONG_BUCKET_NAME_LENGTH2"] = "The length of each part of the bucket ID (strings between dots) must contain from 2 to 64 characters. ";
$MESS["CLO_STORAGE_BAD_BUCKET_NAME2"] = "The bucket ID must begin and end with a letter or a digit.";
$MESS["CLO_STORAGE_BAD_BUCKET_NAME3"] = "Only digit and letter symbols are permitted to be next to a dot (before and after). ";
$MESS["CLO_STORAGE_BUCKET_ALREADY_EXISTS"] = "A bucket with this ID already exists in the cloud storage. The ID must be unique across all the cloud storage users.";
$MESS["CLO_STORAGE_DB_DELETE_ERROR"] = "The cloud bucket has been deleted, but the bucket description has failed to be deleted from the database.";
$MESS["CLO_STORAGE_CLOUD_DELETE_ERROR"] = "Error deleting the bucket: #error_msg#.";
$MESS["CLO_STORAGE_CLOUD_BUCKET_NOT_EMPTY"] = "Error deleting the bucket: the container still has files.";
$MESS["CLO_STORAGE_UNKNOWN_SERVICE"] = "unknown service";
$MESS["CLO_STORAGE_CLOUD_ADD_ERROR"] = "Error creating a bucket: #error_msg#.";
?>lang/en/admin/task_description.php000064400000000770150241560060013240 0ustar00<?
$MESS["TASK_NAME_CLOUDS_DENIED"] = "Access denied";
$MESS["TASK_NAME_CLOUDS_BROWSE"] = "Select files";
$MESS["TASK_NAME_CLOUDS_UPLOAD"] = "Move files";
$MESS["TASK_NAME_CLOUDS_FULL_ACCESS"] = "Full access";
$MESS["TASK_DESC_CLOUDS_DENIED"] = "Access denied";
$MESS["TASK_DESC_CLOUDS_BROWSE"] = "Browse cloud storages";
$MESS["TASK_DESC_CLOUDS_UPLOAD"] = "Upload new files from Site Explorer and download existing files";
$MESS["TASK_DESC_CLOUDS_FULL_ACCESS"] = "Full access to files and settings.";
?>lang/en/admin/menu.php000064400000000143150241560060010631 0ustar00<?
$MESS["CLO_MENU_ITEM"] = "Cloud Storages";
$MESS["CLO_MENU_TITLE"] = "Manage Cloud Storages";
?>lang/en/admin/clouds_storage_list.php000064400000004155150241560060013744 0ustar00<?
$MESS["CLO_STORAGE_LIST_ADD"] = "Add";
$MESS["CLO_STORAGE_LIST_ADD_TITLE"] = "Adds a new cloud storage connection";
$MESS["CLO_STORAGE_LIST_ID"] = "ID";
$MESS["CLO_STORAGE_LIST_ACTIVE"] = "Active";
$MESS["CLO_STORAGE_LIST_MODE"] = "Mode";
$MESS["CLO_STORAGE_LIST_READ_ONLY"] = "Read-only";
$MESS["CLO_STORAGE_LIST_READ_WRITE"] = "Read/Write";
$MESS["CLO_STORAGE_LIST_SORT"] = "Sorting";
$MESS["CLO_STORAGE_LIST_SERVICE"] = "Service";
$MESS["CLO_STORAGE_LIST_BUCKET"] = "Bucket";
$MESS["CLO_STORAGE_LIST_FILE_COUNT"] = "Files";
$MESS["CLO_STORAGE_LIST_FILE_SIZE"] = "Size";
$MESS["CLO_STORAGE_LIST_EDIT"] = "Edit";
$MESS["CLO_STORAGE_LIST_START_MOVE_FILES"] = "Upload files to cloud storage";
$MESS["CLO_STORAGE_LIST_CONT_MOVE_FILES"] = "Continue moving files to cloud storage";
$MESS["CLO_STORAGE_LIST_MOVE_LOCAL"] = "Download files from cloud storage";
$MESS["CLO_STORAGE_LIST_MOVE_LOCAL_CONF"] = "Are you sure you want to move the files from the cloud back to the server?";
$MESS["CLO_STORAGE_LIST_DEACTIVATE"] = "Deactivate";
$MESS["CLO_STORAGE_LIST_DEACTIVATE_CONF"] = "Deactivate cloud storage connection?";
$MESS["CLO_STORAGE_LIST_ACTIVATE"] = "Activate";
$MESS["CLO_STORAGE_LIST_DELETE"] = "Delete";
$MESS["CLO_STORAGE_LIST_DELETE_CONF"] = "Delete cloud storage connection?";
$MESS["CLO_STORAGE_LIST_CANNOT_DELETE"] = "Cannot delete connection: #error_msg#.";
$MESS["CLO_STORAGE_LIST_TITLE"] = "Cloud Storages";
$MESS["CLO_STORAGE_LIST_MOVE_IN_PROGRESS"] = "Files are now being moved to the storage.";
$MESS["CLO_STORAGE_LIST_MOVE_DONE"] = "Files has been moved to the storage.";
$MESS["CLO_STORAGE_LIST_MOVE_PROGRESS"] = "
Total files processed: <b>#total#</b>.<br>
Moved files: <b>#moved# (#bytes#)</b>, skipped files: <b>#skiped#</b>.
";
$MESS["CLO_STORAGE_LIST_STOP"] = "Stop";
$MESS["CLO_STORAGE_LIST_DOWNLOAD_IN_PROGRESS"] = "Files are now being downloaded from the storage.";
$MESS["CLO_STORAGE_LIST_DOWNLOAD_PROGRESS"] = "
<b>#remain# (#bytes#)</b> remains.
";
$MESS["CLO_STORAGE_LIST_DOWNLOAD_DONE"] = "Files has been downloaded from the storage.";
$MESS["CLO_STORAGE_LIST_MOVE_FILE_ERROR"] = "Error moving the file to cloud storage.";
?>lang/en/admin/clouds_file_list.php000064400000002470150241560060013215 0ustar00<?
$MESS["CLO_STORAGE_FILE_NAME"] = "Name";
$MESS["CLO_STORAGE_FILE_SIZE"] = "Size";
$MESS["CLO_STORAGE_FILE_DELETE"] = "Delete";
$MESS["CLO_STORAGE_FILE_DELETE_CONF"] = "Do you want to delete the file irreversibly?";
$MESS["CLO_STORAGE_FILE_SHOW_DIR_SIZE"] = "Folder size";
$MESS["CLO_STORAGE_FILE_SHOW_DIR_SIZE_TITLE"] = "Show folder size, including nested folders";
$MESS["CLO_STORAGE_FILE_LIST_ERROR"] = "Error getting file list.";
$MESS["CLO_STORAGE_FILE_UPLOAD_ERROR"] = "File upload error:";
$MESS["CLO_STORAGE_FILE_EXISTS_ERROR"] = "A file with this name already exists in the cloud storage.";
$MESS["CLO_STORAGE_FILE_OPEN_ERROR"] = "Error opening the file for reading.";
$MESS["CLO_STORAGE_FILE_UNKNOWN_ERROR"] = "Unknown error [#CODE#].";
$MESS["CLO_STORAGE_FILE_UPLOAD_IN_PROGRESS"] = "Now uploading file:";
$MESS["CLO_STORAGE_FILE_UPLOAD_DONE"] = "File uploaded:";
$MESS["CLO_STORAGE_FILE_UPLOAD_PROGRESS"] = "
Uploaded: <b>#bytes#</b> of <b>#file_size#</b>.
";
$MESS["CLO_STORAGE_FILE_STOP"] = "Stop";
$MESS["CLO_STORAGE_FILE_UPLOAD"] = "New file";
$MESS["CLO_STORAGE_FILE_UPLOAD_TITLE"] = "Upload new file to cloud storage.";
$MESS["CLO_STORAGE_FILE_UPLOAD_BTN"] = "Upload";
$MESS["CLO_STORAGE_FILE_CANCEL_BTN"] = "Cancel";
$MESS["CLO_STORAGE_FILE_UPLOAD_INPUT"] = "File";
$MESS["CLO_STORAGE_FILE_PATH_INPUT"] = "Path";
?>lang/en/admin/clouds_storage_edit.php000064400000003776150241560060013726 0ustar00<?
$MESS["CLO_STORAGE_EDIT_TAB"] = "Connection";
$MESS["CLO_STORAGE_EDIT_TAB_TITLE"] = "Configure cloud storage connection parameters";
$MESS["CLO_STORAGE_EDIT_TAB2"] = "Rules";
$MESS["CLO_STORAGE_EDIT_TAB2_TITLE"] = "Set file selection rules for the cloud storage";
$MESS["CLO_STORAGE_EDIT_EDIT_TITLE"] = "Changes cloud storage connection parameters";
$MESS["CLO_STORAGE_EDIT_ADD_TITLE"] = "Adds a new cloud storage connection";
$MESS["CLO_STORAGE_EDIT_MENU_LIST"] = "Connections";
$MESS["CLO_STORAGE_EDIT_MENU_LIST_TITLE"] = "Shows available cloud storage connections";
$MESS["CLO_STORAGE_EDIT_ID"] = "ID";
$MESS["CLO_STORAGE_EDIT_ACTIVE"] = "Active";
$MESS["CLO_STORAGE_EDIT_SORT"] = "Sorting";
$MESS["CLO_STORAGE_EDIT_SERVICE_ID"] = "Provider";
$MESS["CLO_STORAGE_EDIT_LOCATION"] = "Location";
$MESS["CLO_STORAGE_EDIT_BUCKET"] = "Bucket";
$MESS["CLO_STORAGE_EDIT_READ_ONLY"] = "Read-only";
$MESS["CLO_STORAGE_EDIT_CNAME"] = "Domain canonic name (<a href=\"http://en.wikipedia.org/wiki/CNAME_record\">CNAME</a>)";
$MESS["CLO_STORAGE_EDIT_MODULE"] = "Modules";
$MESS["CLO_STORAGE_EDIT_EXTENSIONS"] = "Extensions";
$MESS["CLO_STORAGE_EDIT_SIZE"] = "Sizes";
$MESS["CLO_STORAGE_EDIT_ADD_FILE_RULE"] = "Add new rule";
$MESS["CLO_STORAGE_EDIT_SAVE_ERROR"] = "Error saving cloud storage connection";
$MESS["CLO_STORAGE_EDIT_RULES_NOTE"] = "The rule triggers only if a file satisfies all the rule conditions. If a file doesn't match at least one rule, it will not be put in the cloud.";
$MESS["CLO_STORAGE_EDIT_RULES_NOTE1"] = "Module identifiers. Example: iblock, advertising. Empty module list matches all files of all modules.";
$MESS["CLO_STORAGE_EDIT_RULES_NOTE2"] = "Extensions of files that can be stored in the cloud. Example: gif, png, jpeg, jpg. Empty extension list matches any file. This list is case-insensitive.";
$MESS["CLO_STORAGE_EDIT_RULES_NOTE3"] = "File sizes. Use the file size suffixes to denote the file size: K, M or G. Size ranges are possible, for example: 1K-1M, 2.3M-. If this field is empty, any file size will match.";
?>lang/en/admin/operation_description.php000064400000000335150241560060014273 0ustar00<?
$MESS["OP_NAME_CLOUDS_BROWSE"] = "Browse cloud storages";
$MESS["OP_NAME_CLOUDS_UPLOAD"] = "Upload new files and download existing files";
$MESS["OP_NAME_CLOUDS_CONFIG"] = "Edit cloud storage connection parameters";
?>lang/en/admin/clouds_file_search.php000064400000000611150241560060013502 0ustar00<?
$MESS["CLO_STORAGE_SEARCH_TITLE"] = "Select file in cloud storage";
$MESS["CLO_STORAGE_SEARCH_BUCKET"] = "Cloud storage";
$MESS["CLO_STORAGE_SEARCH_CHOOSE_BUCKET"] = "Select cloud storage";
$MESS["CLO_STORAGE_SEARCH_PATH"] = "Path";
$MESS["CLO_STORAGE_SEARCH_NAME"] = "Name";
$MESS["CLO_STORAGE_SEARCH_SIZE"] = "Size";
$MESS["CLO_STORAGE_SEARCH_LIST_ERROR"] = "Error getting file list.";
?>lang/en/options.php000064400000000130150241560060010264 0ustar00<?
$MESS["CLO_OPTIONS_LOG_404_ERRORS"] = "Log 404 errors for files in cloud storage";
?>default_option.php000064400000000134150241560060010266 0ustar00<?
$clouds_default_option = array(
	"log_404_errors" => "N",
	"delayed_resize" => "N",
);
?>install/db/mysql/install.sql000064400000002251150241560060012132 0ustar00CREATE TABLE b_clouds_file_bucket
(
	ID INT(11) NOT NULL auto_increment,
	ACTIVE CHAR(1) DEFAULT 'Y',
	SORT INT(11) DEFAULT 500,
	READ_ONLY CHAR(1) DEFAULT 'N',
	SERVICE_ID VARCHAR(50),
	BUCKET VARCHAR(63),
	LOCATION VARCHAR(50),
	CNAME VARCHAR(100),
	FILE_COUNT INT(11) default 0,
	FILE_SIZE float default 0,
	LAST_FILE_ID INT(11),
	PREFIX VARCHAR(100),
	SETTINGS TEXT,
	FILE_RULES TEXT,
	PRIMARY KEY pk_b_clouds_file_bucket(ID)
);

CREATE TABLE b_clouds_file_upload
(
	ID VARCHAR(32) NOT NULL,
	TIMESTAMP_X TIMESTAMP NOT NULL,
	FILE_PATH VARCHAR(500) NOT NULL,
	FILE_SIZE INT(11) NULL,
	TMP_FILE VARCHAR(500) NULL,
	BUCKET_ID INT(11) NOT NULL,
	PART_SIZE INT(11) NOT NULL,
	PART_NO INT(11) NOT NULL,
	PART_FAIL_COUNTER INT(11) NOT NULL,
	NEXT_STEP TEXT,
	PRIMARY KEY pk_b_clouds_file_upload(ID)
);

CREATE TABLE b_clouds_file_resize
(
	ID INT(11) NOT NULL auto_increment,
	TIMESTAMP_X TIMESTAMP NOT NULL,
	ERROR_CODE CHAR(1) NOT NULL DEFAULT '0',
	FILE_ID INT(11),
	PARAMS TEXT,
	FROM_PATH VARCHAR(500),
	TO_PATH VARCHAR(500),
	PRIMARY KEY pk_b_file_resize(ID),
	INDEX ix_b_file_resize_ts (TIMESTAMP_X),
	INDEX ix_b_file_resize_path (TO_PATH(100)),
	INDEX ix_b_file_resize_file (FILE_ID)
);
install/db/mysql/uninstall.sql000064400000000201150241560060012466 0ustar00DROP TABLE if exists b_clouds_file_upload;
DROP TABLE if exists b_clouds_file_bucket;
DROP TABLE if exists b_clouds_file_resize;
install/admin/clouds_storage_list.php000064400000000141150241560060014056 0ustar00<?
require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/clouds/admin/clouds_storage_list.php");
?>
install/admin/clouds_file_list.php000064400000000136150241560060013335 0ustar00<?
require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/clouds/admin/clouds_file_list.php");
?>
install/admin/clouds_storage_edit.php000064400000000141150241560060014030 0ustar00<?
require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/clouds/admin/clouds_storage_edit.php");
?>
install/admin/clouds_file_search.php000064400000000140150241560060013622 0ustar00<?
require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/clouds/admin/clouds_file_search.php");
?>
install/unstep2.php000064400000000757150241560060010333 0ustar00<?
if(!check_bitrix_sessid()) return;

if($ex = $APPLICATION->GetException())
	echo CAdminMessage::ShowMessage(Array(
		"TYPE" => "ERROR",
		"MESSAGE" => GetMessage("MOD_UNINST_ERR"),
		"DETAILS" => $ex->GetString(),
		"HTML" => true,
	));
else
	echo CAdminMessage::ShowNote(GetMessage("MOD_UNINST_OK"));
?>
<form action="<?echo $APPLICATION->GetCurPage()?>">
	<input type="hidden" name="lang" value="<?echo LANG?>">
	<input type="submit" name="" value="<?echo GetMessage("MOD_BACK")?>">
<form>
install/themes/.default/clouds.css000064400000000171150241560060013202 0ustar00.clouds-directory-icon
{
	background-position: center -118px;
}
.clouds-up-icon
{
	background-position: center -1574px;
}install/step2.php000064400000001013150241560060007752 0ustar00<?
if(!check_bitrix_sessid()) return;
IncludeModuleLangFile(__FILE__);

if($ex = $APPLICATION->GetException())
	echo CAdminMessage::ShowMessage(Array(
		"TYPE" => "ERROR",
		"MESSAGE" => GetMessage("MOD_INST_ERR"),
		"DETAILS" => $ex->GetString(),
		"HTML" => true,
	));
else
	echo CAdminMessage::ShowNote(GetMessage("MOD_INST_OK"));
?>
<form action="<?echo $APPLICATION->GetCurPage()?>">
	<input type="hidden" name="lang" value="<?echo LANG?>">
	<input type="submit" name="" value="<?echo GetMessage("MOD_BACK")?>">
<form>install/unstep1.php000064400000001210150241560060010313 0ustar00<form action="<?echo $APPLICATION->GetCurPage()?>">
<?=bitrix_sessid_post()?>
	<input type="hidden" name="lang" value="<?=LANGUAGE_ID?>">
	<input type="hidden" name="id" value="clouds">
	<input type="hidden" name="uninstall" value="Y">
	<input type="hidden" name="step" value="2">
	<?echo CAdminMessage::ShowMessage(GetMessage("MOD_UNINST_WARN"))?>
	<p><?echo GetMessage("MOD_UNINST_SAVE")?></p>
	<p><input type="checkbox" name="save_tables" id="save_tables" value="Y" checked><label for="save_tables"><?echo GetMessage("MOD_UNINST_SAVE_TABLES")?></label></p>
	<input type="submit" name="inst" value="<?echo GetMessage("MOD_UNINST_DEL")?>">
</form>install/index.php000064400000021063150241560060010033 0ustar00<?
IncludeModuleLangFile(__FILE__);

if(class_exists("clouds")) return;
Class clouds extends CModule
{
	var $MODULE_ID = "clouds";
	var $MODULE_VERSION;
	var $MODULE_VERSION_DATE;
	var $MODULE_NAME;
	var $MODULE_DESCRIPTION;
	var $MODULE_CSS;
	var $MODULE_GROUP_RIGHTS = "Y";

	function clouds()
	{
		$arModuleVersion = array();

		$path = str_replace("\\", "/", __FILE__);
		$path = substr($path, 0, strlen($path) - strlen("/index.php"));
		include($path."/version.php");

		$this->MODULE_VERSION = $arModuleVersion["VERSION"];
		$this->MODULE_VERSION_DATE = $arModuleVersion["VERSION_DATE"];

		$this->MODULE_NAME = GetMessage("CLO_MODULE_NAME");
		$this->MODULE_DESCRIPTION = GetMessage("CLO_MODULE_DESCRIPTION");
	}

	function GetModuleTasks()
	{
		return array(
			'clouds_denied' => array(
				"LETTER" => "D",
				"BINDING" => "module",
				"OPERATIONS" => array(
				),
			),
			'clouds_browse' => array(
				"LETTER" => "F",
				"BINDING" => "module",
				"OPERATIONS" => array(
					'clouds_browse',
				),
			),
			'clouds_upload' => array(
				"LETTER" => "U",
				"BINDING" => "module",
				"OPERATIONS" => array(
					'clouds_browse',
					'clouds_upload',
				),
			),
			'clouds_full_access' => array(
				"LETTER" => "W",
				"BINDING" => "module",
				"OPERATIONS" => array(
					'clouds_browse',
					'clouds_upload',
					'clouds_config',
				),
			),
		);
	}

	function InstallDB($arParams = array())
	{
		global $DB, $DBType, $APPLICATION;
		$this->errors = false;

		// Database tables creation
		if(!$DB->Query("SELECT 'x' FROM b_clouds_file_bucket WHERE 1=0", true))
		{
			$this->errors = $DB->RunSQLBatch($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/clouds/install/db/".strtolower($DB->type)."/install.sql");
		}


		if($this->errors !== false)
		{
			$APPLICATION->ThrowException(implode("<br>", $this->errors));
			return false;
		}
		else
		{
			$this->InstallTasks();

			RegisterModule("clouds");
			CModule::IncludeModule("clouds");
			RegisterModuleDependences("main", "OnEventLogGetAuditTypes", "clouds", "CCloudStorage", "GetAuditTypes");
			RegisterModuleDependences("main", "OnBeforeProlog", "clouds", "CCloudStorage", "OnBeforeProlog");
			RegisterModuleDependences("main", "OnAdminListDisplay", "clouds", "CCloudStorage", "OnAdminListDisplay");
			RegisterModuleDependences("main", "OnBuildGlobalMenu", "clouds", "CCloudStorage", "OnBuildGlobalMenu");
			RegisterModuleDependences("main", "OnFileSave", "clouds", "CCloudStorage", "OnFileSave");
			RegisterModuleDependences("main", "OnGetFileSRC", "clouds", "CCloudStorage", "OnGetFileSRC");
			RegisterModuleDependences("main", "OnFileCopy", "clouds", "CCloudStorage", "OnFileCopy");
			RegisterModuleDependences("main", "OnFileDelete", "clouds", "CCloudStorage", "OnFileDelete");
			RegisterModuleDependences("main", "OnMakeFileArray", "clouds", "CCloudStorage", "OnMakeFileArray");
			RegisterModuleDependences("main", "OnBeforeResizeImage", "clouds", "CCloudStorage", "OnBeforeResizeImage");
			RegisterModuleDependences("main", "OnAfterResizeImage", "clouds", "CCloudStorage", "OnAfterResizeImage");
			RegisterModuleDependences("clouds", "OnGetStorageService", "clouds", "CCloudStorageService_AmazonS3", "GetObjectInstance");
			RegisterModuleDependences("clouds", "OnGetStorageService", "clouds", "CCloudStorageService_GoogleStorage", "GetObjectInstance");
			RegisterModuleDependences("clouds", "OnGetStorageService", "clouds", "CCloudStorageService_OpenStackStorage", "GetObjectInstance");
			RegisterModuleDependences("clouds", "OnGetStorageService", "clouds", "CCloudStorageService_RackSpaceCloudFiles", "GetObjectInstance");
			RegisterModuleDependences("clouds", "OnGetStorageService", "clouds", "CCloudStorageService_ClodoRU", "GetObjectInstance");
			RegisterModuleDependences("clouds", "OnGetStorageService", "clouds", "CCloudStorageService_Selectel", "GetObjectInstance");
			RegisterModuleDependences("clouds", "OnGetStorageService", "clouds", "CCloudStorageService_HotBox", "GetObjectInstance");

			return true;
		}
	}

	function UnInstallDB($arParams = array())
	{
		global $DB, $DBType, $APPLICATION;
		$this->errors = false;

		if(!array_key_exists("save_tables", $arParams) || $arParams["save_tables"] != "Y")
		{
			$this->errors = $DB->RunSQLBatch($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/clouds/install/db/".strtolower($DB->type)."/uninstall.sql");
			$this->UnInstallTasks();
		}

		UnRegisterModuleDependences("main", "OnEventLogGetAuditTypes", "clouds", "CCloudStorage", "GetAuditTypes");
		UnRegisterModuleDependences("main", "OnBeforeProlog", "clouds", "CCloudStorage", "OnBeforeProlog");
		UnRegisterModuleDependences("main", "OnAdminListDisplay", "clouds", "CCloudStorage", "OnAdminListDisplay");
		UnRegisterModuleDependences("main", "OnBuildGlobalMenu", "clouds", "CCloudStorage", "OnBuildGlobalMenu");
		UnRegisterModuleDependences("main", "OnFileSave", "clouds", "CCloudStorage", "OnFileSave");
		UnRegisterModuleDependences("main", "OnGetFileSRC", "clouds", "CCloudStorage", "OnGetFileSRC");
		UnRegisterModuleDependences("main", "OnFileCopy", "clouds", "CCloudStorage", "OnFileCopy");
		UnRegisterModuleDependences("main", "OnFileDelete", "clouds", "CCloudStorage", "OnFileDelete");
		UnRegisterModuleDependences("main", "OnMakeFileArray", "clouds", "CCloudStorage", "OnMakeFileArray");
		UnRegisterModuleDependences("main", "OnBeforeResizeImage", "clouds", "CCloudStorage", "OnBeforeResizeImage");
		UnRegisterModuleDependences("main", "OnAfterResizeImage", "clouds", "CCloudStorage", "OnAfterResizeImage");
		UnRegisterModuleDependences("clouds", "OnGetStorageService", "clouds", "CCloudStorageService_AmazonS3", "GetObjectInstance");
		UnRegisterModuleDependences("clouds", "OnGetStorageService", "clouds", "CCloudStorageService_GoogleStorage", "GetObjectInstance");
		UnRegisterModuleDependences("clouds", "OnGetStorageService", "clouds", "CCloudStorageService_OpenStackStorage", "GetObjectInstance");
		UnRegisterModuleDependences("clouds", "OnGetStorageService", "clouds", "CCloudStorageService_RackSpaceCloudFiles", "GetObjectInstance");
		UnRegisterModuleDependences("clouds", "OnGetStorageService", "clouds", "CCloudStorageService_ClodoRU", "GetObjectInstance");
		UnRegisterModuleDependences("clouds", "OnGetStorageService", "clouds", "CCloudStorageService_Selectel", "GetObjectInstance");
		UnRegisterModuleDependences("clouds", "OnGetStorageService", "clouds", "CCloudStorageService_HotBox", "GetObjectInstance");

		UnRegisterModule("clouds");

		if(!defined("BX_CLOUDS_UNINSTALLED"))
			define("BX_CLOUDS_UNINSTALLED", true);

		if($this->errors !== false)
		{
			$APPLICATION->ThrowException(implode("<br>", $this->errors));
			return false;
		}

		return true;
	}

	function InstallEvents()
	{
		return true;
	}

	function UnInstallEvents()
	{
		return true;
	}

	function InstallFiles($arParams = array())
	{
		if($_ENV["COMPUTERNAME"]!='BX')
		{
			CopyDirFiles($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/clouds/install/admin", $_SERVER["DOCUMENT_ROOT"]."/bitrix/admin");
			CopyDirFiles($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/clouds/install/themes", $_SERVER["DOCUMENT_ROOT"]."/bitrix/themes", true, true);
		}
		return true;
	}

	function UnInstallFiles()
	{
		if($_ENV["COMPUTERNAME"]!='BX')
		{
			DeleteDirFiles($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/clouds/install/admin/", $_SERVER["DOCUMENT_ROOT"]."/bitrix/admin");
			DeleteDirFiles($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/clouds/install/themes/.default/", $_SERVER["DOCUMENT_ROOT"]."/bitrix/themes/.default");
		}
		return true;
	}

	function DoInstall()
	{
		global $DB, $APPLICATION, $step, $USER;
		if($USER->IsAdmin())
		{
			$step = IntVal($step);
			if($step < 2)
			{
				$APPLICATION->IncludeAdminFile(GetMessage("CLO_INSTALL_TITLE"), $_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/clouds/install/step1.php");
			}
			elseif($step==2)
			{
				if($this->InstallDB())
				{
					$this->InstallFiles();
				}
				$GLOBALS["errors"] = $this->errors;
				$APPLICATION->IncludeAdminFile(GetMessage("CLO_INSTALL_TITLE"), $_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/clouds/install/step2.php");
			}
		}
	}

	function DoUninstall()
	{
		global $DB, $APPLICATION, $step, $USER;
		if($USER->IsAdmin())
		{
			$step = IntVal($step);
			if($step < 2)
			{
				$APPLICATION->IncludeAdminFile(GetMessage("CLO_UNINSTALL_TITLE"), $_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/clouds/install/unstep1.php");
			}
			elseif($step == 2)
			{
				$this->UnInstallDB(array(
					"save_tables" => $_REQUEST["save_tables"],
				));
				$this->UnInstallFiles();
				$GLOBALS["errors"] = $this->errors;
				$APPLICATION->IncludeAdminFile(GetMessage("CLO_UNINSTALL_TITLE"), $_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/clouds/install/unstep2.php");
			}
		}
	}
}
?>install/step1.php000064400000000700150241560060007753 0ustar00<?IncludeModuleLangFile(__FILE__);?>
<p><?echo GetMessage("CLO_INSTALL")?></p>
<form action="<?echo $APPLICATION->GetCurPage()?>" name="form1">
<?=bitrix_sessid_post()?>
<input type="hidden" name="lang" value="<?echo LANG?>">
<input type="hidden" name="id" value="clouds">
<input type="hidden" name="install" value="Y">
<input type="hidden" name="step" value="2">
<input type="submit" name="inst" value="<?echo GetMessage("MOD_INSTALL")?>">
</form>install/version.php000064400000000144150241560060010406 0ustar00<?
$arModuleVersion = array(
	"VERSION" => "17.0.2",
	"VERSION_DATE" => "2017-10-13 13:00:00",
);
?>classes/general/storage_service_clodo.php000064400000005012150241560060014670 0ustar00<?
IncludeModuleLangFile(__FILE__);

class CCloudStorageService_ClodoRU extends CCloudStorageService_OpenStackStorage
{
	function GetObject()
	{
		return new CCloudStorageService_ClodoRU();
	}

	function GetID()
	{
		return "clodo_storage";
	}

	function GetName()
	{
		return "Clodo.ru";
	}

	function GetSettingsHTML($arBucket, $bServiceSet, $cur_SERVICE_ID, $bVarsFromForm)
	{
		if($bVarsFromForm)
			$arSettings = $_POST["SETTINGS"][$this->GetID()];
		else
			$arSettings = unserialize($arBucket["SETTINGS"]);

		if(!is_array($arSettings))
			$arSettings = array("HOST" => "api.clodo.ru", "USER" => "", "KEY" => "");

		$htmlID = htmlspecialcharsbx($this->GetID());

		$result = '
		<tr id="SETTINGS_2_'.$htmlID.'" style="display:'.($cur_SERVICE_ID == $this->GetID() || !$bServiceSet? '': 'none').'" class="settings-tr adm-detail-required-field">
			<td>'.GetMessage("CLO_STORAGE_CLODO_EDIT_HOST").':</td>
			<td><input type="hidden" name="SETTINGS['.$htmlID.'][HOST]" id="'.$htmlID.'HOST" value="'.htmlspecialcharsbx($arSettings['HOST']).'"><input type="text" size="55" name="'.$htmlID.'INP_HOST" id="'.$htmlID.'INP_HOST" value="'.htmlspecialcharsbx($arSettings['HOST']).'" '.($arBucket['READ_ONLY'] == 'Y'? '"disabled"': '').' onchange="BX(\''.$htmlID.'HOST\').value = this.value"></td>
		</tr>
		<tr id="SETTINGS_0_'.$htmlID.'" style="display:'.($cur_SERVICE_ID == $this->GetID() || !$bServiceSet? '': 'none').'" class="settings-tr adm-detail-required-field">
			<td>'.GetMessage("CLO_STORAGE_CLODO_EDIT_USER").':</td>
			<td><input type="hidden" name="SETTINGS['.$htmlID.'][USER]" id="'.$htmlID.'USER" value="'.htmlspecialcharsbx($arSettings['USER']).'"><input type="text" size="55" name="'.$htmlID.'INP_" id="'.$htmlID.'INP_USER" value="'.htmlspecialcharsbx($arSettings['USER']).'" '.($arBucket['READ_ONLY'] == 'Y'? '"disabled"': '').' onchange="BX(\''.$htmlID.'USER\').value = this.value"></td>
		</tr>
		<tr id="SETTINGS_1_'.$htmlID.'" style="display:'.($cur_SERVICE_ID == $this->GetID() || !$bServiceSet? '': 'none').'" class="settings-tr adm-detail-required-field">
			<td>'.GetMessage("CLO_STORAGE_CLODO_EDIT_KEY").':</td>
			<td><input type="hidden" name="SETTINGS['.$htmlID.'][KEY]" id="'.$htmlID.'KEY" value="'.htmlspecialcharsbx($arSettings['KEY']).'"><input type="text" size="55" name="'.$htmlID.'INP_KEY" id="'.$htmlID.'INP_KEY" value="'.htmlspecialcharsbx($arSettings['KEY']).'" autocomplete="off" '.($arBucket['READ_ONLY'] == 'Y'? '"disabled"': '').' onchange="BX(\''.$htmlID.'KEY\').value = this.value"></td>
		</tr>
		';
		return $result;
	}
}
?>classes/general/temp_file.php000064400000005723150241560060012301 0ustar00<?php

class CCloudTempFile
{
	private static $buckets = array();

	protected static function GetAbsoluteRoot()
	{
		return "/tmp";
	}

	protected static $shutdownRegistered = false;
	protected static function RegisterShutdown()
	{
		if (!self::$shutdownRegistered)
		{
			register_shutdown_function(array('CCloudTempFile', 'Cleanup'));
			self::$shutdownRegistered = true;
		}
	}

	public static function GetFileName($obBucket, $file_name = '')
	{
		$dir_name = self::GetAbsoluteRoot();
		$file_name = rel2abs("/", "/".$file_name);
		$i = 0;

		while(true)
		{
			$i++;

			if($file_name == '/')
				$dir_add = md5(mt_rand());
			elseif($i < 25)
				$dir_add = substr(md5(mt_rand()), 0, 3);
			else
				$dir_add = md5(mt_rand());

			$temp_path = $dir_name."/".$dir_add.$file_name;

			if (!$obBucket->FileExists($temp_path))
			{
				self::$buckets[] = array(
					"bucket" => $obBucket,
					"filePath" => $temp_path,
				);
				self::RegisterShutdown();

				return $temp_path;
			}
		}
	}

	public static function GetDirectoryName($obBucket, $hours_to_keep_files = 0, $subdir = "")
	{
		if($hours_to_keep_files <= 0)
			return self::GetFileName('');

		if($subdir === "")
		{
			$dir_name = self::GetAbsoluteRoot().'/BXTEMP-'.date('Y-m-d/H/', time()+3600*$hours_to_keep_files);
			$i = 0;
			while(true)
			{
				$i++;
				$dir_add = md5(mt_rand());
				$temp_path = $dir_name.$dir_add."/";

				if (!$obBucket->FileExists($temp_path))
					break;
			}
		}
		else //Fixed name during the session
		{
			$subdir = implode("/", (is_array($subdir) ? $subdir : array($subdir, bitrix_sessid())))."/";
			while (strpos($subdir, "//") !== false)
				$subdir = str_replace("//", "/", $subdir);

			$bFound = false;
			for($i = $hours_to_keep_files; $i > 0; $i--)
			{
				$dir_name = self::GetAbsoluteRoot().'/BXTEMP-'.date('Y-m-d/H/', time()+3600*$i);
				$temp_path = $dir_name.$subdir;
				
				$list = $obBucket->ListFiles($temp_path, true);
				if($list['file'] || $list['dir'])
				{
					$bFound = true;
					break;
				}
			}

			if(!$bFound)
			{
				$dir_name = self::GetAbsoluteRoot().'/BXTEMP-'.date('Y-m-d/H/', time()+3600*$hours_to_keep_files);
				$temp_path = $dir_name.$subdir;
			}
		}
		self::$buckets[] = array(
			"bucket" => $obBucket,
			"filePath" => null
		);

		self::RegisterShutdown();

		return $temp_path;
	}

	//PHP shutdown cleanup
	public static function Cleanup()
	{
		foreach(self::$buckets as $bucket)
		{
			/* @var \CCloudStorageBucket $obBucket */
			$obBucket = $bucket['bucket'];
			if (!is_null($bucket['filePath']) && $obBucket->FileExists($bucket['filePath']))
			{
				$obBucket->DeleteFile($bucket['filePath']);
			}
			else
			{
				$now = date('Y-m-d/H/', time());
				$dir_name = self::GetAbsoluteRoot()."/";
				$list = $obBucket->ListFiles($dir_name, true);
				foreach ($list['file'] as $filePath)
				{
					if (preg_match("#^BXTEMP-(....-..-../../)#", $filePath, $match) && $match[1] < $now)
					{
						$obBucket->DeleteFile($dir_name.$filePath);
					}
				}
			}
		}
	}
}
classes/general/storage_service_rackspace.php000064400000011171150241560060015527 0ustar00<?
class CCloudStorageService_RackSpaceCloudFiles extends CCloudStorageService_OpenStackStorage
{
	function GetObject()
	{
		return new CCloudStorageService_RackSpaceCloudFiles();
	}

	function GetID()
	{
		return "rackspace_storage";
	}

	function GetName()
	{
		return "Rackspace Cloud Files";
	}

	function _GetToken($host, $user, $key)
	{
		$result = false;
		$cache_id = "v0|".$host."|".$user."|".$key;
		$obCache = new CPHPCache;

		if($obCache->InitCache(3600, $cache_id, "/"))
		{
			$result = $obCache->GetVars();
		}
		else
		{
			$obRequest = new CHTTP;
			$obRequest->additional_headers["X-Auth-User"] = $user;
			$obRequest->additional_headers["X-Auth-Key"] = $key;
			$obRequest->Query("GET", $host, 80, "/v1.0");

			if($obRequest->status == 301 && strlen($obRequest->headers["Location"]) > 0)
			{
				if(preg_match("#^https://(.*?)(/.*)\$#", $obRequest->headers["Location"], $arNewLocation))
				{
					$obRequest = new CHTTP;
					$obRequest->additional_headers["X-Auth-User"] = $user;
					$obRequest->additional_headers["X-Auth-Key"] = $key;
					@$obRequest->Query("GET", $arNewLocation[1], 443, "/v1.0", false, "ssl://");

					if($obRequest->status == 204)
					{
						if(preg_match("#^https://(.*?)(/.*)\$#", $obRequest->headers["X-Storage-Url"], $arStorage))
						{
							$result = $obRequest->headers;
							$result["X-Storage-Host"] = $arStorage[1];
							$result["X-Storage-Port"] = 443;
							$result["X-Storage-Urn"] = $arStorage[2];
							$result["X-Storage-Proto"] = "ssl://";
						}
					}
				}
			}
		}

		if(is_array($result))
		{
			if($obCache->StartDataCache())
				$obCache->EndDataCache($result);
		}

		return $result;
	}

	function SendCDNRequest($settings, $verb, $bucket, $file_name='', $params='', $content=false, $additional_headers=array())
	{
		$arToken = $this->_GetToken($settings["HOST"], $settings["USER"], $settings["KEY"]);
		if(!$arToken)
			return false;

		if(isset($arToken["X-CDN-Management-Url"]))
		{
			if(preg_match("#^http://(.*?)(|:\d+)(/.*)\$#", $arToken["X-CDN-Management-Url"], $arCDN))
			{
				$Host = $arCDN[1];
				$Port = $arCDN[2]? substr($arCDN[2], 1): 80;
				$Urn = $arCDN[3];
				$Proto = "";
			}
			elseif(preg_match("#^https://(.*?)(|:\d+)(/.*)\$#", $arToken["X-CDN-Management-Url"], $arCDN))
			{
				$Host = $arCDN[1];
				$Port = $arCDN[2]? substr($arCDN[2], 1): 443;
				$Urn = $arCDN[3];
				$Proto = "ssl://";
			}
			else
			{
				return false;
			}
		}
		else
		{
			return false;
		}

		$obRequest = new CHTTP;
		$obRequest->additional_headers["X-Auth-Token"] = $arToken["X-Auth-Token"];
		foreach($additional_headers as $key => $value)
			$obRequest->additional_headers[$key] = $value;

		$obRequest->Query(
			$verb,
			$Host,
			$Port,
			$Urn.CCloudUtil::URLEncode("/".$bucket.$file_name.$params, "UTF-8"),
			$content,
			$Proto
		);
		return $obRequest;
	}

	function CreateBucket($arBucket)
	{
		global $APPLICATION;

		$obRequest = $this->SendRequest(
			$arBucket["SETTINGS"],
			"PUT",
			$arBucket["BUCKET"]
		);

		//CDN Enable
		if($this->status == 201)
		{
			$obCDNRequest = $this->SendCDNRequest(
				$arBucket["SETTINGS"],
				"PUT",
				$arBucket["BUCKET"],
				'', //filename
				'', //params
				false, //content
				array(
					"X-CDN-Enabled" => "True",
				)
			);
		}

		return ($this->status == 201)/*Created*/ || ($this->status == 202) /*Accepted*/;
	}

	function GetFileSRC($arBucket, $arFile)
	{
		global $APPLICATION;

		if ($arBucket["SETTINGS"]["FORCE_HTTP"] === "Y")
			$proto = "http";
		else
			$proto = ($APPLICATION->IsHTTPS()? "https": "http");

		if($arBucket["CNAME"])
		{
			$host = $proto."://".$arBucket["CNAME"];
		}
		else
		{
			$result = false;
			$cache_id = md5(serialize($arBucket));
			$obCache = new CPHPCache;
			if($obCache->InitCache(3600, $cache_id, "/"))
			{
				$result = $obCache->GetVars();
			}
			else
			{
				$obCDNRequest = $this->SendCDNRequest(
					$arBucket["SETTINGS"],
					"HEAD",
					$arBucket["BUCKET"]
				);
				if(is_object($obCDNRequest))
				{
					if($obCDNRequest->status == 204)
					{
						$result = array();
						foreach($obCDNRequest->headers as $key => $value)
							$result[strtolower($key)] = $value;
					}
				}
			}

			if($obCache->StartDataCache())
				$obCache->EndDataCache($result);

			if(is_array($result))
				$host = $result["x-cdn-uri"];
			else
				return "/404.php";
		}

		if(is_array($arFile))
			$URI = ltrim($arFile["SUBDIR"]."/".$arFile["FILE_NAME"], "/");
		else
			$URI = ltrim($arFile, "/");

		if($arBucket["PREFIX"])
		{
			if(substr($URI, 0, strlen($arBucket["PREFIX"])+1) !== $arBucket["PREFIX"]."/")
				$URI = $arBucket["PREFIX"]."/".$URI;
		}

		return $host."/".CCloudUtil::URLEncode($URI, "UTF-8");
	}
}
?>classes/general/storage_upload.php000064400000015672150241560060013351 0ustar00<?
/*.
	require_module 'standard';
	require_module 'pcre';
	require_module 'hash';
	require_module 'bitrix_main';
	require_module 'bitrix_clouds_classes_storage_service';
	require_module 'bitrix_clouds_classes_storage_bucket';
.*/
IncludeModuleLangFile(__FILE__);

class CCloudStorageUpload
{
	protected /*.string.*/ $_filePath = "";
	protected /*.string.*/ $_ID = "";
	protected /*.CCloudStorageBucket.*/ $obBucket;
	protected /*.int.*/ $_max_retries = 3;
	protected /*.array[string]string.*/ $_cache = null;

	/**
	 * @param string $filePath
	 * @return void
	*/
	function __construct($filePath)
	{
		$this->_filePath = $filePath;
		$this->_ID = "1".substr(md5($filePath), 1);
	}

	/**
	 * @return array[string]string
	*/
	public function GetArray()
	{
		global $DB;

		if(!isset($this->_cache))
		{
			$rs = $DB->Query("
				SELECT *
				FROM b_clouds_file_upload
				WHERE ID = '".$this->_ID."'
			");
			$this->_cache = $rs->Fetch();
		}

		return $this->_cache;
	}

	/**
	 * @return bool
	*/
	public function isStarted()
	{
		return is_array($this->GetArray());
	}

	/**
	 * @return void
	*/
	public function Delete()
	{
		global $DB;
		//TODO: clean up temp files in Clodo
		$DB->Query("DELETE FROM b_clouds_file_upload WHERE ID = '".$this->_ID."'");
		unset($this->_cache);
	}

	/**
	 * @return void
	*/
	public function DeleteOld()
	{
		global $DB;
		$DB->Query("DELETE FROM b_clouds_file_upload WHERE TIMESTAMP_X < ".$DB->CharToDateFunction(ConvertTimeStamp(time()-24*60*60)));
	}

	/**
	 * @param int $bucket_id
	 * @param float $fileSize
	 * @param string $ContentType
	 * @return bool
	*/
	function Start($bucket_id, $fileSize, $ContentType = 'binary/octet-stream', $tmpFileName = false)
	{
		global $DB;

		if(is_object($bucket_id))
			$obBucket = $bucket_id;
		else
			$obBucket = new CCloudStorageBucket(intval($bucket_id));

		if(!$obBucket->Init())
			return false;

		if(!$this->isStarted())
		{
			$arUploadInfo = /*.(array[string]string).*/array();
			$bStarted = $obBucket->GetService()->InitiateMultipartUpload(
				$obBucket->GetBucketArray(),
				$arUploadInfo,
				$this->_filePath,
				$fileSize,
				$ContentType
			);

			if($bStarted)
			{
				$bAdded = $DB->Add("b_clouds_file_upload", array(
					"ID" => $this->_ID,
					"~TIMESTAMP_X" => $DB->CurrentTimeFunction(),
					"FILE_PATH" => $this->_filePath,
					"FILE_SIZE" => $fileSize,
					"TMP_FILE" => $tmpFileName,
					"BUCKET_ID" => intval($obBucket->ID),
					"PART_SIZE" => $obBucket->GetService()->GetMinUploadPartSize(),
					"PART_NO" => 0,
					"PART_FAIL_COUNTER" => 0,
					"NEXT_STEP" => serialize($arUploadInfo),
				), array("NEXT_STEP"));
				unset($this->_cache);

				return $bAdded !== false;
			}
		}

		return false;
	}

	/**
	 * @param string $data
	 * @return bool
	*/
	function Next($data, $obBucket = null)
	{
		global $APPLICATION;

		if($this->isStarted())
		{
			$ar = $this->GetArray();

			if($obBucket == null)
				$obBucket = new CCloudStorageBucket(intval($ar["BUCKET_ID"]));

			if(!$obBucket->Init())
			{
				$APPLICATION->ThrowException(GetMessage('CLO_STORAGE_UPLOAD_ERROR', array('#errno#'=>1)));
				return false;
			}

			$arUploadInfo = unserialize($ar["NEXT_STEP"]);
			$bSuccess = $obBucket->GetService()->UploadPart(
				$obBucket->GetBucketArray(),
				$arUploadInfo,
				$data
			);

			if (!$this->UpdateProgress($arUploadInfo, $bSuccess))
			{
				$APPLICATION->ThrowException(GetMessage('CLO_STORAGE_UPLOAD_ERROR', array('#errno#'=>2)));
				return false;
			}

			return $bSuccess;
		}

		return false;
	}

	/**
	 * @param string $data
	 * @param int $part_no
	 * @return bool
	*/
	function Part($data, $part_no, $obBucket = null)
	{
		global $APPLICATION;

		if($this->isStarted())
		{
			$ar = $this->GetArray();

			if($obBucket == null)
				$obBucket = new CCloudStorageBucket(intval($ar["BUCKET_ID"]));

			if(!$obBucket->Init())
			{
				$APPLICATION->ThrowException(GetMessage('CLO_STORAGE_UPLOAD_ERROR', array('#errno#'=>3)));
				return false;
			}

			$service = $obBucket->GetService();
			if (!is_callable(array($service, 'UploadPartNo')))
			{
				$APPLICATION->ThrowException(GetMessage('CLO_STORAGE_UPLOAD_ERROR', array('#errno#'=>4)));
				return false;
			}

			$arUploadInfo = unserialize($ar["NEXT_STEP"]);
			$bSuccess = $obBucket->GetService()->UploadPartNo(
				$obBucket->GetBucketArray(),
				$arUploadInfo,
				$data,
				$part_no
			);

			if (!$this->UpdateProgress($arUploadInfo, $bSuccess))
			{
				$APPLICATION->ThrowException(GetMessage('CLO_STORAGE_UPLOAD_ERROR', array('#errno#'=>5)));
				return false;
			}

			return $bSuccess;
		}

		return false;
	}

	/**
	 * @return bool
	*/
	function Finish($obBucket = null)
	{
		if($this->isStarted())
		{
			$ar = $this->GetArray();

			if($obBucket == null)
				$obBucket = new CCloudStorageBucket(intval($ar["BUCKET_ID"]));
			if(!$obBucket->Init())
				return false;

			$arUploadInfo = unserialize($ar["NEXT_STEP"]);
			$bSuccess = $obBucket->GetService()->CompleteMultipartUpload(
				$obBucket->GetBucketArray(),
				$arUploadInfo
			);

			if($bSuccess)
				$this->Delete();

			$this->DeleteOld();

			if ($bSuccess)
			{
				foreach(GetModuleEvents("clouds", "OnAfterCompleteMultipartUpload", true) as $arEvent)
				{
					ExecuteModuleEventEx($arEvent, array($obBucket, array("size" => $ar["FILE_SIZE"]), $this->_filePath));
				}
			}
			
			return $bSuccess;
		}

		return false;
	}

	/**
	 * @return int
	*/
	function GetPartCount()
	{
		$ar = $this->GetArray();

		if(is_array($ar))
			return intval($ar["PART_NO"]);
		else
			return 0;
	}

	/**
	 * @return float
	*/
	function GetPos()
	{
		$ar = $this->GetArray();

		if(is_array($ar))
			return intval($ar["PART_NO"])*doubleval($ar["PART_SIZE"]);
		else
			return 0;
	}

	/**
	 * @return int
	*/
	function getPartSize()
	{
		$ar = $this->GetArray();

		if(is_array($ar))
			return intval($ar["PART_SIZE"]);
		else
			return 0;
	}

	/**
	 * @return bool
	*/
	function hasRetries()
	{
		$ar = $this->GetArray();
		return is_array($ar) && (intval($ar["PART_FAIL_COUNTER"]) < $this->_max_retries);
	}

	/**
	 * @return string
	*/
	function getTempFileName()
	{
		$ar = $this->GetArray();
		if(is_array($ar))
			return $ar["TMP_FILE"];
		else
			return "";
	}

	/**
	 * @param array $arUploadInfo
	 * @param boolean $bSuccess
	 * @return boolean
	*/
	protected function UpdateProgress($arUploadInfo, $bSuccess)
	{
		global $DB;

		if ($bSuccess)
		{
			$arFields = array(
				"NEXT_STEP" => serialize($arUploadInfo),
				"~PART_NO" => "PART_NO + 1",
				"PART_FAIL_COUNTER" => 0,
			);
			$arBinds = array(
				"NEXT_STEP" => $arFields["NEXT_STEP"],
			);
		}
		else
		{
			$arFields = array(
				"~PART_FAIL_COUNTER" => "PART_FAIL_COUNTER + 1",
			);
			$arBinds = array(
			);
		}

		$strUpdate = $DB->PrepareUpdate("b_clouds_file_upload", $arFields);
		if ($strUpdate != "")
		{
			$strSql = "UPDATE b_clouds_file_upload SET ".$strUpdate." WHERE ID = '".$this->_ID."'";
			if(!$DB->QueryBind($strSql, $arBinds))
			{
				unset($this->_cache);
				return false;
			}
		}

		unset($this->_cache);
		return true;
	}
	
}
?>classes/general/storage_service_s3.php000064400000066576150241560060014143 0ustar00<?
IncludeModuleLangFile(__FILE__);

class CCloudStorageService_AmazonS3 extends CCloudStorageService
{
	protected $status = 0;
	protected $verb = '';
	protected $host = '';
	protected $url = '';
	protected $headers =/*.(array[string]string).*/array();
	protected $set_headers =/*.(array[string]string).*/array();
	protected $errno = 0;
	protected $errstr = '';
	protected $result = '';
	protected $new_end_point = '';
	protected $_public = true;
	protected $location = '';
	/**
	 * @return int
	*/
	function GetLastRequestStatus()
	{
		return $this->status;
	}
	/**
	 * @return CCloudStorageService
	*/
	function GetObject()
	{
		return new CCloudStorageService_AmazonS3();
	}
	/**
	 * @return string
	*/
	function GetID()
	{
		return "amazon_s3";
	}
	/**
	 * @return string
	*/
	function GetName()
	{
		return "Amazon Simple Storage Service";
	}
	/**
	 * @return array[string]string
	*/
	function GetLocationList()
	{
		// http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region
		return array(
			"" => "US Standard",
			"us-east-2" => "US East (Ohio)",
			"us-west-1" => "US West (Northern California)",
			"us-west-2" => "US West (Oregon)",
			"ca-central-1" => "Canada (Central)",
			"ap-south-1" => "Asia Pacific (Mumbai)",
			"ap-northeast-2" => "Asia Pacific (Seoul)",
			"ap-southeast-1" => "Asia Pacific (Singapore)",
			"ap-southeast-2" => "Asia Pacific (Sydney)",
			"ap-northeast-1" => "Asia Pacific (Tokyo)",
			"eu-central-1" => "EU (Frankfurt)",
			"eu-west-1" => "EU (Ireland)",
			"eu-west-2" => "EU (London)",
			"sa-east-1" => "South America (Sao Paulo)",
		);
	}
	/**
	 * @return array[string]string
	*/
	function GetAPList()
	{
		// http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region
		return array(
			"" => "s3.amazonaws.com",
			"us-east-2" => "s3.us-east-2.amazonaws.com",
			"us-west-1" => "s3-us-west-1.amazonaws.com",
			"us-west-2" => "s3-us-west-2.amazonaws.com",
			"ca-central-1" => "s3.ca-central-1.amazonaws.com",
			"ap-south-1" => "s3.ap-south-1.amazonaws.com",
			"ap-northeast-2" => "s3.ap-northeast-2.amazonaws.com",
			"ap-southeast-1" => "s3-ap-southeast-1.amazonaws.com",
			"ap-southeast-2" => "s3-ap-southeast-2.amazonaws.com",
			"ap-northeast-1" => "s3-ap-northeast-1.amazonaws.com",
			"eu-central-1" => "s3.eu-central-1.amazonaws.com",
			"eu-west-1" => "s3-eu-west-1.amazonaws.com",
			"eu-west-2" => "s3.eu-west-2.amazonaws.com",
			"sa-east-1" => "South America (Sao Paulo)",
		);
	}
	/**
	 * @param array[string]string $arBucket
	 * @param bool $bServiceSet
	 * @param string $cur_SERVICE_ID
	 * @param bool $bVarsFromForm
	 * @return string
	*/
	function GetSettingsHTML($arBucket, $bServiceSet, $cur_SERVICE_ID, $bVarsFromForm)
	{
		if($bVarsFromForm)
			$arSettings = $_POST["SETTINGS"][$this->GetID()];
		else
			$arSettings = unserialize($arBucket["SETTINGS"]);

		if(!is_array($arSettings))
			$arSettings = array("ACCESS_KEY" => "", "SECRET_KEY" => "");

		$htmlID = htmlspecialcharsbx($this->GetID());

		$result = '
		<tr id="SETTINGS_0_'.$htmlID.'" style="display:'.($cur_SERVICE_ID === $this->GetID() || !$bServiceSet? '': 'none').'" class="settings-tr adm-detail-required-field">
			<td>'.GetMessage("CLO_STORAGE_S3_EDIT_ACCESS_KEY").':</td>
			<td><input type="hidden" name="SETTINGS['.$htmlID.'][ACCESS_KEY]" id="'.$htmlID.'ACCESS_KEY" value="'.htmlspecialcharsbx($arSettings['ACCESS_KEY']).'"><input type="text" size="55" name="'.$htmlID.'INP_ACCESS_KEY" id="'.$htmlID.'INP_ACCESS_KEY" value="'.htmlspecialcharsbx($arSettings['ACCESS_KEY']).'" '.($arBucket['READ_ONLY'] === 'Y'? '"disabled"': '').' onchange="BX(\''.$htmlID.'ACCESS_KEY\').value = this.value"></td>
		</tr>
		<tr id="SETTINGS_1_'.$htmlID.'" style="display:'.($cur_SERVICE_ID === $this->GetID() || !$bServiceSet? '': 'none').'" class="settings-tr adm-detail-required-field">
			<td>'.GetMessage("CLO_STORAGE_S3_EDIT_SECRET_KEY").':</td>
			<td><input type="hidden" name="SETTINGS['.$htmlID.'][SECRET_KEY]" id="'.$htmlID.'SECRET_KEY" value="'.htmlspecialcharsbx($arSettings['SECRET_KEY']).'"><input type="text" size="55" name="'.$htmlID.'INP_SECRET_KEY" id="'.$htmlID.'INP_SECRET_KEY" value="'.htmlspecialcharsbx($arSettings['SECRET_KEY']).'" autocomplete="off" '.($arBucket['READ_ONLY'] === 'Y'? '"disabled"': '').' onchange="BX(\''.$htmlID.'SECRET_KEY\').value = this.value"></td>
		</tr>
		<tr id="SETTINGS_2_'.$htmlID.'" style="display:'.($cur_SERVICE_ID === $this->GetID() || !$bServiceSet? '': 'none').'" class="settings-tr">
			<td>&nbsp;</td>
			<td>'.BeginNote().GetMessage("CLO_STORAGE_S3_EDIT_HELP").EndNote().'</td>
		</tr>
		';
		return $result;
	}
	/**
	 * @param array[string]string $arBucket
	 * @param array[string]string $arSettings
	 * @return bool
	*/
	function CheckSettings($arBucket, &$arSettings)
	{
		global $APPLICATION;
		$aMsg =/*.(array[int][string]string).*/array();

		$result = array(
			"ACCESS_KEY" => is_array($arSettings)? trim($arSettings["ACCESS_KEY"]): '',
			"SECRET_KEY" => is_array($arSettings)? trim($arSettings["SECRET_KEY"]): '',
		);
		if(is_array($arSettings) && array_key_exists("SESSION_TOKEN", $arSettings))
		{
			$result["SESSION_TOKEN"] = trim($arSettings["SESSION_TOKEN"]);
		}

		if($arBucket["READ_ONLY"] !== "Y" && $result["ACCESS_KEY"] === '')
		{
			$aMsg[] = array(
				"id" => $this->GetID()."INP_ACCESS_KEY",
				"text" => GetMessage("CLO_STORAGE_S3_EMPTY_ACCESS_KEY"),
			);
		}

		if($arBucket["READ_ONLY"] !== "Y" && $result["SECRET_KEY"] === '')
		{
			$aMsg[] = array(
				"id" => $this->GetID()."INP_SECRET_KEY",
				"text" => GetMessage("CLO_STORAGE_S3_EMPTY_SECRET_KEY"),
			);
		}

		if(!empty($aMsg))
		{
			$e = new CAdminException($aMsg);
			$APPLICATION->ThrowException($e);
			return false;
		}
		else
		{
			$arSettings = $result;
		}

		return true;
	}
	/**
	 * @param string $data
	 * @param string $key
	 * @return string
	*/
	function hmacsha1($data, $key)
	{
		if(strlen($key)>64)
			$key=pack('H*', sha1($key));
		$key = str_pad($key, 64, chr(0x00));
		$ipad = str_repeat(chr(0x36), 64);
		$opad = str_repeat(chr(0x5c), 64);
		$hmac = pack('H*', sha1(($key^$opad).pack('H*', sha1(($key^$ipad).$data))));
		return $hmac;
	}
	/**
	 * @param array[string]string $arSettings
	 * @param string $RequestMethod
	 * @param string $bucket
	 * @param string $RequestURI
	 * @param string $ContentType
	 * @param array[string]string $additional_headers
	 * @param string $params
	 * @param string|resource $content
	 * @return array[string]string
	*/
	function SignRequest($arSettings, $RequestMethod, $bucket, $RequestURI, $ContentType, $additional_headers, $params = "", $content = "")
	{
		static $search = array("+", "=");
		static $replace = array("%20", "%3D");

		$CanonicalizedResource = strlen($RequestURI)? str_replace($search, $replace, $RequestURI): "/";

		$CanonicalQuery = explode("&", ltrim($params, "?"));
		sort($CanonicalQuery);
		$CanonicalQueryString = implode("&", $CanonicalQuery);

		$CanonicalHeaders = array();
		foreach($additional_headers as $key => $value)
		{
			$key = strtolower($key);
			if (isset($CanonicalHeaders[$key]))
				$CanonicalHeaders[$key] .= ",";
			else
				$CanonicalHeaders[$key] = $key.":";
			$CanonicalHeaders[$key] .= trim($value, " \t\n\r");
		}
		ksort($CanonicalHeaders);
		$CanonicalHeadersString = implode("\n", $CanonicalHeaders);
		$SignedHeaders = implode(";", array_keys($CanonicalHeaders));

		if (is_resource($content))
		{
			$streamPosition = ftell($content);
			$hashResource = hash_init("sha256");
			hash_update_stream($hashResource, $content);
			$HashedPayload = hash_final($hashResource);
			fseek($content, $streamPosition);
		}
		else
		{
			$HashedPayload = hash("sha256", $content, false);
		}

		$CanonicalRequest = "";
		$CanonicalRequest .= $RequestMethod."\n";
		$CanonicalRequest .= $CanonicalizedResource."\n";
		$CanonicalRequest .= $CanonicalQueryString."\n";
		$CanonicalRequest .= $CanonicalHeadersString."\n\n";
		$CanonicalRequest .= $SignedHeaders."\n";
		$CanonicalRequest .= $HashedPayload;

		$Algorithm = "AWS4-HMAC-SHA256";
		$Time = time();
		$RequestDate = gmdate('Ymd', $Time);
		$RequestTime = gmdate('Ymd', $Time).'T'.gmdate('His', $Time).'Z';
		$Region = $this->location? $this->location: 'us-east-1';
		$Service = "s3";
		$Scope = $RequestDate."/".$Region."/".$Service."/aws4_request";

		$StringToSign = "";
		$StringToSign .= $Algorithm."\n";
		$StringToSign .= $RequestTime."\n";
		$StringToSign .= $Scope."\n";
		$StringToSign .= hash("sha256", $CanonicalRequest, false);

		$kSecret  = $arSettings["SECRET_KEY"];
		$kDate    = hash_hmac("sha256", $RequestDate, "AWS4".$kSecret, true);
		$kRegion  = hash_hmac("sha256", $Region, $kDate, true);
		$kService = hash_hmac("sha256", $Service, $kRegion, true);
		$kSigning = hash_hmac("sha256", "aws4_request", $kService, true);

		$Signature = hash_hmac("sha256", $StringToSign, $kSigning, false);

		$Authorization = "$Algorithm Credential=$arSettings[ACCESS_KEY]/$Scope, SignedHeaders=$SignedHeaders, Signature=$Signature";

		return array(
			"Date" => $RequestTime,
			"Authorization" => $Authorization,
			"x-amz-content-sha256" => $HashedPayload,
		);
	}
	/**
	 * @param string $location
	 * @return void
	 **/
	function SetLocation($location)
	{
		if ($location)
			$this->location = $location;
		else
			$this->location = "";
	}
	protected function GetRequestHost($bucket)
	{
		if(
			$this->new_end_point != ""
			&& preg_match('#^(http|https)://'.preg_quote($bucket, '#').'(.+?)/#', $this->new_end_point, $match) > 0
		)
		{
			return $bucket.$match[2];
		}
		elseif ($this->location)
		{
			return $bucket.".s3-".$this->location.".amazonaws.com";
		}
		else
		{
			return $bucket.".s3.amazonaws.com";
		}
	}
	/**
	 * @param array[string]string $arSettings
	 * @param string $verb
	 * @param string $bucket
	 * @param string $file_name
	 * @param string $params
	 * @param string $content
	 * @param array[string]string $additional_headers
	 * @return mixed
	*/
	function SendRequest($arSettings, $verb, $bucket, $file_name='/', $params='', $content='', $additional_headers=/*.(array[string]string).*/array())
	{
		global $APPLICATION;
		$this->status = 0;

		$obRequest = new CHTTP;
		if (isset($additional_headers["option-file-result"]))
		{
			$obRequest->fp = $additional_headers["option-file-result"];
		}

		if(isset($additional_headers["Content-Type"]))
		{
			$ContentType = $additional_headers["Content-Type"];
		}
		else
		{
			$ContentType = $content != ""? 'text/plain': '';
		}
		unset($additional_headers["Content-Type"]);

		foreach($this->set_headers as $key => $value)
		{
			$additional_headers[$key] = $value;
		}

		if(array_key_exists("SESSION_TOKEN", $arSettings))
		{
			$additional_headers["x-amz-security-token"] = $arSettings["SESSION_TOKEN"];
		}

		$additional_headers["host"] = $this->GetRequestHost($bucket);

		foreach($this->SignRequest($arSettings, $verb, $bucket, $file_name, $ContentType, $additional_headers, $params, $content) as $key => $value)
		{
			$obRequest->additional_headers[$key] = $value;
		}

		foreach($additional_headers as $key => $value)
			if(preg_match("/^(option-|host\$)/", $key) == 0)
				$obRequest->additional_headers[$key] = $value;

		$host = $additional_headers["host"];

		$was_end_point = $this->new_end_point;
		$this->new_end_point = '';

		$obRequest->Query($verb, $host, 80, $file_name.$params, $content, '', $ContentType);
		$this->status = $obRequest->status;
		$this->host = $host;
		$this->verb = $verb;
		$this->url =  $file_name.$params;
		$this->headers = $obRequest->headers;
		$this->errno = $obRequest->errno;
		$this->errstr = $obRequest->errstr;
		$this->result = $obRequest->result;

		if($obRequest->status == 200)
		{
			if(
				isset($additional_headers["option-raw-result"])
				|| isset($additional_headers["option--result"])
			)
			{
				return $obRequest->result;
			}
			elseif($obRequest->result != "")
			{
				$obXML = new CDataXML;
				$text = preg_replace("/<"."\\?XML.*?\\?".">/i", "", $obRequest->result);
				if($obXML->LoadString($text))
				{
					$arXML = $obXML->GetArray();
					if(is_array($arXML))
					{
						return $arXML;
					}
				}
				//XML parse error
				$e = new CApplicationException(GetMessage('CLO_STORAGE_S3_XML_PARSE_ERROR', array('#errno#'=>'1')));
				$APPLICATION->ThrowException($e);
				return false;
			}
			else
			{
				//Empty success result
				return array();
			}
		}
		elseif(
			$obRequest->status == 307  //Temporary redirect
			&& isset($obRequest->headers["Location"])
			&& $was_end_point === "" //No recurse yet
		)
		{
			$this->new_end_point = $obRequest->headers["Location"];
			return $this->SendRequest(
				$arSettings,
				$verb,
				$bucket,
				$file_name,
				$params,
				$content,
				$additional_headers
			);
		}
		elseif($obRequest->status > 0)
		{
			if($obRequest->result != "")
			{
				$obXML = new CDataXML;
				if($obXML->LoadString($obRequest->result))
				{
					$node = $obXML->SelectNodes("/Error/Message");
					if (is_object($node))
					{
						$errorMessage = trim($node->textContent(), '.');
						$e = new CApplicationException(GetMessage('CLO_STORAGE_S3_XML_ERROR', array(
							'#errmsg#' => $errorMessage,
						)));
						$APPLICATION->ThrowException($e);
						return false;
					}
				}
			}
			$e = new CApplicationException(GetMessage('CLO_STORAGE_S3_XML_PARSE_ERROR', array('#errno#'=>'2')));
			$APPLICATION->ThrowException($e);
			return false;
		}
		else
		{
			$e = new CApplicationException(GetMessage('CLO_STORAGE_S3_XML_PARSE_ERROR', array('#errno#'=>'3')));
			$APPLICATION->ThrowException($e);
			return false;
		}
	}
	/**
	 * @param array[string]string $arBucket
	 * @return bool
	*/
	function CreateBucket($arBucket)
	{
		global $APPLICATION;

		$arFiles = $this->ListFiles($arBucket, '/');
		if(is_array($arFiles))
			return true;

		if($arBucket["LOCATION"] != "")
			$content =
				'<CreateBucketConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">'.
				'<LocationConstraint>'.$arBucket["LOCATION"].'</LocationConstraint>'.
				'</CreateBucketConfiguration>';
		else
			$content = '';

		$this->SetLocation($arBucket["LOCATION"]);
		$response = $this->SendRequest(
			$arBucket["SETTINGS"],
			'PUT',
			$arBucket["BUCKET"],
			'/',
			'',
			$content
		);

		if($this->status == 409/*Already exists*/)
		{
			$APPLICATION->ResetException();
			return true;
		}
		else
		{
			return is_array($response);
		}
	}
	/**
	 * @param array[string]string $arBucket
	 * @return bool
	*/
	function DeleteBucket($arBucket)
	{
		global $APPLICATION;

		if($arBucket["PREFIX"] != "")
		{
			//Do not delete bucket if there is some files left
			if(!$this->IsEmptyBucket($arBucket))
				return false;

			//Let's pretend we deleted the bucket
			return true;
		}

		$this->SetLocation($arBucket["LOCATION"]);
		$response = $this->SendRequest(
			$arBucket["SETTINGS"],
			'DELETE',
			$arBucket["BUCKET"]
		);

		if(
			$this->status == 204/*No content*/
			|| $this->status == 404/*Not exists*/
			|| $this->status == 403/*Access denied*/
		)
		{
			$APPLICATION->ResetException();
			return true;
		}
		else
		{
			return is_array($response);
		}
	}
	/**
	 * @param array[string]string $arBucket
	 * @return bool
	*/
	function IsEmptyBucket($arBucket)
	{
		global $APPLICATION;

		$this->SetLocation($arBucket["LOCATION"]);
		$response = $this->SendRequest(
			$arBucket["SETTINGS"],
			'GET',
			$arBucket["BUCKET"],
			'/',
			'?max-keys=1'.($arBucket["PREFIX"] != ""? '&prefix='.$arBucket["PREFIX"].'/': '')
		);

		if($this->status == 404 || $this->status == 403)
		{
			$APPLICATION->ResetException();
			return true;
		}
		elseif(is_array($response))
		{
			return
				!isset($response["ListBucketResult"])
				|| !is_array($response["ListBucketResult"])
				|| !isset($response["ListBucketResult"]["#"])
				|| !is_array($response["ListBucketResult"]["#"])
				|| !isset($response["ListBucketResult"]["#"]["Contents"])
				|| !is_array($response["ListBucketResult"]["#"]["Contents"]);
		}
		else
		{
			return false;
		}
	}
	/**
	 * @param array[string]string $arBucket
	 * @param mixed $arFile
	 * @return string
	*/
	function GetFileSRC($arBucket, $arFile)
	{
		$proto = CMain::IsHTTPS()? "https": "http";

		static $aps = null;
		if (!$aps)
			$aps = self::GetAPList();

		if($arBucket["CNAME"] != "")
		{
			$host = $arBucket["CNAME"];
			$pref = "";
		}
		elseif ($proto === "https" && strpos($arBucket["BUCKET"], ".") !== false)
		{
			if (isset($aps[$arBucket["LOCATION"]]))
				$host = $aps[$arBucket["LOCATION"]];
			else
				$host = $aps[""];

			$pref = $arBucket["BUCKET"];
		}
		else
		{
			if (isset($aps[$arBucket["LOCATION"]]))
				$host = $arBucket["BUCKET"].".".$aps[$arBucket["LOCATION"]];
			else
				$host = $aps[""];

			$pref = "";
		}

		if(is_array($arFile))
			$URI = ltrim($arFile["SUBDIR"]."/".$arFile["FILE_NAME"], "/");
		else
			$URI = ltrim($arFile, "/");

		if ($arBucket["PREFIX"] != "")
		{
			if(substr($URI, 0, strlen($arBucket["PREFIX"])+1) !== $arBucket["PREFIX"]."/")
				$URI = $arBucket["PREFIX"]."/".$URI;
		}

		if ($pref !== "")
		{
			$URI = $pref."/".$URI;
		}

		return $proto."://$host/".CCloudUtil::URLEncode($URI, "UTF-8");
	}
	/**
	 * @param array[string]string $arBucket
	 * @param string $filePath
	 * @return bool
	*/
	function FileExists($arBucket, $filePath)
	{
		global $APPLICATION;

		if($arBucket["PREFIX"] != "")
		{
			if(substr($filePath, 0, strlen($arBucket["PREFIX"])+2) != "/".$arBucket["PREFIX"]."/")
				$filePath = "/".$arBucket["PREFIX"]."/".ltrim($filePath, "/");
		}
		$filePath = CCloudUtil::URLEncode($filePath, "UTF-8");

		$this->SetLocation($arBucket["LOCATION"]);
		$this->SendRequest(
			$arBucket["SETTINGS"],
			'HEAD',
			$arBucket["BUCKET"],
			$filePath
		);

		if($this->status == 200)
		{
			if (isset($this->headers["Content-Length"]) && $this->headers["Content-Length"] > 0)
				return $this->headers["Content-Length"];
			else
				return true;
		}
		elseif($this->status == 206)
		{
			$APPLICATION->ResetException();
			return true;
		}
		else//if($this->status == 404)
		{
			$APPLICATION->ResetException();
			return false;
		}
	}

	function FileCopy($arBucket, $arFile, $filePath)
	{
		global $APPLICATION;

		if($arBucket["PREFIX"])
		{
			if(substr($filePath, 0, strlen($arBucket["PREFIX"])+2) != "/".$arBucket["PREFIX"]."/")
				$filePath = "/".$arBucket["PREFIX"]."/".ltrim($filePath, "/");
		}

		$additional_headers = array();
		if($this->_public)
			$additional_headers["x-amz-acl"] = "public-read";
		$additional_headers["x-amz-copy-source"] = CCloudUtil::URLEncode("/".$arBucket["BUCKET"]."/".($arBucket["PREFIX"]? $arBucket["PREFIX"]."/": "").($arFile["SUBDIR"]? $arFile["SUBDIR"]."/": "").$arFile["FILE_NAME"], "UTF-8");
		$additional_headers["Content-Type"] = $arFile["CONTENT_TYPE"];

		$this->SetLocation($arBucket["LOCATION"]);
		$this->SendRequest(
			$arBucket["SETTINGS"],
			'PUT',
			$arBucket["BUCKET"],
			CCloudUtil::URLEncode($filePath, "UTF-8"),
			'',
			'',
			$additional_headers
		);

		if($this->status == 200)
		{
			return $this->GetFileSRC($arBucket, $filePath);
		}
		else//if($this->status == 404)
		{
			$APPLICATION->ResetException();
			return false;
		}
	}

	function DownloadToFile($arBucket, $arFile, $filePath)
	{
		$io = CBXVirtualIo::GetInstance();
		$obRequest = new CHTTP;
		$obRequest->follow_redirect = true;
		return $obRequest->Download($this->GetFileSRC($arBucket, $arFile), $io->GetPhysicalName($filePath));
	}

	function DeleteFile($arBucket, $filePath)
	{
		global $APPLICATION;

		if($arBucket["PREFIX"])
		{
			if(substr($filePath, 0, strlen($arBucket["PREFIX"])+2) != "/".$arBucket["PREFIX"]."/")
				$filePath = "/".$arBucket["PREFIX"]."/".ltrim($filePath, "/");
		}
		$filePath = CCloudUtil::URLEncode($filePath, "UTF-8");

		$this->SetLocation($arBucket["LOCATION"]);
		$this->SendRequest(
			$arBucket["SETTINGS"],
			'DELETE',
			$arBucket["BUCKET"],
			$filePath
		);

		if($this->status == 204)
		{
			$APPLICATION->ResetException();
			return true;
		}
		else//if($this->status == 404)
		{
			$APPLICATION->ResetException();
			return false;
		}
	}

	function SaveFile($arBucket, $filePath, $arFile)
	{
		global $APPLICATION;

		if($arBucket["PREFIX"])
		{
			if(substr($filePath, 0, strlen($arBucket["PREFIX"])+2) != "/".$arBucket["PREFIX"]."/")
				$filePath = "/".$arBucket["PREFIX"]."/".ltrim($filePath, "/");
		}
		$filePath = CCloudUtil::URLEncode($filePath, "UTF-8");

		$additional_headers = array();
		if($this->_public)
			$additional_headers["x-amz-acl"] = "public-read";
		$additional_headers["Content-Type"] = $arFile["type"];
		$additional_headers["Content-Length"] = (array_key_exists("content", $arFile)? CUtil::BinStrlen($arFile["content"]): filesize($arFile["tmp_name"]));

		$this->SetLocation($arBucket["LOCATION"]);
		$this->SendRequest(
			$arBucket["SETTINGS"],
			'PUT',
			$arBucket["BUCKET"],
			$filePath,
			'',
			(array_key_exists("content", $arFile)? $arFile["content"]: fopen($arFile["tmp_name"], "rb")),
			$additional_headers
		);

		if($this->status == 200)
		{
			return true;
		}
		elseif ($this->status == 400 && strpos($this->result, 'ExpiredToken') !== false)
		{
			$this->tokenHasExpired = true;
			return false;
		}
		elseif($this->status == 403)
		{
			AddMessage2Log($this);
			return false;
		}
		else
		{
			AddMessage2Log($this);
			$APPLICATION->ResetException();
			return false;
		}
	}

	function ListFiles($arBucket, $filePath, $bRecursive = false)
	{
		global $APPLICATION;

		$result = array(
			"dir" => array(),
			"file" => array(),
			"file_size" => array(),
		);

		$filePath = trim($filePath, '/');
		if(strlen($filePath))
			$filePath .= '/';

		if($arBucket["PREFIX"])
		{
			if(substr($filePath, 0, strlen($arBucket["PREFIX"])+2) != "/".$arBucket["PREFIX"]."/")
				$filePath = $arBucket["PREFIX"]."/".ltrim($filePath, "/");
		}
		$filePath = $APPLICATION->ConvertCharset($filePath, LANG_CHARSET, "UTF-8");

		$this->SetLocation($arBucket["LOCATION"]);
		$marker = '';
		while(true)
		{
			$response = $this->SendRequest(
				$arBucket["SETTINGS"],
				'GET',
				$arBucket["BUCKET"],
				'/',
				'?'.($bRecursive? '': 'delimiter=%2F&').'prefix='.urlencode($filePath)
					.'&marker='.str_replace("+", "%20", urlencode($marker))
			);

			if(
				$this->status == 200
				&& is_array($response)
				&& isset($response["ListBucketResult"])
				&& is_array($response["ListBucketResult"])
				&& isset($response["ListBucketResult"]["#"])
				&& is_array($response["ListBucketResult"]["#"])
			)
			{
				if(
					isset($response["ListBucketResult"]["#"]["CommonPrefixes"])
					&& is_array($response["ListBucketResult"]["#"]["CommonPrefixes"])
				)
				{
					foreach($response["ListBucketResult"]["#"]["CommonPrefixes"] as $a)
					{
						$dir_name = substr(rtrim($a["#"]["Prefix"][0]["#"], "/"), strlen($filePath));
						$result["dir"][] = $APPLICATION->ConvertCharset(urldecode($dir_name), "UTF-8", LANG_CHARSET);
					}
				}

				$lastKey = null;
				if(
					isset($response["ListBucketResult"]["#"]["Contents"])
					&& is_array($response["ListBucketResult"]["#"]["Contents"])
				)
				{
					foreach($response["ListBucketResult"]["#"]["Contents"] as $a)
					{
						$file_name = substr($a["#"]["Key"][0]["#"], strlen($filePath));
						$result["file"][] = $APPLICATION->ConvertCharset($file_name, "UTF-8", LANG_CHARSET);
						$result["file_size"][] = $a["#"]["Size"][0]["#"];
						$lastKey = $a["#"]["Key"][0]["#"];
					}
				}

				if(
					isset($response["ListBucketResult"]["#"]["IsTruncated"])
					&& is_array($response["ListBucketResult"]["#"]["IsTruncated"])
					&& $response["ListBucketResult"]["#"]["IsTruncated"][0]["#"] === "true"
				)
				{
					if (strlen($response["ListBucketResult"]["#"]["NextMarker"][0]["#"]) > 0)
					{
						$marker = $response["ListBucketResult"]["#"]["NextMarker"][0]["#"];
						continue;
					}
					elseif ($lastKey !== null);
					{
						$marker = $lastKey;
						continue;
					}
				}

				break;
			}
			elseif ($this->status == 400 && strpos($this->result, 'ExpiredToken') !== false)
			{
				$this->tokenHasExpired = true;
				return false;
			}
			else
			{
				return false;
			}
		}

		return $result;
	}

	function InitiateMultipartUpload($arBucket, &$NS, $filePath, $fileSize, $ContentType)
	{
		$filePath = '/'.trim($filePath, '/');
		if($arBucket["PREFIX"])
		{
			if(substr($filePath, 0, strlen($arBucket["PREFIX"])+2) != "/".$arBucket["PREFIX"]."/")
				$filePath = "/".$arBucket["PREFIX"].$filePath;
		}
		$filePathU = CCloudUtil::URLEncode($filePath, "UTF-8");

		$additional_headers = array();
		if($this->_public)
			$additional_headers["x-amz-acl"] = "public-read";
		$additional_headers["Content-Type"] = $ContentType;

		$this->SetLocation($arBucket["LOCATION"]);
		$response = $this->SendRequest(
			$arBucket["SETTINGS"],
			'POST',
			$arBucket["BUCKET"],
			$filePathU,
			'?uploads=',
			'',
			$additional_headers
		);

		if(
			$this->status == 200
			&& is_array($response)
			&& isset($response["InitiateMultipartUploadResult"])
			&& is_array($response["InitiateMultipartUploadResult"])
			&& isset($response["InitiateMultipartUploadResult"]["#"])
			&& is_array($response["InitiateMultipartUploadResult"]["#"])
			&& isset($response["InitiateMultipartUploadResult"]["#"]["UploadId"])
			&& is_array($response["InitiateMultipartUploadResult"]["#"]["UploadId"])
			&& isset($response["InitiateMultipartUploadResult"]["#"]["UploadId"][0])
			&& is_array($response["InitiateMultipartUploadResult"]["#"]["UploadId"][0])
			&& isset($response["InitiateMultipartUploadResult"]["#"]["UploadId"][0]["#"])
			&& is_string($response["InitiateMultipartUploadResult"]["#"]["UploadId"][0]["#"])
		)
		{
			$NS = array(
				"filePath" => $filePath,
				"UploadId" => $response["InitiateMultipartUploadResult"]["#"]["UploadId"][0]["#"],
				"Parts" => array(),
			);
			return true;
		}
		else
		{
			return false;
		}
	}

	function GetMinUploadPartSize()
	{
		return BX_S3_MIN_UPLOAD_PART_SIZE;
	}

	function UploadPartNo($arBucket, &$NS, $data, $part_no)
	{
		$filePath = '/'.trim($NS["filePath"], '/');
		if($arBucket["PREFIX"])
		{
			if(substr($filePath, 0, strlen($arBucket["PREFIX"])+2) != "/".$arBucket["PREFIX"]."/")
				$filePath = "/".$arBucket["PREFIX"].$filePath;
		}
		$filePath = CCloudUtil::URLEncode($filePath, "UTF-8");

		$this->SetLocation($arBucket["LOCATION"]);
		$this->SendRequest(
			$arBucket["SETTINGS"],
			'PUT',
			$arBucket["BUCKET"],
			$filePath,
			'?partNumber='.($part_no + 1).'&uploadId='.urlencode($NS["UploadId"]),
			$data
		);

		if($this->status == 200 && is_array($this->headers))
		{
			foreach ($this->headers as $key => $value)
			{
				if (strtolower($key) === "etag")
				{
					$NS["Parts"][$part_no] = $value;
					return true;
				}
			}
		}
		return false;
	}

	function UploadPart($arBucket, &$NS, $data)
	{
		return $this->UploadPartNo($arBucket, $NS, $data, count($NS["Parts"]));
	}

	function CompleteMultipartUpload($arBucket, &$NS)
	{
		$filePath = '/'.trim($NS["filePath"], '/');
		if($arBucket["PREFIX"])
		{
			if(substr($filePath, 0, strlen($arBucket["PREFIX"])+2) != "/".$arBucket["PREFIX"]."/")
				$filePath = "/".$arBucket["PREFIX"].$filePath;
		}
		$filePath = CCloudUtil::URLEncode($filePath, "UTF-8");

		ksort($NS["Parts"]);
		$data = "";
		foreach($NS["Parts"] as $PartNumber => $ETag)
		{
			$data .= "<Part><PartNumber>".($PartNumber+1)."</PartNumber><ETag>".$ETag."</ETag></Part>\n";
		}

		$this->SetLocation($arBucket["LOCATION"]);
		$this->SendRequest(
			$arBucket["SETTINGS"],
			'POST',
			$arBucket["BUCKET"],
			$filePath,
			'?uploadId='.urlencode($NS["UploadId"]),
			"<CompleteMultipartUpload>".$data."</CompleteMultipartUpload>"
		);

		return $this->status == 200;
	}

	function setPublic($state = true)
	{
		$this->_public = $state !== false;
	}

	function setHeader($key, $value)
	{
		$this->set_headers[$key] = $value;
	}

	function unsetHeader($key)
	{
		unset($this->set_headers[$key]);
	}

	function getHeaders()
	{
		return $this->headers;
	}
}
classes/general/storage_service_openstack.php000064400000044554150241560060015575 0ustar00<?
IncludeModuleLangFile(__FILE__);

class CCloudStorageService_OpenStackStorage extends CCloudStorageService
{
	protected $status = 0;
	protected $errno = 0;
	protected $errstr = '';
	protected $result = '';
	protected $verb = '';
	protected $url = '';

	function GetLastRequestStatus()
	{
		return $this->status;
	}

	function GetObject()
	{
		return new CCloudStorageService_OpenStackStorage();
	}

	function GetID()
	{
		return "openstack_storage";
	}

	function GetName()
	{
		return "OpenStack Object Storage";
	}

	function GetLocationList()
	{
		return array(
			"" => "N/A",
		);
	}

	function GetSettingsHTML($arBucket, $bServiceSet, $cur_SERVICE_ID, $bVarsFromForm)
	{
		if($bVarsFromForm)
			$arSettings = $_POST["SETTINGS"][$this->GetID()];
		else
			$arSettings = unserialize($arBucket["SETTINGS"]);

		if(!is_array($arSettings))
		{
			$arSettings = array(
				"HOST" => "",
				"USER" => "",
				"KEY" => "",
				"FORCE_HTTP" => "N",
			);
		}

		$htmlID = htmlspecialcharsbx($this->GetID());
		$show = (($cur_SERVICE_ID == $this->GetID()) || !$bServiceSet)? '': 'none';

		$result = '
		<tr id="SETTINGS_2_'.$htmlID.'" style="display:'.$show.'" class="settings-tr adm-detail-required-field">
			<td>'.GetMessage("CLO_STORAGE_OPENSTACK_EDIT_HOST").':</td>
			<td><input type="hidden" name="SETTINGS['.$htmlID.'][HOST]" id="'.$htmlID.'HOST" value="'.htmlspecialcharsbx($arSettings['HOST']).'"><input type="text" size="55" name="'.$htmlID.'INP_HOST" id="'.$htmlID.'INP_HOST" value="'.htmlspecialcharsbx($arSettings['HOST']).'" '.($arBucket['READ_ONLY'] == 'Y'? '"disabled"': '').' onchange="BX(\''.$htmlID.'HOST\').value = this.value"></td>
		</tr>
		<tr id="SETTINGS_0_'.$htmlID.'" style="display:'.$show.'" class="settings-tr adm-detail-required-field">
			<td>'.GetMessage("CLO_STORAGE_OPENSTACK_EDIT_USER").':</td>
			<td><input type="hidden" name="SETTINGS['.$htmlID.'][USER]" id="'.$htmlID.'USER" value="'.htmlspecialcharsbx($arSettings['USER']).'"><input type="text" size="55" name="'.$htmlID.'INP_" id="'.$htmlID.'INP_USER" value="'.htmlspecialcharsbx($arSettings['USER']).'" '.($arBucket['READ_ONLY'] == 'Y'? '"disabled"': '').' onchange="BX(\''.$htmlID.'USER\').value = this.value"></td>
		</tr>
		<tr id="SETTINGS_1_'.$htmlID.'" style="display:'.$show.'" class="settings-tr adm-detail-required-field">
			<td>'.GetMessage("CLO_STORAGE_OPENSTACK_EDIT_KEY").':</td>
			<td><input type="hidden" name="SETTINGS['.$htmlID.'][KEY]" id="'.$htmlID.'KEY" value="'.htmlspecialcharsbx($arSettings['KEY']).'"><input type="text" size="55" name="'.$htmlID.'INP_KEY" id="'.$htmlID.'INP_KEY" value="'.htmlspecialcharsbx($arSettings['KEY']).'" autocomplete="off" '.($arBucket['READ_ONLY'] == 'Y'? '"disabled"': '').' onchange="BX(\''.$htmlID.'KEY\').value = this.value"></td>
		</tr>
		<tr id="SETTINGS_3_'.$htmlID.'" style="display:'.$show.'" class="settings-tr">
			<td>'.GetMessage("CLO_STORAGE_OPENSTACK_FORCE_HTTP").':</td>
			<td><input type="hidden" name="SETTINGS['.$htmlID.'][FORCE_HTTP]" id="'.$htmlID.'KEY" value="N"><input type="checkbox" name="SETTINGS['.$htmlID.'][FORCE_HTTP]" id="'.$htmlID.'FORCE_HTTP" value="Y" '.($arSettings['FORCE_HTTP'] == 'Y'? 'checked="checked"': '').'></td>
		</tr>
		';
		return $result;
	}

	function CheckSettings($arBucket, &$arSettings)
	{
		global $APPLICATION;
		$aMsg = array();

		$result = array(
			"HOST" => is_array($arSettings)? trim($arSettings["HOST"]): '',
			"USER" => is_array($arSettings)? trim($arSettings["USER"]): '',
			"KEY" => is_array($arSettings)? trim($arSettings["KEY"]): '',
			"FORCE_HTTP" => is_array($arSettings) && $arSettings["FORCE_HTTP"] == "Y"? "Y": "N",
		);

		if($arBucket["READ_ONLY"] !== "Y" && !strlen($result["HOST"]))
			$aMsg[] = array("id" => $this->GetID()."INP_HOST", "text" => GetMessage("CLO_STORAGE_OPENSTACK_EMPTY_HOST"));

		if($arBucket["READ_ONLY"] !== "Y" && !strlen($result["USER"]))
			$aMsg[] = array("id" => $this->GetID()."INP_USER", "text" => GetMessage("CLO_STORAGE_OPENSTACK_EMPTY_USER"));

		if($arBucket["READ_ONLY"] !== "Y" && !strlen($result["KEY"]))
			$aMsg[] = array("id" => $this->GetID()."INP_KEY", "text" => GetMessage("CLO_STORAGE_OPENSTACK_EMPTY_KEY"));


		if(empty($aMsg))
		{
			if(!$this->_GetToken($result["HOST"], $result["USER"], $result["KEY"]))
				$aMsg[] = array("text" => GetMessage("CLO_STORAGE_OPENSTACK_ERROR_GET_TOKEN"));
		}

		if(!empty($aMsg))
		{
			$e = new CAdminException($aMsg);
			$APPLICATION->ThrowException($e);
			return false;
		}
		else
		{
			$arSettings = $result;
		}

		return true;
	}

	function _GetToken($host, $user, $key)
	{
		global $APPLICATION;
		static $results = array();
		$cache_id = "v0|".$host."|".$user."|".$key;

		if(array_key_exists($cache_id, $results))
		{
			$result = $results[$cache_id];
		}
		else
		{
			$result = false;
			$obCache = new CPHPCache;

			if($obCache->InitCache(600, $cache_id, "/")) /*TODO make setting*/
			{
				$result = $obCache->GetVars();
			}
			else
			{
				$obRequest = new CHTTP;
				$obRequest->additional_headers["X-Auth-User"] = $user;
				$obRequest->additional_headers["X-Auth-Key"] = $key;
				$obRequest->Query("GET", $host, 80, "/v1.0");
				if($obRequest->status == 412)
				{
					$APPLICATION->ResetException();
					$obRequest = new CHTTP;
					$obRequest->additional_headers["X-Auth-User"] = $user;
					$obRequest->additional_headers["X-Auth-Key"] = $key;
					$obRequest->Query("GET", $host, 80, "/auth/v1.0");
				}

				if($obRequest->status == 204 || $obRequest->status == 200)
				{
					$arStorage = array();
					if(preg_match("#^http://(.*?)(|:\d+)(/.*)\$#", $obRequest->headers["X-Storage-Url"], $arStorage))
					{
						$result = $obRequest->headers;
						$result["X-Storage-NoProtoUrl"] = $arStorage[1].($arStorage[2] == ':80'? '': $arStorage[2]).$arStorage[3];
						$result["X-Storage-Host"] = $arStorage[1];
						$result["X-Storage-Port"] = $arStorage[2]? substr($arStorage[2], 1): 80;
						$result["X-Storage-Urn"] = $arStorage[3];
						$result["X-Storage-Proto"] = "";
					}
				}
			}

			if(is_array($result))
			{
				if($obCache->StartDataCache())
					$obCache->EndDataCache($result);
			}

			$results[$cache_id] = $result;
		}

		return $result;
	}

	function SendRequest($settings, $verb, $bucket, $file_name='', $params='', $content=false, $additional_headers=array())
	{
		$arToken = $this->_GetToken($settings["HOST"], $settings["USER"], $settings["KEY"]);
		if(!$arToken)
			return false;

		$this->status = 0;
		$obRequest = new CHTTP;

		$RequestURI = $file_name;

		$ContentType = "N";
		$obRequest->additional_headers["X-Auth-Token"] = $arToken["X-Auth-Token"];
		foreach($additional_headers as $key => $value)
		{
			if($key == "Content-Type")
				$ContentType = $value;
			else
				$obRequest->additional_headers[$key] = $value;
		}

		@$obRequest->Query(
			$this->verb = $verb,
			$arToken["X-Storage-Host"],
			$arToken["X-Storage-Port"],
			$this->url = $arToken["X-Storage-Urn"]."/".$bucket.$RequestURI.$params,
			$content,
			$arToken["X-Storage-Proto"],
			$ContentType
		);
		$this->status = $obRequest->status;
		$this->errno = $obRequest->errno;
		$this->errstr = $obRequest->errstr;
		$this->result = $obRequest->result;

		return $obRequest;
	}

	function CreateBucket($arBucket)
	{
		global $APPLICATION;

		$obRequest = $this->SendRequest(
			$arBucket["SETTINGS"],
			"PUT",
			$arBucket["BUCKET"],
			'', //filename
			'', //params
			false, //content
			array(
				"X-Container-Read" => ".r:*",
				"X-Container-Meta-Web-Listings" => "false",
				"X-Container-Meta-Type" => "public",
			)
		);

		return ($this->status == 201)/*Created*/ || ($this->status == 202) /*Accepted*/;
	}

	function DeleteBucket($arBucket)
	{
		global $APPLICATION;

		if($arBucket["PREFIX"])
		{
			//Do not delete bucket if there is some files left
			if(!$this->IsEmptyBucket($arBucket))
				return false;

			//Do not delete bucket if there is some files left in other prefixes
			$arAllBucket = $arBucket;
			$arBucket["PREFIX"] = "";
			if(!$this->IsEmptyBucket($arAllBucket))
				return true;
		}

		$obRequest = $this->SendRequest(
			$arBucket["SETTINGS"],
			"DELETE",
			$arBucket["BUCKET"]
		);

		if(
			$this->status == 204/*No Content*/
			|| $this->status == 404/*Not Found*/
		)
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	function IsEmptyBucket($arBucket)
	{
		global $APPLICATION;

		$obRequest = $this->SendRequest(
			$arBucket["SETTINGS"],
			"GET",
			$arBucket["BUCKET"],
			'',
			"?limit=1&format=xml".($arBucket["PREFIX"]? '&prefix='.$arBucket["PREFIX"]: '')
		);

		$arXML = false;
		if(is_object($obRequest) && $obRequest->result)
		{
			$obXML = new CDataXML;
			$text = preg_replace("/<"."\\?XML.*?\\?".">/i", "", $obRequest->result);
			if($obXML->LoadString($text))
			{
				$arXML = $obXML->GetArray();
			}
		}

		if($this->status == 404)
		{
			return true;
		}
		elseif(is_array($arXML))
		{
			return
				!isset($arXML["container"])
				|| !is_array($arXML["container"])
				|| !isset($arXML["container"]["#"])
				|| !is_array($arXML["container"]["#"])
				|| !isset($arXML["container"]["#"]["object"])
				|| !is_array($arXML["container"]["#"]["object"]);
		}
		else
		{
			return false;
		}
	}

	function GetFileSRC($arBucket, $arFile)
	{
		global $APPLICATION;
		
		if ($arBucket["SETTINGS"]["FORCE_HTTP"] === "Y")
			$proto = "http";
		else
			$proto = ($APPLICATION->IsHTTPS()? "https": "http");

		if($arBucket["CNAME"])
		{
			$host = $proto."://".$arBucket["CNAME"];
		}
		else
		{
			$arToken = $this->_GetToken(
				$arBucket["SETTINGS"]["HOST"],
				$arBucket["SETTINGS"]["USER"],
				$arBucket["SETTINGS"]["KEY"]
			);

			if(is_array($arToken))
			{
				if ($arToken["X-Storage-NoProtoUrl"])
					$host = $proto."://".$arToken["X-Storage-NoProtoUrl"]."/".$arBucket["BUCKET"];
				else
					$host = $arToken["X-Storage-Url"]."/".$arBucket["BUCKET"];
			}
			else
			{
				return "/404.php";
			}
		}

		if(is_array($arFile))
			$URI = ltrim($arFile["SUBDIR"]."/".$arFile["FILE_NAME"], "/");
		else
			$URI = ltrim($arFile, "/");

		if($arBucket["PREFIX"])
		{
			if(substr($URI, 0, strlen($arBucket["PREFIX"])+1) !== $arBucket["PREFIX"]."/")
				$URI = $arBucket["PREFIX"]."/".$URI;
		}

		return $host."/".CCloudUtil::URLEncode($URI, "UTF-8");
	}

	function FileExists($arBucket, $filePath)
	{
		global $APPLICATION;

		if($arBucket["PREFIX"])
		{
			if(substr($filePath, 0, strlen($arBucket["PREFIX"])+2) != "/".$arBucket["PREFIX"]."/")
				$filePath = "/".$arBucket["PREFIX"]."/".ltrim($filePath, "/");
		}
		$filePath = CCloudUtil::URLEncode($filePath, "UTF-8");

		$obRequest = $this->SendRequest(
			$arBucket["SETTINGS"],
			"HEAD",
			$arBucket["BUCKET"],
			$filePath
		);

		return ($this->status == 200 || $this->status == 206);
	}

	function FileCopy($arBucket, $arFile, $filePath)
	{
		global $APPLICATION;

		if($arBucket["PREFIX"])
		{
			if(substr($filePath, 0, strlen($arBucket["PREFIX"])+2) != "/".$arBucket["PREFIX"]."/")
				$filePath = "/".$arBucket["PREFIX"]."/".ltrim($filePath, "/");
		}

		$obRequest = $this->SendRequest(
			$arBucket["SETTINGS"],
			"PUT",
			$arBucket["BUCKET"],
			CCloudUtil::URLEncode($filePath, "UTF-8"),
			'',
			false,
			array(
				"X-Copy-From" => CCloudUtil::URLEncode("/".$arBucket["BUCKET"]."/".($arBucket["PREFIX"]? $arBucket["PREFIX"]."/": "").($arFile["SUBDIR"]? $arFile["SUBDIR"]."/": "").$arFile["FILE_NAME"], "UTF-8"),
			)
		);

		if($this->status == 200 || $this->status == 201)
			return $this->GetFileSRC($arBucket, $filePath);
		else
			return false;
	}

	function DownloadToFile($arBucket, $arFile, $filePath)
	{
		$io = CBXVirtualIo::GetInstance();
		$obRequest = new CHTTP;
		$obRequest->follow_redirect = true;
		return $obRequest->Download($this->GetFileSRC($arBucket, $arFile), $io->GetPhysicalName($filePath));
	}

	function DeleteFile($arBucket, $filePath)
	{
		global $APPLICATION;

		if($arBucket["PREFIX"])
		{
			if(substr($filePath, 0, strlen($arBucket["PREFIX"])+2) != "/".$arBucket["PREFIX"]."/")
				$filePath = "/".$arBucket["PREFIX"]."/".ltrim($filePath, "/");
		}
		$filePath = CCloudUtil::URLEncode($filePath, "UTF-8");

		$obRequest = $this->SendRequest(
			$arBucket["SETTINGS"],
			"DELETE",
			$arBucket["BUCKET"],
			$filePath
		);

		return ($obRequest->status == 204 || $obRequest->status == 404);
	}

	function SaveFile($arBucket, $filePath, $arFile)
	{
		global $APPLICATION;

		if($arBucket["PREFIX"])
		{
			if(substr($filePath, 0, strlen($arBucket["PREFIX"])+2) != "/".$arBucket["PREFIX"]."/")
				$filePath = "/".$arBucket["PREFIX"]."/".ltrim($filePath, "/");
		}
		$filePath = CCloudUtil::URLEncode($filePath, "UTF-8");

		if (array_key_exists("content", $arFile))
		{
			$obRequest = $this->SendRequest(
				$arBucket["SETTINGS"],
				"PUT",
				$arBucket["BUCKET"],
				$filePath,
				"",
				$arFile["content"],
				array(
					"Content-Type" => $arFile["type"],
					"Content-Length" => CUtil::BinStrlen($arFile["content"]),
				)
			);
		}
		else
		{
			$obRequest = $this->SendRequest(
				$arBucket["SETTINGS"],
				"PUT",
				$arBucket["BUCKET"],
				$filePath,
				"",
				fopen($arFile["tmp_name"], "rb"),
				array(
					"Content-Type" => $arFile["type"],
					"Content-Length" => filesize($arFile["tmp_name"]),
				)
			);
		}

		if($obRequest->status == 201)
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	function ListFiles($arBucket, $filePath, $bRecursive = false)
	{
		global $APPLICATION;

		$result = array(
			"dir" => array(),
			"file" => array(),
			"file_size" => array(),
		);

		$filePath = trim($filePath, '/');
		if(strlen($filePath))
			$filePath .= '/';

		if($arBucket["PREFIX"])
		{
			if(substr($filePath, 0, strlen($arBucket["PREFIX"])+2) != "/".$arBucket["PREFIX"]."/")
				$filePath = $arBucket["PREFIX"]."/".ltrim($filePath, "/");
		}
		$filePath = $APPLICATION->ConvertCharset($filePath, LANG_CHARSET, "UTF-8");

		$marker = '';
		$new_marker = false;
		while(true)
		{
			$obRequest = $this->SendRequest(
				$arBucket["SETTINGS"],
				"GET",
				$arBucket["BUCKET"],
				'/',
				$s='?format=xml&'.($bRecursive? '': '&delimiter=/').'&prefix='.urlencode($filePath).'&marker='.urlencode($marker)
			);
			$bFound = false;
			if(is_object($obRequest) && $obRequest->result && $this->status == 200)
			{
				$obXML = new CDataXML;
				$text = preg_replace("/<"."\\?XML.*?\\?".">/i", "", $obRequest->result);
				if($obXML->LoadString($text))
				{
					$arXML = $obXML->GetArray();
					if(
						isset($arXML["container"])
						&& is_array($arXML["container"])
						&& isset($arXML["container"]["#"])
						&& is_array($arXML["container"]["#"])
						&& !empty($arXML["container"]["#"])
					)
					{
						if(
							isset($arXML["container"]["#"]["object"])
							&& is_array($arXML["container"]["#"]["object"])
							&& !empty($arXML["container"]["#"]["object"])
						)
						{
							$bFound = true;
							foreach($arXML["container"]["#"]["object"] as $a)
							{
								$new_marker = $a["#"]["name"][0]["#"];
								if($a["#"]["content_type"][0]["#"] === "application/directory")
								{
									$dir_name = trim(substr($a["#"]["name"][0]["#"], strlen($filePath)), "/");
									$result["dir"][$APPLICATION->ConvertCharset(urldecode($dir_name), "UTF-8", LANG_CHARSET)] = true;
								}
								else
								{
									$file_name = substr($a["#"]["name"][0]["#"], strlen($filePath));
									$file_name = $APPLICATION->ConvertCharset(urldecode($file_name), "UTF-8", LANG_CHARSET);
									if (!in_array($file_name, $result["file"]))
									{
										$result["file"][] = $file_name;
										$result["file_size"][] = $a["#"]["bytes"][0]["#"];
									}
								}
							}
						}

						if(
							isset($arXML["container"]["#"]["subdir"])
							&& is_array($arXML["container"]["#"]["subdir"])
							&& !empty($arXML["container"]["#"]["subdir"])
						)
						{
							$bFound = true;
							foreach($arXML["container"]["#"]["subdir"] as $a)
							{
								$new_marker = $a["@"]["name"];
								$dir_name = trim(substr($a["@"]["name"], strlen($filePath)), "/");
								$result["dir"][$APPLICATION->ConvertCharset(urldecode($dir_name), "UTF-8", LANG_CHARSET)] = true;
							}
						}
					}
				}
			}
			else
			{
				return false;
			}

			if($new_marker === $marker)
				break;

			if(!$bFound)
				break;

			$marker = $new_marker;
		}
		$result["dir"] = array_keys($result["dir"]);
		return $result;
	}

	function InitiateMultipartUpload($arBucket, &$NS, $filePath, $fileSize, $ContentType)
	{
		$filePath = '/'.trim($filePath, '/');
		if($arBucket["PREFIX"])
		{
			if(substr($filePath, 0, strlen($arBucket["PREFIX"])+2) != "/".$arBucket["PREFIX"]."/")
				$filePath = "/".$arBucket["PREFIX"].$filePath;
		}

		$NS = array(
			"filePath" => $filePath,
			"fileTemp" => CCloudStorage::translit("/tmp".str_replace(' ', '_', $filePath), "/"),
			"partsCount" => 0,
			"Parts" => array(),
			"Content-Type" => $ContentType,
		);

		return true;
	}

	function GetMinUploadPartSize()
	{
		return 5*1024*1024; //5MB
	}

	function UploadPartNo($arBucket, &$NS, $data, $part_no)
	{
		$filePath = $NS["fileTemp"]."/".sprintf("%06d", $part_no + 1);
		$filePath = CCloudUtil::URLEncode($filePath, "UTF-8");

		$obRequest = $this->SendRequest(
			$arBucket["SETTINGS"],
			"PUT",
			$arBucket["BUCKET"],
			$filePath,
			"",
			$data
		);

		if(is_object($obRequest) && $this->status == 201)
		{
			$NS["partsCount"]++;
			$NS["Parts"][$part_no] = $filePath;
			return true;
		}
		else
		{
			return false;
		}
	}

	function UploadPart($arBucket, &$NS, $data)
	{
		return $this->UploadPartNo($arBucket, $NS, $data, count($NS["Parts"]));
	}

	function CompleteMultipartUpload($arBucket, &$NS)
	{
		$filePath = CCloudUtil::URLEncode($NS["fileTemp"], "UTF-8");

		$obRequest = $this->SendRequest(
			$arBucket["SETTINGS"],
			"PUT",
			$arBucket["BUCKET"],
			$filePath,
			"",
			false,
			array(
				"Content-Type" => $NS["Content-Type"],
				"X-Object-Manifest" => $arBucket["BUCKET"].$filePath."/",
			)
		);

		if(is_object($obRequest) && $this->status == 201)
		{
			$obRequest = $this->SendRequest(
				$arBucket["SETTINGS"],
				"PUT",
				$arBucket["BUCKET"],
				CCloudUtil::URLEncode($NS["filePath"], "UTF-8"),
				'',
				false,
				array(
					"Content-Type" => $NS["Content-Type"],
					"X-Copy-From" => "/".$arBucket["BUCKET"].$filePath,
				)
			);

			if(
				is_object($obRequest)
				&& (
					$this->status == 201
					|| $this->status == 200
				)
			)
				$result = true;
			else
				$result = false;

			$this->DeleteFile($arBucket, $NS["fileTemp"]);
			ksort($NS["Parts"]);
			foreach ($NS["Parts"] as $tmpPath)
			{
				$this->DeleteFile($arBucket, $tmpPath);
			}

			return $result;
		}
		else
		{
			//May be delete uploaded tmp file?
			return false;
		}
	}
}
?>classes/general/util.php000064400000001074150241560060011305 0ustar00<?
class CCloudUtil
{
	/**
	 * @param string $str
	 * @param string $charset
	 * @return string
	*/
	public static function URLEncode($str, $charset)
	{
		global $APPLICATION;
		$strEncodedURL = '';
		$arUrlComponents = preg_split("#(://|/|\\?|=|&)#", $str, -1, PREG_SPLIT_DELIM_CAPTURE);
		foreach($arUrlComponents as $i => $part_of_url)
		{
			if((intval($i) % 2) == 1)
				$strEncodedURL .= (string)$part_of_url;
			else
				$strEncodedURL .= urlencode($APPLICATION->ConvertCharset(urldecode($part_of_url), LANG_CHARSET, $charset));
		}
		return $strEncodedURL;
	}
}
?>classes/general/storage_service_google.php000064400000056417150241560060015063 0ustar00<?
IncludeModuleLangFile(__FILE__);

class CCloudStorageService_GoogleStorage extends CCloudStorageService
{
	protected $status = 0;
	protected $headers = array();
	protected $errno = 0;
	protected $errstr = '';
	protected $result = '';
	protected $new_end_point;

	function GetLastRequestStatus()
	{
		return $this->status;
	}

	function GetObject()
	{
		return new CCloudStorageService_GoogleStorage();
	}

	function GetID()
	{
		return "google_storage";
	}

	function GetName()
	{
		return "Google Storage";
	}

	function GetLocationList()
	{
		return array(
			"EU" => "Europe",
			"US" => "United States",
		);
	}

	function GetSettingsHTML($arBucket, $bServiceSet, $cur_SERVICE_ID, $bVarsFromForm)
	{
		if($bVarsFromForm)
			$arSettings = $_POST["SETTINGS"][$this->GetID()];
		else
			$arSettings = unserialize($arBucket["SETTINGS"]);

		if(!is_array($arSettings))
			$arSettings = array("PROJECT_ID" => "", "ACCESS_KEY" => "", "SECRET_KEY" => "");

		$htmlID = htmlspecialcharsbx($this->GetID());

		$result = '
		<tr id="SETTINGS_0_'.$htmlID.'" style="display:'.($cur_SERVICE_ID == $this->GetID() || !$bServiceSet? '': 'none').'" class="settings-tr adm-detail-required-field">
			<td>'.GetMessage("CLO_STORAGE_GOOGLE_EDIT_PROJECT_ID").':</td>
			<td><input type="hidden" name="SETTINGS['.$htmlID.'][PROJECT_ID]" id="'.$htmlID.'PROJECT_ID" value="'.htmlspecialcharsbx($arSettings['PROJECT_ID']).'"><input type="text" size="55" name="'.$htmlID.'INP_" id="'.$htmlID.'INP_PROJECT_ID" value="'.htmlspecialcharsbx($arSettings['PROJECT_ID']).'" '.($arBucket['READ_ONLY'] == 'Y'? '"disabled"': '').' onchange="BX(\''.$htmlID.'PROJECT_ID\').value = this.value"></td>
		</tr>
		<tr id="SETTINGS_1_'.$htmlID.'" style="display:'.($cur_SERVICE_ID == $this->GetID() || !$bServiceSet? '': 'none').'" class="settings-tr adm-detail-required-field">
			<td>'.GetMessage("CLO_STORAGE_GOOGLE_EDIT_ACCESS_KEY").':</td>
			<td><input type="hidden" name="SETTINGS['.$htmlID.'][ACCESS_KEY]" id="'.$htmlID.'ACCESS_KEY" value="'.htmlspecialcharsbx($arSettings['ACCESS_KEY']).'"><input type="text" size="55" name="'.$htmlID.'INP_ACCESS_KEY" id="'.$htmlID.'INP_ACCESS_KEY" value="'.htmlspecialcharsbx($arSettings['ACCESS_KEY']).'" '.($arBucket['READ_ONLY'] == 'Y'? '"disabled"': '').' onchange="BX(\''.$htmlID.'ACCESS_KEY\').value = this.value"></td>
		</tr>
		<tr id="SETTINGS_2_'.$htmlID.'" style="display:'.($cur_SERVICE_ID == $this->GetID() || !$bServiceSet? '': 'none').'" class="settings-tr adm-detail-required-field">
			<td>'.GetMessage("CLO_STORAGE_GOOGLE_EDIT_SECRET_KEY").':</td>
			<td><input type="hidden" name="SETTINGS['.$htmlID.'][SECRET_KEY]" id="'.$htmlID.'SECRET_KEY" value="'.htmlspecialcharsbx($arSettings['SECRET_KEY']).'"><input type="text" size="55" name="'.$htmlID.'INP_SECRET_KEY" id="'.$htmlID.'INP_SECRET_KEY" value="'.htmlspecialcharsbx($arSettings['SECRET_KEY']).'" autocomplete="off" '.($arBucket['READ_ONLY'] == 'Y'? '"disabled"': '').' onchange="BX(\''.$htmlID.'SECRET_KEY\').value = this.value"></td>
		</tr>
		<tr id="SETTINGS_3_'.$htmlID.'" style="display:'.($cur_SERVICE_ID == $this->GetID() || !$bServiceSet? '': 'none').'" class="settings-tr">
			<td>&nbsp;</td>
			<td>'.BeginNote().GetMessage("CLO_STORAGE_GOOGLE_EDIT_HELP").EndNote().'</td>
		</tr>
		';
		return $result;
	}

	function CheckSettings($arBucket, &$arSettings)
	{
		global $APPLICATION;
		$aMsg = array();

		$result = array(
			"PROJECT_ID" => is_array($arSettings)? trim($arSettings["PROJECT_ID"]): '',
			"ACCESS_KEY" => is_array($arSettings)? trim($arSettings["ACCESS_KEY"]): '',
			"SECRET_KEY" => is_array($arSettings)? trim($arSettings["SECRET_KEY"]): '',
		);

		if($arBucket["READ_ONLY"] !== "Y" && !strlen($result["PROJECT_ID"]))
			$aMsg[] = array("id" => $this->GetID()."INP_PROJECT_ID", "text" => GetMessage("CLO_STORAGE_GOOGLE_EMPTY_PROJECT_ID"));

		if($arBucket["READ_ONLY"] !== "Y" && !strlen($result["ACCESS_KEY"]))
			$aMsg[] = array("id" => $this->GetID()."INP_ACCESS_KEY", "text" => GetMessage("CLO_STORAGE_GOOGLE_EMPTY_ACCESS_KEY"));

		if($arBucket["READ_ONLY"] !== "Y" && !strlen($result["SECRET_KEY"]))
			$aMsg[] = array("id" => $this->GetID()."INP_SECRET_KEY", "text" => GetMessage("CLO_STORAGE_GOOGLE_EMPTY_SECRET_KEY"));

		if(!empty($aMsg))
		{
			$e = new CAdminException($aMsg);
			$APPLICATION->ThrowException($e);
			return false;
		}
		else
		{
			$arSettings = $result;
		}

		return true;
	}

	function CreateBucket($arBucket)
	{
		global $APPLICATION;

		if($arBucket["LOCATION"])
			$content =
				'<CreateBucketConfiguration>'.
				'<LocationConstraint>'.$arBucket["LOCATION"].'</LocationConstraint>'.
				'</CreateBucketConfiguration>';
		else
			$content = '';

		$response = $this->SendRequest(
			$arBucket["SETTINGS"]["ACCESS_KEY"],
			$arBucket["SETTINGS"]["SECRET_KEY"],
			'PUT',
			$arBucket["BUCKET"],
			'/',
			'',
			$content,
			array(
				"x-goog-project-id" => $arBucket["SETTINGS"]["PROJECT_ID"],
			)
		);

		if($this->status == 409/*Already exists*/)
		{
			$APPLICATION->ResetException();
			return true;
		}
		else
		{
			return is_array($response);
		}
	}

	function DeleteBucket($arBucket)
	{
		global $APPLICATION;

		if($arBucket["PREFIX"])
		{
			//Do not delete bucket if there is some files left
			if(!$this->IsEmptyBucket($arBucket))
				return false;

			//Do not delete bucket if there is some files left in other prefixes
			$arAllBucket = $arBucket;
			$arBucket["PREFIX"] = "";
			if(!$this->IsEmptyBucket($arAllBucket))
				return true;
		}

		$response = $this->SendRequest(
			$arBucket["SETTINGS"]["ACCESS_KEY"],
			$arBucket["SETTINGS"]["SECRET_KEY"],
			'DELETE',
			$arBucket["BUCKET"]
		);

		if($this->status == 204/*No content*/ || $this->status == 404/*Not exists*/)
		{
			$APPLICATION->ResetException();
			return true;
		}
		else
		{
			return is_array($response);
		}
	}

	function IsEmptyBucket($arBucket)
	{
		global $APPLICATION;

		$response = $this->SendRequest(
			$arBucket["SETTINGS"]["ACCESS_KEY"],
			$arBucket["SETTINGS"]["SECRET_KEY"],
			'GET',
			$arBucket["BUCKET"],
			'/',
			'?max-keys=1'.($arBucket["PREFIX"]? '&prefix='.$arBucket["PREFIX"]: '')
		);

		if($this->status == 404)
		{
			$APPLICATION->ResetException();
			return true;
		}
		elseif(is_array($response))
		{
			return
				!isset($response["ListBucketResult"])
				|| !is_array($response["ListBucketResult"])
				|| !isset($response["ListBucketResult"]["#"])
				|| !is_array($response["ListBucketResult"]["#"])
				|| !isset($response["ListBucketResult"]["#"]["Contents"])
				|| !is_array($response["ListBucketResult"]["#"]["Contents"]);
		}
		else
		{
			return false;
		}
	}

	function GetFileSRC($arBucket, $arFile)
	{
		global $APPLICATION;

		if($arBucket["CNAME"])
		{
			$host = $arBucket["CNAME"];
		}
		else
		{
			switch($arBucket["LOCATION"])
			{
			case "EU":
				$host = $arBucket["BUCKET"].".commondatastorage.googleapis.com";
				break;
			case "US":
				$host = $arBucket["BUCKET"].".commondatastorage.googleapis.com";
				break;
			default:
				$host = $arBucket["BUCKET"].".commondatastorage.googleapis.com";
				break;
			}
		}

		if(is_array($arFile))
			$URI = ltrim($arFile["SUBDIR"]."/".$arFile["FILE_NAME"], "/");
		else
			$URI = ltrim($arFile, "/");

		if($arBucket["PREFIX"])
		{
			if(substr($URI, 0, strlen($arBucket["PREFIX"])+1) !== $arBucket["PREFIX"]."/")
				$URI = $arBucket["PREFIX"]."/".$URI;
		}

		$proto = $APPLICATION->IsHTTPS()? "https": "http";

		return $proto."://$host/".CCloudUtil::URLEncode($URI, "UTF-8");
	}

	function FileExists($arBucket, $filePath)
	{
		global $APPLICATION;

		if($arBucket["PREFIX"])
		{
			if(substr($filePath, 0, strlen($arBucket["PREFIX"])+2) != "/".$arBucket["PREFIX"]."/")
				$filePath = "/".$arBucket["PREFIX"]."/".ltrim($filePath, "/");
		}
		$filePath = CCloudUtil::URLEncode($filePath, "UTF-8");

		$response = $this->SendRequest(
			$arBucket["SETTINGS"]["ACCESS_KEY"],
			$arBucket["SETTINGS"]["SECRET_KEY"],
			'HEAD',
			$arBucket["BUCKET"],
			$filePath
		);

		if($this->status == 200)
		{
			return true;
		}
		elseif($this->status == 206)
		{
			$APPLICATION->ResetException();
			return true;
		}
		else//if($this->status == 404)
		{
			$APPLICATION->ResetException();
			return false;
		}
	}

	function FileCopy($arBucket, $arFile, $filePath)
	{
		global $APPLICATION;

		if($arBucket["PREFIX"])
		{
			if(substr($filePath, 0, strlen($arBucket["PREFIX"])+2) != "/".$arBucket["PREFIX"]."/")
				$filePath = "/".$arBucket["PREFIX"]."/".ltrim($filePath, "/");
		}

		$response = $this->SendRequest(
			$arBucket["SETTINGS"]["ACCESS_KEY"],
			$arBucket["SETTINGS"]["SECRET_KEY"],
			'PUT',
			$arBucket["BUCKET"],
			CCloudUtil::URLEncode($filePath, "UTF-8"),
			'',
			'',
			array(
				"x-goog-acl"=>"public-read",
				"x-goog-copy-source"=>CCloudUtil::URLEncode("/".$arBucket["BUCKET"]."/".($arBucket["PREFIX"]? $arBucket["PREFIX"]."/": "").($arFile["SUBDIR"]? $arFile["SUBDIR"]."/": "").$arFile["FILE_NAME"], "UTF-8"),
				"Content-Type"=>$arFile["CONTENT_TYPE"]
			)
		);

		if($this->status == 200)
		{
			return $this->GetFileSRC($arBucket, $filePath);
		}
		else//if($this->status == 404)
		{
			$APPLICATION->ResetException();
			return false;
		}
	}

	function DownloadToFile($arBucket, $arFile, $filePath)
	{
		$io = CBXVirtualIo::GetInstance();
		$obRequest = new CHTTP;
		$obRequest->follow_redirect = true;
		return $obRequest->Download($this->GetFileSRC($arBucket, $arFile), $io->GetPhysicalName($filePath));
	}

	function DeleteFile($arBucket, $filePath)
	{
		global $APPLICATION;

		if($arBucket["PREFIX"])
		{
			if(substr($filePath, 0, strlen($arBucket["PREFIX"])+2) != "/".$arBucket["PREFIX"]."/")
				$filePath = "/".$arBucket["PREFIX"]."/".ltrim($filePath, "/");
		}
		$filePath = CCloudUtil::URLEncode($filePath, "UTF-8");

		$response = $this->SendRequest(
			$arBucket["SETTINGS"]["ACCESS_KEY"],
			$arBucket["SETTINGS"]["SECRET_KEY"],
			'DELETE',
			$arBucket["BUCKET"],
			$filePath
		);

		if($this->status == 204 || $this->status == 404)
		{
			$APPLICATION->ResetException();
			return true;
		}
		else
		{
			$APPLICATION->ResetException();
			return false;
		}
	}

	function SaveFile($arBucket, $filePath, $arFile)
	{
		global $APPLICATION;

		if($arBucket["PREFIX"])
		{
			if(substr($filePath, 0, strlen($arBucket["PREFIX"])+2) != "/".$arBucket["PREFIX"]."/")
				$filePath = "/".$arBucket["PREFIX"]."/".ltrim($filePath, "/");
		}
		$filePath = CCloudUtil::URLEncode($filePath, "UTF-8");

		$response = $this->SendRequest(
			$arBucket["SETTINGS"]["ACCESS_KEY"],
			$arBucket["SETTINGS"]["SECRET_KEY"],
			'PUT',
			$arBucket["BUCKET"],
			$filePath,
			'',
			(array_key_exists("content", $arFile)? $arFile["content"]: fopen($arFile["tmp_name"], "rb")),
			array(
				"x-goog-acl" => "public-read",
				"Content-Type" => $arFile["type"],
				"Content-Length" => (array_key_exists("content", $arFile)? CUtil::BinStrlen($arFile["content"]): filesize($arFile["tmp_name"])),
			)
		);

		if($this->status == 200)
		{
			return true;
		}
		else
		{
			$APPLICATION->ResetException();
			return false;
		}
	}

	function ListFiles($arBucket, $filePath, $bRecursive = false)
	{
		global $APPLICATION;

		$result = array(
			"dir" => array(),
			"file" => array(),
			"file_size" => array(),
		);

		$filePath = trim($filePath, '/');
		if(strlen($filePath))
			$filePath .= '/';

		if($arBucket["PREFIX"])
		{
			if(substr($filePath, 0, strlen($arBucket["PREFIX"])+2) != "/".$arBucket["PREFIX"]."/")
				$filePath = $arBucket["PREFIX"]."/".ltrim($filePath, "/");
		}
		$filePath = $APPLICATION->ConvertCharset($filePath, LANG_CHARSET, "UTF-8");

		$marker = '';
		while(true)
		{
			$response = $this->SendRequest(
				$arBucket["SETTINGS"]["ACCESS_KEY"],
				$arBucket["SETTINGS"]["SECRET_KEY"],
				'GET',
				$arBucket["BUCKET"],
				'/',
				'?'.($bRecursive? '': 'delimiter=/&').'prefix='.urlencode($filePath).'&marker='.urlencode($marker)
			);
			if(
				$this->status == 200
				&& is_array($response)
				&& isset($response["ListBucketResult"])
				&& is_array($response["ListBucketResult"])
				&& isset($response["ListBucketResult"]["#"])
				&& is_array($response["ListBucketResult"]["#"])
			)
			{
				if(
					isset($response["ListBucketResult"]["#"]["CommonPrefixes"])
					&& is_array($response["ListBucketResult"]["#"]["CommonPrefixes"])
				)
				{
					foreach($response["ListBucketResult"]["#"]["CommonPrefixes"] as $a)
					{
						$dir_name = substr(rtrim($a["#"]["Prefix"][0]["#"], "/"), strlen($filePath));
						$result["dir"][] = $APPLICATION->ConvertCharset(urldecode($dir_name), "UTF-8", LANG_CHARSET);
					}
				}

				if(
					isset($response["ListBucketResult"]["#"]["Contents"])
					&& is_array($response["ListBucketResult"]["#"]["Contents"])
				)
				{
					foreach($response["ListBucketResult"]["#"]["Contents"] as $a)
					{
						$file_name = substr($a["#"]["Key"][0]["#"], strlen($filePath));
						$result["file"][] = $APPLICATION->ConvertCharset(urldecode($file_name), "UTF-8", LANG_CHARSET);
						$result["file_size"][] = $a["#"]["Size"][0]["#"];
					}
				}

				if(
					isset($response["ListBucketResult"]["#"]["IsTruncated"])
					&& is_array($response["ListBucketResult"]["#"]["IsTruncated"])
					&& $response["ListBucketResult"]["#"]["IsTruncated"][0]["#"] === "true"
					&& strlen($response["ListBucketResult"]["#"]["NextMarker"][0]["#"]) > 0
				)
				{
					$marker = $response["ListBucketResult"]["#"]["NextMarker"][0]["#"];
					continue;
				}
				else
				{
					break;
				}
			}
			else
			{
				$APPLICATION->ResetException();
				return false;
			}
		}

		return $result;
	}

	protected function StartUpload($arBucket, $filePath, $ContentType)
	{
		$filePath = '/'.trim($filePath, '/');
		if($arBucket["PREFIX"])
		{
			if(substr($filePath, 0, strlen($arBucket["PREFIX"])+2) != "/".$arBucket["PREFIX"]."/")
				$filePath = "/".$arBucket["PREFIX"].$filePath;
		}
		$filePathU = CCloudUtil::URLEncode($filePath, "UTF-8");

		$response = $this->SendRequest(
			$arBucket["SETTINGS"]["ACCESS_KEY"],
			$arBucket["SETTINGS"]["SECRET_KEY"],
			'POST',
			$arBucket["BUCKET"],
			$filePathU,
			'',
			'',
			array(
				"x-goog-acl"=>"public-read",
				"x-goog-resumable"=>"start",
				"Content-Type"=>$ContentType,
			)
		);

		if(
			$this->status == 201
			&& is_array($this->headers)
			&& isset($this->headers["Location"])
			&& preg_match("/upload_id=(.*)\$/", $this->headers["Location"], $match)
		)
		{
			return array(
				"filePath" => $filePath,
				"filePos" => 0,
				"upload_id" => $match[1],
			);
		}

		return false;
	}

	function InitiateMultipartUpload($arBucket, &$NS, $filePath, $fileSize, $ContentType)
	{
		$upload_info = $this->StartUpload($arBucket, $filePath, $ContentType);
		if ($upload_info)
		{
			$upload_info["fileSize"] = $fileSize;
			$upload_info["ContentType"] = $ContentType;
			$NS = $upload_info;
			return true;
		}
		else
		{
			return false;
		}
	}

	function GetMinUploadPartSize()
	{
		return 5*1024*1024; //5MB
	}

	private function UploadRange($filePathU, $arBucket, &$NS, $data, $pos)
	{
		$response = $this->SendRequest(
			$arBucket["SETTINGS"]["ACCESS_KEY"],
			$arBucket["SETTINGS"]["SECRET_KEY"],
			'PUT',
			$arBucket["BUCKET"],
			$filePathU.'?upload_id='.urlencode($NS["upload_id"]),
			'',
			'',
			array(
				"Content-Range" => "bytes */".$NS["fileSize"],
			)
		);

		$data_len = CUtil::BinStrlen($data);

		$response = $this->SendRequest(
			$arBucket["SETTINGS"]["ACCESS_KEY"],
			$arBucket["SETTINGS"]["SECRET_KEY"],
			'PUT',
			$arBucket["BUCKET"],
			$filePathU.'?upload_id='.urlencode($NS["upload_id"]),
			'',
			$data,
			array(
				"Content-Range" => "bytes ".$pos."-".($pos+$data_len-1)."/".$NS["fileSize"],
			)
		);
	}
	
	function UploadPartNo($arBucket, &$NS, $data, $part_no)
	{
		global $APPLICATION;
		$part_no = intval($part_no);

		$found = false;
		if (isset($NS["Parts"]))
		{
			foreach ($NS["Parts"] as $first_part_no => $part)
			{
				if ($part["part_no"] === ($part_no - 1))
				{
					$found = $first_part_no;
					break;
				}
			}
		}
		else
		{
			$NS["Parts"] = array();
		}

		if ($found === false)
		{
			$partFileName = '/'.trim($NS["filePath"], '/').".tmp".$part_no;
			if($arBucket["PREFIX"])
			{
				if(substr($partFileName, 0, strlen($arBucket["PREFIX"])+2) != "/".$arBucket["PREFIX"]."/")
					$partFileName = "/".$arBucket["PREFIX"].$partFileName;
			}
			$upload_info = $this->StartUpload($arBucket, $partFileName, $NS["ContentType"]);
			if ($upload_info)
			{
				$upload_info["fileSize"] = "*";
				$upload_info["part_no"] = $part_no;
				$found = $part_no;
				$NS["Parts"][$part_no] = $upload_info;
				ksort($NS["Parts"]);
			}
			else
			{
				return false;
			}
		}

		$NS["Parts"][$found]["part_no"] = $part_no;
		if (
			(isset($NS["Parts"][$part_no + 1]))
			|| (($NS["Parts"][$found]["part_no"] * $this->GetMinUploadPartSize() + $this->GetMinUploadPartSize()) >= $NS["fileSize"])
		)
		{
			$data_len = CUtil::BinStrlen($data);
			$NS["Parts"][$found]["fileSize"] = $NS["Parts"][$found]["filePos"] + $data_len;
		}

		$filePath = $NS["Parts"][$found]["filePath"];
		$filePathU = CCloudUtil::URLEncode($filePath, "UTF-8");

		$this->UploadRange($filePathU, $arBucket, $NS["Parts"][$found], $data, $NS["Parts"][$found]["filePos"]);

		if(
			$this->status == 308
			&& is_array($this->headers)
			&& preg_match("/^bytes=(\\d+)-(\\d+)\$/", $this->headers["Range"], $match)
		)
		{
			$APPLICATION->ResetException();
			$NS["Parts"][$found]["filePos"] = $match[2]+1;
			return true;
		}
		elseif($this->status == 200)
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	function UploadPart($arBucket, &$NS, $data)
	{
		global $APPLICATION;

		$filePath = '/'.trim($NS["filePath"], '/');
		if($arBucket["PREFIX"])
		{
			if(substr($filePath, 0, strlen($arBucket["PREFIX"])+2) != "/".$arBucket["PREFIX"]."/")
				$filePath = "/".$arBucket["PREFIX"].$filePath;
		}
		$filePathU = CCloudUtil::URLEncode($filePath, "UTF-8");

		$this->UploadRange($filePathU, $arBucket, $NS, $data, $NS["filePos"]);

		if(
			$this->status == 308
			&& is_array($this->headers)
			&& preg_match("/^bytes=(\\d+)-(\\d+)\$/", $this->headers["Range"], $match)
		)
		{
			$APPLICATION->ResetException();
			$NS["filePos"] = $match[2]+1;
			return true;
		}
		elseif($this->status == 200)
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	function CompleteMultipartUpload($arBucket, &$NS)
	{
		if (isset($NS["Parts"]))
		{
			// https://cloud.google.com/storage/docs/xml-api/put-object-compose
			$filePath = '/'.trim($NS["filePath"], '/');
			if($arBucket["PREFIX"])
			{
				if(substr($filePath, 0, strlen($arBucket["PREFIX"])+2) != "/".$arBucket["PREFIX"]."/")
					$filePath = "/".$arBucket["PREFIX"].$filePath;
			}
			$filePathU = CCloudUtil::URLEncode($filePath, "UTF-8");

			$xml = "<ComposeRequest>";
			foreach ($NS["Parts"] as $i => $part)
			{
				$xml .= "<Component><Name>".ltrim($part["filePath"], '/')."</Name></Component>";
			}
			$xml .= "</ComposeRequest>";

			$response = $this->SendRequest(
				$arBucket["SETTINGS"]["ACCESS_KEY"],
				$arBucket["SETTINGS"]["SECRET_KEY"],
				'PUT',
				$arBucket["BUCKET"],
				$filePathU.'?compose',
				'',
				$xml,
				array(
					"x-goog-acl"=>"public-read",
					"Content-Type"=>$NS["ContentType"],
				)
			);

			if ($this->status == 200)
			{
				foreach ($NS["Parts"] as $i => $part)
				{
					$this->DeleteFile($arBucket, $part["filePath"]);
				}
				return true;
			}
			else
			{
				AddMessage2Log($this);
				return false;
			}
		}
		return true;
	}

	function SendRequest($access_key, $secret_key, $verb, $bucket, $file_name='/', $params='', $content='', $additional_headers=array())
	{
		global $APPLICATION;
		$this->status = 0;

		if(isset($additional_headers["Content-Type"]))
		{
			$ContentType = $additional_headers["Content-Type"];
			unset($additional_headers["Content-Type"]);
		}
		else
		{
			$ContentType = $content? 'text/plain': '';
		}

		if(!array_key_exists("x-goog-api-version", $additional_headers))
			$additional_headers["x-goog-api-version"] = "1";

		$RequestMethod = $verb;
		$RequestURI = $file_name;
		$RequestDATE = gmdate('D, d M Y H:i:s', time()).' GMT';

		//Prepare Signature
		$CanonicalizedAmzHeaders = "";
		ksort($additional_headers);
		foreach($additional_headers as $key => $value)
			if(preg_match("/^x-goog-/", $key))
				$CanonicalizedAmzHeaders .= $key.":".$value."\n";

		$CanonicalizedResource = "/".$bucket.$RequestURI;

		$StringToSign = "$RequestMethod\n\n$ContentType\n$RequestDATE\n$CanonicalizedAmzHeaders$CanonicalizedResource";
		//$utf = $APPLICATION->ConvertCharset($StringToSign, LANG_CHARSET, "UTF-8");

		$Signature = base64_encode($this->hmacsha1($StringToSign, $secret_key));
		$Authorization = "GOOG1 ".$access_key.":".$Signature;

		$obRequest = new CHTTP;
		$obRequest->additional_headers["Date"] = $RequestDATE;
		$obRequest->additional_headers["Authorization"] = $Authorization;
		foreach($additional_headers as $key => $value)
			if(!preg_match("/^option-/", $key))
				$obRequest->additional_headers[$key] = $value;

		if(
			$this->new_end_point
			&& preg_match('#^(http|https)://'.preg_quote($bucket, '#').'(.+)/#', $this->new_end_point, $match))
		{
			$host = $match[2];
		}
		else
		{
			$host = $bucket.".commondatastorage.googleapis.com";
		}

		$was_end_point = $this->new_end_point;
		$this->new_end_point = '';

		$obRequest->Query(
			$this->verb = $RequestMethod,
			$host, 80,
			$this->url = $RequestURI.$params,
			$content, '', $ContentType
		);
		$this->headers_sent = $obRequest->additional_headers;
		$this->status = $obRequest->status;
		$this->headers = $obRequest->headers;
		$this->errno = $obRequest->errno;
		$this->errstr = $obRequest->errstr;
		$this->result = $obRequest->result;

		if($obRequest->status == 200)
		{
			if(isset($additional_headers["option-raw-result"]))
			{
				return $obRequest->result;
			}
			elseif($obRequest->result)
			{
				$obXML = new CDataXML;
				$text = preg_replace("/<"."\\?XML.*?\\?".">/i", "", $obRequest->result);
				if($obXML->LoadString($text))
				{
					$arXML = $obXML->GetArray();
					if(is_array($arXML))
					{
						return $arXML;
					}
				}
				//XML parse error
				$APPLICATION->ThrowException(GetMessage('CLO_STORAGE_GOOGLE_XML_PARSE_ERROR', array('#errno#'=>1)));
				return false;
			}
			else
			{
				//Empty success result
				return array();
			}
		}
		elseif(
			$obRequest->status == 307  //Temporary redirect
			&& isset($obRequest->headers["Location"])
			&& !$was_end_point //No recurse yet
		)
		{
			$this->new_end_point = $obRequest->headers["Location"];
			return $this->SendRequest(
				$access_key,
				$secret_key,
				$verb,
				$bucket,
				$file_name,
				$params,
				$content,
				$additional_headers
			);
		}
		elseif($obRequest->status > 0)
		{
			if($obRequest->result)
			{
				$obXML = new CDataXML;
				if($obXML->LoadString($obRequest->result))
				{
					$arXML = $obXML->GetArray();
					if(is_array($arXML) && is_string($arXML["Error"]["#"]["Message"][0]["#"]))
					{
						$APPLICATION->ThrowException(GetMessage('CLO_STORAGE_GOOGLE_XML_ERROR', array('#errmsg#'=>trim($arXML["Error"]["#"]["Message"][0]["#"], '.'))));
						return false;
					}
				}
			}
			$APPLICATION->ThrowException(GetMessage('CLO_STORAGE_GOOGLE_XML_PARSE_ERROR', array('#errno#'=>2)));
			return false;
		}
		else
		{
			$APPLICATION->ThrowException(GetMessage('CLO_STORAGE_GOOGLE_XML_PARSE_ERROR', array('#errno#'=>3)));
			return false;
		}
	}

	function hmacsha1($data, $key)
	{
		if(strlen($key)>64)
			$key=pack('H*', sha1($key));
		$key = str_pad($key, 64, chr(0x00));
		$ipad = str_repeat(chr(0x36), 64);
		$opad = str_repeat(chr(0x5c), 64);
		$hmac = pack('H*', sha1(($key^$opad).pack('H*', sha1(($key^$ipad).$data))));
		return $hmac;
	}
}
?>classes/general/storage_service_hotbox.php000064400000010341150241560060015074 0ustar00<?
IncludeModuleLangFile(__FILE__);

class CCloudStorageService_HotBox extends CCloudStorageService_AmazonS3
{
	protected $status = 0;
	protected $verb = '';
	protected $host = '';
	protected $url = '';
	protected $headers =/*.(array[string]string).*/array();
	protected $set_headers =/*.(array[string]string).*/array();
	protected $errno = 0;
	protected $errstr = '';
	protected $result = '';
	protected $new_end_point = '';
	protected $_public = true;
	protected $location = '';
	/**
	 * @return int
	*/
	function GetLastRequestStatus()
	{
		return $this->status;
	}
	/**
	 * @return CCloudStorageService
	*/
	function GetObject()
	{
		return new CCloudStorageService_HotBox();
	}
	/**
	 * @return string
	*/
	function GetID()
	{
		return "hot_box";
	}
	/**
	 * @return string
	*/
	function GetName()
	{
		return "HotBox";
	}
	/**
	 * @return array[string]string
	*/
	function GetLocationList()
	{
		return array(
			"" => "hb.bizmrg.com",
		);
	}
	/**
	 * @param array[string]string $arBucket
	 * @param bool $bServiceSet
	 * @param string $cur_SERVICE_ID
	 * @param bool $bVarsFromForm
	 * @return string
	*/
	function GetSettingsHTML($arBucket, $bServiceSet, $cur_SERVICE_ID, $bVarsFromForm)
	{
		if($bVarsFromForm)
			$arSettings = $_POST["SETTINGS"][$this->GetID()];
		else
			$arSettings = unserialize($arBucket["SETTINGS"]);

		if(!is_array($arSettings))
			$arSettings = array("ACCESS_KEY" => "", "SECRET_KEY" => "");

		$htmlID = htmlspecialcharsbx($this->GetID());

		$result = '
		<tr id="SETTINGS_0_'.$htmlID.'" style="display:'.($cur_SERVICE_ID === $this->GetID() || !$bServiceSet? '': 'none').'" class="settings-tr adm-detail-required-field">
			<td>'.GetMessage("CLO_STORAGE_S3_EDIT_ACCESS_KEY").':</td>
			<td><input type="hidden" name="SETTINGS['.$htmlID.'][ACCESS_KEY]" id="'.$htmlID.'ACCESS_KEY" value="'.htmlspecialcharsbx($arSettings['ACCESS_KEY']).'"><input type="text" size="55" name="'.$htmlID.'INP_ACCESS_KEY" id="'.$htmlID.'INP_ACCESS_KEY" value="'.htmlspecialcharsbx($arSettings['ACCESS_KEY']).'" '.($arBucket['READ_ONLY'] === 'Y'? '"disabled"': '').' onchange="BX(\''.$htmlID.'ACCESS_KEY\').value = this.value"></td>
		</tr>
		<tr id="SETTINGS_1_'.$htmlID.'" style="display:'.($cur_SERVICE_ID === $this->GetID() || !$bServiceSet? '': 'none').'" class="settings-tr adm-detail-required-field">
			<td>'.GetMessage("CLO_STORAGE_S3_EDIT_SECRET_KEY").':</td>
			<td><input type="hidden" name="SETTINGS['.$htmlID.'][SECRET_KEY]" id="'.$htmlID.'SECRET_KEY" value="'.htmlspecialcharsbx($arSettings['SECRET_KEY']).'"><input type="text" size="55" name="'.$htmlID.'INP_SECRET_KEY" id="'.$htmlID.'INP_SECRET_KEY" value="'.htmlspecialcharsbx($arSettings['SECRET_KEY']).'" autocomplete="off" '.($arBucket['READ_ONLY'] === 'Y'? '"disabled"': '').' onchange="BX(\''.$htmlID.'SECRET_KEY\').value = this.value"></td>
		</tr>
		';
		return $result;
	}
	protected function GetRequestHost($bucket)
	{
		if(
			$this->new_end_point != ""
			&& preg_match('#^(http|https)://'.preg_quote($bucket, '#').'(.+?)/#', $this->new_end_point, $match) > 0
		)
		{
			return $bucket.$match[2];
		}
		else
		{
			return $bucket.".hb.bizmrg.com";
		}
	}
	/**
	 * @param array[string]string $arBucket
	 * @param mixed $arFile
	 * @return string
	*/
	function GetFileSRC($arBucket, $arFile)
	{
		$proto = CMain::IsHTTPS()? "https": "http";

		if($arBucket["CNAME"] != "")
		{
			$host = $arBucket["CNAME"];
			$pref = "";
		}
		elseif ($proto === "https" && strpos($arBucket["BUCKET"], ".") !== false)
		{
			$host = "hb.bizmrg.com";
			$pref = $arBucket["BUCKET"];
		}
		else
		{
			$host = $arBucket["BUCKET"].".hb.bizmrg.com";
			$pref = "";
		}

		if(is_array($arFile))
			$URI = ltrim($arFile["SUBDIR"]."/".$arFile["FILE_NAME"], "/");
		else
			$URI = ltrim($arFile, "/");

		if ($arBucket["PREFIX"] != "")
		{
			if(substr($URI, 0, strlen($arBucket["PREFIX"])+1) !== $arBucket["PREFIX"]."/")
				$URI = $arBucket["PREFIX"]."/".$URI;
		}

		if ($pref !== "")
		{
			$URI = $pref."/".$URI;
		}

		return $proto."://$host/".CCloudUtil::URLEncode($URI, "UTF-8");
	}
	/**
	 * @param array[string]string $arBucket
	 * @return bool
	*/
	function DeleteBucket($arBucket)
	{
		//Do not delete bucket if there is some files left
		if(!$this->IsEmptyBucket($arBucket))
			return false;

		return parent::DeleteBucket($arBucket);
	}
}
classes/general/storage_service.php000064400000010473150241560060013517 0ustar00<?
abstract class CCloudStorageService
{
	public $tokenHasExpired = false;
	/**
	 * @return CCloudStorageService
	 * @deprecated
	*/
	abstract public function GetObject();
	/**
	 * @return CCloudStorageService
	*/
	public static function GetObjectInstance()
	{
		return new static();
	}
	/**
	 * @return string
	*/
	abstract public function GetID();
	/**
	 * @return string
	*/
	abstract public function GetName();
	/**
	 * @return array[string]string
	*/
	abstract public function GetLocationList();
	/**
	 * @param array[string]string $arBucket
	 * @param bool $bServiceSet
	 * @param string $cur_SERVICE_ID
	 * @param bool $bVarsFromForm
	 * @return string
	*/
	abstract public function GetSettingsHTML($arBucket, $bServiceSet, $cur_SERVICE_ID, $bVarsFromForm);
	/**
	 * @param array[string]string $arBucket
	 * @param array[string]string $arSettings
	 * @return bool
	*/
	abstract public function CheckSettings($arBucket, &$arSettings);
	/**
	 * @param array[string]string $arBucket
	 * @return bool
	*/
	abstract public function CreateBucket($arBucket);
	/**
	 * @param array[string]string $arBucket
	 * @return bool
	*/
	abstract public function DeleteBucket($arBucket);
	/**
	 * @param array[string]string $arBucket
	 * @return bool
	*/
	abstract public function IsEmptyBucket($arBucket);
	/**
	 * @param array[string]string $arBucket
	 * @param mixed $arFile
	 * @return string
	*/
	abstract public function GetFileSRC($arBucket, $arFile);
	/**
	 * @param array[string]string $arBucket
	 * @param string $filePath
	 * @return bool
	*/
	abstract public function FileExists($arBucket, $filePath);
	/**
	 * @param array[string]string $arBucket
	 * @param mixed $arFile
	 * @param string $filePath
	 * @return bool
	*/
	abstract public function FileCopy($arBucket, $arFile, $filePath);
	/**
	 * @param array[string]string $arBucket
	 * @param string $sourcePath
	 * @param string $targetPath
	 * @param bool $overwrite
	 * @return bool
	*/
	public function FileRename($arBucket, $sourcePath, $targetPath, $overwrite = true)
	{
		if ($this->FileExists($arBucket, $sourcePath))
		{
			$contentType = $this->headers["Content-Type"];
		}
		else
		{
			return false;
		}

		if ($this->FileExists($arBucket, $targetPath))
		{
			if (!$overwrite)
			{
				return false;
			}

			if (!$this->DeleteFile($arBucket, $targetPath))
			{
				return false;
			}
		}

		$arFile = array(
			"SUBDIR" => 0,
			"FILE_NAME" => ltrim($sourcePath, "/"),
			"CONTENT_TYPE" => $contentType,
		);

		if (!$this->FileCopy($arBucket, $arFile, $targetPath))
		{
			return false;
		}

		if (!$this->DeleteFile($arBucket, $sourcePath))
		{
			return false;
		}

		return true;
	}
	/**
	 * @param array[string]string $arBucket
	 * @param mixed $arFile
	 * @param string $filePath
	 * @return bool
	*/
	abstract public function DownloadToFile($arBucket, $arFile, $filePath);
	/**
	 * @param array[string]string $arBucket
	 * @param string $filePath
	 * @return bool
	*/
	abstract public function DeleteFile($arBucket, $filePath);
	/**
	 * @param array[string]string $arBucket
	 * @param string $filePath
	 * @param mixed $arFile
	 * @return bool
	*/
	abstract public function SaveFile($arBucket, $filePath, $arFile);
	/**
	 * @param array[string]string $arBucket
	 * @param string $filePath
	 * @param bool $bRecursive
	 * @return array[string][int]string
	*/
	abstract public function ListFiles($arBucket, $filePath, $bRecursive = false);
	/**
	 * @param array[string]string $arBucket
	 * @param mixed $NS
	 * @param string $filePath
	 * @param float $fileSize
	 * @param string $ContentType
	 * @return bool
	*/
	abstract public function InitiateMultipartUpload($arBucket, &$NS, $filePath, $fileSize, $ContentType);
	/**
	 * @return float
	*/
	abstract public function GetMinUploadPartSize();
	/**
	 * @param array[string]string $arBucket
	 * @param mixed $NS
	 * @param string $data
	 * @return bool
	*/
	abstract public function UploadPart($arBucket, &$NS, $data);
	/**
	 * @param array[string]string $arBucket
	 * @param mixed $NS
	 * @return bool
	*/
	abstract public function CompleteMultipartUpload($arBucket, &$NS);
	/**
	 * @param string $name
	 * @param string $value
	 * @return void
	*/
	public function SetHeader($name, $value)
	{
	}
	/**
	 * @param string $name
	 * @return void
	 */
	public function UnsetHeader($name)
	{
	}
	/**
	 * @param bool $public
	 * @return void
	 */
	public function SetPublic($public)
	{
	}
}
?>classes/general/storage_service_selectel.php000064400000005322150241560060015374 0ustar00<?
IncludeModuleLangFile(__FILE__);

class CCloudStorageService_Selectel extends CCloudStorageService_OpenStackStorage
{
	function GetObject()
	{
		return new CCloudStorageService_Selectel();
	}

	function GetID()
	{
		return "selectel_storage";
	}

	function GetName()
	{
		return "Selectel";
	}

	function GetSettingsHTML($arBucket, $bServiceSet, $cur_SERVICE_ID, $bVarsFromForm)
	{
		if($bVarsFromForm)
			$arSettings = $_POST["SETTINGS"][$this->GetID()];
		else
			$arSettings = unserialize($arBucket["SETTINGS"]);

		if(!is_array($arSettings))
			$arSettings = array("HOST" => "auth.selcdn.ru", "USER" => "", "KEY" => "");

		$htmlID = htmlspecialcharsbx($this->GetID());

		$result = '
		<tr id="SETTINGS_2_'.$htmlID.'" style="display:'.($cur_SERVICE_ID == $this->GetID() || !$bServiceSet? '': 'none').'" class="settings-tr adm-detail-required-field">
			<td>'.GetMessage("CLO_STORAGE_SELECTEL_EDIT_HOST").':</td>
			<td><input type="hidden" name="SETTINGS['.$htmlID.'][HOST]" id="'.$htmlID.'HOST" value="'.htmlspecialcharsbx($arSettings['HOST']).'"><input type="text" size="55" name="'.$htmlID.'INP_HOST" id="'.$htmlID.'INP_HOST" value="'.htmlspecialcharsbx($arSettings['HOST']).'" '.($arBucket['READ_ONLY'] == 'Y'? '"disabled"': '').' onchange="BX(\''.$htmlID.'HOST\').value = this.value"></td>
		</tr>
		<tr id="SETTINGS_0_'.$htmlID.'" style="display:'.($cur_SERVICE_ID == $this->GetID() || !$bServiceSet? '': 'none').'" class="settings-tr adm-detail-required-field">
			<td>'.GetMessage("CLO_STORAGE_SELECTEL_EDIT_USER").':</td>
			<td><input type="hidden" name="SETTINGS['.$htmlID.'][USER]" id="'.$htmlID.'USER" value="'.htmlspecialcharsbx($arSettings['USER']).'"><input type="text" size="55" name="'.$htmlID.'INP_" id="'.$htmlID.'INP_USER" value="'.htmlspecialcharsbx($arSettings['USER']).'" '.($arBucket['READ_ONLY'] == 'Y'? '"disabled"': '').' onchange="BX(\''.$htmlID.'USER\').value = this.value"></td>
		</tr>
		<tr id="SETTINGS_1_'.$htmlID.'" style="display:'.($cur_SERVICE_ID == $this->GetID() || !$bServiceSet? '': 'none').'" class="settings-tr adm-detail-required-field">
			<td>'.GetMessage("CLO_STORAGE_SELECTEL_EDIT_KEY").':</td>
			<td><input type="hidden" name="SETTINGS['.$htmlID.'][KEY]" id="'.$htmlID.'KEY" value="'.htmlspecialcharsbx($arSettings['KEY']).'"><input type="text" size="55" name="'.$htmlID.'INP_KEY" id="'.$htmlID.'INP_KEY" value="'.htmlspecialcharsbx($arSettings['KEY']).'" autocomplete="off" '.($arBucket['READ_ONLY'] == 'Y'? '"disabled"': '').' onchange="BX(\''.$htmlID.'KEY\').value = this.value"></td>
		</tr>
		';
		return $result;
	}

	function CheckSettings($arBucket, &$arSettings)
	{
		if(is_array($arSettings))
			$arSettings["HOST"] = "auth.selcdn.ru";

		return parent::CheckSettings($arBucket, $arSettings);
	}
}
?>classes/general/storage.php000064400000113027150241560060011776 0ustar00<?php
IncludeModuleLangFile(__FILE__);

class CCloudStorage
{
	const FILE_SKIPPED = 0;
	const FILE_MOVED = 1;
	const FILE_PARTLY_UPLOADED = 2;
	const FILE_UPLOAD_ERROR = 3;

	public static $part_size = 0;
	public static $part_count = 0;

	private static $_services = /*.(array[string]CCloudStorageService).*/
		null;

	/**
	 * @return void
	 */
	static function _init()
	{
		if (!isset(self::$_services))
		{
			$obService = /*.(CCloudStorageService).*/
				null;
			self::$_services = /*.(array[string]CCloudStorageService).*/
				array();
			foreach (GetModuleEvents("clouds", "OnGetStorageService", true) as $arEvent)
			{
				$obService = ExecuteModuleEventEx($arEvent);
				if (is_object($obService))
					self::$_services[$obService->GetID()] = $obService;
			}
		}
	}

	/**
	 * @param string $ID
	 * @return CCloudStorageService
	 */
	public static function GetServiceByID($ID)
	{
		self::_init();
		if (array_key_exists($ID, self::$_services))
			return self::$_services[$ID];
		else
			return null;
	}

	/**
	 * @return array[string]CCloudStorageService
	 */
	public static function GetServiceList()
	{
		self::_init();
		return self::$_services;
	}

	/**
	 * @param string $ID
	 * @return array[string]string
	 */
	public static function GetServiceLocationList($ID)
	{
		$obService = CCloudStorage::GetServiceByID($ID);
		if (is_object($obService))
			return $obService->GetLocationList();
		else
			return /*.(array[string]string).*/
				array();
	}

	/**
	 * @param string $ID
	 * @return string
	 */
	public static function GetServiceDescription($ID)
	{
		$obService = CCloudStorage::GetServiceByID($ID);
		if (is_object($obService))
			return $obService->GetName();
		else
			return "";
	}

	/**
	 * @param array [string]string $arFile
	 * @param string $strFileName
	 * @return CCloudStorageBucket
	 */
	public static function FindBucketForFile($arFile, $strFileName)
	{
		if (array_key_exists("size", $arFile))
			$file_size = intval($arFile["size"]);
		else
			$file_size = intval($arFile["FILE_SIZE"]);

		foreach (CCloudStorageBucket::GetAllBuckets() as $bucket)
		{
			if ($bucket["ACTIVE"] === "Y" && $bucket["READ_ONLY"] !== "Y")
			{
				foreach ($bucket["FILE_RULES_COMPILED"] as $rule)
				{
					if ($rule["MODULE_MASK"] != "")
					{
						$bMatchModule = (preg_match($rule["MODULE_MASK"], $arFile["MODULE_ID"]) > 0);
					}
					else
					{
						$bMatchModule = true;
					}

					if ($rule["EXTENTION_MASK"] != "")
					{
						$bMatchExtention =
							(preg_match($rule["EXTENTION_MASK"], $strFileName) > 0)
							|| (preg_match($rule["EXTENTION_MASK"], $arFile["ORIGINAL_NAME"]) > 0);
					}
					else
					{
						$bMatchExtention = true;
					}

					if ($rule["SIZE_ARRAY"])
					{
						$bMatchSize = false;
						foreach ($rule["SIZE_ARRAY"] as $size)
						{
							if (
								($file_size >= $size[0])
								&& ($size[1] === 0.0 || $file_size <= $size[1])
							)
								$bMatchSize = true;
						}
					}
					else
					{
						$bMatchSize = true;
					}

					if ($bMatchModule && $bMatchExtention && $bMatchSize)
					{
						return new CCloudStorageBucket(intval($bucket["ID"]));
					}
				}
			}
		}
		return null;
	}

	/**
	 * @param array [string]string $arFile
	 * @param array [string]string $arResizeParams
	 * @param array [string]mixed $callbackData
	 * @param bool $bNeedResize
	 * @param array [string]string $sourceImageFile
	 * @param array [string]string $cacheImageFileTmp
	 * @return bool
	 */
	public static function OnBeforeResizeImage($arFile, $arResizeParams, &$callbackData, &$bNeedResize, &$sourceImageFile, &$cacheImageFileTmp)
	{
		$callbackData = null;

		if (intval($arFile["HANDLER_ID"]) <= 0)
			return false;

		$obSourceBucket = new CCloudStorageBucket(intval($arFile["HANDLER_ID"]));
		if (!$obSourceBucket->Init())
			return false;

		$callbackData = /*.(array[string]mixed).*/
			array();
		$callbackData["obSourceBucket"] = $obSourceBucket;

		//Assume target bucket same as source
		$callbackData["obTargetBucket"] = $obTargetBucket = $obSourceBucket;

		//if original file bucket is read only
		if ($obSourceBucket->READ_ONLY === "Y") //Try to find bucket with write rights
		{
			$bucket = CCloudStorage::FindBucketForFile($arFile, $arFile["FILE_NAME"]);
			if (!is_object($bucket))
				return false;
			if ($bucket->Init())
			{
				$callbackData["obTargetBucket"] = $obTargetBucket = $bucket;
			}
		}

		if (defined("BX_MOBILE") && constant("BX_MOBILE") === true)
			$bImmediate = true;
		else
			$bImmediate = $arResizeParams[5];

		$callbackData["cacheID"] = $arFile["ID"]."/".md5(serialize($arResizeParams));
		$callbackData["cacheOBJ"] = new CPHPCache;
		$callbackData["fileDIR"] = "/"."resize_cache/".$callbackData["cacheID"]."/".$arFile["SUBDIR"];
		$callbackData["fileNAME"] = $arFile["FILE_NAME"];
		$callbackData["fileURL"] = $callbackData["fileDIR"]."/".$callbackData["fileNAME"];

		$result = true;
		if ($callbackData["cacheOBJ"]->StartDataCache(CACHED_clouds_file_resize, $callbackData["cacheID"], "clouds"))
		{
			$cacheImageFile = $callbackData["obTargetBucket"]->GetFileSRC($callbackData["fileURL"]);
			$arDestinationSize = array();

			//Check if it is cache file was deleted, but there was a successful resize
			if (
				!$bImmediate
				&& COption::GetOptionString("clouds", "delayed_resize") === "Y"
				&& is_array($delayInfo = CCloudStorage::ResizeImageFileGet($cacheImageFile))
				&& $delayInfo["ERROR_CODE"] < 10
			)
			{
				$callbackData["cacheSTARTED"] = true;
				if ($arFile["FILE_SIZE"] > 1)
					$callbackData["fileSize"] = $arFile["FILE_SIZE"];
				$bNeedResize = false;
				$result = true;
			}
			elseif (
				is_array($delayInfo = CCloudStorage::ResizeImageFileGet($cacheImageFile))
				&& $delayInfo["ERROR_CODE"] < 10
			)
			{
				$callbackData["cacheSTARTED"] = true;
				if ($arFile["FILE_SIZE"] > 1)
					$callbackData["fileSize"] = $arFile["FILE_SIZE"];
				$bNeedResize = false;
				$result = true;
			}
			//Check if it is cache file was deleted, but not the file in the cloud
			elseif ($fs = $obTargetBucket->FileExists($callbackData["fileURL"]))
			{
				//If file was resized before the fact was registered
				if (COption::GetOptionString("clouds", "delayed_resize") === "Y")
				{
					CCloudStorage::ResizeImageFileAdd(
						$arDestinationSize,
						$arFile,
						$cacheImageFile,
						$arResizeParams,
						9 //already where
					);
				}

				$callbackData["cacheSTARTED"] = true;
				if ($fs > 1)
					$callbackData["fileSize"] = $fs;
				$bNeedResize = false;
				$result = true;
			}
			else
			{
				$callbackData["tmpFile"] = CFile::GetTempName('', $arFile["FILE_NAME"]);
				$callbackData["tmpFile"] = preg_replace("#[\\\\\\/]+#", "/", $callbackData["tmpFile"]);

				if (
					!$bImmediate
					&& COption::GetOptionString("clouds", "delayed_resize") === "Y"
					&& CCloudStorage::ResizeImageFileDelay(
						$arDestinationSize,
						$arFile,
						$cacheImageFile,
						$arResizeParams
					)
				)
				{
					$callbackData["cacheSTARTED"] = false;
					$bNeedResize = false;
					$callbackData["cacheOBJ"]->AbortDataCache();
					$callbackData["cacheVARS"] = array(
						"cacheImageFile" => $cacheImageFile,
						"width" => $arDestinationSize["width"],
						"height" => $arDestinationSize["height"],
					);
					$result = true;
				}
				elseif ($obSourceBucket->DownloadToFile($arFile, $callbackData["tmpFile"]))
				{
					$callbackData["cacheSTARTED"] = true;
					$bNeedResize = true;
					$sourceImageFile = $callbackData["tmpFile"];
					$cacheImageFileTmp = CFile::GetTempName('', $arFile["FILE_NAME"]);
					$result = true;
				}
				else
				{
					$callbackData["cacheSTARTED"] = false;
					$bNeedResize = false;
					$callbackData["cacheOBJ"]->AbortDataCache();
					$result = false;
				}
			}
		}
		else
		{
			$callbackData["cacheSTARTED"] = false;
			$callbackData["cacheVARS"] = $callbackData["cacheOBJ"]->GetVars();
			$bNeedResize = false;
			$result = true;
		}

		return $result;
	}

	public static function OnAfterResizeImage($arFile, $arResizeParams, &$callbackData, &$cacheImageFile, &$cacheImageFileTmp, &$arImageSize)
	{
		global $arCloudImageSizeCache;
		$io = CBXVirtualIo::GetInstance();

		if (!is_array($callbackData))
			return false;

		if ($callbackData["cacheSTARTED"])
		{
			/** @var CCloudStorageBucket $obTargetBucket */
			$obTargetBucket = $callbackData["obTargetBucket"];
			/** @var CPHPCache $cacheOBJ */
			$cacheOBJ = $callbackData["cacheOBJ"];

			if (isset($callbackData["tmpFile"])) //have to upload to the cloud
			{
				$arFileToStore = CFile::MakeFileArray($io->GetPhysicalName($cacheImageFileTmp));
				if (!preg_match("/^image\\//", $arFileToStore["type"]))
					$arFileToStore["type"] = $arFile["CONTENT_TYPE"];

				if ($obTargetBucket->SaveFile($callbackData["fileURL"], $arFileToStore))
				{
					$cacheImageFile = $obTargetBucket->GetFileSRC($callbackData["fileURL"]);

					$arImageSize = CFile::GetImageSize($cacheImageFileTmp);
					$arImageSize[2] = filesize($io->GetPhysicalName($cacheImageFileTmp));
					$iFileSize = filesize($arFileToStore["tmp_name"]);

					if (!is_array($arImageSize))
						$arImageSize = array(0, 0);
					$cacheOBJ->EndDataCache(array(
						"cacheImageFile" => $cacheImageFile,
						"width" => $arImageSize[0],
						"height" => $arImageSize[1],
						"size" => $arImageSize[2],
					));

					$tmpFile = $io->GetPhysicalName($callbackData["tmpFile"]);
					unlink($tmpFile);
					@rmdir(substr($tmpFile, 0, -strlen(bx_basename($tmpFile))));

					$arCloudImageSizeCache[$cacheImageFile] = $arImageSize;

					$obTargetBucket->IncFileCounter($iFileSize);

					if (
						COption::GetOptionString("clouds", "delayed_resize") === "Y"
						&& !is_array(CCloudStorage::ResizeImageFileGet($cacheImageFile))
					)
					{
						$arDestinationSize = array();
						CCloudStorage::ResizeImageFileAdd(
							$arDestinationSize,
							$arFile,
							$cacheImageFile,
							$arResizeParams,
							9 //already there
						);
					}

					return true;
				}
				else
				{
					$cacheOBJ->AbortDataCache();

					$tmpFile = $io->GetPhysicalName($callbackData["tmpFile"]);
					unlink($tmpFile);
					@rmdir(substr($tmpFile, 0, -strlen(bx_basename($tmpFile))));

					unlink($cacheImageFileTmp);
					@rmdir(substr($cacheImageFileTmp, 0, -strlen(bx_basename($cacheImageFileTmp))));

					// $cacheImageFile not clear what to do
					return false;
				}
			}
			else //the file is already in the cloud
			{
				$bNeedCreatePicture = false;
				$arSourceSize = array("x" => 0, "y" => 0, "width" => 0, "height" => 0);
				$arDestinationSize = array("x" => 0, "y" => 0, "width" => 0, "height" => 0);
				CFile::ScaleImage($arFile["WIDTH"], $arFile["HEIGHT"], $arResizeParams[0], $arResizeParams[1], $bNeedCreatePicture, $arSourceSize, $arDestinationSize);

				$cacheImageFile = $obTargetBucket->GetFileSRC($callbackData["fileURL"]);
				$arImageSize = array(
					$arDestinationSize["width"],
					$arDestinationSize["height"],
					isset($callbackData["fileSize"])? $callbackData["fileSize"]: $obTargetBucket->GetFileSize($callbackData["fileURL"]),
				);
				$cacheOBJ->EndDataCache(array(
					"cacheImageFile" => $cacheImageFile,
					"width" => $arImageSize[0],
					"height" => $arImageSize[1],
					"size" => $arImageSize[2],
				));

				$arCloudImageSizeCache[$cacheImageFile] = $arImageSize;

				return true;
			}
		}
		elseif (is_array($callbackData["cacheVARS"]))
		{
			$cacheImageFile = $callbackData["cacheVARS"]["cacheImageFile"];
			$arImageSize = array(
				$callbackData["cacheVARS"]["width"],
				$callbackData["cacheVARS"]["height"],
				$callbackData["cacheVARS"]["size"],
			);
			$arCloudImageSizeCache[$cacheImageFile] = $arImageSize;
			return true;
		}

		return false;
	}

	public static function ResizeImageFileGet($destinationFile)
	{
		global $DB;
		$destinationFile = preg_replace("/^https?:/i", "", $destinationFile);
		$q = $DB->Query("
			select
				ID
				,ERROR_CODE
				,FILE_ID
				,".$DB->DateToCharFunction("TIMESTAMP_X", "FULL")." TIMESTAMP_X
			from b_clouds_file_resize
			where TO_PATH = '".$DB->ForSql($destinationFile)."'
		");
		$a = $q->Fetch();
		return $a;
	}

	public static function ResizeImageFileAdd(&$arDestinationSize, $sourceFile, $destinationFile, $arResizeParams, $errorCode = 0)
	{
		global $DB;
		$destinationFile = preg_replace("/^https?:/i", "", $destinationFile);
		$q = $DB->Query("
			select
				ID
				,ERROR_CODE
				,PARAMS
				,".$DB->DateToCharFunction("TIMESTAMP_X", "FULL")." TIMESTAMP_X
			from b_clouds_file_resize
			where TO_PATH = '".$DB->ForSql($destinationFile)."'
		");

		$a = $q->Fetch();
		if ($a && $a["ERROR_CODE"] >= 10 && $a["ERROR_CODE"] < 20)
		{
			$DB->Query("DELETE from b_clouds_file_resize WHERE ID = ".$a["ID"]);
			$a = false;
		}

		if (!$a)
		{
			$arResizeParams["type"] = $sourceFile["CONTENT_TYPE"];
			$DB->Add("b_clouds_file_resize", array(
				"~TIMESTAMP_X" => $DB->CurrentTimeFunction(),
				"ERROR_CODE" => intval($errorCode),
				"PARAMS" => serialize($arResizeParams),
				"FROM_PATH" => $sourceFile["SRC"],
				"TO_PATH" => $destinationFile,
				"FILE_ID" => $sourceFile["ID"],
			));
		}
	}

	public static function ResizeImageFileDelay(&$arDestinationSize, $sourceFile, $destinationFile, $arResizeParams)
	{
		global $DB;
		$destinationFile = preg_replace("/^https?:/i", "", $destinationFile);
		$q = $DB->Query("
			select
				ID
				,ERROR_CODE
				,PARAMS
				,".$DB->DateToCharFunction("TIMESTAMP_X", "FULL")." TIMESTAMP_X
			from b_clouds_file_resize
			where TO_PATH = '".$DB->ForSql($destinationFile)."'
		");
		if ($resize = $q->Fetch())
		{
			if ($resize["ERROR_CODE"] < 10)
			{
				$arResizeParams = unserialize($resize["PARAMS"]);
				$id = $resize["ID"];
			} //Give it a try
			elseif (
				$resize["ERROR_CODE"] >= 10
				&& $resize["ERROR_CODE"] < 20
				&& (MakeTimeStamp($resize["TIMESTAMP_X"]) + 300/*5min*/) < (time() + CTimeZone::GetOffset())
			)
			{
				$DB->Query("
					UPDATE b_clouds_file_resize
					SET ERROR_CODE='1'
					WHERE ID=".$resize["ID"]."
				");
				$arResizeParams = unserialize($resize["PARAMS"]);
				$id = $resize["ID"];
			}
			else
			{
				return false;
			}
		}
		else
		{
			$id = 0;
		}

		$sourceImageWidth = $sourceFile["WIDTH"];
		$sourceImageHeight = $sourceFile["HEIGHT"];
		$arSize = $arResizeParams[0];
		$resizeType = $arResizeParams[1];
		$arWaterMark = $arResizeParams[2];
		$jpgQuality = $arResizeParams[3];
		$arFilters = $arResizeParams[4];
		$bNeedCreatePicture = false;
		$arSourceSize = array("x" => 0, "y" => 0, "width" => 0, "height" => 0);
		$arDestinationSize = array("x" => 0, "y" => 0, "width" => 0, "height" => 0);

		CFile::ScaleImage(
			$sourceImageWidth,
			$sourceImageHeight,
			$arSize,
			$resizeType,
			$bNeedCreatePicture,
			$arSourceSize,
			$arDestinationSize
		);
		$bNeedCreatePicture |= is_array($arWaterMark) && !empty($arWaterMark);
		$bNeedCreatePicture |= is_array($arFilters) && !empty($arFilters);

		if ($bNeedCreatePicture)
		{
			if ($id <= 0)
			{
				$arResizeParams["type"] = $sourceFile["CONTENT_TYPE"];
				$id = $DB->Add("b_clouds_file_resize", array(
					"~TIMESTAMP_X" => $DB->CurrentTimeFunction(),
					"ERROR_CODE" => "2",
					"PARAMS" => serialize($arResizeParams),
					"FROM_PATH" => $sourceFile["SRC"],
					"TO_PATH" => $destinationFile,
					"FILE_ID" => $sourceFile["ID"],
				));
			}

			return $id > 0;
		}
		else
		{
			return false;
		}
	}

	/**
	 * @param CCloudStorageBucket $obBucket
	 * @param string $path
	 * @return bool
	 */
	public static function ResizeImageFileCheck($obBucket, $path)
	{
		global $DB;
		$path = preg_replace("/^https?:/i", "", $path);
		$q = $DB->Query("
			select
				ID
				,ERROR_CODE
				,TO_PATH
				,FROM_PATH
				,PARAMS
				,".$DB->DateToCharFunction("TIMESTAMP_X", "FULL")." TIMESTAMP_X
			from b_clouds_file_resize
			where TO_PATH = '".$DB->ForSql($path)."'
		");
		$task = $q->Fetch();
		if (!$task)
			return false;

		//File in the Sky with Diamonds
		if ($task["ERROR_CODE"] == 9)
		{
			return true;
		}

		//Fatal error
		if ($task["ERROR_CODE"] >= 20)
		{
			return false;
		}

		//Recoverable error
		if ($task["ERROR_CODE"] >= 10 && $task["ERROR_CODE"] < 20)
		{
			if ((MakeTimeStamp($task["TIMESTAMP_X"]) + 300/*5min*/) > (time() + CTimeZone::GetOffset()))
				return false;
		}

		$DB->Query("
			UPDATE b_clouds_file_resize
			SET ERROR_CODE = '11'
			WHERE ID = ".$task["ID"]."
		");

		$tmpFile = CFile::MakeFileArray($task["FROM_PATH"]);
		if (!is_array($tmpFile) || !file_exists($tmpFile["tmp_name"]))
		{
			$DB->Query("
				UPDATE b_clouds_file_resize
				SET ERROR_CODE = '22'
				WHERE ID = ".$task["ID"]."
			");
			return false;
		}

		$arResizeParams = unserialize($task["PARAMS"]);
		if (!is_array($arResizeParams))
		{
			$DB->Query("
				UPDATE b_clouds_file_resize
				SET ERROR_CODE = '23'
				WHERE ID = ".$task["ID"]."
			");
			return false;
		}

		$DB->Query("
			UPDATE b_clouds_file_resize
			SET ERROR_CODE = '14'
			WHERE ID = ".$task["ID"]."
		");

		$arSize = $arResizeParams[0];
		$resizeType = $arResizeParams[1];
		$arWaterMark = $arResizeParams[2];
		$jpgQuality = $arResizeParams[3];
		$arFilters = $arResizeParams[4];

		$to_path = CFile::GetTempName('', bx_basename($task["TO_PATH"]));

		if (!CFile::ResizeImageFile($tmpFile["tmp_name"], $to_path, $arSize, $resizeType, $arWaterMark, $jpgQuality, $arFilters))
		{
			$DB->Query("
				UPDATE b_clouds_file_resize
				SET ERROR_CODE = '25'
				WHERE ID = ".$task["ID"]."
			");
			return false;
		}

		$DB->Query("
			UPDATE b_clouds_file_resize
			SET ERROR_CODE = '16'
			WHERE ID = ".$task["ID"]."
		");

		$fileToStore = CFile::MakeFileArray($to_path);
		if ($arResizeParams["type"] && !preg_match("/^image\\//", $fileToStore["type"]))
			$fileToStore["type"] = $arResizeParams["type"];

		$baseURL = preg_replace("/^https?:/i", "", $obBucket->GetFileSRC("/"));
		$pathToStore = substr($task["TO_PATH"], strlen($baseURL) - 1);
		if (!$obBucket->SaveFile(urldecode($pathToStore), $fileToStore))
		{
			$DB->Query("
				UPDATE b_clouds_file_resize
				SET ERROR_CODE = '27'
				WHERE ID = ".$task["ID"]."
			");
			return false;
		}
		$obBucket->IncFileCounter($fileToStore["size"]);
		$DB->Query("
			UPDATE b_clouds_file_resize
			SET ERROR_CODE = '9'
			WHERE ID = ".$task["ID"]."
		");
		return true;
	}

	public static function OnMakeFileArray($arSourceFile, &$arDestination)
	{
		if (!is_array($arSourceFile))
		{
			$file = $arSourceFile;
			if (substr($file, 0, strlen($_SERVER["DOCUMENT_ROOT"])) == $_SERVER["DOCUMENT_ROOT"])
				$file = ltrim(substr($file, strlen($_SERVER["DOCUMENT_ROOT"])), "/");

			if (!preg_match("/^http:\\/\\//", $file))
				return false;

			$bucket = CCloudStorage::FindBucketByFile($file);
			if (!is_object($bucket))
				return false;

			$filePath = substr($file, strlen($bucket->GetFileSRC("/")) - 1);
			$filePath = urldecode($filePath);

			$target = CFile::GetTempName('', bx_basename($filePath));
			$target = preg_replace("#[\\\\\\/]+#", "/", $target);

			if ($bucket->DownloadToFile($filePath, $target))
			{
				$arDestination = $target;
			}

			return true;
		}
		else
		{
			if ($arSourceFile["HANDLER_ID"] <= 0)
				return false;

			$bucket = new CCloudStorageBucket($arSourceFile["HANDLER_ID"]);
			if (!$bucket->Init())
				return false;

			$target = CFile::GetTempName('', $arSourceFile["FILE_NAME"]);
			$target = preg_replace("#[\\\\\\/]+#", "/", $target);

			if ($bucket->DownloadToFile($arSourceFile, $target))
			{
				$arDestination["name"] = (strlen($arSourceFile['ORIGINAL_NAME']) > 0? $arSourceFile['ORIGINAL_NAME']: $arSourceFile['FILE_NAME']);
				$arDestination["size"] = $arSourceFile['FILE_SIZE'];
				$arDestination["type"] = $arSourceFile['CONTENT_TYPE'];
				$arDestination["description"] = $arSourceFile['DESCRIPTION'];
				$arDestination["tmp_name"] = $target;
			}

			return true;
		}
	}

	public static function OnFileDelete($arFile)
	{
		global $DB;

		if ($arFile["HANDLER_ID"] <= 0)
			return false;

		$bucket = new CCloudStorageBucket($arFile["HANDLER_ID"]);
		if ((!$bucket->Init()) || ($bucket->READ_ONLY === "Y"))
			return false;

		$result = $bucket->DeleteFile("/".$arFile["SUBDIR"]."/".$arFile["FILE_NAME"]);
		if ($result)
			$bucket->DecFileCounter($arFile["FILE_SIZE"]);

		$path = '/resize_cache/'.$arFile["ID"]."/";
		$arCloudFiles = $bucket->ListFiles($path, true);
		if (is_array($arCloudFiles["file"]))
		{
			$delete_size = 0;
			foreach ($arCloudFiles["file"] as $i => $file_name)
			{
				$tmp = $bucket->DeleteFile($path.$file_name);
				if ($tmp)
				{
					$bucket->DecFileCounter($arCloudFiles["file_size"][$i]);
					$delete_size += $arCloudFiles["file_size"][$i];
				}
			}
			/****************************** QUOTA ******************************/
			if($delete_size > 0 && COption::GetOptionInt("main", "disk_space") > 0)
				CDiskQuota::updateDiskQuota("file", $delete_size, "delete");
			/****************************** QUOTA ******************************/
		}

		$DB->Query("
			DELETE FROM b_clouds_file_resize
			WHERE FILE_ID = ".intval($arFile["ID"])."
		", true);

		return $result;
	}

	public static function DeleteDirFilesEx($path)
	{
		$path = rtrim($path, "/")."/";
		foreach (CCloudStorageBucket::GetAllBuckets() as $bucket)
		{
			$obBucket = new CCloudStorageBucket($bucket["ID"]);
			if ($obBucket->Init())
			{
				$arCloudFiles = $obBucket->ListFiles($path, true);
				if (is_array($arCloudFiles["file"]))
				{
					foreach ($arCloudFiles["file"] as $i => $file_name)
					{
						$tmp = $obBucket->DeleteFile($path.$file_name);
						if ($tmp)
							$obBucket->DecFileCounter($arCloudFiles["file_size"][$i]);
					}
				}
			}
		}
	}

	public static function OnFileCopy(&$arFile, $newPath = "")
	{
		if ($arFile["HANDLER_ID"] <= 0)
			return false;

		$bucket = new CCloudStorageBucket($arFile["HANDLER_ID"]);
		if (!$bucket->Init())
			return false;

		if ($bucket->READ_ONLY == "Y")
			return false;

		$filePath = "";
		$newName = "";

		if (strlen($newPath))
		{
			$filePath = "/".trim(str_replace("//", "/", $newPath), "/");
		}
		else
		{
			$strFileExt = strrchr($arFile["FILE_NAME"], ".");
			while (true)
			{
				$newName = md5(uniqid(mt_rand(), true)).$strFileExt;
				$filePath = "/".$arFile["SUBDIR"]."/".$newName;
				if (!$bucket->FileExists($filePath))
					break;
			}
		}

		$result = $bucket->FileCopy($arFile, $filePath);

		if ($result)
		{
			$bucket->IncFileCounter($arFile["FILE_SIZE"]);

			if (strlen($newPath))
			{
				$arFile["FILE_NAME"] = bx_basename($filePath);
				$arFile["SUBDIR"] = substr($filePath, 1, -(strlen(bx_basename($filePath)) + 1));
			}
			else
			{
				$arFile["FILE_NAME"] = $newName;
			}
		}

		return $result;
	}

	public static function OnGetFileSRC($arFile)
	{
		if ($arFile["HANDLER_ID"] <= 0)
			return false;

		$bucket = new CCloudStorageBucket($arFile["HANDLER_ID"]);
		if ($bucket->Init())
			return $bucket->GetFileSRC($arFile);
		else
			return false;

	}

	public static function MoveFile($arFile, $obTargetBucket)
	{
		$io = CBXVirtualIo::GetInstance();

		//Try to find suitable bucket for the file
		$bucket = CCloudStorage::FindBucketForFile($arFile, $arFile["FILE_NAME"]);
		if (!is_object($bucket))
			return CCloudStorage::FILE_SKIPPED;

		if (!$bucket->Init())
			return CCloudStorage::FILE_SKIPPED;

		//Check if this is same bucket as the target
		if ($bucket->ID != $obTargetBucket->ID)
			return CCloudStorage::FILE_SKIPPED;

		if ($bucket->FileExists($bucket->GetFileSRC($arFile))) //TODO rename file
			return CCloudStorage::FILE_SKIPPED;

		$filePath = "/".$arFile["SUBDIR"]."/".$arFile["FILE_NAME"];
		$filePath = preg_replace("#[\\\\\\/]+#", "/", $filePath);

		if ($arFile["FILE_SIZE"] > $bucket->GetService()->GetMinUploadPartSize())
		{
			$obUpload = new CCloudStorageUpload($filePath);
			if (!$obUpload->isStarted())
			{
				if ($arFile["HANDLER_ID"])
				{
					$ar = array();
					if (!CCloudStorage::OnMakeFileArray($arFile, $ar))
						return CCloudStorage::FILE_SKIPPED;
					if (!isset($ar["tmp_name"]))
						return CCloudStorage::FILE_SKIPPED;
				}
				else
				{
					$ar = CFile::MakeFileArray($arFile["ID"]);
					if (!isset($ar["tmp_name"]))
						return CCloudStorage::FILE_SKIPPED;
				}

				$temp_file = CTempFile::GetDirectoryName(2, "clouds").bx_basename($arFile["FILE_NAME"]);
				$temp_fileX = $io->GetPhysicalName($temp_file);
				CheckDirPath($temp_fileX);

				if (file_exists($ar["tmp_name"]))
				{
					$sourceFile = $ar["tmp_name"];
				}
				elseif (file_exists($io->GetPhysicalName($ar["tmp_name"])))
				{
					$sourceFile = $io->GetPhysicalName($ar["tmp_name"]);
				}
				else
				{
					return CCloudStorage::FILE_SKIPPED;
				}

				if (!copy($sourceFile, $temp_fileX))
					return CCloudStorage::FILE_SKIPPED;

				if ($obUpload->Start($bucket->ID, $arFile["FILE_SIZE"], $arFile["CONTENT_TYPE"], $temp_file))
					return CCloudStorage::FILE_PARTLY_UPLOADED;
				else
					return CCloudStorage::FILE_SKIPPED;
			}
			else
			{
				$temp_file = $obUpload->getTempFileName();
				$temp_fileX = $io->GetPhysicalName($temp_file);

				$fp = fopen($temp_fileX, "rb");
				if (!is_resource($fp))
					return CCloudStorage::FILE_SKIPPED;

				$pos = $obUpload->getPos();
				if ($pos > filesize($temp_fileX))
				{
					if ($obUpload->Finish())
					{
						$bucket->IncFileCounter(filesize($temp_fileX));

						if ($arFile["HANDLER_ID"])
							CCloudStorage::OnFileDelete($arFile);
						else
						{
							$ar = CFile::MakeFileArray($arFile["ID"]);
							$fileNameX = $io->GetPhysicalName($ar["tmp_name"]);
							unlink($fileNameX);
							@rmdir(substr($fileNameX, 0, -strlen(bx_basename($fileNameX))));
						}

						return CCloudStorage::FILE_MOVED;
					}
					else
						return CCloudStorage::FILE_SKIPPED;
				}

				fseek($fp, $pos);
				self::$part_count = $obUpload->GetPartCount();
				self::$part_size = $obUpload->getPartSize();
				$part = fread($fp, self::$part_size);
				while ($obUpload->hasRetries())
				{
					if ($obUpload->Next($part))
						return CCloudStorage::FILE_PARTLY_UPLOADED;
				}
				return CCloudStorage::FILE_SKIPPED;
			}
		}
		else
		{
			if ($arFile["HANDLER_ID"])
			{
				$ar = array();
				if (!CCloudStorage::OnMakeFileArray($arFile, $ar))
					return CCloudStorage::FILE_SKIPPED;
				if (!isset($ar["tmp_name"]))
					return CCloudStorage::FILE_SKIPPED;
			}
			else
			{
				$ar = CFile::MakeFileArray($arFile["ID"]);
				if (!isset($ar["tmp_name"]))
					return CCloudStorage::FILE_SKIPPED;
			}

			$res = $bucket->SaveFile($filePath, $ar);
			if ($res)
			{
				$bucket->IncFileCounter(filesize($ar["tmp_name"]));

				if (file_exists($ar["tmp_name"]))
				{
					unlink($ar["tmp_name"]);
					@rmdir(substr($ar["tmp_name"], 0, -strlen(bx_basename($ar["tmp_name"]))));
				}

				if ($arFile["HANDLER_ID"])
					CCloudStorage::OnFileDelete($arFile);
			}
			else
			{        //delete temporary copy
				if ($arFile["HANDLER_ID"])
				{
					unlink($ar["tmp_name"]);
					@rmdir(substr($ar["tmp_name"], 0, -strlen(bx_basename($ar["tmp_name"]))));
				}
			}

			return $res? CCloudStorage::FILE_MOVED: CCloudStorage::FILE_SKIPPED;
		}
	}

	public static function OnFileSave(&$arFile, $strFileName, $strSavePath, $bForceMD5 = false, $bSkipExt = false, $dirAdd = '')
	{
		if (!$arFile["tmp_name"] && !array_key_exists("content", $arFile))
			return false;

		if (array_key_exists("bucket", $arFile))
			$bucket = $arFile["bucket"];
		else
			$bucket = CCloudStorage::FindBucketForFile($arFile, $strFileName);

		if (!is_object($bucket))
			return false;

		if (!$bucket->Init())
			return false;

		$copySize = false;
		$subDir = "";
		$filePath = "";

		if (array_key_exists("content", $arFile))
		{
			$arFile["tmp_name"] = CTempFile::GetFileName($arFile["name"]);
			CheckDirPath($arFile["tmp_name"]);
			$fp = fopen($arFile["tmp_name"], "ab");
			if ($fp)
			{
				fwrite($fp, $arFile["content"]);
				fclose($fp);
			}
		}

		if (array_key_exists("bucket", $arFile))
		{
			$newName = bx_basename($arFile["tmp_name"]);

			$prefix = $bucket->GetFileSRC("/");
			$subDir = substr($arFile["tmp_name"], strlen($prefix));
			$subDir = substr($subDir, 0, -strlen($newName) - 1);
		}
		else
		{
			if (
				$bForceMD5 != true
				&& COption::GetOptionString("main", "save_original_file_name", "N") == "Y"
			)
			{
				if (COption::GetOptionString("main", "convert_original_file_name", "Y") == "Y")
					$newName = CCloudStorage::translit($strFileName);
				else
					$newName = $strFileName;
			}
			else
			{
				$strFileExt = ($bSkipExt == true? '': strrchr($strFileName, "."));
				$newName = md5(uniqid(mt_rand(), true)).$strFileExt;
			}

			//check for double extension vulnerability
			$newName = RemoveScriptExtension($newName);
			$dir_add = $dirAdd;

			if (empty($dir_add))
			{
				while (true)
				{
					$dir_add = md5(mt_rand());
					$dir_add = substr($dir_add, 0, 3)."/".$dir_add;

					$subDir = trim($strSavePath, "/")."/".$dir_add;
					$filePath = "/".$subDir."/".$newName;

					if (!$bucket->FileExists($filePath))
						break;
				}
			}
			else
			{
				$subDir = trim($strSavePath, "/")."/".$dir_add;
				$filePath = "/".$subDir."/".$newName;
			}

			$targetPath = $bucket->GetFileSRC("/");
			if (strpos($arFile["tmp_name"], $targetPath) === 0)
			{
				$arDbFile = array(
					"SUBDIR" => "",
					"FILE_NAME" => substr($arFile["tmp_name"], strlen($targetPath)),
					"CONTENT_TYPE" => $arFile["type"],
				);
				$copyPath = $bucket->FileCopy($arDbFile, $filePath);
				if (!$copyPath)
					return false;

				$copySize = $bucket->GetFileSize("/".urldecode(substr($copyPath, strlen($targetPath))));
			}
			else
			{
				$imgArray = CFile::GetImageSize($arFile["tmp_name"], true, false);
				if (is_array($imgArray) && $imgArray[2] == IMAGETYPE_JPEG)
				{
					$exifData = CFile::ExtractImageExif($arFile["tmp_name"]);
					if ($exifData && isset($exifData['Orientation']))
					{
						$properlyOriented = CFile::ImageHandleOrientation($exifData['Orientation'], $arFile["tmp_name"]);
						if ($properlyOriented)
						{
							$jpgQuality = intval(COption::GetOptionString('main', 'image_resize_quality', '95'));
							if ($jpgQuality <= 0 || $jpgQuality > 100)
								$jpgQuality = 95;

							imagejpeg($properlyOriented, $arFile["tmp_name"], $jpgQuality);
							clearstatcache(true, $arFile["tmp_name"]);
						}
						$arFile['size'] = filesize($arFile["tmp_name"]);
					}
				}

				if (!$bucket->SaveFile($filePath, $arFile))
					return false;
			}
		}

		$arFile["HANDLER_ID"] = $bucket->ID;
		$arFile["SUBDIR"] = $subDir;
		$arFile["FILE_NAME"] = $newName;
		$arFile["WIDTH"] = 0;
		$arFile["HEIGHT"] = 0;

		if (array_key_exists("bucket", $arFile))
		{
			$arFile["WIDTH"] = $arFile["width"];
			$arFile["HEIGHT"] = $arFile["height"];
			$arFile["size"] = $arFile["file_size"];
		}
		elseif ($copySize !== false)
		{
			$arFile["WIDTH"] = $arFile["width"];
			$arFile["HEIGHT"] = $arFile["height"];
			$arFile["size"] = $copySize;
			$bucket->IncFileCounter($copySize);
		}
		else
		{
			$bucket->IncFileCounter(filesize($arFile["tmp_name"]));
			$flashEnabled = !CFile::IsImage($arFile["ORIGINAL_NAME"], $arFile["type"]);
			$imgArray = CFile::GetImageSize($arFile["tmp_name"], true, $flashEnabled);
			if (is_array($imgArray))
			{
				$arFile["WIDTH"] = $imgArray[0];
				$arFile["HEIGHT"] = $imgArray[1];
			}
		}

		if (isset($arFile["old_file"]))
			CFile::DoDelete($arFile["old_file"]);

		return true;
	}

	public static function FindBucketByFile($file_name)
	{
		foreach (CCloudStorageBucket::GetAllBuckets() as $bucket)
		{
			if ($bucket["ACTIVE"] == "Y")
			{
				$obBucket = new CCloudStorageBucket($bucket["ID"]);
				if ($obBucket->Init())
				{
					$prefix = $obBucket->GetFileSRC("/");
					if (substr($file_name, 0, strlen($prefix)) === $prefix)
						return $obBucket;
				}
			}
		}
		return false;
	}

	public static function FindFileURIByURN($urn, $log_descr = "")
	{
		foreach (CCloudStorageBucket::GetAllBuckets() as $bucket)
		{
			if ($bucket["ACTIVE"] == "Y")
			{
				$obBucket = new CCloudStorageBucket($bucket["ID"]);
				if ($obBucket->Init() && $obBucket->FileExists($urn))
				{
					$uri = $obBucket->GetFileSRC($urn);

					if ($log_descr && COption::GetOptionString("clouds", "log_404_errors") === "Y")
						CEventLog::Log("WARNING", "CLOUDS_404", "clouds", $uri, $log_descr);

					return $uri;
				}
			}
		}
		return "";
	}

	public static function OnBuildGlobalMenu(&$aGlobalMenu, &$aModuleMenu)
	{
		global $USER;
		if (!$USER->CanDoOperation("clouds_browse"))
			return;

		//When UnRegisterModuleDependences is called from module uninstall
		//cached EventHandlers may be called
		if (defined("BX_CLOUDS_UNINSTALLED"))
			return;

		$aMenu = array(
			"parent_menu" => "global_menu_content",
			"section" => "clouds",
			"sort" => 150,
			"text" => GetMessage("CLO_STORAGE_MENU"),
			"title" => GetMessage("CLO_STORAGE_TITLE"),
			"icon" => "clouds_menu_icon",
			"page_icon" => "clouds_page_icon",
			"items_id" => "menu_clouds",
			"items" => array()
		);

		$rsBuckets = CCloudStorageBucket::GetList(array("SORT" => "DESC", "ID" => "ASC"));
		while ($arBucket = $rsBuckets->Fetch())
			$aMenu["items"][] = array(
				"text" => $arBucket["BUCKET"],
				"url" => "clouds_file_list.php?lang=".LANGUAGE_ID."&bucket=".$arBucket["ID"]."&path=/",
				"more_url" => array(
					"clouds_file_list.php?bucket=".$arBucket["ID"],
				),
				"title" => "",
				"page_icon" => "clouds_page_icon",
				"items_id" => "menu_clouds_bucket_".$arBucket["ID"],
				"module_id" => "clouds",
				"items" => array()
			);

		if (!empty($aMenu["items"]))
			$aModuleMenu[] = $aMenu;
	}

	public static function OnAdminListDisplay(&$obList)
	{
		global $USER;

		if ($obList->table_id !== "tbl_fileman_admin")
			return;

		if (!is_object($USER) || !$USER->CanDoOperation("clouds_upload"))
			return;

		static $clouds = null;
		if (!isset($clouds))
		{
			$clouds = array();
			$rsClouds = CCloudStorageBucket::GetList(array("SORT" => "DESC", "ID" => "ASC"));
			while ($arStorage = $rsClouds->Fetch())
			{
				if ($arStorage["READ_ONLY"] == "N" && $arStorage["ACTIVE"] == "Y")
					$clouds[$arStorage["ID"]] = $arStorage["BUCKET"];
			}
		}

		if (empty($clouds))
			return;

		foreach ($obList->aRows as $obRow)
		{
			if ($obRow->arRes["TYPE"] === "F")
			{
				$ID = "F".$obRow->arRes["NAME"];
				$file = $obRow->arRes["NAME"];
				$path = substr($obRow->arRes["ABS_PATH"], 0, -strlen($file));

				$arSubMenu = array();
				foreach ($clouds as $id => $bucket)
					$arSubMenu[] = array(
						"TEXT" => $bucket,
						"ACTION" => $s = "if(confirm('".GetMessage("CLO_STORAGE_UPLOAD_CONF")."')) jsUtils.Redirect([], '".CUtil::AddSlashes("/bitrix/admin/clouds_file_list.php?lang=".LANGUAGE_ID."&bucket=".urlencode($id)."&path=".urlencode($path)."&ID=".urlencode($ID)."&action=upload&".bitrix_sessid_get())."');"
					);

				$obRow->aActions[] = array(
					"TEXT" => GetMessage("CLO_STORAGE_UPLOAD_MENU"),
					"MENU" => $arSubMenu,
				);
			}
		}
	}

	public static function HasActiveBuckets()
	{
		foreach (CCloudStorageBucket::GetAllBuckets() as $bucket)
			if ($bucket["ACTIVE"] === "Y")
				return true;
		return false;
	}

	public static function OnBeforeProlog()
	{
		if (defined("BX_CHECK_SHORT_URI") && BX_CHECK_SHORT_URI)
		{
			$upload_dir = "/".trim(COption::GetOptionString("main", "upload_dir", "upload"), "/")."/";
			$request_uri = urldecode($_SERVER["REQUEST_URI"]);
			$request_uri = CCloudUtil::URLEncode($request_uri, LANG_CHARSET);
			foreach (CCloudStorageBucket::GetAllBuckets() as $arBucket)
			{
				if ($arBucket["ACTIVE"] == "Y")
				{
					$obBucket = new CCloudStorageBucket($arBucket["ID"]);
					if ($obBucket->Init())
					{
						$match = array();
						if (
							COption::GetOptionString("clouds", "delayed_resize") === "Y"
							&& preg_match("#^(/".$obBucket->PREFIX."|)(/resize_cache/.*\$)#", $request_uri, $match)
						)
						{
							session_write_close();
							$to_file = $obBucket->GetFileSRC(urldecode($match[2]));
							if (CCloudStorage::ResizeImageFileCheck($obBucket, $to_file))
							{
								$cache_time = 3600 * 24 * 30; // 30 days
								header("Cache-Control: max-age=".$cache_time);
								header("Expires: ".gmdate("D, d M Y H:i:s", time() + $cache_time)." GMT");
								header_remove("Pragma");
								LocalRedirect($to_file, true, "301 Moved Permanently");
							}
						}
						elseif (
							!preg_match("/[?&]/", $request_uri)
							&& $obBucket->FileExists($request_uri)
						)
						{
							if (COption::GetOptionString("clouds", "log_404_errors") === "Y")
								CEventLog::Log("WARNING", "CLOUDS_404", "clouds", $_SERVER["REQUEST_URI"], $_SERVER["HTTP_REFERER"]);
							LocalRedirect($obBucket->GetFileSRC($request_uri), true);
						}
						elseif (strpos($request_uri, $upload_dir) === 0)
						{
							$check_url = substr($request_uri, strlen($upload_dir) - 1);
							if ($obBucket->FileExists($check_url))
							{
								if (COption::GetOptionString("clouds", "log_404_errors") === "Y")
									CEventLog::Log("WARNING", "CLOUDS_404", "clouds", $_SERVER["REQUEST_URI"], $_SERVER["HTTP_REFERER"]);
								LocalRedirect($obBucket->GetFileSRC($check_url), true);
							}
						}
					}
				}
			}
		}
	}

	public static function GetAuditTypes()
	{
		return array(
			"CLOUDS_404" => "[CLOUDS_404] ".GetMessage("CLO_404_ON_MOVED_FILE"),
		);
	}

	public static function translit($file_name, $safe_chars = '')
	{
		return CUtil::translit($file_name, LANGUAGE_ID, array(
			"safe_chars" => "-. ".$safe_chars,
			"change_case" => false,
			"max_len" => 255,
		));
	}

	/**
	 * @param array [string]string $arFile
	 * @return void
	 */
	public static function FixFileContentType(&$arFile)
	{
		global $DB;
		$fixedContentType = "";

		if ($arFile["CONTENT_TYPE"] === "image/jpg")
			$fixedContentType = "image/jpeg";
		else
		{
			$hexContentType = unpack("H*", $arFile["CONTENT_TYPE"]);
			if (
				$hexContentType[1] === "e0f3e4e8ee2f6d706567"
				|| $hexContentType[1] === "d0b0d183d0b4d0b8d0be2f6d706567"
			)
				$fixedContentType = "audio/mpeg";
		}

		if ($fixedContentType !== "")
		{
			$arFile["CONTENT_TYPE"] = $fixedContentType;
			$DB->Query("
				UPDATE b_file
				SET CONTENT_TYPE = '".$DB->ForSQL($fixedContentType)."'
				WHERE ID = ".intval($arFile["ID"])."
			");
			CFile::CleanCache($arFile["ID"]);
		}
	}
}
classes/general/security_service_s3.php000064400000021024150241560060014321 0ustar00<?
IncludeModuleLangFile(__FILE__);

class CCloudSecurityService_AmazonS3
{
	protected $status = 0;
	protected $headers = array();
	protected $errno = 0;
	protected $errstr = '';
	protected $result = '';

	function GetLastRequestStatus()
	{
		return $this->status;
	}

	function GetObject()
	{
		return new CCloudSecurityService_AmazonS3();
	}

	function GetID()
	{
		return "amazon_sts";
	}

	function GetName()
	{
		return "AWS Security Token Service";
	}

	function GetDefaultBucketControlPolicy($bucket, $prefix)
	{
		return array(
			'Statement' => array(
				array(
					'Effect' => 'Allow',
					'Action' => array(
						's3:DeleteObject',
						's3:GetObject',
						's3:PutObject',
						's3:PutObjectAcl'
					),
					'Resource' => 'arn:aws:s3:::'.$bucket.'/'.$prefix.'/*',
				),
				array(
					'Effect' => 'Allow',
					'Action' => array(
						's3:ListBucket'
					),
					'Resource' => 'arn:aws:s3:::'.$bucket,
					'Condition' => array(
						'StringLike' => array(
							's3:prefix' => $prefix."/*"
						),
					),
				),
			),
		);
	}

	function GetFederationToken($arBucket, $Policy, $Name, $DurationSeconds = 129600/*36h*/)
	{
		global $APPLICATION;

		$response = $this->SendRequest(
			$arBucket["SETTINGS"]["ACCESS_KEY"],
			$arBucket["SETTINGS"]["SECRET_KEY"],
			'GET',
			$arBucket["BUCKET"],
			'/',
			array(
				'Action' => "GetFederationToken",
				'DurationSeconds' => intval($DurationSeconds),
				'Name' => $Name,
				'Policy' => $this->PHPToJSObject($Policy),
			)
		);

		if(
			is_array($response)
			&& isset($response["GetFederationTokenResponse"])
			&& is_array($response["GetFederationTokenResponse"])
			&& isset($response["GetFederationTokenResponse"]["#"])
			&& is_array($response["GetFederationTokenResponse"]["#"])
			&& isset($response["GetFederationTokenResponse"]["#"]["GetFederationTokenResult"])
			&& is_array($response["GetFederationTokenResponse"]["#"]["GetFederationTokenResult"])
			&& isset($response["GetFederationTokenResponse"]["#"]["GetFederationTokenResult"][0])
			&& is_array($response["GetFederationTokenResponse"]["#"]["GetFederationTokenResult"][0])
			&& isset($response["GetFederationTokenResponse"]["#"]["GetFederationTokenResult"][0]["#"])
			&& is_array($response["GetFederationTokenResponse"]["#"]["GetFederationTokenResult"][0]["#"])
			&& isset($response["GetFederationTokenResponse"]["#"]["GetFederationTokenResult"][0]["#"]["Credentials"])
			&& is_array($response["GetFederationTokenResponse"]["#"]["GetFederationTokenResult"][0]["#"]["Credentials"])
		)
		{
			$Credentials = $response["GetFederationTokenResponse"]["#"]["GetFederationTokenResult"][0]["#"]["Credentials"];

			if(
				isset($Credentials[0])
				&& is_array($Credentials[0])
				&& isset($Credentials[0]["#"])
				&& is_array($Credentials[0]["#"])
				&& isset($Credentials[0]["#"]["SessionToken"])
				&& is_array($Credentials[0]["#"]["SessionToken"])
				&& isset($Credentials[0]["#"]["SessionToken"][0])
				&& is_array($Credentials[0]["#"]["SessionToken"][0])
				&& isset($Credentials[0]["#"]["SessionToken"][0]["#"])
			)
				$SessionToken = $Credentials[0]["#"]["SessionToken"][0]["#"];
			else
				return 1;

			if(
				isset($Credentials[0])
				&& is_array($Credentials[0])
				&& isset($Credentials[0]["#"])
				&& is_array($Credentials[0]["#"])
				&& isset($Credentials[0]["#"]["SecretAccessKey"])
				&& is_array($Credentials[0]["#"]["SecretAccessKey"])
				&& isset($Credentials[0]["#"]["SecretAccessKey"][0])
				&& is_array($Credentials[0]["#"]["SecretAccessKey"][0])
				&& isset($Credentials[0]["#"]["SecretAccessKey"][0]["#"])
			)
				$SecretAccessKey = $Credentials[0]["#"]["SecretAccessKey"][0]["#"];
			else
				return 2;

			if(
				isset($Credentials[0])
				&& is_array($Credentials[0])
				&& isset($Credentials[0]["#"])
				&& is_array($Credentials[0]["#"])
				&& isset($Credentials[0]["#"]["AccessKeyId"])
				&& is_array($Credentials[0]["#"]["AccessKeyId"])
				&& isset($Credentials[0]["#"]["AccessKeyId"][0])
				&& is_array($Credentials[0]["#"]["AccessKeyId"][0])
				&& isset($Credentials[0]["#"]["AccessKeyId"][0]["#"])
			)
				$AccessKeyId = $Credentials[0]["#"]["AccessKeyId"][0]["#"];
			else
				return 3;

			return array(
				"ACCESS_KEY" => $AccessKeyId,
				"SECRET_KEY" => $SecretAccessKey,
				"SESSION_TOKEN" => $SessionToken,
			);
		}
		else
		{
			return false;
		}
	}

	function SendRequest($access_key, $secret_key, $verb, $bucket, $file_name='/', $params='')
	{
		global $APPLICATION;
		$this->status = 0;

		$RequestMethod = $verb;
		$RequestHost = "sts.amazonaws.com";
		$RequestURI = "/";
		$RequestParams = "";

		$params['SignatureVersion'] = 2;
		$params['SignatureMethod'] = 'HmacSHA1';
		$params['AWSAccessKeyId'] = $access_key;
		$params['Timestamp'] = gmdate('Y-m-d').'T'.gmdate('H:i:s');//.preg_replace("/(\d\d)\$/", ":\\1", date("O"));
		$params['Version'] = '2011-06-15';
		ksort($params);
		foreach($params as $name => $value)
		{
			if($RequestParams != '')
				$RequestParams .= '&';
			$RequestParams .= urlencode($name)."=".urlencode($value);
		}

		$StringToSign =  "$RequestMethod\n"
				."$RequestHost\n"
				."$RequestURI\n"
				."$RequestParams"
		;
		$Signature = urlencode(base64_encode($this->hmacsha1($StringToSign, $secret_key)));

		$obRequest = new CHTTP;
		$obRequest->Query($RequestMethod, $RequestHost, 443, $RequestURI."?$RequestParams&Signature=$Signature", false, 'ssl://');
		$this->status = $obRequest->status;
		$this->headers = $obRequest->headers;
		$this->errno = $obRequest->errno;
		$this->errstr = $obRequest->errstr;
		$this->result = $obRequest->result;

		if($obRequest->status == 200)
		{
			if($obRequest->result)
			{
				$obXML = new CDataXML;
				$text = preg_replace("/<"."\\?XML.*?\\?".">/i", "", $obRequest->result);
				if($obXML->LoadString($text))
				{
					$arXML = $obXML->GetArray();
					if(is_array($arXML))
					{
						return $arXML;
					}
				}
				//XML parse error
				$APPLICATION->ThrowException(GetMessage('CLO_SECSERV_S3_XML_PARSE_ERROR', array('#errno#'=>1)));
				return false;
			}
			else
			{
				//Empty success result
				return array();
			}
		}
		elseif($obRequest->status > 0)
		{
			if($obRequest->result)
			{
				$APPLICATION->ThrowException(GetMessage('CLO_SECSERV_S3_XML_ERROR', array('#errmsg#'=>$obRequest->result)));
				return false;
			}
			$APPLICATION->ThrowException(GetMessage('CLO_SECSERV_S3_XML_PARSE_ERROR', array('#errno#'=>2)));
			return false;
		}
		else
		{
			$APPLICATION->ThrowException(GetMessage('CLO_SECSERV_S3_XML_PARSE_ERROR', array('#errno#'=>3)));
			return false;
		}
	}

	function hmacsha1($data, $key)
	{
		if(strlen($key)>64)
			$key=pack('H*', sha1($key));
		$key = str_pad($key, 64, chr(0x00));
		$ipad = str_repeat(chr(0x36), 64);
		$opad = str_repeat(chr(0x5c), 64);
		$hmac = pack('H*', sha1(($key^$opad).pack('H*', sha1(($key^$ipad).$data))));
		return $hmac;
	}

	function PhpToJSObject($arData, $bWS = false, $bSkipTilda = false)
	{
		static $aSearch = array("\r", "\n");
		if(is_array($arData))
		{
			if($arData == array_values($arData))
			{
				foreach($arData as $key => $value)
				{
					if(is_array($value))
					{
						$arData[$key] = $this->PhpToJSObject($value, $bWS, $bSkipTilda);
					}
					elseif(is_bool($value))
					{
						if($value === true)
							$arData[$key] = 'true';
						else
							$arData[$key] = 'false';
					}
					else
					{
						if(preg_match("#['\"\\n\\r<\\\\]#", $value))
							$arData[$key] = '"'.CUtil::JSEscape($value).'"';
						else
							$arData[$key] = '"'.$value.'"';
					}
				}
				return '['.implode(',', $arData).']';
			}

			$sWS = ','.($bWS ? "\n" : '');
			$res = ($bWS ? "\n" : '').'{';
			$first = true;
			foreach($arData as $key => $value)
			{
				if ($bSkipTilda && substr($key, 0, 1) == '~')
					continue;

				if($first)
					$first = false;
				else
					$res .= $sWS;

				if(preg_match("#['\"\\n\\r<\\\\]#", $key))
					$res .= '"'.str_replace($aSearch, '', CUtil::JSEscape($key)).'":';
				else
					$res .= '"'.$key.'":';

				if(is_array($value))
				{
					$res .= $this->PhpToJSObject($value, $bWS, $bSkipTilda);
				}
				elseif(is_bool($value))
				{
					if($value === true)
						$res .= 'true';
					else
						$res .= 'false';
				}
				else
				{
					if(preg_match("#['\"\\n\\r<\\\\]#", $value))
						$res .= '"'.CUtil::JSEscape($value).'"';
					else
						$res .= '"'.$value.'"';
				}
			}
			$res .= ($bWS ? "\n" : '').'}';

			return $res;
		}
		elseif(is_bool($arData))
		{
			if($arData === true)
				return 'true';
			else
				return 'false';
		}
		else
		{
			if(preg_match("#['\"\\n\\r<\\\\]#", $arData))
				return '"'.CUtil::JSEscape($arData).'"';
			else
				return '"'.$arData.'"';
		}
	}
}
?>classes/general/storage_bucket.php000064400000047245150241560060013343 0ustar00<?php
IncludeModuleLangFile(__FILE__);

/**
 * @property integer $ID
 * @property string $ACTIVE
 * @property integer $SORT
 * @property string $READ_ONLY
 * @property string $SERVICE_ID
 * @property string $BUCKET
 * @property string $LOCATION
 * @property string $CNAME
 * @property integer $FILE_COUNT
 * @property float $FILE_SIZE
 * @property integer $LAST_FILE_ID
 * @property string $PREFIX
 * @property string $SETTINGS
 * @property string $FILE_RULES
 */
class CCloudStorageBucket extends CAllCloudStorageBucket
{
	protected/*.array[string]string.*/$arBucket;
	/** @var CCloudStorageService $service */
	protected/*.CCloudStorageService.*/ $service;
	protected static/*.array[int][string]string.*/$arBuckets;
	/**
	 * @param int $ID
	 */
	public function __construct($ID)
	{
		$this->_ID = intval($ID);
	}
	/**
	 * @return array[string]string
	*/
	public function getBucketArray()
	{
		if(!isset($this->arBucket))
		{
			self::_init();
			$this->arBucket = self::$arBuckets[$this->_ID];
		}
		return $this->arBucket;
	}
	/**
	 * @return CCloudStorageService
	*/
	public function getService()
	{
		return $this->service;
	}
	/**
	 * @param string $str
	 * @return string
	*/
	private function CompileModuleRule($str)
	{
		$res = array();
		$ar = explode(",", $str);
		foreach($ar as $s)
		{
			$s = trim($s);
			if($s !== '')
				$res[$s] = preg_quote($s, '/');
		}
		if(!empty($res))
			return "/^(".implode("|", $res).")\$/";
		else
			return "";
	}
	/**
	 * @param string $str
	 * @return string
	*/
	private function CompileExtentionRule($str)
	{
		$res = array();
		$ar = explode(",", $str);
		foreach($ar as $s)
		{
			$s = trim($s);
			if($s !== '')
				$res[$s] = preg_quote(".".$s, '/');
		}
		if(!empty($res))
			return "/(".implode("|", $res).")\$/i";
		else
			return "";
	}
	/**
	 * @param string $str
	 * @return double
	*/
	private function ParseSize($str)
	{
		static $scale = array(
			'' => 1.0,
			'K' => 1024.0,
			'M' => 1048576.0,
			'G' => 1073741824.0,
		);
		$str = strtoupper(trim($str));
		if($str !== '' && preg_match("/([0-9.]+)(|K|M|G)\$/", $str, $match) > 0)
		{
			return doubleval($match[1])*$scale[$match[2]];
		}
		else
		{
			return 0.0;
		}
	}
	/**
	 * @param string $str
	 * @return array[int][int]double
	*/
	private function CompileSizeRule($str)
	{
		$res = /*.(array[int][int]double).*/array();
		$ar = explode(",", $str);
		foreach($ar as $s)
		{
			$s = trim($s);
			if($s !== '')
			{
				$arSize = explode("-", $s);
				if(count($arSize) == 1)
					$res[] = array(self::ParseSize($arSize[0]), self::ParseSize($arSize[0]));
				else
					$res[] = array(self::ParseSize($arSize[0]), self::ParseSize($arSize[1]));
			}
		}
		return $res;
	}
	/**
	 * @param array[int][string]string $arRules
	 * @return array[int][string]string
	*/
	private function CompileRules($arRules)
	{
		$arCompiled = /*.(array[int][string]string).*/array();
		if(is_array($arRules))
		{
			foreach($arRules as $rule)
			{
				if(is_array($rule))
				{
					$arCompiled[] = array(
						"MODULE_MASK" => isset($rule["MODULE"])? self::CompileModuleRule($rule["MODULE"]): "",
						"EXTENTION_MASK" => isset($rule["EXTENSION"])? self::CompileExtentionRule($rule["EXTENSION"]): "",
						"SIZE_ARRAY" => isset($rule["SIZE"])? self::CompileSizeRule($rule["SIZE"]): "",
					);
				}
			}
		}
		return $arCompiled;
	}
	/**
	 * @return void
	*/
	private static function _init()
	{
		global $DB, $CACHE_MANAGER;

		if(isset(self::$arBuckets))
			return;

		$cache_id = "cloud_buckets_v2";
		if(
			CACHED_b_clouds_file_bucket !== false
			&& $CACHE_MANAGER->Read(CACHED_b_clouds_file_bucket, $cache_id, "b_clouds_file_bucket")
		)
		{
			self::$arBuckets = $CACHE_MANAGER->Get($cache_id);
		}
		else
		{
			self::$arBuckets = /*.(array[int]CCloudStorageBucket).*/array();

			$rs = $DB->Query("
				SELECT *
				FROM b_clouds_file_bucket
				ORDER BY SORT DESC, ID ASC
			");
			while(is_array($ar = $rs->Fetch()))
			{
				if($ar["FILE_RULES"] != "")
					$arRules = unserialize($ar["FILE_RULES"]);
				else
					$arRules = array();

				$ar["FILE_RULES_COMPILED"] = self::CompileRules($arRules);

				if($ar["SETTINGS"] != "")
					$arSettings = unserialize($ar["SETTINGS"]);
				else
					$arSettings = array();

				if(is_array($arSettings))
					$ar["SETTINGS"] = $arSettings;
				else
					$ar["SETTINGS"] = array();

				self::$arBuckets[intval($ar['ID'])] = $ar;
			}

			if(CACHED_b_clouds_file_bucket !== false)
				$CACHE_MANAGER->Set($cache_id, self::$arBuckets);
		}
	}
	/**
	 * @param string $name
	 * @return mixed
	*/
	function __get($name)
	{
		if(!isset($this->arBucket))
		{
			self::_init();
			$this->arBucket = self::$arBuckets[$this->_ID];
		}

		if(isset($this->arBucket) && array_key_exists($name, $this->arBucket))
			return $this->arBucket[$name];
		else
			return null;
	}
	/**
	 * @return bool
	*/
	function Init()
	{
		if(is_object($this->service))
		{
			return true;
		}
		else
		{
			if($this->SERVICE_ID)
				$this->service = CCloudStorage::GetServiceByID($this->SERVICE_ID);
			return is_object($this->service);
		}
	}
	/**
	 * @return bool
	*/
	function RenewToken()
	{
		if ($this->service->tokenHasExpired)
		{
			$newSettings = false;
			foreach(GetModuleEvents("clouds", "OnExpiredToken", true) as $arEvent)
			{
				$newSettings = ExecuteModuleEventEx($arEvent, array($this->arBucket));
				if ($newSettings)
					break;
			}
			if ($newSettings)
			{
				$updateResult = $this->Update(array("SETTINGS" => $newSettings));
				if ($updateResult)
				{
					$this->service->tokenHasExpired = false;
					return true;
				}
			}
		}

		return false;
	}
	/**
	 * @param array[string]string $arSettings
	 * @return bool
	*/
	function CheckSettings(&$arSettings)
	{
		return $this->service->CheckSettings($this->arBucket, $arSettings);
	}
	/**
	 * @return bool
	*/
	function CreateBucket()
	{
		return $this->service->CreateBucket($this->arBucket);
	}
	/**
	 * @param mixed $arFile
	 * @return string
	*/
	function GetFileSRC($arFile)
	{
		if(is_array($arFile) && isset($arFile["URN"]))
			return $this->service->GetFileSRC($this->arBucket, $arFile["URN"]);
		else
			return preg_replace("'(?<!:)/+'s", "/", $this->service->GetFileSRC($this->arBucket, $arFile));
	}
	/**
	 * @param string $filePath
	 * @return bool
	*/
	function FileExists($filePath)
	{
		return $this->service->FileExists($this->arBucket, $filePath);
	}
	/**
	 * @param mixed $arFile
	 * @param string $filePath
	 * @return bool
	*/
	function DownloadToFile($arFile, $filePath)
	{
		return $this->service->DownloadToFile($this->arBucket, $arFile, $filePath);
	}
	/**
	 * @param string $filePath
	 * @param mixed $arFile
	 * @return bool
	*/
	function SaveFile($filePath, $arFile)
	{
		$result = $this->service->SaveFile($this->arBucket, $filePath, $arFile);
		if (!$result && $this->RenewToken())
		{
			$result = $this->service->SaveFile($this->getBucketArray(), $filePath, $arFile);
		}

		if ($result)
		{
			foreach(GetModuleEvents("clouds", "OnAfterSaveFile", true) as $arEvent)
			{
				ExecuteModuleEventEx($arEvent, array($this, $arFile, $filePath));
			}
		}
		return $result;
	}
	/**
	 * @param string $filePath
	 * @return bool
	*/
	function DeleteFile($filePath)
	{
		$result = $this->service->DeleteFile($this->arBucket, $filePath);
		if ($result)
		{
			foreach(GetModuleEvents("clouds", "OnAfterDeleteFile", true) as $arEvent)
			{
				ExecuteModuleEventEx($arEvent, array($this, array('del' => 'Y'), $filePath));
			}
		}
		return $result;
	}
	/**
	 * @param mixed $arFile
	 * @param string $filePath
	 * @return bool
	*/
	function FileCopy($arFile, $filePath)
	{
		$result = $this->service->FileCopy($this->arBucket, $arFile, $filePath);
		if ($result)
		{
			foreach(GetModuleEvents("clouds", "OnAfterCopyFile", true) as $arEvent)
			{
				ExecuteModuleEventEx($arEvent, array($this, $arFile, $filePath));
			}
		}
		return $result;
	}
	/**
	 * @param string $sourcePath
	 * @param string $targetPath
	 * @param bool $overwrite
	 * @return bool
	*/
	function FileRename($sourcePath, $targetPath, $overwrite = true)
	{
		$result = $this->service->FileRename($this->arBucket, $sourcePath, $targetPath, $overwrite);
		if ($result)
		{
			foreach(GetModuleEvents("clouds", "OnAfterRenameFile", true) as $arEvent)
			{
				ExecuteModuleEventEx($arEvent, array($this, $sourcePath, $targetFile));
			}
		}
		return $result;
	}
	/**
	 * @param string $filePath
	 * @param bool $bRecursive
	 * @return array[string][int]string
	*/
	function ListFiles($filePath = "/", $bRecursive = false)
	{
		$result = $this->service->ListFiles($this->arBucket, $filePath, $bRecursive);
		if (!$result && $this->RenewToken())
		{
			$result = $this->service->ListFiles($this->getBucketArray(), $filePath, $bRecursive);
		}
		return $result;
	}
	/**
	 * @param string $filePath
	 * @return double
	*/
	function GetFileSize($filePath)
	{
		$DIR_NAME = substr($filePath, 0, strrpos($filePath, "/") + 1);
		$FILE_NAME = substr($filePath, strlen($DIR_NAME));

		$arListing = $this->service->ListFiles($this->arBucket, $DIR_NAME, false);
		if(is_array($arListing))
		{
			foreach($arListing["file"] as $i => $name)
				if($name === $FILE_NAME)
					return doubleval($arListing["file_size"][$i]);
		}
		return 0.0;
	}
	/**
	 * @return array[int][string]string
	*/
	static function GetAllBuckets()
	{
		self::_init();
		return self::$arBuckets;
	}
	/**
	 * @param array[string]string $arFields
	 * @param int $ID
	 * @return bool
	*/
	function CheckFields(&$arFields, $ID)
	{
		global $APPLICATION;
		$aMsg = array();

		if(array_key_exists("ACTIVE", $arFields))
			$arFields["ACTIVE"] = $arFields["ACTIVE"] === "N"? "N": "Y";

		if(array_key_exists("READ_ONLY", $arFields))
			$arFields["READ_ONLY"] = $arFields["READ_ONLY"] === "Y"? "Y": "N";

		$arServices = CCloudStorage::GetServiceList();
		if(isset($arFields["SERVICE_ID"]))
		{
			if(!array_key_exists($arFields["SERVICE_ID"], $arServices))
				$aMsg[] = array("id" => "SERVICE_ID", "text" => GetMessage("CLO_STORAGE_WRONG_SERVICE"));
		}

		if(isset($arFields["BUCKET"]))
		{
			$arFields["BUCKET"] = trim($arFields["BUCKET"]);

			$bBadLength = false;
			if(strpos($arFields["BUCKET"], ".") !== false)
			{
				$arName = explode(".", $arFields["BUCKET"]);
				$bBadLength = false;
				foreach($arName as $str)
					if(strlen($str) < 2 || strlen($str) > 63)
						$bBadLength = true;
			}

			if(strlen($arFields["BUCKET"]) <= 0)
				$aMsg[] = array("id" => "BUCKET", "text" => GetMessage("CLO_STORAGE_EMPTY_BUCKET"));
			if(preg_match("/[^a-z0-9._-]/", $arFields["BUCKET"]) > 0)
				$aMsg[] = array("id" => "BUCKET", "text" => GetMessage("CLO_STORAGE_BAD_BUCKET_NAME"));
			if(strlen($arFields["BUCKET"]) < 2 || strlen($arFields["BUCKET"]) > 63)
				$aMsg[] = array("id" => "BUCKET", "text" => GetMessage("CLO_STORAGE_WRONG_BUCKET_NAME_LENGTH"));
			if($bBadLength)
				$aMsg[] = array("id" => "BUCKET", "text" => GetMessage("CLO_STORAGE_WRONG_BUCKET_NAME_LENGTH2"));
			if(!preg_match("/^[a-z0-9].*[a-z0-9]\$/", $arFields["BUCKET"]))
				$aMsg[] = array("id" => "BUCKET", "text" => GetMessage("CLO_STORAGE_BAD_BUCKET_NAME2"));
			if(preg_match("/(-\\.|\\.-)/", $arFields["BUCKET"]) > 0)
				$aMsg[] = array("id" => "BUCKET", "text" => GetMessage("CLO_STORAGE_BAD_BUCKET_NAME3"));

			if(strlen($arFields["BUCKET"]) > 0)
			{
				$rsBucket = self::GetList(array(), array(
					"=SERVICE_ID" => $arFields["SERVICE_ID"],
					"=BUCKET" => $arFields["BUCKET"],
				));
				$arBucket = $rsBucket->Fetch();
				if(is_array($arBucket) && $arBucket["ID"] != $ID)
					$aMsg[] = array("id" => "BUCKET", "text" => GetMessage("CLO_STORAGE_BUCKET_ALREADY_EXISTS"));
			}
		}

		if(!empty($aMsg))
		{
			$e = new CAdminException($aMsg);
			$APPLICATION->ThrowException($e);
			return false;
		}
		return true;
	}
	/**
	 * @param array[string]string $arOrder
	 * @param array[string]string $arFilter
	 * @param array[string]string $arSelect
	 * @return CDBResult
	*/
	static function GetList($arOrder=false, $arFilter=false, $arSelect=false)
	{
		global $DB;

		if(!is_array($arSelect))
			$arSelect =/*.(array[string]string).*/array();
		if(count($arSelect) < 1)
			$arSelect = array(
				"ID",
				"ACTIVE",
				"READ_ONLY",
				"SORT",
				"SERVICE_ID",
				"LOCATION",
				"BUCKET",
				"SETTINGS",
				"CNAME",
				"PREFIX",
				"FILE_COUNT",
				"FILE_SIZE",
				"LAST_FILE_ID",
				"FILE_RULES",
			);

		if(!is_array($arOrder))
			$arOrder =/*.(array[string]string).*/array();

		$arQueryOrder = array();
		foreach($arOrder as $strColumn => $strDirection)
		{
			$strColumn = strtoupper($strColumn);
			$strDirection = strtoupper($strDirection)==="ASC"? "ASC": "DESC";
			switch($strColumn)
			{
				case "ID":
				case "SORT":
					$arSelect[] = $strColumn;
					$arQueryOrder[$strColumn] = $strColumn." ".$strDirection;
					break;
				default:
					break;
			}
		}

		$arQuerySelect = array();
		foreach($arSelect as $strColumn)
		{
			$strColumn = strtoupper($strColumn);
			switch($strColumn)
			{
				case "ID":
				case "ACTIVE":
				case "READ_ONLY":
				case "SORT":
				case "SERVICE_ID":
				case "LOCATION":
				case "BUCKET":
				case "SETTINGS":
				case "CNAME":
				case "PREFIX":
				case "FILE_COUNT":
				case "FILE_SIZE":
				case "LAST_FILE_ID":
				case "FILE_RULES":
					$arQuerySelect[$strColumn] = "s.".$strColumn;
					break;
			}
		}
		if(count($arQuerySelect) < 1)
			$arQuerySelect = array("ID"=>"s.ID");

		$obQueryWhere = new CSQLWhere;
		$arFields = array(
			"ID" => array(
				"TABLE_ALIAS" => "s",
				"FIELD_NAME" => "s.ID",
				"FIELD_TYPE" => "int",
			),
			"ACTIVE" => array(
				"TABLE_ALIAS" => "s",
				"FIELD_NAME" => "s.ACTIVE",
				"FIELD_TYPE" => "string",
			),
			"READ_ONLY" => array(
				"TABLE_ALIAS" => "s",
				"FIELD_NAME" => "s.READ_ONLY",
				"FIELD_TYPE" => "string",
			),
			"SERVICE_ID" => array(
				"TABLE_ALIAS" => "s",
				"FIELD_NAME" => "s.SERVICE_ID",
				"FIELD_TYPE" => "string",
			),
			"BUCKET" => array(
				"TABLE_ALIAS" => "s",
				"FIELD_NAME" => "s.BUCKET",
				"FIELD_TYPE" => "string",
			),
		);
		$obQueryWhere->SetFields($arFields);

		if(!is_array($arFilter))
			$arFilter =/*.(array[string]string).*/array();
		$strQueryWhere = $obQueryWhere->GetQuery($arFilter);

		$bDistinct = $obQueryWhere->bDistinctReqired;

		$strSql = "
			SELECT ".($bDistinct? "DISTINCT": "")."
			".implode(", ", $arQuerySelect)."
			FROM
				b_clouds_file_bucket s
			".$obQueryWhere->GetJoins()."
		";

		if($strQueryWhere != "")
		{
			$strSql .= "
				WHERE
				".$strQueryWhere."
			";
		}

		if(count($arQueryOrder) > 0)
		{
			$strSql .= "
				ORDER BY
				".implode(", ", $arQueryOrder)."
			";
		}

		return $DB->Query($strSql);
	}
	/**
	 * @param array[string]string $arFields
	 * @return mixed
	*/
	function Add($arFields)
	{
		global $DB, $APPLICATION, $CACHE_MANAGER;
		$strError = '';
		$this->_ID = 0;

		if(!$this->CheckFields($arFields, 0))
			return false;

		$arFields["FILE_COUNT"] = 0;
		if(is_array($arFields["FILE_RULES"]))
			$arFields["FILE_RULES"] = serialize($arFields["FILE_RULES"]);
		else
			$arFields["FILE_RULES"] = false;

		$this->arBucket = $arFields;
		if($this->Init())
		{

			if(!$this->CheckSettings($arFields["SETTINGS"]))
				return false;
			$this->arBucket["SETTINGS"] = $arFields["SETTINGS"];

			if($this->CreateBucket())
			{
				$arFields["SETTINGS"] = serialize($arFields["SETTINGS"]);
				$this->_ID = $DB->Add("b_clouds_file_bucket", $arFields);
				self::$arBuckets = null;
				$this->arBucket = null;
				if(CACHED_b_clouds_file_bucket !== false)
					$CACHE_MANAGER->CleanDir("b_clouds_file_bucket");
				return $this->_ID;
			}
			else
			{
				$e = $APPLICATION->GetException();
				if(is_object($e))
					$strError = GetMessage("CLO_STORAGE_CLOUD_ADD_ERROR", array("#error_msg#" => $e->GetString()));
				else
					$strError = GetMessage("CLO_STORAGE_CLOUD_ADD_ERROR", array("#error_msg#" => 'CSB42343'));
			}
		}
		else
		{
			$strError = GetMessage("CLO_STORAGE_CLOUD_ADD_ERROR", array("#error_msg#" => GetMessage("CLO_STORAGE_UNKNOWN_SERVICE")));
		}

		$APPLICATION->ResetException();
		$e = new CApplicationException($strError);
		$APPLICATION->ThrowException($e);
		return false;
	}
	/**
	 * @return bool
	*/
	function Delete()
	{
		global $DB, $APPLICATION, $CACHE_MANAGER;
		$strError = '';

		if($this->Init())
		{
			if($this->service->IsEmptyBucket($this->arBucket))
			{
				if($this->service->DeleteBucket($this->arBucket))
				{
					$res = $DB->Query("DELETE FROM b_clouds_file_bucket WHERE ID = ".$this->_ID);
					if(CACHED_b_clouds_file_bucket !== false)
						$CACHE_MANAGER->CleanDir("b_clouds_file_bucket");
					if(is_object($res))
					{
						$this->arBucket = null;
						$this->_ID = 0;
						return true;
					}
					else
					{
						$strError = GetMessage("CLO_STORAGE_DB_DELETE_ERROR");
					}
				}
				else
				{
					$e = $APPLICATION->GetException();
					$strError = GetMessage("CLO_STORAGE_CLOUD_DELETE_ERROR", array("#error_msg#" => is_object($e)? $e->GetString(): ''));
				}
			}
			else
			{
				$e = $APPLICATION->GetException();
				if(is_object($e))
					$strError = GetMessage("CLO_STORAGE_CLOUD_DELETE_ERROR", array("#error_msg#" => $e->GetString()));
				else
					$strError = GetMessage("CLO_STORAGE_CLOUD_BUCKET_NOT_EMPTY");
			}
		}
		else
		{
			$strError = GetMessage("CLO_STORAGE_CLOUD_DELETE_ERROR", array("#error_msg#" => GetMessage("CLO_STORAGE_UNKNOWN_SERVICE")));
		}

		$APPLICATION->ResetException();
		$e = new CApplicationException($strError);
		$APPLICATION->ThrowException($e);
		return false;
	}
	/**
	 * @param array[string]string $arFields
	 * @return mixed
	*/
	function Update($arFields)
	{
		global $DB, $CACHE_MANAGER;

		if($this->_ID <= 0)
			return false;

		$this->service = CCloudStorage::GetServiceByID($this->SERVICE_ID);
		if(!is_object($this->service))
			return false;

		unset($arFields["FILE_COUNT"]);
		unset($arFields["SERVICE_ID"]);
		unset($arFields["LOCATION"]);
		unset($arFields["BUCKET"]);

		if(!$this->CheckFields($arFields, $this->_ID))
			return false;

		if(array_key_exists("FILE_RULES", $arFields))
		{
			if(is_array($arFields["FILE_RULES"]))
				$arFields["FILE_RULES"] = serialize($arFields["FILE_RULES"]);
			else
				$arFields["FILE_RULES"] = false;
		}

		if(array_key_exists("SETTINGS", $arFields))
		{
			if(!$this->CheckSettings($arFields["SETTINGS"]))
				return false;
			$arFields["SETTINGS"] = serialize($arFields["SETTINGS"]);
		}

		$strUpdate = $DB->PrepareUpdate("b_clouds_file_bucket", $arFields);
		if(strlen($strUpdate) > 0)
		{
			$strSql = "
				UPDATE b_clouds_file_bucket SET
				".$strUpdate."
				WHERE ID = ".$this->_ID."
			";
			if(!is_object($DB->Query($strSql)))
				return false;
		}

		self::$arBuckets = null;
		$this->arBucket = null;
		if(CACHED_b_clouds_file_bucket !== false)
			$CACHE_MANAGER->CleanDir("b_clouds_file_bucket");

		return $this->_ID;
	}
	/**
	 * @param array[string][int]string $arPOST
	 * @return array[int][string]string
	*/
	static function ConvertPOST($arPOST)
	{
		$arRules =/*.(array[int][string]string).*/array();

		if(isset($arPOST["MODULE"]) && is_array($arPOST["MODULE"]))
		{
			foreach($arPOST["MODULE"] as $i => $MODULE)
			{
				if(!isset($arRules[intval($i)]))
					$arRules[intval($i)] = array("MODULE" => "", "EXTENSION" => "", "SIZE" => "");
				$arRules[intval($i)]["MODULE"] = $MODULE;
			}
		}

		if(isset($arPOST["EXTENSION"]) && is_array($arPOST["EXTENSION"]))
		{
			foreach($arPOST["EXTENSION"] as $i => $EXTENSION)
			{
				if(!isset($arRules[intval($i)]))
					$arRules[intval($i)] = array("MODULE" => "", "EXTENSION" => "", "SIZE" => "");
				$arRules[intval($i)]["EXTENSION"] = $EXTENSION;
			}
		}

		if(isset($arPOST["SIZE"]) && is_array($arPOST["SIZE"]))
		{
			foreach($arPOST["SIZE"] as $i => $SIZE)
			{
				if(!isset($arRules[intval($i)]))
					$arRules[intval($i)] = array("MODULE" => "", "EXTENSION" => "", "SIZE" => "");
				$arRules[intval($i)]["SIZE"] = $SIZE;
			}
		}

		return $arRules;
	}
	/**
	 * @param string $name
	 * @param string $value
	 * @return void
	*/
	function setHeader($name, $value)
	{
		$this->service->setHeader($name, $value);
	}
}
classes/mysql/storage_bucket.php000064400000002744150241560060013066 0ustar00<?php
class CAllCloudStorageBucket
{
	protected/*.int.*/$_ID = 0;
	/**
	 * @param double $file_size
	 * @param int $file_count
	 * @return CDBResult
	*/
	public function SetFileCounter($file_size, $file_count)
	{
		global $DB, $CACHE_MANAGER;
		$res = $DB->Query("
			UPDATE b_clouds_file_bucket
			SET FILE_COUNT = ".intval($file_count)."
			,FILE_SIZE = ".roundDB($file_size)."
			WHERE ID = ".$this->_ID."
		");
		if(CACHED_b_clouds_file_bucket !== false)
			$CACHE_MANAGER->CleanDir("b_clouds_file_bucket");
		return $res;
	}
	/**
	 * @param double $file_size
	 * @return CDBResult
	*/
	function IncFileCounter($file_size = 0.0)
	{
		global $DB, $CACHE_MANAGER;
		$res = $DB->Query("
			UPDATE b_clouds_file_bucket
			SET FILE_COUNT = FILE_COUNT + 1
			".($file_size > 0.0? ",FILE_SIZE = FILE_SIZE + ".roundDB($file_size): "")."
			WHERE ID = ".$this->_ID."
		");
		if(CACHED_b_clouds_file_bucket !== false)
			$CACHE_MANAGER->CleanDir("b_clouds_file_bucket");
		return $res;
	}
	/**
	 * @param double $file_size
	 * @return CDBResult
	*/
	function DecFileCounter($file_size = 0.0)
	{
		global $DB, $CACHE_MANAGER;
		$res = $DB->Query("
			UPDATE b_clouds_file_bucket
			SET FILE_COUNT = FILE_COUNT - 1
			".($file_size > 0.0? ",FILE_SIZE = if(FILE_SIZE - ".roundDB($file_size)." > 0, FILE_SIZE - ".roundDB($file_size).", 0)": "")."
			WHERE ID = ".$this->_ID." AND FILE_COUNT > 0
		");
		if(CACHED_b_clouds_file_bucket !== false)
			$CACHE_MANAGER->CleanDir("b_clouds_file_bucket");
		return $res;
	}
}
admin/task_description.php000064400000001411150241560060011706 0ustar00<?
if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true)
	die();

use Bitrix\Main\Localization\Loc;

Loc::loadMessages(__FILE__);

return array(
	"CLOUDS_DENIED" => array(
		"title" => Loc::getMessage('TASK_NAME_CLOUDS_DENIED'),
		"description" => Loc::getMessage('TASK_DESC_CLOUDS_DENIED'),
	),
	"CLOUDS_BROWSE" => array(
		"title" => Loc::getMessage('TASK_NAME_CLOUDS_BROWSE'),
		"description" => Loc::getMessage('TASK_DESC_CLOUDS_BROWSE'),
	),
	"CLOUDS_UPLOAD" => array(
		"title" => Loc::getMessage('TASK_NAME_CLOUDS_UPLOAD'),
		"description" => Loc::getMessage('TASK_DESC_CLOUDS_UPLOAD'),
	),
	"CLOUDS_FULL_ACCESS" => array(
		"title" => Loc::getMessage('TASK_NAME_CLOUDS_FULL_ACCESS'),
		"description" => Loc::getMessage('TASK_DESC_CLOUDS_FULL_ACCESS'),
	),
);
admin/menu.php000064400000001064150241560060007311 0ustar00<?
/*.require_module 'bitrix_main_include_prolog_admin_before';.*/
IncludeModuleLangFile(__FILE__);

if(!$USER->CanDoOperation("clouds_config"))
	return false;

$arMenu = array(
	"parent_menu" => "global_menu_settings",
	"section" => "clouds",
	"sort" => 1650,
	"text" => GetMessage("CLO_MENU_ITEM"),
	"title" => GetMessage("CLO_MENU_TITLE"),
	"url" => "clouds_storage_list.php?lang=".LANGUAGE_ID,
	"more_url" => array("clouds_storage_list.php", "clouds_storage_edit.php"),
	"icon" => "clouds_menu_icon",
	"page_icon" => "clouds_page_icon",
);

return $arMenu;
?>
admin/clouds_storage_list.php000064400000034545150241560060012427 0ustar00<?
define("ADMIN_MODULE_NAME", "clouds");

/*.require_module 'standard';.*/
/*.require_module 'pcre';.*/
/*.require_module 'bitrix_main_include_prolog_admin_before';.*/
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_admin_before.php");
if(!$USER->CanDoOperation("clouds_config"))
	$APPLICATION->AuthForm(GetMessage("ACCESS_DENIED"));

/*.require_module 'bitrix_clouds_include';.*/
if(!CModule::IncludeModule('clouds'))
	$APPLICATION->AuthForm(GetMessage("ACCESS_DENIED"));

IncludeModuleLangFile(__FILE__);

$io = CBXVirtualIo::GetInstance();
$sTableID = "tbl_clouds_storage_list";
$oSort = new CAdminSorting($sTableID, "ID", "ASC");
$lAdmin = new CAdminList($sTableID, $oSort);
$bOnTheMove = isset($_GET["themove"]);

$upload_dir = $_SERVER["DOCUMENT_ROOT"]."/".COption::GetOptionString("main", "upload_dir", "upload");
$bHasLocalStorage = file_exists($upload_dir) && (is_dir($upload_dir) || is_link($upload_dir)) && is_writable($upload_dir);

$arID = $lAdmin->GroupAction();
$action = isset($_REQUEST["action"]) && is_string($_REQUEST["action"])? "$_REQUEST[action]": "";
if(is_array($arID))
{
	foreach($arID as $ID)
	{
		if(strlen($ID) <= 0 || intval($ID) <= 0)
			continue;

		switch($action)
		{
		case "delete":
			$ob = new CCloudStorageBucket(intval($ID));
			if(!$ob->Delete())
			{
				$e = $APPLICATION->GetException();
				$lAdmin->AddUpdateError($e->GetString(), $ID);
			}
			break;
		case "deactivate":
			$ob = new CCloudStorageBucket(intval($ID));
			if($ob->ACTIVE === "Y")
				$ob->Update(array("ACTIVE"=>"N"));
			break;
		case "activate":
			$ob = new CCloudStorageBucket(intval($ID));
			if($ob->ACTIVE === "N")
				$ob->Update(array("ACTIVE"=>"Y"));
			break;
		case "download":
			$ob = new CCloudStorageBucket(intval($ID));
			if($ob->Init() && $ob->ACTIVE === "Y")
			{
				if(isset($_SESSION["last_file_id"]))
					$last_file_id = intval($_SESSION["last_file_id"]);
				else
					$last_file_id = 0;

				if(isset($_SESSION["last_file_pos"]))
					$last_file_pos = doubleval($_SESSION["last_file_pos"]);
				else
					$last_file_pos = 0;

				$rsNextFile = $DB->Query("
					SELECT MIN(ID) ID, COUNT(1) CNT, SUM(FILE_SIZE) FILE_SIZE
					FROM b_file
					WHERE ID > ".intval($last_file_id)."
					AND HANDLER_ID = '".$DB->ForSQL($ob->ID)."'
				");

				$lAdmin->BeginPrologContent();
				if(
					is_array($ar = $rsNextFile->Fetch())
					&& (intval($ar["ID"]) > 0)
				)
				{
					$bNextFile = true;
					$bFileMoved = false;
					$maxPartSize = 1024*1024; //1M

					$arFile = CFile::GetFileArray($ar["ID"]);
					$filePath = preg_replace("#[\\\\\\/]+#", "/", "/".$arFile["SUBDIR"]."/".$arFile["FILE_NAME"]);
					$absPath = preg_replace("#[\\\\\\/]+#", "/", $_SERVER["DOCUMENT_ROOT"]."/".COption::GetOptionString("main", "upload_dir", "upload").$filePath);
					$absPath = $io->GetPhysicalName($absPath);
					$absTempPath = $absPath."~";

					if(!file_exists($absPath))
					{
						CheckDirPath($absTempPath);

						$obRequest = new CHTTP;
						$obRequest->follow_redirect = true;
						$obRequest->fp = fopen($absTempPath, "ab");
						if(is_resource($obRequest->fp))
						{
							if($arFile["FILE_SIZE"] > $maxPartSize)
							{
								$obRequest->additional_headers["Range"] = sprintf("bytes=%u-%u", $last_file_pos, ($last_file_pos+$maxPartSize > $arFile["FILE_SIZE"]? $arFile["FILE_SIZE"]: $last_file_pos+$maxPartSize)-1);
							}

							$res = $obRequest->HTTPQuery('GET', $ob->GetFileSRC($arFile));

							fclose($obRequest->fp);
							unset($obRequest->fp);

							if($res && ($obRequest->status == 200 || $obRequest->status == 206))
							{
								$bFileMoved = true;
								if($arFile["FILE_SIZE"] > $maxPartSize)
								{
									$last_file_pos += $maxPartSize;
									$_SESSION["last_file_pos"] = $last_file_pos;
									$bNextFile = false;
								}
								else
								{
									$last_file_pos = $arFile["FILE_SIZE"];
								}

								if(
									array_key_exists("Content-Range", $obRequest->headers)
									&& preg_match("/(\\d+)-(\\d+)\\/(\\d+)\$/", $obRequest->headers["Content-Range"], $match)
								)
									$FILE_SIZE = $match[3];
								elseif(
									array_key_exists("Content-Length", $obRequest->headers)
									&& preg_match("/^(\\d+)\$/", $obRequest->headers["Content-Length"], $match)
									&& $match[1] > $maxPartSize
								)
									$FILE_SIZE = 0; //Chunk download not supported
								else
									$FILE_SIZE = $arFile["FILE_SIZE"];

								if($last_file_pos > $FILE_SIZE)
								{
									$last_file_pos = $arFile["FILE_SIZE"];
									$bFileMoved = true;
									$bNextFile = true;
								}
							}
							else
							{
								//An error occured
								@unlink($absTempPath);
								$bFileMoved = false;
							}
						}
					}

					if($bNextFile)
					{
						$_SESSION["last_file_id"] = $ar["ID"];
						$_SESSION["last_file_pos"] = 0.0;

						if($bFileMoved)
						{
							rename($absTempPath, $absPath);
							$ob->DeleteFile($filePath);
							$DB->Query("
								UPDATE b_file
								SET HANDLER_ID = null
								WHERE ID = ".intval($arFile["ID"])."
							");
							CFile::CleanCache($arFile["ID"]);
							$ob->DecFileCounter((float)$arFile["FILE_SIZE"]);
							$ob->Update(array("LAST_FILE_ID" => 0));
						}
					}

					CAdminMessage::ShowMessage(array(
						"TYPE"=>"PROGRESS",
						"MESSAGE"=>GetMessage("CLO_STORAGE_LIST_DOWNLOAD_IN_PROGRESS"),
						"DETAILS"=>GetMessage("CLO_STORAGE_LIST_DOWNLOAD_PROGRESS", array(
							"#remain#" => $ar["CNT"] - $bNextFile,
							"#bytes#" => CFile::FormatSize($ar["FILE_SIZE"] - $last_file_pos),
						)),
						"HTML"=>true,
						"BUTTONS" => array(
							array(
								"VALUE" => GetMessage("CLO_STORAGE_LIST_STOP"),
								"ONCLICK" => 'window.location = \'/bitrix/admin/clouds_storage_list.php?lang='.LANGUAGE_ID.'\'',
							),
						),
					));

					$bOnTheMove = true;
					echo '<script>', $lAdmin->ActionDoGroup($ID, "download", "themove=y"), '</script>';
				}
				else
				{
					unset($_SESSION["last_file_id"]);
					unset($_SESSION["last_file_pos"]);

					CAdminMessage::ShowMessage(array(
						"MESSAGE"=>GetMessage("CLO_STORAGE_LIST_DOWNLOAD_DONE"),
						"TYPE"=>"OK",
						"HTML"=>true,
					));
					$bOnTheMove = false;
				}
				$lAdmin->EndPrologContent();
			}
			break;
		case "move":
			$message = /*.(CAdminMessage).*/null;
			$ob = new CCloudStorageBucket(intval($ID));
			if($ob->ACTIVE === "Y" && $ob->READ_ONLY === "N")
			{
				$_done = 0;
				$_size = 0.0;
				$_skip = 0;

				if(intval($ob->LAST_FILE_ID) > 0)
				{
					if(isset($_SESSION["arMoveStat_done"]))
						$_done = intval($_SESSION["arMoveStat_done"]);
					if(isset($_SESSION["arMoveStat_size"]))
						$_size = doubleval($_SESSION["arMoveStat_size"]);
					if(isset($_SESSION["arMoveStat_skip"]))
						$_skip = intval($_SESSION["arMoveStat_skip"]);
				}

				$files_per_step = 50;
				$rsNextFile = $DB->Query($DB->TopSQL("
					SELECT *
					FROM b_file
					WHERE ID > ".intval($ob->LAST_FILE_ID)."
					AND (HANDLER_ID IS NULL OR HANDLER_ID <> '".$DB->ForSQL($ob->ID)."')
					ORDER BY ID ASC
				", $files_per_step));

				$counter = 0;
				$bWasMoved = false;
				$moveResult = CCloudStorage::FILE_SKIPPED;
				while(
					$moveResult == CCloudStorage::FILE_PARTLY_UPLOADED
					|| is_array($arFile = $rsNextFile->Fetch())
				)
				{
					CCloudStorage::FixFileContentType($arFile);
					$moveResult = CCloudStorage::MoveFile($arFile, $ob);
					if($moveResult == CCloudStorage::FILE_MOVED)
					{
						$DB->Query("
							UPDATE b_file
							SET HANDLER_ID = '".$DB->ForSQL($ob->ID)."'
							WHERE ID = ".intval($arFile["ID"])."
						");
						CFile::CleanCache($arFile["ID"]);
						$_done += 1;
						$_size += doubleval($arFile["FILE_SIZE"]);
						$bWasMoved = true;
						$ob->Update(array("LAST_FILE_ID" => $arFile["ID"]));
						$counter++;
					}
					elseif($moveResult == CCloudStorage::FILE_SKIPPED)
					{
						$e = $APPLICATION->GetException();
						if(is_object($e))
						{
							$message = new CAdminMessage(GetMessage("CLO_STORAGE_LIST_MOVE_FILE_ERROR"), $e);
							break;
						}
						else
						{
							$_skip += 1;
							$ob->Update(array("LAST_FILE_ID" => $arFile["ID"]));
							$counter++;
						}
					}
					else//if($moveResult == CCloudStorage::FILE_PARTLY_UPLOADED)
					{
						$bWasMoved = true;
					}

					if($bWasMoved)
					{
						usleep(300);
						break;
					}
				}

				$lAdmin->BeginPrologContent();
				if(is_object($message))
				{
					echo $message->Show();
				}
				elseif($counter < $files_per_step && !$bWasMoved)
				{
					CAdminMessage::ShowMessage(array(
						"MESSAGE"=>GetMessage("CLO_STORAGE_LIST_MOVE_DONE"),
						"DETAILS"=>GetMessage("CLO_STORAGE_LIST_MOVE_PROGRESS", array(
							"#bytes#" => CFile::FormatSize($_size),
							"#total#" => $_done + $_skip,
							"#moved#" => $_done,
							"#skiped#" => $_skip,
						)),
						"HTML"=>true,
						"TYPE"=>"OK",
					));
					$bOnTheMove = false;
					$ob->Update(array("LAST_FILE_ID" => false));
				}
				else
				{
					CAdminMessage::ShowMessage(array(
						"TYPE"=>"PROGRESS",
						"MESSAGE"=>GetMessage("CLO_STORAGE_LIST_MOVE_IN_PROGRESS"),
						"DETAILS"=>GetMessage("CLO_STORAGE_LIST_MOVE_PROGRESS", array(
							"#bytes#" => CFile::FormatSize($_size + CCloudStorage::$part_count*CCloudStorage::$part_size),
							"#total#" => $_done + $_skip,
							"#moved#" => $_done,
							"#skiped#" => $_skip,
						)),
						"HTML"=>true,
						"BUTTONS" => array(
							array(
								"VALUE" => GetMessage("CLO_STORAGE_LIST_STOP"),
								"ONCLICK" => 'window.location = \'/bitrix/admin/clouds_storage_list.php?lang='.LANGUAGE_ID.'\'',
							),
						),
					));
					$bOnTheMove = true;
					echo '<script>', $lAdmin->ActionDoGroup($ID, "move", "themove=y"), '</script>';
				}
				$lAdmin->EndPrologContent();

				$_SESSION["arMoveStat_done"] = $_done;
				$_SESSION["arMoveStat_size"] = $_size;
				$_SESSION["arMoveStat_skip"] = $_skip;
			}
			break;
		default:
			break;
		}
	}
}

$arHeaders = array(
	array(
		"id" => "SORT",
		"content" => GetMessage("CLO_STORAGE_LIST_SORT"),
		"align" => "right",
		"default" => true,
	),
	array(
		"id" => "ID",
		"content" => GetMessage("CLO_STORAGE_LIST_ID"),
		"align" => "right",
		"default" => true,
	),
	array(
		"id" => "ACTIVE",
		"content" => GetMessage("CLO_STORAGE_LIST_ACTIVE"),
		"align" => "center",
		"default" => true,
	),
	array(
		"id" => "FILE_COUNT",
		"content" => GetMessage("CLO_STORAGE_LIST_FILE_COUNT"),
		"align" => "right",
		"default" => true,
	),
	array(
		"id" => "FILE_SIZE",
		"content" => GetMessage("CLO_STORAGE_LIST_FILE_SIZE"),
		"align" => "right",
		"default" => true,
	),
	array(
		"id" => "READ_ONLY",
		"content" => GetMessage("CLO_STORAGE_LIST_MODE"),
		"align" => "center",
		"default" => true,
	),
	array(
		"id" => "SERVICE",
		"content" => GetMessage("CLO_STORAGE_LIST_SERVICE"),
		"default" => true,
	),
	array(
		"id" => "BUCKET",
		"content" => GetMessage("CLO_STORAGE_LIST_BUCKET"),
		"align" => "center",
		"default" => true,
	),
);
$lAdmin->AddHeaders($arHeaders);

$rsData = CCloudStorageBucket::GetList(array("SORT"=>"DESC", "ID"=>"ASC"));
$rsData = new CAdminResult($rsData, $sTableID);
while(is_array($arRes = $rsData->Fetch()))
{
	$row =& $lAdmin->AddRow($arRes["ID"], $arRes);

	$row->AddViewField("ID", '<a href="clouds_storage_edit.php?lang='.LANGUAGE_ID.'&ID='.$arRes["ID"].'">'.$arRes["ID"].'</a>');

	if($arRes["ACTIVE"] === "Y")
		$html = '<div class="lamp-green"></div>';
	else
		$html = '<div class="lamp-red"></div>';

	$row->AddViewField("ACTIVE", $html);
	$row->AddViewField("READ_ONLY", $arRes["READ_ONLY"]==="Y"? GetMessage("CLO_STORAGE_LIST_READ_ONLY"): GetMessage("CLO_STORAGE_LIST_READ_WRITE"));
	$row->AddViewField("SERVICE", CCloudStorage::GetServiceDescription($arRes["SERVICE_ID"]));
	$row->AddViewField("FILE_SIZE", CFile::FormatSize($arRes["FILE_SIZE"]));

	$arActions = array(
		array(
			"ICON" => "edit",
			"DEFAULT" => true,
			"TEXT" => GetMessage("CLO_STORAGE_LIST_EDIT"),
			"ACTION" => $lAdmin->ActionRedirect('clouds_storage_edit.php?lang='.LANGUAGE_ID.'&ID='.$arRes["ID"])
		)
	);
	$arActions[] = array("SEPARATOR"=>"Y");

	if($arRes["ACTIVE"] === "Y")
	{
		if($arRes["READ_ONLY"] !== "Y")
		{
			if(intval($arRes["LAST_FILE_ID"]) > 0)
			{
				$arActions[] = array(
					"TEXT"=>GetMessage("CLO_STORAGE_LIST_CONT_MOVE_FILES"),
					"ACTION"=>$lAdmin->ActionDoGroup($arRes["ID"], "move")
				);
			}
			else
			{
				$arActions[] = array(
					"TEXT"=>GetMessage("CLO_STORAGE_LIST_START_MOVE_FILES"),
					"ACTION"=>$lAdmin->ActionDoGroup($arRes["ID"], "move")
				);
			}
		}

		if($bHasLocalStorage)
		{
			$arActions[] = array(
				"TEXT"=>GetMessage("CLO_STORAGE_LIST_MOVE_LOCAL"),
				"ACTION"=>"if(confirm('".GetMessage("CLO_STORAGE_LIST_MOVE_LOCAL_CONF")."')) ".$lAdmin->ActionDoGroup($arRes["ID"], "download")
			);
		}

		$arActions[] = array(
			"TEXT"=>GetMessage("CLO_STORAGE_LIST_DEACTIVATE"),
			"ACTION"=>"if(confirm('".GetMessage("CLO_STORAGE_LIST_DEACTIVATE_CONF")."')) ".$lAdmin->ActionDoGroup($arRes["ID"], "deactivate")
		);
	}
	else
	{
		$arActions[] = array(
			"TEXT"=>GetMessage("CLO_STORAGE_LIST_ACTIVATE"),
			"ACTION"=>$lAdmin->ActionDoGroup($arRes["ID"], "activate")
		);
	}

	if(intval($arRes["B_FILE_COUNT"]) > 0)
	{
		$arActions[] = array(
			"ICON"=>"delete",
			"TEXT"=>GetMessage("CLO_STORAGE_LIST_DELETE"),
			"ACTION"=>"alert('".GetMessage("CLO_STORAGE_LIST_CANNOT_DELETE")."')"
		);
	}
	else
	{
		$arActions[] = array(
			"ICON"=>"delete",
			"TEXT"=>GetMessage("CLO_STORAGE_LIST_DELETE"),
			"ACTION"=>"if(confirm('".GetMessage("CLO_STORAGE_LIST_DELETE_CONF")."')) ".$lAdmin->ActionDoGroup($arRes["ID"], "delete")
		);
	}

	if(!empty($arActions) && !$bOnTheMove)
		$row->AddActions($arActions);

}

$arFooter = array(
	array(
		"title" => GetMessage("MAIN_ADMIN_LIST_SELECTED"),
		"value" => $rsData->SelectedRowsCount(),
	),
	array(
		"counter" => true,
		"title" => GetMessage("MAIN_ADMIN_LIST_CHECKED"),
		"value" => 0,
	),
);

$lAdmin->AddFooter($arFooter);

$aContext = array(
	array(
		"TEXT" => GetMessage("CLO_STORAGE_LIST_ADD"),
		"LINK" => "/bitrix/admin/clouds_storage_edit.php?lang=".LANGUAGE_ID,
		"TITLE" => GetMessage("CLO_STORAGE_LIST_ADD_TITLE"),
		"ICON" => "btn_new",
	),
);

$lAdmin->AddAdminContextMenu($aContext, /*$bShowExcel=*/false);

$lAdmin->CheckListMode();

$APPLICATION->SetTitle(GetMessage("CLO_STORAGE_LIST_TITLE"));

require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_admin_after.php");

$lAdmin->DisplayList();

require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/epilog_admin.php");
?>admin/clouds_file_list.php000064400000065137150241560060011703 0ustar00<?
define("ADMIN_MODULE_NAME", "clouds");

/*.require_module 'standard';.*/
/*.require_module 'pcre';.*/
/*.require_module 'bitrix_main_include_prolog_admin_before';.*/
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_admin_before.php");

if(!$USER->CanDoOperation("clouds_browse"))
	$APPLICATION->AuthForm(GetMessage("ACCESS_DENIED"));

/*.require_module 'bitrix_clouds_include';.*/
if(!CModule::IncludeModule('clouds'))
	$APPLICATION->AuthForm(GetMessage("ACCESS_DENIED"));

IncludeModuleLangFile(__FILE__);

$obBucket = new CCloudStorageBucket(intval($_GET["bucket"]));
if(!$obBucket->Init())
{
	$APPLICATION->SetTitle($obBucket->BUCKET);
	require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_admin_after.php");
	$message = new CAdminMessage(array(
		"MESSAGE" => GetMessage("CLO_STORAGE_FILE_LIST_ERROR"),
		"DETAILS" => GetMessage("CLO_STORAGE_FILE_UNKNOWN_ERROR", array("#CODE#" => "L00")),
	));
	echo $message->Show();
	require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/epilog_admin.php");
	die();
}

$PHPchunkSize = 1024*1024; // 1M later TODO return_bytes(ini_get('post_max_size'))
$CLOchunkSize = $obBucket->GetService()->GetMinUploadPartSize();

$message = /*.(CAdminMessage).*/null;
$path = (string)$_GET["path"];
$sTableID = "tbl_clouds_file_list";
$lAdmin = new CAdminList($sTableID);

$arFilterFields = Array(
	"find_name",
);
$lAdmin->InitFilter($arFilterFields);

$arID = $lAdmin->GroupAction();
$action = isset($_REQUEST["action"]) && is_string($_REQUEST["action"])? "$_REQUEST[action]": "";
if($USER->CanDoOperation("clouds_upload") && is_array($arID))
{
	foreach($arID as $ID)
	{
		if(strlen($ID) <= 0)
			continue;
		$ID = urldecode($ID);

		switch($action)
		{
		case "delete":
			if(substr($ID, 0, 1) === "F")
			{
				$file_size = $obBucket->GetFileSize($path.substr($ID, 1));
				if(!$obBucket->DeleteFile($path.substr($ID, 1)))
				{
					$e = $APPLICATION->GetException();
					if(is_object($e))
						$lAdmin->AddUpdateError($e->GetString(), $ID);
					else
						$lAdmin->AddUpdateError(GetMessage("CLO_STORAGE_FILE_UNKNOWN_ERROR", array(
							"#CODE#" => "D01",
						)), $ID);
				}
				else
				{
					$obBucket->DecFileCounter($file_size);
				}
			}
			elseif(substr($ID, 0, 1) === "D")
			{
				$arFiles = $obBucket->ListFiles($path.substr($ID, 1), true);
				foreach($arFiles["file"] as $i => $file)
				{
					if(!$obBucket->DeleteFile($path.substr($ID, 1)."/".$file))
					{
						$e = $APPLICATION->GetException();
						if(is_object($e))
							$lAdmin->AddUpdateError($e->GetString(), $ID);
						else
							$lAdmin->AddUpdateError(GetMessage("CLO_STORAGE_FILE_UNKNOWN_ERROR", array(
								"#CODE#" => "D02",
							)), $ID);
						break;
					}
					else
					{
						$obBucket->DecFileCounter($arFiles["file_size"][$i]);
					}
				}
			}
			break;
		case "chunk_upload":
			require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_admin_js.php");
			$strError = "";
			$bytes = 0;
			$fileSize = doubleval($_REQUEST["file_size"]);
			$tempDir = CTempFile::GetDirectoryName(6, "clouds_ipload");
			$absPath = $tempDir."tmp_name";
			if(isset($_REQUEST["file_name"]))
			{
				$filePath = $_REQUEST["file_name"];
				$filePath = "/".$_REQUEST["path_to_upload"]."/".$filePath;
				$filePath = preg_replace("#[\\\\\\/]+#", "/", $filePath);

				if (isset($_REQUEST["chunk_start"]) && $_REQUEST["chunk_start"] == 0)
				{
					if($obBucket->FileExists($filePath))
						$strError = GetMessage("CLO_STORAGE_FILE_EXISTS_ERROR");
				}
			}

			if(isset($_REQUEST["chunk_start"]))
			{
				CheckDirPath($tempDir);

				// read contents from the input stream
				$inputHandler = fopen('php://input', "rb");
				// create a temp file where to save data from the input stream
				$fileHandler = fopen($absPath, "ab");
				// save data from the input stream
				while(!feof($inputHandler))
					fwrite($fileHandler, fread($inputHandler, 1024*1024));
				fclose($fileHandler);
			}
			else
			{
				@unlink($absPath);
			}

			if($strError == "")
			{
				if($fileSize <= $CLOchunkSize)
				{
					if(!file_exists($absPath))
					{
						$moveResult = CCloudStorage::FILE_PARTLY_UPLOADED;
						?><script>
							readFileChunk(0, <?echo $PHPchunkSize-1?>);
						</script><?
					}
					elseif(filesize($absPath) < $fileSize)
					{
						$bytes = filesize($absPath);
						$moveResult = CCloudStorage::FILE_PARTLY_UPLOADED;
						?><script>
							readFileChunk(<?echo $bytes?>, <?echo min($fileSize-1, $bytes+$PHPchunkSize-1)?>);
						</script><?
					}
					else
					{
						$ar = CFile::MakeFileArray($absPath);

						if(!is_array($ar) || !isset($ar["tmp_name"]))
						{
							$strError = GetMessage("CLO_STORAGE_FILE_UNKNOWN_ERROR", array("#CODE#" => "e11"));
						}
						else
						{
							$res = $obBucket->SaveFile($filePath, $ar);
							if($res)
							{
								$bytes = $fileSize;
								$moveResult = CCloudStorage::FILE_MOVED;
								$obBucket->IncFileCounter($fileSize);
							}
							else
							{
								$strError = GetMessage("CLO_STORAGE_FILE_UNKNOWN_ERROR", array("#CODE#" => "e12"));
							}
							@unlink($absPath);
						}
					}
				}
				else
				{
					$obUpload = new CCloudStorageUpload($filePath);
					if(!$obUpload->isStarted())
					{
						if($obUpload->Start($obBucket->ID, $fileSize, $_REQUEST["file_type"]))
						{
							$moveResult = CCloudStorage::FILE_PARTLY_UPLOADED;
							?><script>
								readFileChunk(0, <?echo $PHPchunkSize-1?>);
							</script><?
						}
						else
							$strError = GetMessage("CLO_STORAGE_FILE_UNKNOWN_ERROR", array("#CODE#" => "e01"));
					}
					else
					{
						$pos = $obUpload->getPos();
						if($pos > $fileSize)
						{
							if($obUpload->Finish())
							{
								$bytes = $fileSize;
								$obBucket->IncFileCounter($fileSize);
								@unlink($absPath);
								$moveResult = CCloudStorage::FILE_MOVED;
							}
							else
							{
								$strError = GetMessage("CLO_STORAGE_FILE_UNKNOWN_ERROR", array("#CODE#" => "e02"));
							}
						}
						else
						{
							if(!file_exists($absPath))
							{
								$moveResult = CCloudStorage::FILE_PARTLY_UPLOADED;
								?><script>
									readFileChunk(<?echo $pos?>, <?echo $pos + $PHPchunkSize-1?>);
								</script><?
							}
							elseif(
								filesize($absPath) < $obUpload->getPartSize()
								&& ($pos + filesize($absPath) < $fileSize)
							)
							{
								$bytes = $pos + filesize($absPath);
								$moveResult = CCloudStorage::FILE_PARTLY_UPLOADED;
								?><script>
									readFileChunk(<?echo $bytes?>, <?echo min($fileSize-1, $bytes+$PHPchunkSize-1)?>);
								</script><?
							}
							else
							{
								$part = file_get_contents($absPath);
								$bytes = $pos + filesize($absPath);
								$moveResult = CCloudStorage::FILE_SKIPPED;
								while($obUpload->hasRetries())
								{
									if($obUpload->Next($part))
									{
										$moveResult = CCloudStorage::FILE_PARTLY_UPLOADED;
										break;
									}
								}

								if($moveResult == CCloudStorage::FILE_SKIPPED)
									$strError = GetMessage("CLO_STORAGE_FILE_UNKNOWN_ERROR", array("#CODE#" => "e03"));
								else
								{
									?><script>
										readFileChunk(<?echo $obUpload->getPos()?>, <?echo min($fileSize-1, $obUpload->getPos()+$PHPchunkSize-1)?>);
									</script><?
									@unlink($absPath);
								}
							}
						}
					}
				}
			}

			if($strError != "")
			{
				$e = $APPLICATION->GetException();
				if(!is_object($e))
					$e = new CApplicationException($strError);
				$message = new CAdminMessage(GetMessage("CLO_STORAGE_FILE_UPLOAD_ERROR"), $e);
			}

			if(is_object($message))
			{
				echo $message->Show();
				$message = null;
			}
			elseif($moveResult == CCloudStorage::FILE_PARTLY_UPLOADED)
			{
				CAdminMessage::ShowMessage(array(
					"TYPE"=>"PROGRESS",
					"MESSAGE"=>GetMessage("CLO_STORAGE_FILE_UPLOAD_IN_PROGRESS"),
					"DETAILS"=>GetMessage("CLO_STORAGE_FILE_UPLOAD_PROGRESS", array(
						"#bytes#" => CFile::FormatSize($bytes),
						"#file_size#" => CFile::FormatSize($fileSize),
					))."#PROGRESS_BAR#",
					"HTML"=>true,
					"PROGRESS_TOTAL" => $fileSize,
					"PROGRESS_VALUE" => $bytes,
					"BUTTONS" => array(
						array(
							"VALUE" => GetMessage("CLO_STORAGE_FILE_STOP"),
							"ONCLICK" => 'window.location = \''.CUtil::AddSlashes("/bitrix/admin/clouds_file_list.php?lang=".urlencode(LANGUAGE_ID)."&bucket=".urlencode($obBucket->ID)."&path=".urlencode($path)).'\'',
						),
					),
				));
			}
			else
			{
				CAdminMessage::ShowMessage(array(
					"MESSAGE"=>GetMessage("CLO_STORAGE_FILE_UPLOAD_DONE"),
					"DETAILS"=>GetMessage("CLO_STORAGE_FILE_UPLOAD_PROGRESS", array(
						"#bytes#" => CFile::FormatSize($bytes),
						"#file_size#" => CFile::FormatSize($fileSize),
					)),
					"HTML"=>true,
					"TYPE"=>"OK",
				));
				?><script>
					<?=$sTableID?>.GetAdminList('<?echo CUtil::JSEscape($APPLICATION->GetCurPage().'?lang='.urlencode(LANGUAGE_ID).'&bucket='.urlencode($obBucket->ID).'&path='.urlencode($path))?>');
				</script><?
			}

			require($_SERVER["DOCUMENT_ROOT"].BX_ROOT."/modules/main/include/epilog_admin_js.php");
		case "upload":
			$strError = "";
			$io = CBXVirtualIo::GetInstance();

			$f = null;
			if($ID === "Fnew" && isset($_FILES["upload"]))
			{
				if($_FILES["upload"]["error"] == 0)
				{
					$filePath = $_FILES["upload"]["name"];
					$filePath = "/".$_REQUEST["path_to_upload"]."/".$filePath;
					$filePath = preg_replace("#[\\\\\\/]+#", "/", $filePath);

					$f = $io->GetFile($_FILES["upload"]["tmp_name"]);
				}
				else
				{
					$message = new CAdminMessage(GetMessage("CLO_STORAGE_FILE_UPLOAD_ERROR"), new CApplicationException(GetMessage("CLO_STORAGE_FILE_OPEN_ERROR")));
				}
			}
			elseif($ID !== "Fnew")
			{
				//TODO check for ../../../
				$filePath = substr($ID, 1);
				$filePath = "/".$path."/".$filePath;
				$filePath = preg_replace("#[\\\\\\/]+#", "/", $filePath);

				$f = $io->GetFile(preg_replace("#[\\\\\\/]+#", "/", $_SERVER["DOCUMENT_ROOT"]."/".$path."/".substr($ID, 1)));
			}
			elseif(isset($_REQUEST["filePath"]))
			{
				$obUpload = new CCloudStorageUpload($_REQUEST["filePath"]);
				if($obUpload->isStarted())
				{
					$tempFile = $obUpload->getTempFileName();
					if($tempFile)
						$f = $io->GetFile($tempFile);
				}
			}

			if(!$f)
				break;

			if(
				substr($ID, 0, 1) !== "F"
				|| $obBucket->ACTIVE !== "Y"
				|| $obBucket->READ_ONLY !== "N"
			)
				break;

			$fp = $f->Open("rb");
			if(!is_resource($fp))
			{
				$message = new CAdminMessage(GetMessage("CLO_STORAGE_FILE_UPLOAD_ERROR"), new CApplicationException(GetMessage("CLO_STORAGE_FILE_OPEN_ERROR")));
				break;
			}

			$bytes = 0;
			$fileSize = $f->GetFileSize();
			if($fileSize > $obBucket->GetService()->GetMinUploadPartSize())
			{
				$obUpload = new CCloudStorageUpload($filePath);

				if(!$obUpload->isStarted())
				{
					if($obBucket->FileExists($filePath))
					{
						$message = new CAdminMessage(GetMessage("CLO_STORAGE_FILE_UPLOAD_ERROR"), new CApplicationException(GetMessage("CLO_STORAGE_FILE_EXISTS_ERROR")));
						break;
					}

					$tempFile = CTempFile::GetDirectoryName(6, "clouds_upload").$f->GetName();
					$tempFileX = $io->GetPhysicalName($tempFile);
					CheckDirPath($tempFileX);
					if(copy($io->GetPhysicalName($f->GetPathWithName()), $tempFileX))
					{
						if($obUpload->Start($obBucket->ID, $fileSize, CFile::GetContentType($tempFile), $tempFile))
							$moveResult = CCloudStorage::FILE_PARTLY_UPLOADED;
						else
							$strError = GetMessage("CLO_STORAGE_FILE_UNKNOWN_ERROR", array("#CODE#" => "e01"));
					}
					else
					{
						$strError = GetMessage("CLO_STORAGE_FILE_UNKNOWN_ERROR", array("#CODE#" => "e04"));
					}
				}
				else
				{
					$pos = $obUpload->getPos();
					if($pos > $fileSize)
					{
						if($obUpload->Finish())
						{
							$bytes = $fileSize;
							$obBucket->IncFileCounter($fileSize);
							@unlink($io->GetPhysicalName($f->GetPathWithName()));
							$moveResult = CCloudStorage::FILE_MOVED;
						}
						else
						{
							$strError = GetMessage("CLO_STORAGE_FILE_UNKNOWN_ERROR", array("#CODE#" => "e02"));
						}
					}
					else
					{
						fseek($fp, $pos);
						$part = fread($fp, $obUpload->getPartSize());
						$bytes = $pos + $part;
						$moveResult = CCloudStorage::FILE_SKIPPED;
						while($obUpload->hasRetries())
						{
							if($obUpload->Next($part))
							{
								$moveResult = CCloudStorage::FILE_PARTLY_UPLOADED;
								break;
							}
						}

						if($moveResult == CCloudStorage::FILE_SKIPPED)
							$strError = GetMessage("CLO_STORAGE_FILE_UNKNOWN_ERROR", array("#CODE#" => "e03"));
					}
				}
			}
			else
			{
				if($obBucket->FileExists($filePath))
				{
					$message = new CAdminMessage(GetMessage("CLO_STORAGE_FILE_UPLOAD_ERROR"), new CApplicationException(GetMessage("CLO_STORAGE_FILE_EXISTS_ERROR")));
					break;
				}

				$ar = CFile::MakeFileArray($io->GetPhysicalName($f->GetPathWithName()));
				if(!is_array($ar) || !isset($ar["tmp_name"]))
				{
					$strError = GetMessage("CLO_STORAGE_FILE_UNKNOWN_ERROR", array("#CODE#" => "e11"));
				}
				else
				{
					$res = $obBucket->SaveFile($filePath, $ar);
					if($res)
					{
						$bytes = $fileSize;
						$moveResult = CCloudStorage::FILE_MOVED;
						$obBucket->IncFileCounter($fileSize);
						@unlink($io->GetPhysicalName($f->GetPathWithName()));
					}
					else
					{
						$strError = GetMessage("CLO_STORAGE_FILE_UNKNOWN_ERROR", array("#CODE#" => "e12"));
					}
				}
			}

			$lAdmin->BeginPrologContent();

			if($strError != "")
			{
				$e = $APPLICATION->GetException();
				if(!is_object($e))
					$e = new CApplicationException($strError);

				$message = new CAdminMessage(GetMessage("CLO_STORAGE_FILE_UPLOAD_ERROR"), $e);
			}

			if(is_object($message))
			{
				echo $message->Show();
				$message = null;
			}
			elseif($moveResult == CCloudStorage::FILE_PARTLY_UPLOADED)
			{
				CAdminMessage::ShowMessage(array(
					"MESSAGE"=>GetMessage("CLO_STORAGE_FILE_UPLOAD_IN_PROGRESS"),
					"DETAILS"=>GetMessage("CLO_STORAGE_FILE_UPLOAD_PROGRESS", array(
						"#bytes#" => CFile::FormatSize($bytes),
						"#file_size#" => CFile::FormatSize($fileSize),
					)).'#PROGRESS_BAR#',
					"HTML"=>true,
					"TYPE"=>"PROGRESS",
					"PROGRESS_TOTAL" => $fileSize,
					"PROGRESS_VALUE" => $bytes,
					"BUTTONS" => array(
						array(
							"VALUE" => GetMessage("CLO_STORAGE_FILE_STOP"),
							"ONCLICK" => 'window.location = \''.CUtil::JSEscape("/bitrix/admin/clouds_file_list.php?lang=".urlencode(LANGUAGE_ID)."&bucket=".urlencode($obBucket->ID)."&path=".urlencode($path)).'\'',
						),
					),
				));
			}
			else
			{
				CAdminMessage::ShowMessage(array(
					"MESSAGE"=>GetMessage("CLO_STORAGE_FILE_UPLOAD_DONE"),
					"DETAILS"=>GetMessage("CLO_STORAGE_FILE_UPLOAD_PROGRESS", array(
						"#bytes#" => CFile::FormatSize($bytes),
						"#file_size#" => CFile::FormatSize($fileSize),
					)),
					"HTML"=>true,
					"TYPE"=>"OK",
				));
			}
			$lAdmin->EndPrologContent();

			if($moveResult == CCloudStorage::FILE_PARTLY_UPLOADED)
			{
				$lAdmin->BeginEpilogContent();
				echo '<script>BX.ready(function(){', $lAdmin->ActionDoGroup(urlencode($ID), "upload", "bucket=".urlencode($obBucket->ID)."&path=".urlencode($path)."&filePath=".urlencode($filePath)), '});</script>';
				$lAdmin->EndEpilogContent();
			}
			break;
		default:
			break;
		}
	}
}

$arHeaders = array(
	array(
		"id" => "FILE_NAME",
		"content" => GetMessage("CLO_STORAGE_FILE_NAME"),
		"default" => true,
	),
	array(
		"id" => "FILE_SIZE",
		"content" => GetMessage("CLO_STORAGE_FILE_SIZE"),
		"align" => "right",
		"default" => true,
	),
);

$lAdmin->AddHeaders($arHeaders);

$arData = /*.(array[int][string]string).*/array();
$arFiles = $obBucket->ListFiles($path);

if($path != "/")
{
	$arData[] = array(
		"ID" => "D..",
		"TYPE" => "dir",
		"NAME" => "..",
		"SIZE" => "",
	);
}

if(is_array($arFiles))
{
	foreach($arFiles["dir"] as $i => $dir)
	{
		if ($find_name == "" || strpos($dir, $find_name) !== false)
		{
			$arData[] = array(
				"ID" => "D".urlencode($dir),
				"TYPE" => "dir",
				"NAME" => $dir,
				"SIZE" => '',
			);
		}
	}

	foreach($arFiles["file"] as $i => $file)
	{
		if ($find_name == "" || strpos($file, $find_name) !== false)
		{
			$arData[] = array(
				"ID" => "F".urlencode($file),
				"TYPE" => "file",
				"NAME" => $file,
				"SIZE" => $arFiles["file_size"][$i],
			);
		}
	}
}
else
{
	$e = $APPLICATION->GetException();
	if(is_object($e))
		$message = new CAdminMessage(GetMessage("CLO_STORAGE_FILE_LIST_ERROR"), $e);
	else
		$message = new CAdminMessage(array(
			"MESSAGE" => GetMessage("CLO_STORAGE_FILE_LIST_ERROR"),
			"DETAILS" => GetMessage("CLO_STORAGE_FILE_UNKNOWN_ERROR", array("#CODE#" => "L01")),
		));
}

$total_size = 0.0;
$total_count = 0;

$rsData = new CDBResult;
$rsData->InitFromArray($arData);
$rsData = new CAdminResult($rsData, $sTableID);
$rsData->NavStart();
$lAdmin->NavText($rsData->GetNavPrint(''));

while(is_array($arRes = $rsData->NavNext()))
{
	$row =& $lAdmin->AddRow($arRes["ID"], $arRes);

	if($arRes["TYPE"] === "dir")
	{
		if($arRes["NAME"] === "..")
		{
			$row->bReadOnly = true;
			$row->AddViewField("FILE_NAME", '<a href="'.htmlspecialcharsbx('clouds_file_list.php?lang='.urlencode(LANGUAGE_ID).'&bucket='.urlencode($obBucket->ID).'&path='.urlencode(preg_replace('#([^/]+)/$#', '', $path))).'" class="adm-list-table-icon-link"><span class="adm-submenu-item-link-icon adm-list-table-icon clouds-up-icon"></span><span class="adm-list-table-link">'.htmlspecialcharsex($arRes["NAME"]).'</span></a>');
			$row->AddViewField("FILE_SIZE", '&nbsp;');
		}
		else
		{
			$row->AddViewField("FILE_NAME", '<a href="'.htmlspecialcharsbx('clouds_file_list.php?lang='.urlencode(LANGUAGE_ID).'&bucket='.urlencode($obBucket->ID).'&path='.urlencode($path.$arRes["NAME"].'/')).'" class="adm-list-table-icon-link"><span class="adm-submenu-item-link-icon adm-list-table-icon clouds-directory-icon"></span><span class="adm-list-table-link">'.htmlspecialcharsex($arRes["NAME"]).'</span></a>');
			if($_GET["size"] === "y")
			{
				$arDirFiles = $obBucket->ListFiles($path.$arRes["NAME"]."/", true);
				$size = array_sum($arDirFiles["file_size"]);
				$row->AddViewField("FILE_SIZE", CFile::FormatSize((float)$size));
				$total_size += $size;
				$total_count += count($arDirFiles["file"]);
			}
			else
			{
				$row->AddViewField("FILE_SIZE", '&nbsp;');
			}
		}
	}
	else
	{
		$row->AddViewField("FILE_NAME", '<a href="'.htmlspecialcharsbx($obBucket->GetFileSRC(array("URN" => $path.$arRes["NAME"]))).'">'.htmlspecialcharsex($arRes["NAME"]).'</a>');
		$row->AddViewField("FILE_SIZE", CFile::FormatSize((float)$arRes["SIZE"]));
		$total_size += $arRes["SIZE"];
		$total_count++;
	}

	$arActions = /*.(array[int][string]string).*/array();

	if($USER->CanDoOperation("clouds_upload"))
		$arActions[] = array(
			"ICON"=>"delete",
			"TEXT"=>GetMessage("CLO_STORAGE_FILE_DELETE"),
			"ACTION"=>"if(confirm('".GetMessage("CLO_STORAGE_FILE_DELETE_CONF")."')) ".$lAdmin->ActionDoGroup($arRes["ID"], "delete", 'bucket='.urlencode($obBucket->ID).'&path='.urlencode($path))
		);

	if(!empty($arActions))
		$row->AddActions($arActions);
}

if(
	($_GET["size"] === "y")
	&& is_array($arFiles)
	&& (
		(round($total_size/1024) != round($obBucket->FILE_SIZE/1024))
		|| ($total_count != $obBucket->FILE_COUNT)
	)
)
{
	$obBucket->SetFileCounter($total_size, $total_count);
}

$arFooter = array(
	array(
		"title" => GetMessage("MAIN_ADMIN_LIST_SELECTED"),
		"value" => $path === "/"? $rsData->SelectedRowsCount(): $rsData->SelectedRowsCount()-1, // W/O ..
	),
	array(
		"title" => GetMessage("MAIN_ADMIN_LIST_CHECKED"),
		"value" => 0,
		"counter" => true,
	),
);
if($total_size > 0)
{
	$arFooter[] = array(
		"title" => GetMessage("CLO_STORAGE_FILE_SIZE").":",
		"value" => CFile::FormatSize($total_size),
	);
}
$lAdmin->AddFooter($arFooter);

$arGroupActions = array();

if($USER->CanDoOperation("clouds_upload"))
	$arGroupActions["delete"] = GetMessage("MAIN_ADMIN_LIST_DELETE");

$lAdmin->AddGroupActionTable($arGroupActions);

$chain = $lAdmin->CreateChain();
$arPath = explode("/", $path);
$curPath = "/";
foreach($arPath as $dir)
{
	if($dir != "")
	{
		$curPath .= $dir."/";
		$url = "clouds_file_list.php?lang=".urlencode(LANGUAGE_ID)."&bucket=".urlencode($obBucket->ID)."&path=".urlencode($curPath);
		$chain->AddItem(array(
			"TEXT" => htmlspecialcharsex($dir),
			"LINK" => htmlspecialcharsbx($url),
			"ONCLICK" => $lAdmin->ActionAjaxReload($url).';return false;',
		));
	}
}
$lAdmin->ShowChain($chain);

$aContext = array();
if(
	$obBucket->ACTIVE === "Y"
	&& $obBucket->READ_ONLY === "N"
	&& $USER->CanDoOperation("clouds_upload")
)
{
	$aContext[] = array(
		"TEXT" => GetMessage("CLO_STORAGE_FILE_UPLOAD"),
		"LINK" => "javascript:show_upload_form()",
		"TITLE" => GetMessage("CLO_STORAGE_FILE_UPLOAD_TITLE"),
		"ICON" => "btn_new",
	);
}
$aContext[] = array(
	"TEXT" => GetMessage("CLO_STORAGE_FILE_SHOW_DIR_SIZE"),
	"LINK" => "/bitrix/admin/clouds_file_list.php?lang=".urlencode(LANGUAGE_ID).'&bucket='.urlencode($obBucket->ID).'&path='.urlencode($path).'&size=y',
	"TITLE" => GetMessage("CLO_STORAGE_FILE_SHOW_DIR_SIZE_TITLE"),
);

$lAdmin->AddAdminContextMenu($aContext, /*$bShowExcel=*/false);

$lAdmin->BeginPrologContent();
if(is_object($message))
	echo $message->Show();
$lAdmin->EndPrologContent();

$lAdmin->CheckListMode();

$APPLICATION->SetTitle($obBucket->BUCKET);

require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_admin_after.php");

if($USER->CanDoOperation("clouds_upload")):

CUtil::InitJSCore(array('fx'));

$aTabs = array(
	array(
		"DIV" => "edit1",
		"TAB" => GetMessage("CLO_STORAGE_FILE_UPLOAD"),
		"ICON"=>"main_user_edit",
		"TITLE"=>GetMessage("CLO_STORAGE_FILE_UPLOAD_TITLE"),
	),
);
$tabControl = new CAdminTabControl("tabControl", $aTabs, true, true);
?>

<form name="find_form" method="GET" action="<?echo $APPLICATION->GetCurPage()?>?">
<?
$oFilter = new CAdminFilter(
	$sTableID."_filter",
	array(
	)
);
$oFilter->Begin();
?>
<tr>
	<td><b><?= GetMessage("CLO_STORAGE_FILE_NAME")?>:</b></td>
	<td nowrap>
		<input type="text" name="find_name" value="<?= htmlspecialcharsbx($find_name)?>" size="35">
	</td>
</tr>
<?
$oFilter->Buttons(array(
	"table_id"=>$sTableID,
	"url"=>"/bitrix/admin/clouds_file_list.php?lang=".urlencode(LANGUAGE_ID).'&bucket='.urlencode($obBucket->ID).'&path='.urlencode($path),
	"form"=>"find_form",
));
$oFilter->End();
?>
</form>

<script>

function show_upload_form()
{
	(new BX.fx({
		start: 0,
		finish: 200,
		time: 0.5,
		type: 'accelerated',
		callback: function(res){
			BX('upload_form', true).style.height = res+'px';
		},
		callback_start: function(){
			BX('upload_form', true).style.height = '0px';
			BX('upload_form', true).style.overflow = 'hidden';
			BX('upload_form', true).style.display = 'block';
		},
		callback_complete: function(){
			BX('upload_form', true).style.height = 'auto';
			BX('upload_form', true).style.overflow = 'auto';
		}
	})).start();
}
function hide_upload_form()
{
	BX('upload_form').style.display='none';
	return;
}
function get_upload_url(additional_args)
{
	var result = 'clouds_file_list.php?'
		+ 'action=chunk_upload'
		+ '&ID=Fnew'
		+ '&lang=<?echo urlencode(LANGUAGE_ID)?>'
		+ '&path=<?echo urlencode($path)?>'
		+ '&path_to_upload=' + BX('path_to_upload').value
		+ '&<?echo bitrix_sessid_get()?>'
		+ '&bucket=<?echo CUtil::JSEscape($obBucket->ID)?>'
	;
	if(additional_args)
	{
		for(x in additional_args)
			result += '&' + x + '=' + BX.util.urlencode(additional_args[x]);
	}
	return result;
}

function chunk_upload(opt_Chunk, file, opt_startByte)
{
	var data = new ArrayBuffer(opt_Chunk.length);
	var ui8a = new Uint8Array(data, 0);
	for (var i = 0; i < opt_Chunk.length; i++)
		ui8a[i] = (opt_Chunk.charCodeAt(i) & 0xff);

	var blob;

	try
	{

		blob = new Blob([ui8a]);
	}
	catch (e)
	{
		var bb = new (window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder)();
		bb.append(data);
		blob = bb.getBlob();
	}

	ShowWaitWindow();

	BX.ajax({
		'method': 'POST',
		'dataType': 'html',
		'url': get_upload_url({
			file_name: file.name,
			file_size: file.size,
			file_type: file.type,
			chunk_start: opt_startByte
		}),
		'data': blob,
		'onsuccess': function(result){
			BX('upload_progress').innerHTML = result;
			var href = BX('stop_button');
			if(!href)
			{
				CloseWaitWindow();
				BX('start_upload_button').enabled = true;
			}
		},
		'preparePost': false
	});
}

function start_upload()
{
	if (!window.File || !window.FileReader || !window.FileList || !window.Blob)
	{
		BX('editform').submit();
		return;
	}

	var files = BX('upload').files;
	if (!files || !files.length)
		return;

	var file = files[0];

	ShowWaitWindow();
	BX('start_upload_button').enabled = false;

	BX.ajax.post(
		get_upload_url({
			file_name: file.name,
			file_size: file.size,
			file_type: file.type
		}),
		{},
		function(result){
			BX('upload_progress').innerHTML = result;
			var href = BX('stop_button');
			if(!href)
			{
				CloseWaitWindow();
				BX('start_upload_button').disabled = false;
			}
		}
	);

}

function readFileChunk(opt_startByte, opt_stopByte)
{
	var files = BX('upload').files;
	if (!files || !files.length)
		return;

	var file = files[0];
	var start = parseInt(opt_startByte) || 0;
	var stop = parseInt(opt_stopByte) || file.size - 1;

	var reader = new FileReader();
	reader.onloadend = function(evt)
	{
		if (evt.target.readyState == FileReader.DONE)
			chunk_upload(evt.target.result, file, start);
	};

	if (file.webkitSlice) //Deprecated
		var blob = file.webkitSlice(start, stop + 1);
	else if (file.mozSlice) //Deprecated
		var blob = file.mozSlice(start, stop + 1);
	else if (file.slice)
		var blob = file.slice(start, stop + 1);

	reader.readAsBinaryString(blob);
}
</script>
<div id="upload_form" style="display:none;height:200px;">
<div id="upload_progress"></div>
<form method="POST" action="<?echo htmlspecialcharsbx($APPLICATION->GetCurPageParam())?>"  enctype="multipart/form-data" name="editform" id="editform">
<?
$tabControl->Begin();
$tabControl->BeginNextTab();
?>
<tr><td width="40%"><?echo GetMessage("CLO_STORAGE_FILE_PATH_INPUT")?>:</td><td width="60%"><input type="text" id="path_to_upload" name="path_to_upload" size="45" value="<?echo htmlspecialcharsbx($path)?>"></td></tr>
<tr><td><?echo GetMessage("CLO_STORAGE_FILE_UPLOAD_INPUT")?>:</td><td><input type="file" id="upload" name="upload"></td></tr>
<?$tabControl->Buttons(false);?>
<input type="hidden" name="action" value="upload">
<input type="hidden" name="ID" value="Fnew">
<?echo bitrix_sessid_post();?>
<input type="hidden" name="lang" value="<?echo LANGUAGE_ID?>">
<input type="button" id="start_upload_button" onclick="start_upload();" value="<?echo GetMessage("CLO_STORAGE_FILE_UPLOAD_BTN")?>" class="adm-btn-save">
<input type="button" value="<?echo GetMessage("CLO_STORAGE_FILE_CANCEL_BTN")?>" onclick="hide_upload_form()">
<?
$tabControl->End();
?>
</form>
</div>
<?

endif;

$lAdmin->DisplayList();

require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/epilog_admin.php");
?>admin/clouds_storage_edit.php000064400000030662150241560060012375 0ustar00<?
define("ADMIN_MODULE_NAME", "clouds");

/*.require_module 'standard';.*/
/*.require_module 'hash';.*/
/*.require_module 'bitrix_main_include_prolog_admin_before';.*/
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_admin_before.php");

if(!$USER->CanDoOperation("clouds_config"))
	$APPLICATION->AuthForm(GetMessage("ACCESS_DENIED"));

/*.require_module 'bitrix_clouds_include';.*/
if(!CModule::IncludeModule('clouds'))
	$APPLICATION->AuthForm(GetMessage("ACCESS_DENIED"));

IncludeModuleLangFile(__FILE__);

$aTabs = array(
	array(
		"DIV" => "edit1",
		"TAB" => GetMessage("CLO_STORAGE_EDIT_TAB"),
		"ICON"=>"main_user_edit",
		"TITLE"=>GetMessage("CLO_STORAGE_EDIT_TAB_TITLE"),
	),
	array(
		"DIV" => "edit2",
		"TAB" => GetMessage("CLO_STORAGE_EDIT_TAB2"),
		"ICON"=>"main_user_edit",
		"TITLE"=>GetMessage("CLO_STORAGE_EDIT_TAB2_TITLE"),
	),
);
$tabControl = new CAdminTabControl("tabControl", $aTabs);

$ID = intval($_REQUEST["ID"]); // Id of the edited record
$bVarsFromForm = false;
$message = /*.(CAdminMessage).*/null;

if($_SERVER["REQUEST_METHOD"] === "POST" && check_bitrix_sessid())
{
	if(isset($_REQUEST["save"]) || isset($_REQUEST["apply"]))
	{
		$ob = new CCloudStorageBucket($ID);
		$arFields = array(
			"ACTIVE" => $_POST["ACTIVE"] === "Y"? "Y": "N",
			"READ_ONLY" => $_POST["READ_ONLY"] === "Y"? "Y": "N",
			"SORT" => $_POST["SORT"],
			"SERVICE_ID" => $_POST["SERVICE_ID"],
			"BUCKET" => $_POST["BUCKET"],
			"LOCATION" => $_POST["LOCATION"][$_POST["SERVICE_ID"]],
			"SETTINGS" => $_POST["SETTINGS"][$_POST["SERVICE_ID"]],
			"CNAME" => $_POST["CNAME"],
			"FILE_RULES" => CCloudStorageBucket::ConvertPOST($_POST),
		);

		if($ID > 0)
			$res = $ob->Update($arFields);
		else
			$res = $ob->Add($arFields);

		if($res > 0)
		{
			if(isset($_REQUEST["apply"]))
				LocalRedirect("/bitrix/admin/clouds_storage_edit.php?ID=".$res."&lang=".LANGUAGE_ID."&".$tabControl->ActiveTabParam());
			else
				LocalRedirect("/bitrix/admin/clouds_storage_list.php?lang=".LANGUAGE_ID);
		}
		else
		{
			$e = $APPLICATION->GetException();
			if(is_object($e))
				$message = new CAdminMessage(GetMessage("CLO_STORAGE_EDIT_SAVE_ERROR"), $e);
			$bVarsFromForm = true;
		}
	}
	elseif(isset($_REQUEST["delete"]) && $ID > 1)
	{
		$ob = new CCloudStorageBucket($ID);
		if($ob->Delete())
			LocalRedirect("/bitrix/admin/clouds_storage_list.php?lang=".LANGUAGE_ID);
		else
			$bVarsFromForm = true;
	}
}

if($bVarsFromForm)
{
	$arRes = array(
		"ACTIVE" => (string)$_REQUEST["ACTIVE"],
		"SORT" => "500",
		"READ_ONLY" => (string)$_REQUEST["READ_ONLY"],
		"SERVICE_ID" => (string)$_REQUEST["SERVICE_ID"],
		"BUCKET" => (string)$_REQUEST["BUCKET"],
		"LOCATION" => (string)$_REQUEST["LOCATION"],
		"CNAME" => (string)$_REQUEST["CNAME"],
		"SETTINGS" => "",
	);

	if(isset($_REQUEST["SETTINGS"]) && is_array($_REQUEST["SETTINGS"]))
		$arRes["SETTINGS"] = $_REQUEST["SETTINGS"];
}
else
{
	$arRes = null;
	if($ID > 0)
	{
		$rs = CCloudStorageBucket::GetList(array("ID" => "ASC"), array("=ID" => $ID));
		$arRes = $rs->Fetch();
	}

	if(!is_array($arRes))
	{
		$ID = 0;
		$arRes = array(
			"ACTIVE" => "Y",
			"SORT" => "500",
			"READ_ONLY" => "N",
			"SERVICE_ID" => "",
			"BUCKET" => "upload-".md5(uniqid("", true)),
			"LOCATION" => "",
			"CNAME" => "",
			"SETTINGS" => "",
		);
	}
}

$APPLICATION->SetTitle(($ID > 0? GetMessage("CLO_STORAGE_EDIT_EDIT_TITLE") : GetMessage("CLO_STORAGE_EDIT_ADD_TITLE")));

require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_admin_after.php");

$aMenu = array(
	array(
		"TEXT" => GetMessage("CLO_STORAGE_EDIT_MENU_LIST"),
		"TITLE" => GetMessage("CLO_STORAGE_EDIT_MENU_LIST_TITLE"),
		"LINK" => "clouds_storage_list.php?lang=".LANGUAGE_ID,
		"ICON" => "btn_list",
	)
);
$context = new CAdminContextMenu($aMenu);
$context->Show();

if(is_object($message))
	echo $message->Show();
?>
<script>
function ChangeLocation(select)
{
	var trs;
	trs = BX.findChildren(BX('editform'), {'tag':'tr','class':'location-tr'}, true);
	for(var i = 0;i < trs.length; i++)
		trs[i].style.display = 'none';

	trs = BX.findChildren(BX('editform'), {'tag':'tr','class':'settings-tr'}, true);
	for(var i = 0;i < trs.length; i++)
		trs[i].style.display = 'none';

	BX('LOCATION_' + select.value).style.display = '';

	var i = 0;
	while(true)
	{
		var tr = BX('SETTINGS_' + i + '_' + select.value);
		if(tr)
		{
			tr.style.display = '';
		}
		else
		{
			break;
		}
		i++;
	}
}

function editAddRule()
{
	var tbl = BX('tblRULES');
	var oRow = tbl.insertRow(-1);
	var oCell1 = oRow.insertCell(0); oCell1.innerHTML = '<input name="MODULE[]" type="text" style="width:100%">';
	var oCell2 = oRow.insertCell(1); oCell2.innerHTML = '<input name="EXTENSION[]" type="text" style="width:100%">';
	var oCell3 = oRow.insertCell(2); oCell3.innerHTML = '<input name="SIZE[]" type="text" style="width:100%">';
	var oCell4 = oRow.insertCell(3); oCell4.innerHTML = '<img src="/bitrix/themes/.default/images/actions/delete_button.gif" onclick="editDeleteRule(this) "/>';

	if (document.forms.editform.BXAUTOSAVE)
	{
		setTimeout(function() {
			var r = BX.findChildren(oRow, {tag: 'input'}, true);
			if (r && r.length > 0)
			{
				for (var i=0,l=r.length;i<l;i++)
				{
					r[i].form.BXAUTOSAVE.RegisterInput(r[i]);
				}
			}
		}, 10);
	}
}

function editDeleteRule(img)
{
	var oTR = BX.findParent(img, {tag: 'tr'});
	oTR.parentNode.removeChild(oTR);
}
</script>
<form method="POST" action="<?echo $APPLICATION->GetCurPage()?>"  enctype="multipart/form-data" name="editform" id="editform">
<?
$tabControl->Begin();
?>
<?
$tabControl->BeginNextTab();
?>
	<?if($ID > 0)
	{?>
		<tr>
			<td><?echo GetMessage("CLO_STORAGE_EDIT_ID")?>:</td>
			<td><?echo $ID;?></td>
		</tr>
	<?}?>
	<tr>
		<td width="40%"><?echo GetMessage("CLO_STORAGE_EDIT_ACTIVE")?>:</td>
		<td width="60%"><input type="hidden" name="ACTIVE" value="N"><input type="checkbox" name="ACTIVE" value="Y"<?if($arRes["ACTIVE"] === "Y") echo " checked"?>></td>
	</tr>
	<tr>
		<td><?echo GetMessage("CLO_STORAGE_EDIT_SORT")?>:</td>
		<td><input type="text" size="6" name="SORT" value="<?echo intval($arRes["SORT"])?>"></td>
	</tr>
	<?if($ID > 0)
	{?>
		<tr>
			<td><?echo GetMessage("CLO_STORAGE_EDIT_SERVICE_ID")?>:</td>
			<td>
			<?
			$obService = /*.(CCloudStorageService).*/null;
			foreach(CCloudStorage::GetServiceList() as $SERVICE_ID => $obService)
			{
				if($arRes["SERVICE_ID"] === $SERVICE_ID)
				{
					echo htmlspecialcharsex($obService->GetName());
					break;
				}
			}
			?>
			<input type="hidden" name="SERVICE_ID" value="<?echo htmlspecialcharsbx($arRes["SERVICE_ID"]);?>">
			</td>
		</tr>
		<tr id="LOCATION_<?echo htmlspecialcharsbx($arRes["SERVICE_ID"])?>" class="location-tr">
			<td><?echo GetMessage("CLO_STORAGE_EDIT_LOCATION")?>:</td>
			<td>
			<?
			foreach(CCloudStorage::GetServiceLocationList($arRes["SERVICE_ID"]) as $LOCATION_ID => $LOCATION_NAME)
			{
				if($arRes["LOCATION"] == $LOCATION_ID)
					echo htmlspecialcharsex($LOCATION_NAME);
			}
			?>
			<input type="hidden" name="LOCATION[<?echo htmlspecialcharsbx($arRes["SERVICE_ID"]);?>]" value="<?echo htmlspecialcharsbx($arRes["LOCATION"]);?>">
			</td>
		</tr>
		<?if(is_object($obService)) echo $obService->GetSettingsHTML($arRes, true, $arRes["SERVICE_ID"], $bVarsFromForm);?>
	<?}
	else
	{?>
		<tr>
			<td><?echo GetMessage("CLO_STORAGE_EDIT_SERVICE_ID")?>:</td>
			<td>
			<select name="SERVICE_ID" onchange="ChangeLocation(this)">
			<?
			$bServiceSet = false;
			foreach(CCloudStorage::GetServiceList() as $SERVICE_ID => $obService)
			{
				?><option value="<?echo htmlspecialcharsbx($SERVICE_ID)?>"<?if($arRes["SERVICE_ID"] === $SERVICE_ID) echo " selected"?>><?echo htmlspecialcharsex($obService->GetName())?></option><?
				if($arRes["SERVICE_ID"] === $SERVICE_ID)
					$bServiceSet = true;
			}
			?>
			</select>
			</td>
		</tr>
		<?foreach(CCloudStorage::GetServiceList() as $SERVICE_ID => $obService)
		{?>
		<tr id="LOCATION_<?echo htmlspecialcharsbx($SERVICE_ID)?>" style="display:<?echo $arRes["SERVICE_ID"] === $SERVICE_ID || !$bServiceSet? "": "none"?>" class="location-tr">
			<td><?echo GetMessage("CLO_STORAGE_EDIT_LOCATION")?>:</td>
			<td>
			<select name="LOCATION[<?echo htmlspecialcharsbx($SERVICE_ID)?>]">
			<?
			foreach(CCloudStorage::GetServiceLocationList($SERVICE_ID) as $LOCATION_ID => $LOCATION_NAME)
			{
				?><option value="<?echo htmlspecialcharsbx($LOCATION_ID)?>"<?if($arRes["SERVICE_ID"] === $LOCATION_ID) echo " selected"?>><?echo htmlspecialcharsex($LOCATION_NAME)?></option><?
			}
			?>
			</select>
			</td>
		</tr>
		<?echo $obService->GetSettingsHTML($arRes, $bServiceSet, $arRes["SERVICE_ID"], $bVarsFromForm)?>
		<?$bServiceSet = true;?>
		<?}?>
	<?}?>
	<?if($ID > 0)
	{?>
		<tr class="adm-detail-required-field">
			<td><?echo GetMessage("CLO_STORAGE_EDIT_BUCKET")?>:</td>
			<td><input type="hidden" name="BUCKET" value="<?echo htmlspecialcharsbx($arRes["BUCKET"])?>"><?echo htmlspecialcharsex($arRes["BUCKET"])?></td>
		</tr>
	<?
	}
	else
	{?>
		<tr class="adm-detail-required-field">
			<td><?echo GetMessage("CLO_STORAGE_EDIT_BUCKET")?>:</td>
			<td><input type="text" size="55" name="BUCKET" value="<?echo htmlspecialcharsbx($arRes["BUCKET"])?>"></td>
		</tr>
	<?}?>
	<tr>
		<td><?echo GetMessage("CLO_STORAGE_EDIT_READ_ONLY")?>:</td>
		<td><input type="hidden" name="READ_ONLY" value="N"><input type="checkbox" name="READ_ONLY" value="Y"<?if($arRes["READ_ONLY"] === "Y") echo " checked"?>></td>
	</tr>
	<tr>
		<td><?echo GetMessage("CLO_STORAGE_EDIT_CNAME")?>:</td>
		<td><input type="text" size="55" name="CNAME" value="<?echo htmlspecialcharsbx($arRes["CNAME"])?>"></td>
	</tr>
<?
$tabControl->BeginNextTab();
?>
	<tr><td align="center">
<?
if($bVarsFromForm)
	$arRules = CCloudStorageBucket::ConvertPOST($_POST);
elseif(isset($arRes["FILE_RULES"]))
	$arRules = unserialize($arRes["FILE_RULES"]);
else
	$arRules = array();

if(!is_array($arRules))
	$arRules = array();
?>
		<table border="0" cellspacing="0" cellpadding="0" class="internal" align="center" id="tblRULES">
			<tr class="heading">
				<td><?echo GetMessage("CLO_STORAGE_EDIT_MODULE")?><sup><span class="required">1</span></sup></td>
				<td><?echo GetMessage("CLO_STORAGE_EDIT_EXTENSIONS")?><sup><span class="required">2</span></sup></td>
				<td><?echo GetMessage("CLO_STORAGE_EDIT_SIZE")?><sup><span class="required">3</span></sup></td>
				<td>&nbsp;</td>
			</tr>
	<?
	$ii = 0;
	foreach($arRules as $rule)
	{
	?>
			<tr>
				<td><input name="MODULE[]" type="text" value="<?echo htmlspecialcharsbx($rule["MODULE"])?>" style="width:100%"></td>
				<td><input name="EXTENSION[]" type="text" value="<?echo htmlspecialcharsbx($rule["EXTENSION"])?>" style="width:100%"></td>
				<td><input name="SIZE[]" type="text" value="<?echo htmlspecialcharsbx($rule["SIZE"])?>" style="width:100%"></td>
				<td><img src="/bitrix/themes/.default/images/actions/delete_button.gif" onclick="editDeleteRule(this)" /></td>
			</tr>
	<?
		$ii++;
	}
	if($ii == 0 && $ID == 0)
	{
		?>
			<tr>
				<td><input name="MODULE[]" type="text" style="width:100%"></td>
				<td><input name="EXTENSION[]" type="text" style="width:100%"></td>
				<td><input name="SIZE[]" type="text" style="width:100%"></td>
				<td><img src="/bitrix/themes/.default/images/actions/delete_button.gif" onclick="editDeleteRule(this)" /></td>
			</tr>
		<?
		$ii=1;
	}	?>
		</table>
<script type="text/javascript">
BX.ready(function() {
	BX.addCustomEvent(document.forms.editform, 'onAutoSaveRestore', function(ob, data)
	{
		if (data['MODULE[]'] && BX.type.isArray(data['MODULE[]']) && data['MODULE[]'].length > <?=$ii?>)
		{
			for (var i=<?=$ii?>; i<data['MODULE[]'].length; i++)
				editAddRule();
		}
	});
});
</script><br>
		<a class="adm-btn" href="javascript:void(0)" onclick="editAddRule(this)" hidefocus="true" class="bx-action-href"><?echo GetMessage("CLO_STORAGE_EDIT_ADD_FILE_RULE")?></a>
	</td></tr>
	<tr><td>
		<?echo
			BeginNote(),
			'<p>',GetMessage("CLO_STORAGE_EDIT_RULES_NOTE"),'</p>',
			'<span class="required">1</span> - ',GetMessage("CLO_STORAGE_EDIT_RULES_NOTE1"),'<br />',
			'<span class="required">2</span> - ',GetMessage("CLO_STORAGE_EDIT_RULES_NOTE2"),'<br />',
			'<span class="required">3</span> - ',GetMessage("CLO_STORAGE_EDIT_RULES_NOTE3"),'<br />',
			EndNote();
		?>
	</td></tr>
<?
$tabControl->Buttons(
	array(
		"back_url"=>"clouds_storage_list.php?lang=".LANGUAGE_ID,
	)
);
?>
<?echo bitrix_sessid_post();?>
<input type="hidden" name="lang" value="<?echo LANGUAGE_ID?>">
<input type="hidden" name="ID" value="<?echo $ID?>">
<?
$tabControl->End();
?>
</form>

<?
$tabControl->ShowWarnings("editform", $message);

require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/epilog_admin.php");
?>admin/operation_description.php000064400000000640150241560060012747 0ustar00<?
if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true)
	die();

use Bitrix\Main\Localization\Loc;

Loc::loadMessages(__FILE__);

return array(
	"CLOUDS_BROWSE" => array(
		"title" => Loc::getMessage('OP_NAME_CLOUDS_BROWSE'),
	),
	"CLOUDS_UPLOAD" => array(
		"title" => Loc::getMessage('OP_NAME_CLOUDS_UPLOAD'),
	),
	"CLOUDS_CONFIG" => array(
		"title" => Loc::getMessage('OP_NAME_CLOUDS_CONFIG'),
	),
);
admin/clouds_file_search.php000064400000013631150241560060012165 0ustar00<?
define("ADMIN_MODULE_NAME", "clouds");

/*.require_module 'standard';.*/
/*.require_module 'pcre';.*/
/*.require_module 'bitrix_main_include_prolog_admin_before';.*/
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_admin_before.php");

if(!$USER->CanDoOperation("clouds_browse"))
	$APPLICATION->AuthForm(GetMessage("ACCESS_DENIED"));

/*.require_module 'bitrix_clouds_include';.*/
if(!CModule::IncludeModule('clouds'))
	$APPLICATION->AuthForm(GetMessage("ACCESS_DENIED"));

IncludeModuleLangFile(__FILE__);

$bucket_id = 0;
$arBuckets = array();
foreach(CCloudStorageBucket::GetAllBuckets() as $arBucket)
{
	if($arBucket["ACTIVE"] == "Y")
	{
		$bucket_id = $arBucket["ID"];
		$arBuckets[$bucket_id] = $arBucket["BUCKET"];
	}
}

$message = /*.(CAdminMessage).*/null;
$sTableID = "tbl_clouds_file_search";
$lAdmin = new CAdminList($sTableID);

$lAdmin->InitFilter(array("bucket", "path"));
$path = isset($_GET["path"])? $_GET["path"]: $path;
$path = preg_replace("#[\\\\\\/]+#", "/", "/".$path."/");
$n = preg_replace("/[^a-zA-Z0-9_:\\[\\]]/", "", $_GET["n"]);
if(intval($bucket) <= 0 && count($arBuckets) == 1)
	$bucket = $bucket_id;

//TODO when there is only one cloud storage there is no need for filter or at least we can preset it
$arHeaders = array(
	array(
		"id" => "FILE_NAME",
		"content" => GetMessage("CLO_STORAGE_SEARCH_NAME"),
		"default" => true,
	),
	array(
		"id" => "FILE_SIZE",
		"content" => GetMessage("CLO_STORAGE_SEARCH_SIZE"),
		"align" => "right",
		"default" => true,
	),
);

$lAdmin->AddHeaders($arHeaders);

$arData = /*.(array[int][string]string).*/array();

$obBucket = new CCloudStorageBucket($bucket);
if($obBucket->Init() && $_GET["file"]!=="y")
{
	$arFiles = $obBucket->ListFiles($path);

	if($path != "/")
		$arData[] = array("ID" => "D..", "TYPE" => "dir", "NAME" => "..", "SIZE" => "");
	if(is_array($arFiles))
	{
		foreach($arFiles["dir"] as $i => $dir)
			$arData[] = array("ID" => "D".$dir, "TYPE" => "dir", "NAME" => $dir, "SIZE" => '');
		foreach($arFiles["file"] as $i => $file)
			$arData[] = array("ID" => "F".$file, "TYPE" => "file", "NAME" => $file, "SIZE" => $arFiles["file_size"][$i]);
	}
	else
	{
		$e = $APPLICATION->GetException();
		if(is_object($e))
			$message = new CAdminMessage(GetMessage("CLO_STORAGE_SEARCH_LIST_ERROR"), $e);
	}
}

$rsData = new CDBResult;
$rsData->InitFromArray($arData);
$rsData = new CAdminResult($rsData, $sTableID);
$rsData->NavStart();
$lAdmin->NavText($rsData->GetNavPrint(''));

while(is_array($arRes = $rsData->NavNext()))
{
	if($arRes["TYPE"] === "dir")
	{
		if($arRes["NAME"] === "..")
			$link = 'clouds_file_search.php?lang='.LANGUAGE_ID.'&n='.urlencode($n).'&bucket='.$obBucket->ID.'&path='.urlencode(preg_replace('#([^/]+)/$#', '', $path));
		else
			$link = 'clouds_file_search.php?lang='.LANGUAGE_ID.'&n='.urlencode($n).'&bucket='.$obBucket->ID.'&path='.urlencode($path.$arRes["NAME"].'/');
	}
	else
	{
		$link = 'clouds_file_search.php?lang='.LANGUAGE_ID.'&n='.urlencode($n).'&file=y&bucket='.$obBucket->ID.'&path='.urlencode($path.$arRes["NAME"]);
	}

	$row =& $lAdmin->AddRow($arRes["ID"], $arRes, $link);

	$showFieldIcon = "";
	$showFieldText = "";
	if($arRes["TYPE"] === "dir")
	{
		$showFieldIcon = '<a href="'.htmlspecialcharsbx($link).'"><span id="fileman_menu_icon_sections" class="adm-submenu-item-link-icon"></span></a>';
		$showFieldText = '<a href="'.htmlspecialcharsbx($link).'">'.htmlspecialcharsex($arRes["NAME"]).'</a>';
	}
	else
	{
		$showFieldIcon = "";
		$showFieldText = '<a href="'.htmlspecialcharsbx($link).'">'.htmlspecialcharsex($arRes["NAME"]).'</a>';
	}

	$showField = '<table cellpadding="0" cellspacing="0" border="0"><tr><td align="left">'.$showFieldIcon.'</td><td align="left">&nbsp;'.$showFieldText.'</td></tr></table>';

	if($arRes["TYPE"] === "dir")
	{
		$row->AddViewField("FILE_NAME", $showField);
		$row->AddViewField("FILE_SIZE", '&nbsp;');
	}
	else
	{
		$row->AddViewField("FILE_NAME", $showField);
		$row->AddViewField("FILE_SIZE", CFile::FormatSize((float)$arRes["SIZE"]));
	}
}

$lAdmin->BeginPrologContent();

if(is_object($message))
	echo $message->Show();

if($obBucket->Init() && $_GET["file"] === "y")
	echo "<script>SelFile('".CUtil::JSEscape(urldecode($obBucket->GetFileSRC(rtrim($path, "/"))))."');</script>";

$lAdmin->EndPrologContent();

$lAdmin->CheckListMode();

$APPLICATION->SetTitle(GetMessage("CLO_STORAGE_SEARCH_TITLE"));

require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_popup_admin.php");
?>
<form name="form1" method="GET" action="<?echo $APPLICATION->GetCurPage()?>">
<?
$arFindFields = Array(
	"bucket"=>GetMessage("CLO_STORAGE_SEARCH_BUCKET"),
	"path"=>GetMessage("CLO_STORAGE_SEARCH_PATH"),
);
$oFilter = new CAdminFilter($sTableID."_filter", $arFindFields);
$oFilter->Begin();
?>
<script language="JavaScript">
function SelFile(name)
{
	if (window.opener && window.opener.BX)
	{
		window.opener.BX.onCustomEvent('onCloudFileIsChosen', [name]);
	}
	el = window.opener.document.getElementById('<?echo CUtil::JSEscape($n)?>');
	if(el)
	{
		el.value = name;
		if (window.opener.BX)
			window.opener.BX.fireEvent(el, 'change');
	}
	window.close();
}
</script>
	<tr>
		<td><b><?echo GetMessage("CLO_STORAGE_SEARCH_BUCKET")?></b></td>
		<td><select name="bucket">
			<option value=""><?echo GetMessage("CLO_STORAGE_SEARCH_CHOOSE_BUCKET")?></option>
			<?foreach($arBuckets as $id => $name):?>
					<option value="<?echo htmlspecialcharsbx($id)?>" <?if($id == $bucket) echo "selected"?>><?echo htmlspecialcharsex($name)?></option>
			<?endforeach?>
		</select></td>
	</tr>

	<tr>
		<td><?echo GetMessage("CLO_STORAGE_SEARCH_PATH")?></td>
		<td><input type="text" name="path" size="45" value="<?echo htmlspecialcharsbx($path)?>"></td>
	</tr>
<?
$oFilter->Buttons(array(
	"url" => "/bitrix/admin/clouds_file_search.php?lang=".LANGUAGE_ID."&n=".urlencode($n),
	"table_id" => $sTableID,
));
$oFilter->End();
?>
</form>
<?
$lAdmin->DisplayList();

require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/epilog_popup_admin.php");
?>include.php000064400000003065150241560060006703 0ustar00<?
/*.require_module 'standard';.*/
/*.require_module 'bitrix_main';.*/
/**
 * @global CDatabase $DB
 */
if(!defined("CACHED_b_clouds_file_bucket")) define("CACHED_b_clouds_file_bucket", 360000);
if(!defined("CACHED_clouds_file_resize")) define("CACHED_clouds_file_resize", 360000);
if(!defined("BX_S3_MIN_UPLOAD_PART_SIZE")) define("BX_S3_MIN_UPLOAD_PART_SIZE", 5242880); //5MB
$db_type = strtolower($DB->type);
CModule::AddAutoloadClasses(
	"clouds",
	array(
		"CCloudUtil" =>  "classes/general/util.php",
		"CCloudStorage" =>  "classes/general/storage.php",
		"CAllCloudStorageBucket" =>  "classes/".$db_type."/storage_bucket.php",
		"CCloudStorageBucket" =>  "classes/general/storage_bucket.php",
		"CCloudStorageService" => "classes/general/storage_service.php",
		"CCloudStorageService_AmazonS3" =>  "classes/general/storage_service_s3.php",
		"CCloudStorageService_GoogleStorage" =>  "classes/general/storage_service_google.php",
		"CCloudStorageService_OpenStackStorage" =>  "classes/general/storage_service_openstack.php",
		"CCloudStorageService_RackSpaceCloudFiles" =>  "classes/general/storage_service_rackspace.php",
		"CCloudStorageService_ClodoRU" =>  "classes/general/storage_service_clodo.php",
		"CCloudStorageService_Selectel" =>  "classes/general/storage_service_selectel.php",
		"CCloudStorageService_HotBox" =>  "classes/general/storage_service_hotbox.php",
		"CCloudStorageUpload" => "classes/general/storage_upload.php",
		"CCloudSecurityService_AmazonS3" => "classes/general/security_service_s3.php",
		"CCloudTempFile" => "classes/general/temp_file.php",
	)
);
?>options.php000064400000011200150241560060006741 0ustar00<?
$module_id = "clouds";
$RIGHT_R = $USER->CanDoOperation('clouds_config');
$RIGHT_W = $USER->CanDoOperation('clouds_config');
if($RIGHT_R || $RIGHT_W) :

IncludeModuleLangFile($_SERVER["DOCUMENT_ROOT"].BX_ROOT."/modules/main/options.php");
IncludeModuleLangFile(__FILE__);

$arAllOptions = array(
	array("log_404_errors", GetMessage("CLO_OPTIONS_LOG_404_ERRORS"), array("checkbox")),
);

$aTabs = array(
	array("DIV" => "edit1", "TAB" => GetMessage("MAIN_TAB_SET"), "ICON" => "clouds_settings", "TITLE" => GetMessage("MAIN_TAB_TITLE_SET")),
	array("DIV" => "edit2", "TAB" => GetMessage("MAIN_TAB_RIGHTS"), "ICON" => "clouds_settings", "TITLE" => GetMessage("MAIN_TAB_TITLE_RIGHTS")),
);
$tabControl = new CAdminTabControl("tabControl", $aTabs);

CModule::IncludeModule($module_id);

if($REQUEST_METHOD=="POST" && strlen($Update.$Apply.$RestoreDefaults) > 0 && $RIGHT_W && check_bitrix_sessid())
{

	if(strlen($RestoreDefaults)>0)
	{
		COption::RemoveOption($module_id);
	}
	else
	{
		foreach($arAllOptions as $arOption)
		{
			$name = $arOption[0];
			$val = trim($_REQUEST[$name], " \t\n\r");
			if($arOption[2][0]=="checkbox" && $val!="Y")
				$val="N";
			COption::SetOptionString($module_id, $name, $val, $arOption[1]);
		}
	}

	ob_start();
	$Update = $Update.$Apply;
	require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/admin/group_rights2.php");
	ob_end_clean();

	if(strlen($_REQUEST["back_url_settings"]) > 0)
	{
		if((strlen($Apply) > 0) || (strlen($RestoreDefaults) > 0))
			LocalRedirect($APPLICATION->GetCurPage()."?mid=".urlencode($module_id)."&lang=".urlencode(LANGUAGE_ID)."&back_url_settings=".urlencode($_REQUEST["back_url_settings"])."&".$tabControl->ActiveTabParam());
		else
			LocalRedirect($_REQUEST["back_url_settings"]);
	}
	else
	{
		LocalRedirect($APPLICATION->GetCurPage()."?mid=".urlencode($module_id)."&lang=".urlencode(LANGUAGE_ID)."&".$tabControl->ActiveTabParam());
	}
}

?>
<form method="post" action="<?echo $APPLICATION->GetCurPage()?>?mid=<?=urlencode($module_id)?>&amp;lang=<?=LANGUAGE_ID?>">
<?
$tabControl->Begin();
$tabControl->BeginNextTab();

	foreach($arAllOptions as $arOption):
		$val = COption::GetOptionString($module_id, $arOption[0]);
		$type = $arOption[2];
	?>
	<tr>
		<td width="40%" nowrap <?if($type[0]=="textarea") echo 'class="adm-detail-valign-top"'?>>
			<label for="<?echo htmlspecialcharsbx($arOption[0])?>"><?echo $arOption[1]?></label>
		<td width="60%">
			<?if($type[0]=="checkbox"):?>
				<input type="checkbox" name="<?echo htmlspecialcharsbx($arOption[0])?>" id="<?echo htmlspecialcharsbx($arOption[0])?>" value="Y"<?if($val=="Y")echo" checked";?>>
			<?elseif($type[0]=="text"):?>
				<input type="text" size="<?echo $type[1]?>" maxlength="255" value="<?echo htmlspecialcharsbx($val)?>" name="<?echo htmlspecialcharsbx($arOption[0])?>" id="<?echo htmlspecialcharsbx($arOption[0])?>">
			<?elseif($type[0]=="textarea"):?>
				<textarea rows="<?echo $type[1]?>" cols="<?echo $type[2]?>" name="<?echo htmlspecialcharsbx($arOption[0])?>" id="<?echo htmlspecialcharsbx($arOption[0])?>"><?echo htmlspecialcharsbx($val)?></textarea>
			<?elseif($type[0]=="selectbox"):
				?><select name="<?echo htmlspecialcharsbx($arOption[0])?>"><?
				foreach ($type[1] as $key => $value)
				{
					?><option value="<?echo $key?>"<?if($val==$key)echo" selected"?>><?echo htmlspecialcharsbx($value)?></option><?
				}
				?></select><?
			endif?>
		</td>
	</tr>
	<?endforeach?>
<?$tabControl->BeginNextTab();?>
<?require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/admin/group_rights2.php");?>
<?$tabControl->Buttons();?>
	<input <?if(!$RIGHT_W) echo "disabled" ?> type="submit" name="Update" value="<?=GetMessage("MAIN_SAVE")?>" title="<?=GetMessage("MAIN_OPT_SAVE_TITLE")?>" class="adm-btn-save">
	<input <?if(!$RIGHT_W) echo "disabled" ?> type="submit" name="Apply" value="<?=GetMessage("MAIN_OPT_APPLY")?>" title="<?=GetMessage("MAIN_OPT_APPLY_TITLE")?>">
	<?if(strlen($_REQUEST["back_url_settings"])>0):?>
		<input <?if(!$RIGHT_W) echo "disabled" ?> type="button" name="Cancel" value="<?=GetMessage("MAIN_OPT_CANCEL")?>" title="<?=GetMessage("MAIN_OPT_CANCEL_TITLE")?>" onclick="window.location='<?echo htmlspecialcharsbx(CUtil::addslashes($_REQUEST["back_url_settings"]))?>'">
		<input type="hidden" name="back_url_settings" value="<?=htmlspecialcharsbx($_REQUEST["back_url_settings"])?>">
	<?endif?>
	<input <?if(!$RIGHT_W) echo "disabled" ?> type="submit" name="RestoreDefaults" title="<?echo GetMessage("MAIN_HINT_RESTORE_DEFAULTS")?>" onclick="return confirm('<?echo AddSlashes(GetMessage("MAIN_HINT_RESTORE_DEFAULTS_WARNING"))?>')" value="<?echo GetMessage("MAIN_RESTORE_DEFAULTS")?>">
	<?=bitrix_sessid_post();?>
<?$tabControl->End();?>
</form>
<?endif;?>