gifts2017

Организация простейшего внешнего хранилища прикрепленных к документу (элементу справочника, ...) файлов на web-сервере, или не засоряем базу 1С

Опубликовал . .  (gaabora) в раздел Администрирование - Чистка базы

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

Для решения проблемы с неприличным объёмом базы данных 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:\wamp\bin\apache\apache_ВЕРСИЯ_\bin\

...
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:\wamp\www\ изменённую вверсия Sabre с github, переходим в браузере на http://localhost/Sabre1c-master/install/ и настраиваем как пожелаем. Создаём папку для загрузок, какую указали (по-умолчанию upload) в d:\wamp\www\Sabre1c-master\ переходим на http://localhost/Sabre1c-master/?CWD=\Тест\123 и загружаем любой файл, проверяем результат в папке d:\wamp\www\Sabre1c-master\upload\Тест\123\ появился загруженный файл.

Работу файл-менеджера проверял как на windows, так и на linux web-серверах, проблем с кодировкой имени файла при загрузке\скачивании удалось избежать. Пробелы в имени файла при загрузке заменяются символами нижнего подчёркивания. Если есть необходимость запретить загружать файлы с расширением, не включенным в список разрешенных, можно раскоментировать и попровить несколько строк в файле core\upload.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:\wamp\www\Sabre1c-master\upload\"
	ИмяХранилищаДопИнф="ХранилищеДополнительнойИнформации";
	Выборка = Справочники[ИмяХранилищаДопИнф].Выбрать();
	Пока выборка.Следующий() = 1 Цикл
		Попытка
			// если у вас числовая нумерация, ID=Формат(выборка.Объект.Код,"ЧГ=0");
			ID=выборка.Объект.Код;
		Исключение
			Попытка
				// если у вас числовая нумерация, ID=Формат(выборка.Объект.Номер,"ЧГ=0");
				ID=выборка.Объект.Номер;
			Исключение
				ID="null";
			КонецПопытки;
		КонецПопытки;
		
		РезультПуть=Путь + выборка.Объект.Метаданные().Имя + "\" + ID + "\";
		СоздатьКаталог(РезультПуть);
		Если выборка.ИмяФайла <>"" Тогда
			Результ = РезультПуть + СтрЗаменить(выборка.ИмяФайла, "/", " ");
			выборка.Хранилище.Получить().Записать(Результ);
			Сообщить("Выгружен "+Результ);
		КонецЕсли;
	КонецЦикла;
КонецПроцедуры

Всё нижеописанное Вы можете повторить для себя, но исключительно на свой страх и риск. Автор не несет ответственности за возникновение каких-либо проблем.

И удалить выгруженные файлы из БД.

Процедура УдалениеФайловХранилищаНажатие(Элемент)
	Выборка = Справочники.ХранилищеДополнительнойИнформации.Выбрать();
	Пока Выборка.Следующий() Цикл
		Если Выборка.Объект.Метаданные().Имя = "ЗаказПокупателя" Тогда
			ТекЭлемент = Выборка.ПолучитьОбъект();
			Попытка 
				ТекЭлемент.Удалить();
			Исключение 
				Сообщить("Не удалось удалить элемент!" + ТекЭлемент.Код);
			КонецПопытки;
		КонецЕсли;
	КонецЦикла;
КонецПроцедуры

Теперь, чтобы фактический размер БД уменьшился после удаления из нее хлама, осталось только выгрузить и загрузить ИБ.

См. также

Подписаться Добавить вознаграждение

Комментарии

1. Two World (Prometeus2011) 03.06.15 17:03
Плюс за оригинальность и труды, но есть 2 замечания:
1. Трудоемко. Требует использование стороннего ПО. Проще использовать зашитую в платформу 8.х возможность клиент-серверного обмена.
2. Замена принципа работы интерфейса (в частности порядка прикрепления файлов к объектам) всегда переносится пользователями болезненно, особенно в организации, где пользюков, человек эдак 150 в базе сидит. По-этому, лучше внешне не менять ничего, а лишь при вызове штатных обработчиков перехватывать их исполнения и класть файлу не в ХЗ, а передавать на сервер. Но да это не столь важно.

В общем, как вариант... Сам озабочен этим, ибо графики много, а хранить ее в базе - не кошерно.
2. Дмитрий Агеев (Dimon2005) 04.06.15 11:28
Надо будет попробовать. Спасибо!!
3. ффф ыыы (zqzq) 05.06.15 09:41
Если у документа поменяют номер или у справочника код - все связанные файлы потеряются?.. Тогда уж к ссылке нужно привязываться.

В БСП вроде что-то было для хранения файлов вне базы через веб-сервер.
4. Иван Петров (dgolovanov) 05.06.15 16:32
Охренеть, простейший. Внедрите БСП и будет вам хранение файлов во внешних томах на дисках.
Silenser; exciter; +2 Ответить
5. Алексей _ (iolko) 15.06.15 07:03
Вы ощущаете когнитивный диссонанс, когда сталкиваетесь с многогигабайтной базой данных, забитой разношёрстными файлами хранилища дополнительной информации
.

Есть такой момент, НО. В 1С (практически все типовые конфигурации) этот механизм используют (если не настраивать хранение файлов на дисках).
Здесь необходимо четкое понимание объемов хранения, и последствий, которые за собой эти хранимые объемы повлекут.

У нас в компании уже много лет реализовано хранение прикрепленных файлов на дисках, а в базу пишется только путь до файла. При этом в данный момент объем хранимой информации, а это:
screen shot-ы экранов пользователя с ошибками в отделе тех поддержки, различные заявки и пр, довольно велик, но собственно хранится и ни как не нагружает БД. При чем можно достаточно четко разграничить права доступа к этой информации средствами АД.
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа