Для решения проблемы с неприличным объёмом базы данных 1C из-за хранения в ней приложенных файлов в справочнике типа «ХранилищеДополнительнойИнформации» и всех вытекающих из этого неудобств, таких как огромного размера выгрузки ИБ и файла бэкапов, было написано следующее. (Данное решение не претендует на замену встроенных механизмов хранения файлов в конфигурациях типа «документооборот» без соответствующей доработки, однако, ничто не мешает доработать описанный принцип под конкретные нужды.)
Принцип довольно прост:
- Добавляем на форму нужного объекта HTML-поле, в котором будет отображаться web-интерфейс файлового менеджера (по-моему, ограничений на платформу здесь нет, HTML на форме можно было и в 7.7 отобразить, поправьте, если не прав),
- Берём любой понравившийся web- файловый менеджер, и ставим его на web-сервер (в данной статье как пример взят и изменен под свои нужды дистрибутив простого php файлового менеджера Sabre (изменённая версия на github) как web сервер использовался WAMP с основной кодировкой utf-8. Также все отлчино работает на LAMP. Версия php — предпочитаю свежую, но, возможно, Sabre будет работать и на 5.3 и ниже.)
- При открытии формы объекта, отображаем на нашей форме файл-менеджер, вызванный с определенными GET-параметрами (например, относительный путь к папке, формируемый из имени и номера объекта). Также, если нужно, можно сделать разделение по ролям, кому можно удалятьредактироватьпросматривать, кому — нет и вместо передачи простых GET-запросов хоть XML или JSON через POST и авторизацию прикрутить, как душе угодно)
- В итоге пользователь может скачивать и прикреплять файлы, подробности процесса остаются для него не очевидными, а сами файлы лежат себе на том же (или другом) сервере в определенном месте, удобно распределенные по папкам — напр. /Документ/325/файл_документа_325.pdf и не захламляют базу.
Реализация:
Рассмотрим довольно простую и быструю реализацию задумки на примере WAMP:
устанавливаем последнюю версию web-сервера (допустим, в папку d:wamp) Чтобы можно было загружать файлы до 100 мегабайт изменяем php.ini в d:wampinapacheapache_ВЕРСИЯ_in
...
post_max_size = 100M
...
upload_max_filesize = 100M
...
Чтобы сервис стартовал автоматически, запускаем services.msc, ищем wampapache64 (если x64) и ставим тип запуска — «Автоматически»
Важно! Чтобы wampmanager.exe при выходе не завершал заодно и работу web-сервера, что, сами понимаете чем чревато, изменяем wampmanager.tpl и wampmanager.ini предварительно завершив wampmanager.exe. Ищем блок [myexit] и комментируем нежелательные действия: wampmanager.ini:
[myexit]
;WAMPMYEXITSTART
;Action: service; Service: wampapache64; ServiceAction: stop; Flags: ignoreerrors
;Action: service; Service: wampmysqld64; ServiceAction: stop; Flags: ignoreerrors
Action: exit
;WAMPMYEXITEND
wampmanager.tpl:
[myexit]
;WAMPMYEXITSTART
;Action: service; Service: ${c_apacheService}; ServiceAction: stop; Flags: ignoreerrors
;Action: service; Service: ${c_mysqlService}; ServiceAction: stop; Flags: ignoreerrors
Action: exit
;WAMPMYEXITEND
Далее распаковываем в папку d:wampwww изменённую вверсия Sabre с github, переходим в браузере на http://localhost/Sabre1c-master/install/ и настраиваем как пожелаем. Создаём папку для загрузок, какую указали (по-умолчанию upload) в d:wampwwwSabre1c-master переходим на http://localhost/Sabre1c-master/?CWD=Тест123 и загружаем любой файл, проверяем результат в папке d:wampwwwSabre1c-masteruploadТест123 появился загруженный файл.
Работу файл-менеджера проверял как на windows, так и на linux web-серверах, проблем с кодировкой имени файла при загрузкескачивании удалось избежать. Пробелы в имени файла при загрузке заменяются символами нижнего подчёркивания. Если есть необходимость запретить загружать файлы с расширением, не включенным в список разрешенных, можно раскоментировать и попровить несколько строк в файле coreupload.php:
$ext_allowed = array('txt', 'jpg', 'pdf', 'zip', 'png');
if(!in_array(strtolower($extension), $ext_allowed)){
header('location: ../?action=upload&file=');
exit;
}
Теперь идём в 1с и размещаем на нужном документе или справочнике ПолеHTMLДокумента с аналогичным именем и добавляем в функцию модуля ПриОткрытии() код:
// пример для обычных форм 8.X, Документ
Процедура ПриОткрытии(Отказ) {
Если ДокументОбъект.Номер Тогда
ЭлементыФормы.ПолеHTMLДокумента.Видимость=Истина;
// если у вас числовая нумерация, Адрес="http://localhost/Sabre1c-master/?CWD="+"/"+ДокументОбъект.Метаданные().Имя+"/"+Формат(ДокументОбъект.Номер,"ЧГ=0");
Адрес="http://localhost/Sabre1c-master/?CWD="+"/"+ДокументОбъект.Метаданные().Имя+"/"+ДокументОбъект.Номер;
ЭлементыФормы.ПолеHTMLДокумента.Документ.URL = Адрес;
КонецЕсли;
КонецПроцедуры
// пример для управляемых форм 8.X, Справочник
&НаКлиенте
Процедура ПриОткрытии(Отказ)
Если Объект.Код Тогда
Элементы.ПолеHTMLДокумента.Видимость=Истина;
// если у вас числовая нумерация, Адрес="localhost/Sabre1c-master/?CWD="+"/contacts/"+Формат(Объект.Код,"ЧГ=0");
Адрес="localhost/Sabre1c-master/?CWD="+"/contacts/"+Объект.Код;
ПолеHTMLДокумента=Адрес;
КонецЕсли;
КонецПроцедуры
Готово.
Также можно написать простейшую обработку, чтобы выгрузить все файлы из хранилища в базе в папку на диске.
Процедура ЭкспортФайловХранилищаНажатие(Элемент)
Путь="d:wampwwwSabre1c-masterupload"
ИмяХранилищаДопИнф="ХранилищеДополнительнойИнформации";
Выборка = Справочники[ИмяХранилищаДопИнф].Выбрать();
Пока выборка.Следующий() = 1 Цикл
Попытка
// если у вас числовая нумерация, ID=Формат(выборка.Объект.Код,"ЧГ=0");
ID=выборка.Объект.Код;
Исключение
Попытка
// если у вас числовая нумерация, ID=Формат(выборка.Объект.Номер,"ЧГ=0");
ID=выборка.Объект.Номер;
Исключение
ID="null";
КонецПопытки;
КонецПопытки;
РезультПуть=Путь + выборка.Объект.Метаданные().Имя + "" + ID + "";
СоздатьКаталог(РезультПуть);
Если выборка.ИмяФайла <>"" Тогда
Результ = РезультПуть + СтрЗаменить(выборка.ИмяФайла, "/", " ");
выборка.Хранилище.Получить().Записать(Результ);
Сообщить("Выгружен "+Результ);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Всё нижеописанное Вы можете повторить для себя, но исключительно на свой страх и риск. Автор не несет ответственности за возникновение каких-либо проблем.
И удалить выгруженные файлы из БД.
Процедура УдалениеФайловХранилищаНажатие(Элемент)
Выборка = Справочники.ХранилищеДополнительнойИнформации.Выбрать();
Пока Выборка.Следующий() Цикл
Если Выборка.Объект.Метаданные().Имя = "ЗаказПокупателя" Тогда
ТекЭлемент = Выборка.ПолучитьОбъект();
Попытка
ТекЭлемент.Удалить();
Исключение
Сообщить("Не удалось удалить элемент!" + ТекЭлемент.Код);
КонецПопытки;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Теперь, чтобы фактический размер БД уменьшился после удаления из нее хлама, осталось только выгрузить и загрузить ИБ.
Плюс за оригинальность и труды, но есть 2 замечания:
1. Трудоемко. Требует использование стороннего ПО. Проще использовать зашитую в платформу 8.х возможность клиент-серверного обмена.
2. Замена принципа работы интерфейса (в частности порядка прикрепления файлов к объектам) всегда переносится пользователями болезненно, особенно в организации, где пользюков, человек эдак 150 в базе сидит. По-этому, лучше внешне не менять ничего, а лишь при вызове штатных обработчиков перехватывать их исполнения и класть файлу не в ХЗ, а передавать на сервер. Но да это не столь важно.
В общем, как вариант… Сам озабочен этим, ибо графики много, а хранить ее в базе — не кошерно.
Надо будет попробовать. Спасибо!!
Если у документа поменяют номер или у справочника код — все связанные файлы потеряются?.. Тогда уж к ссылке нужно привязываться.
В БСП вроде что-то было для хранения файлов вне базы через веб-сервер.
Охренеть, простейший. Внедрите БСП и будет вам хранение файлов во внешних томах на дисках.
.
Есть такой момент, НО. В 1С (практически все типовые конфигурации) этот механизм используют (если не настраивать хранение файлов на дисках).
Здесь необходимо четкое понимание объемов хранения, и последствий, которые за собой эти хранимые объемы повлекут.
У нас в компании уже много лет реализовано хранение прикрепленных файлов на дисках, а в базу пишется только путь до файла. При этом в данный момент объем хранимой информации, а это:
screen shot-ы экранов пользователя с ошибками в отделе тех поддержки, различные заявки и пр, довольно велик, но собственно хранится и ни как не нагружает БД. При чем можно достаточно четко разграничить права доступа к этой информации средствами АД.