Сканирование, хранение и печать сертификатов продукции [Обновлено 17.01.2011]




Принцип обмена данными из 1С с сайтом (на MySQL) и выдачи (публикации) этих данных по запросу.
PHP-Скрипт автоматической загрузки данных из файла данных в формате CSV в базу данных сайта работающего на WordPress.

В продолжение моей темы: 1С:Альфа-Авто Автосалон Автосервис: обмен с сайтом.
С помощью данного скрипта можно загружать в автоматическом режиме, по расписанию, данные сервисных книжек (ремонтов авто) из 1С:Альфа-Авто Автосалон Автосервис.
Также можно загружать данные в ручном режиме: для этого делается скрытая страница, где размещается специальная кнопка.
Комментарии размещенные внутри скрипта разъяснят логику и порядок действия.
Комментарии с "/////    echo" использовались для отладки.
Дополнительно создана таблица для журналирования результатов загрузки данных.
Скрипт включает в себя защиту от SQL инъекций (думаю безопасность соблюдена в полной мере).
В кратце:
1. Пишется скрипт, который запускает этот.
2. Создается регламентное задание в WordPress, по которому запускается скрипт из п.1. 
3. Этот скрипт осуществляет проверку на существование файла обмена в папке.
4. Если данные не новые, загрузка не производится.
5. Если данные новые, очищается таблица сервисных книжек.
6. Загружаются новые данные.

Собственно сам скрипт:

<?php // Полная загрузка сервисных книжек, создан 2026-01-05 12:44:55

global $wpdb2;
global $failure;
global $file_hist;

/////  echo '<H2><b>Старт загрузки</b></H2><br>';

$failure=FALSE;
//подключаемся к базе
$wpdb2 = include_once 'connection.php'; ; // подключаемся к MySQL
// если не удалось подключиться, и нужно оборвать PHP с сообщением об этой ошибке
if (!empty($wpdb2->error))
{
/////   echo '<H2><b>Ошибка подключения к БД, завершение.</b></H2><br>';
$failure=TRUE;
wp_die( $wpdb2->error );
}

$m_size_file=0;
$m_mtime_file=0;
$m_comment='';
/////проверка существования файлов выгрузки из 1С
////файл выгрузки сервисных книжек
$file_hist = ABSPATH.'/_1c_alfa_exchange/AA_hist.csv';
if (!file_exists($file_hist))
{
/////   echo '<H2><b>Файл обмена с сервисными книжками не существует.</b></H2><br>';
$m_comment='Файл обмена с сервисными книжками не существует';
$failure=TRUE;
}

/////инициируем таблицу лога
/////если не существует файла то возврат и ничего не делаем
if ($failure){
///включает защиту от SQL инъекций и данные можно передавать как есть, например: $_GET['foo']
/////   echo '<H2><b>Попытка вставить запись в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>$m_comment));
wp_die();
/////    echo '<H2><b>Возврат в начало.</b></H2><br>';
return $failure;
}
/////проверка лога загрузки, что бы не загружать тоже самое
$masiv_data_file=stat($file_hist);   ////передаем в массив свойство файла
$m_size_file=$masiv_data_file[7];    ////получаем размер файла
$m_mtime_file=$masiv_data_file[9];   ////получаем дату модификации файла
////создаем запрос на получение последней удачной загрузки
////выбираем по штампу времени создания (редактирования) файла загрузки AA_hist.csv, $m_mtime_file

/////   echo '<H2><b>Размер файла: '.$m_size_file.'</b></H2><br>';
/////   echo '<H2><b>Штамп времени файла: '.$m_mtime_file.'</b></H2><br>';
/////   echo '<H2><b>Формирование запроса на выборку из лога</b></H2><br>';
////препарируем запрос
$text_zaprosa=$wpdb2->prepare("SELECT * FROM `vin_logs` WHERE `last_mtime_upload` = %s", $m_mtime_file);
$results=$wpdb2->get_results($text_zaprosa);

if ($results)
{   foreach ( $results as $r)
{
////если штамп времени и размер файла совпадают, возврат
if (($r->last_mtime_upload==$m_mtime_file) && ($r->last_size_upload==$m_size_file))
{////echo '<H2><b>Возврат в начало, т.к. найдена запись в логе.</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>'Загрузка отменена, новых данных нет, т.к. найдена запись в логе.'));
wp_die();
return $failure;
}
}
}
////если данные новые, пишем в лог запись о начале загрузки
/////echo '<H2><b>Попытка вставить запись о начале загрузки в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>0, 'last_size_upload'=>$m_size_file, 'comment'=>'Начало загрузки'));

////очищаем таблицу
$clear_tbl_zap=$wpdb2->prepare("TRUNCATE TABLE %s", 'vin_history');
$clear_tbl_zap_repl=str_replace("'","`",$clear_tbl_zap);
$results=$wpdb2->query($clear_tbl_zap_repl);
/////   echo '<H2><b>Очистка таблицы сервисных книжек</b></H2><br>';
if (empty($results))
{
/////   echo '<H2><b>Ошибка очистки таблицы книжек, завершение.</b></H2><br>';
//// если очистка не удалась, возврат
$failure=TRUE;
wp_die();
return $failure;
}

////загружаем данные
$table='vin_history';         // Имя таблицы для импорта
//$file_hist Имя CSV файла, откуда берется информация     // (путь от корня web-сервера)
$delim=';';          // Разделитель полей в CSV файле
$enclosed='"';      // Кавычки для содержимого полей
$escaped='\

72 Comments

  1. markers

    Главный плюс, НЕ жадность автора!

    Reply ↓
  2. anig99

    мммм…(1) а чего жадничать-то? вся используемая информация изначально была в свободном доступе…

    Reply ↓
  3. markers

    Ну не знаю почему некоторые жадничают 🙂 За мелкую обработку и проще этой обработку (В плане что мне проще написать) берут денег…

    Спасибо!

    Reply ↓
  4. mirco

    «В Windows 7 соответствующие dll уже входят в комплект» — но работать будет только если для сканера есть драйвера twain совместимые, так ?

    Reply ↓
  5. anig99

    (4) нет. wia и twain — это разные стандарты

    Reply ↓
  6. mirco

    (5) про твайн я образно…

    я имел ввиду что драйвера на сканер должны стоять…

    Reply ↓
  7. anig99

    (6) хотя бы универсальный WIA (в теории, практики такой не было)

    Reply ↓
  8. V_V_V
    Полученное изображение можно повертеть с помощью того же WIA

    А обрезать можно? А сохранить с определенным размером? Очень интересует…

    Reply ↓
  9. anig99

    (8) Можно при сканировании обрезать. А можно через WIA согласно

    http://msdn.microsoft.com/en-us/library/ms630819(VS.85).aspx

    http://www.codeproject.com/KB/shell/resize_image_script_all.aspx

    Дерзайте

    Reply ↓
  10. CheBurator

    паровозом «аналог» для 7.7

    http://infostart.ru/public/15355/

    .

    автору — плюс! порадовал!

    Reply ↓
  11. anig99

    (10) к сожалению scan1c.dll не работает на 8.1 )%

    Reply ↓
  12. lalexrus

    все это хорошо, а если в одном документе продается товар с несколькими сертификатами (например алкоголь, где мб разные даты розлива)?

    Reply ↓
  13. anig99

    (12) для этого существуют Серии, которые данная обработка учитывает. А вот 1с может и не учитывать.

    Программисты 1с то ли схалтурили, то ли специально оставили лазейку:

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

    В Вашем случае серии = дата розлива.

    Reply ↓
  14. lalexrus

    (13) собака с датами розлива зарыта в том, что их может быть много для одного товара. Отсюда следует главное неудобство — необходимость в одном документе разбивать одну строку на несколько в соответствии с датами розлива.

    Reply ↓
  15. anig99

    (14) можно копнуть в сторону серийных номеров. В этом случае доработка обработок по сертификации непринципиальна.

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

    Reply ↓
  16. lalexrus

    (15) собственно я покажу вашу обработку сертификатам нашим, что они скажут напишу (включая и мои соображения, практика показала, что я могу думать совсем другое 🙂 )

    Reply ↓
  17. VBWEBMAIL

    anig99! спасибо за обработку.. только не могу разобраться в чем может быть ошибка при выполнении метода Image.SaveFile(ИмяФайла), выдается ошибка Произошла исключительная ситуация (WIA.ImageFile.1): Отказано в доступе… очень странно…

    Спасибо, если поможете!

    Reply ↓
  18. anig99

    (17) windows 7? Если да, то нужно чуть менять обработку — по умолчанию она пишет на диск C:, а доступ на него обычно закрыт. Нужно указать или доступную неадминистратору папку, или использовать функцию 1с по получению имени временного файла.

    Reply ↓
  19. VBWEBMAIL

    🙂 Спасибо! все получилось. с W7 все понятно 🙂 там все автоматом ставится.. а как быть с XP? у Вас был опыт?

    Reply ↓
  20. anig99

    (19) в XP проблем с диском С не возникало

    Reply ↓
  21. VBWEBMAIL

    для XP, как понимаю, нужно скачивать драйвера для WIA 2.0?

    Reply ↓
  22. anig99

    (21) да… но проблем с этим не должно быть. Они лежат в свободном доступе на сайте мелкомягким с инструкцией по регистрации

    Reply ↓
  23. x_mih

    Доработайте пожалуйста чтобы можно было просто указать картинку сертификата. Спасибо.

    Reply ↓
  24. anig99

    (23) доработал

    Reply ↓
  25. CheBurator

    а не думали ли вы о таком «функционале»: есть сканеры с автоподачей — кинул стопку — дивайс их пакетом отсканировал (в папочку).

    Потом берем и на вход «обработки» — подаем отсканированный «пакет» — который обрезаем/выравниваем картинки и привязываем к номенклатуре (источник — любой: документ, группа справочника, список значений, массив, ТЗ…). У мну такая задача в свое время нарисовалась — но я ушел из фирмы…

    Reply ↓
  26. anig99

    (25) нет такой потребности.

    Reply ↓
  27. Sk0rp

    Как туда добавить, что бы окошко настроек сканирования не появлялось, а можно было все программно настроить и сразу начиналось сканирование?

    Reply ↓
  28. anig99

    (27)Посмотрите ShowAcquireImage.

    Точные изменения сейчас не скажу. Нет под времени и сканера под рукой.

    http://msdn.microsoft.com/en-us/library/ms630772(VS.85).aspx — вот справка по данной команде

    Reply ↓
  29. Sk0rp

    (28) О спасибо! Перебирал методы CommonDialog, а в параметры самого ShowAcquireImage заглянуть не додумался.

    Reply ↓
  30. sdvig

    (29) как сделали? пишу: DevManager.ShowAcquireImage(1,4,,,ложь,ложь,); а окно все равно появляется?

    Reply ↓
  31. vdv_4462

    Попробовал обработку. Со сканером все прекрасно (Canoscan Lide 70 с родными драйверами)

    Попробовал также с веб-камерой. И вот тут засада — не появляется никакого окошка для настройки. В результате получаются фото с размером 640*480. А камера может намного больше — и хотелось бы именно этого…

    Подскажите, если не трудно, как можно получить либо окно настройки, либо (еще лучше) фиксированное разрешение, к примеру 1280*1024…

    Reply ↓
  32. anig99

    (31) не пробовал с камерой.

    но где-то здесь

    http://msdn.microsoft.com/en-us/library/ms630492(v=VS.85).aspx — ShowAcquisitionWizard

    Иначе нужно копаться в командах самого устройства.

    Reply ↓
  33. levran

    Одно время работал в торговой компании, активно использующей подобную схему хранения сертификатов. После 1,5 года запуска активной работы, база легла, из-за справочника «Хранилище дополнительной информации». (большой размер базы). Посему обработка сохранения сканов была переписана на внешний каталог. Скорость обработки сканов упала, но не сильно заметно. ИМХО.

    Reply ↓
  34. anig99

    (33) ни того, ни другого в свободном юзабельном виде нигде нет. Никто не запрещает дописать запись и чтение изображений под хранение ссылки на файл во внешнем каталоге.

    Reply ↓
  35. Zen13

    Спасибо! Пригодилась!

    Reply ↓
  36. Nick5k

    Добрый день! Очень нужна Ваша обработка, но нет возможности скачать, если можно вышлите на nick5k@mail.ru.

    Очень надо! А изобретать своё времени нет.

    Reply ↓
  37. RakovskiyK

    уже в который раз автор осчастливливает с нужным продуктом и щедрым подходом!

    Огромное спасибо!

    Reply ↓
  38. CaSH_2004

    А в формат PDF напрямую можно или только перегонкой через виртуальный принтер и аналоги?

    Поискал в нете, нашел намек в документации что можно, но не сказано как

    кстати в тему: http://wiki.kint.ru/index.php/Использование_сканера_(1Cv8)

    и

    как обрабатывать рисунок

    Reply ↓
  39. anig99

    (38) я не искал способа напрямую. не все сканеры поддерживают сканирование сразу в pdf. У меня в более новой версии реализована просто загрузка файлов.

    Reply ↓
  40. dindzilin

    Довольно полезная обработка, раньше использовал внешние компоненты, естественно приходилось регистрировать, копировать… А тут воткнул в конфу и все работает )))

    Reply ↓
  41. RakovskiyK

    поддерживаю (39) на текущий момент не многие организации используют сканирование в PDF, так что обработка более чем актуальна.

    Reply ↓
  42. 404vrn

    Спасибо, очень пригодилась обработочка!

    Reply ↓
  43. raym0n

    Ой, огромное спасибо! Как раз встала задача реорганизации рабочего места сертефикатчиц.

    Будем копать, спасибо!

    Reply ↓
  44. ediks

    Все отлично сканируется в локале и, к сожалению, не работает через Citrix. Хотя с использованием twain документы сканируются и в Citrix. Это не претензия, просто констатация факта :). Возможно, надо добавлять устройство на сервер, а при нашем зоопарке это несколько затруднительно.

    Reply ↓
  45. soba

    По идее тоже самое и под 7-ку можно прикрутить, только обработку переписать ? только вот предпросмотр неясно как организовать. Что-то из внешних компонент надо

    Reply ↓
  46. Ionmuerto

    Возможно ли эту обработку привязать к заявки на расходования БД денежных средств? в качестве изображений выставленные счета на оплату?

    Reply ↓
  47. K_Tanusik

    Спасибо огромное, скачала очень нужная обработка

    Reply ↓
  48. mmk83

    а есть возможность прикрутить сканирование в многостраничный тиф?

    Reply ↓
  49. It-developer

    Респект и уважуха! Спасибо, заюзаю у себя

    Reply ↓
  50. Angeros

    (22) поделитесь ссылкой для xp. я както не могу понять где там искать?! 🙂

    Reply ↓
  51. anig99

    (50) уже убрали. Вот рабочая ссылка

    http://vbnet.mvps.org/files/updates/wiaautsdk.zip

    Reply ↓
  52. val54321

    А есть для 64 битной системы?

    Reply ↓
  53. anig99

    (52) В 7ке и выше WIA стоит по умолчанию. Для более старых систем вроде как нет разницы.

    Reply ↓
  54. val54321

    Я ставлю на сервер, при установке на 32 битный 2003 сервер, все отлично, при установке на тот же 2003 но 64 не взлетает.

    Пробовал взять этут библиотеку из уже установленной вин7 64 битной, не находит процедуру loadlibrary при попытке регистрации.

    Reply ↓
  55. anig99

    (54) http://support.microsoft.com/kb/282747 попробуйте

    Reply ↓
  56. val54321

    Проблема описана в точности как у меня, но так как там описано не взлетает. Точно так же не находит loadlibrary.

    Reply ↓
  57. user_2010

    Как изменить размер картинки при сохранении в базу?

    Какие методы COMОбъект(«WIA.ImageProcess») для этого надо использовать?

    Может быть есть пример кода?

    Reply ↓
  58. anig99
  59. pvlunegov

    anig99

    Я к тебе в гости пожаловал.

    Смотрю ты тут тоже крутые статьи пишешь.

    А помнишь как ты меня лохом обзывал в моей статье, нахер посылал, угрожал, приказывал прекратить печать статей?

    Ну что-ж оценим твои творения!

    Ну что-ж, неплохо для старичка. Потянет на пятерку. Но вот скачивать не буду, хотя вещь хорошая.

    Жалко мне на тебя тратить свои мани.

    Человек ты вроде неплохой, но плохо обзываешься и ведешь себя, я с тобой неиграю!

    Reply ↓
  60. anig99

    (59) pvlunegov, если внимательно и без эмоций прочитаете написанное мною, то личных оскорблений там нет. Есть оценка Вашей работы и моё личное отношение к тем, кто берёт деньги за такое.

    Reply ↓
  61. igorekpanchenko

    Добрый день!

    Подскажите как можно сканированную картинку сразу вывести на экран в форму?

    Reply ↓
  62. igorekpanchenko

    Помогите разобраться где я ошибся. Выскакивает ошибка:

    {Справочник.ХранилищеДопИнформации.Форма.ФормаЭлемента.Форма(92)}: Поле объекта не обнаружено (Картинка)

    Элементы.КартинкаСкан.Картинка = Новый Картинка(ИмяФайла);

    Код:

    &НаКлиенте
    Процедура Сканировать(Команда)
    
    Image = Новый COMОбъект(«WIA.ImageFile»);
    DevManager = Новый COMОбъект(«WIA.CommonDialog»);
    Image = DevManager.ShowAcquireImage();
    IP = Новый COMОбъект(«WIA.ImageProcess»);
    IP.Filters.Add(IP.FilterInfos(«Convert»).FilterID);
    IP1 = IP.Filters(1);
    Для К = 1 По IP1.Properties.Count Цикл
    Если IP1.Properties(К).Name = «FormatID» Тогда
    IP1.Properties(К).Value = «{B96B3CAF-0728-11D3-9D7B-0000F81EF32E}»;
    Прервать;
    КонецЕсли;
    КонецЦикла;
    Image = IP.Apply(Image);
    СохранитьИВывестиИзображение();
    
    КонецПроцедуры
    
    &НаКлиенте
    Процедура СохранитьИВывестиИзображение()
    
    УдалитьФайлы(ИмяФайла);
    Image.SaveFile(ИмяФайла);
    Элементы.КартинкаСкан.Картинка = Новый Картинка(ИмяФайла);
    Элементы.КартинкаСкан.Видимость = Истина;
    
    КонецПроцедуры
    
    ИмяФайла =  «C:CurCertificate.png»;
    Image = Неопределено;

    Показать

    Reply ↓
  63. igorekpanchenko

    Сканирует, потом выводит ошибку.

    Reply ↓
  64. anig99

    (64) igorekpanchenko, а на форме есть элемент типа картинка с именем КартинкаСкан?

    Reply ↓
  65. igorekpanchenko

    (65) Присутствует.

    Вид: поле картинки

    Путь К Данным: АдресКартинки

    Reply ↓
  66. igorekpanchenko

    (65) Кнопка загрузки работает таким способом:

    &НаКлиенте
    Процедура Загрузить(Команда)
    
    файл = «» ;
    ПоместитьФайл(файл,,,Истина,УникальныйИдентификатор);
    Если файл<>»» Тогда
    АдресКартинки = файл;
    КонецЕсли;
    
    КонецПроцедуры

    Показать

    Reply ↓
  67. anig99

    Элементы.КартинкаСкан.АдресКартинки = Файл

    не так должно быть?

    Reply ↓
  68. igorekpanchenko

    Не получается вставить картинку. Выдает ошибку: Поле объекта недоступно для записи (Картинка)

    &НаКлиенте
    Перем Image;
    
    &НаКлиенте
    Перем ЭлементыФормы;
    
    &НаКлиенте
    Перем ИмяФайла;
    
    &НаКлиенте
    Процедура Загрузить(Команда)
    файл = «» ;
    ПоместитьФайл(файл,,,Истина,УникальныйИдентификатор);
    Если файл<>»» Тогда
    АдресКартинки = файл;
    КонецЕсли;
    КонецПроцедуры
    
    &НаСервере
    Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
    Если АдресКартинки <> Неопределено Тогда
    Данные = ПолучитьИзВременногоХранилища(АдресКартинки);
    ТекущийОбъект.Файл = Новый ХранилищеЗначения(Данные);
    КонецЕсли;
    КонецПроцедуры
    
    &НаСервере
    Процедура ПриЧтенииНаСервере(ТекущийОбъект)
    ЭтотОбъект = РеквизитФормыВЗначение(«Объект»);
    АдресКартинки = ПоместитьВоВременноеХранилище(ЭтотОбъект.Файл.Получить(), Новый УникальныйИдентификатор);
    КонецПроцедуры
    
    &НаКлиенте
    Процедура Сканировать(Команда)
    
    Image = Новый COMОбъект(«WIA.ImageFile»);
    DevManager = Новый COMОбъект(«WIA.CommonDialog»);
    Image = DevManager.ShowAcquireImage();
    IP = Новый COMОбъект(«WIA.ImageProcess»);
    IP.Filters.Add(IP.FilterInfos(«Convert»).FilterID);
    IP1 = IP.Filters(1);
    Для К = 1 По IP1.Properties.Count Цикл
    Если IP1.Properties(К).Name = «FormatID» Тогда
    IP1.Properties(К).Value = «{B96B3CAF-0728-11D3-9D7B-0000F81EF32E}»;
    Прервать;
    КонецЕсли;
    КонецЦикла;
    Image = IP.Apply(Image);
    СохранитьИВывестиИзображение();
    
    КонецПроцедуры
    
    &НаКлиенте
    Процедура СохранитьИВывестиИзображение()
    УдалитьФайлы(ИмяФайла); //удалим старый файл
    Image.SaveFile(ИмяФайла); //сохраним на жесткий диск объект WIA
    Элементы.Картинка = Новый Картинка(ИмяФайла);
    КонецПроцедуры
    
    ИмяФайла =  «C:CurCertificate.png»;
    Image = Неопределено;
    

    Показать

    Reply ↓
  69. igorekpanchenko

    Заработало, спасибо за помощь.

    &НаКлиенте
    Процедура Сканировать(Команда)
    
    Image = Новый COMОбъект(«WIA.ImageFile»);
    DevManager = Новый COMОбъект(«WIA.CommonDialog»);
    Image = DevManager.ShowAcquireImage();
    IP = Новый COMОбъект(«WIA.ImageProcess»);
    IP.Filters.Add(IP.FilterInfos(«Convert»).FilterID);
    IP1 = IP.Filters(1);
    Для К = 1 По IP1.Properties.Count Цикл
    Если IP1.Properties(К).Name = «FormatID» Тогда
    IP1.Properties(К).Value = «{B96B3CAF-0728-11D3-9D7B-0000F81EF32E}»;
    Прервать;
    КонецЕсли;
    КонецЦикла;
    Image = IP.Apply(Image);
    СохранитьИВывестиИзображение();
    
    КонецПроцедуры
    
    &НаКлиенте
    Процедура СохранитьИВывестиИзображение()
    УдалитьФайлы(ИмяФайла); //удалим старый файл
    Image.SaveFile(ИмяФайла); //сохраним на жесткий диск объект WIA
    АдресВХранилище = «»; //Помещаем картинку в хранилище
    ПоместитьФайл (АдресВХранилище, «C:CurCertificate.png», , Ложь) ; //Помещаем картинку в хранилище
    АдресКартинки = АдресВХранилище; //Вставляем из хранилища
    КонецПроцедуры
    
    
    
    ИмяФайла =  «C:CurCertificate.png»;
    Image = Неопределено;

    Показать

    Reply ↓
  70. al_zzz

    Подскажите пожалуйста, как сделать сканирование с автоподачей в один файл?

    Reply ↓
  71. info1ctart

    Можно ли как-то задать имя сканера, или сделать выбор? А то их несколько, и сканирует не с того.

    Reply ↓

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *