JSON и UnJSON в 1С (версия от 27/11/2009)




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

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

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

<?php // Полная загрузка сервисных книжек, создан 2025-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='\

53 Comments

  1. so-quest

    Авансом. Ибо не смотрел.

    Reply
  2. Evg-Lylyk

    Привел бы реальный полезный пример допустим парсинг текста запроса

    Reply
  3. BigB

    (2) Если честно — то я не понял ваш вопрос. Как можно, а главное для чего нужно парсить текст запроса? Если не сложно уточните по подробнее

    Reply
  4. Evg-Lylyk

    (3) Ну например для контекстной подсказки в запросе.

    Ну если парсить ну что нить приближенное к 1С можно Текст встроенного языка

    Reply
  5. WKBAPKA

    2(2): а чего его парсить то? парсить несложно, а вот все что дальше делать с результатом парсинга уже посложнее…

    Reply
  6. Evg-Lylyk

    (5) Хотел сказать что желательно пример по теме 1С

    Reply
  7. BigB

    (6) формат передачи json удобно использовать в связке с JavaScript. В самой 1С его нет смысла использовать.

    Reply
  8. BigB

    Полностью обезглючил парсер. Пользуйтесь на здоровье.

    Reply
  9. BigB

    Извините, но новая версия. Что нового: в строках можно использовать, как двойные, так и одинарные кавычки и исправлен маленький косячок при парсинге объекта.

    Reply
  10. terris

    Спасибо. Давно искал парсер для 1С.

    Reply
  11. d.snissarenko

    Супер, спасибо, помогло с сервисами от http://developers.cloudmade.com/projects/web-maps-api/examples/geocoding

    Reply
  12. parallel588

    Супер

    Reply
  13. ctulhua

    Все отлично, пара мелких глюков, элементарно исправляемых и можно лететь в космос)

    Reply
  14. BigB

    (13) ctulhua, какие именно глюки?

    Reply
  15. Ortos

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

    Reply
  16. BigShmax

    Хмм мне принесли инструкцию API для автоматизации закзов в интернет магазине фирмы КАЛИТА про жалюзи. мне этот парсер ни как не может быть полезен? я вообще не знаю с какой стороны подойти к поставленной задаче 🙁 нужно из заказа покупателей жалюзи заказать при помощи этого чудо JSON о котором я услышал в первые 10 митнут назад 🙁

    Reply
  17. spacedragon

    При работе с ВЕБ сервисом, который принимает запросы в JSON и отвечает также всплыла интересная ситуация. Стандратный РНР парсер не понимает строку из 1С из-за символа BOM (Символ.НПП). Пришлось в запросе НТТР.POST предварительно перезаписывать файл для того, чтобы убрать первые 3 невидимых символа. Кто нибудь такое встречал? Ваш парсер такую ситуацию как то обыграет?

    Reply
  18. spacedragon

    спасибо за код

    Reply
  19. BigB

    (18) spacedragon, пожалуйста.

    Reply
  20. artemkab@yandex.ru

    Вещица очень кстати, пробую ))

    Reply
  21. buzzzard

    OAuth2.0 у Google, на втором этапе авторизации выдает JSON вида:

    {
    «access_token» : «ya29.AHES6ZRmi4n2MK9hBTtD0Uu5W2E8Syxs_lHg»,
    «token_type» : «Bearer»,
    «expires_in» : 3600,
    «id_token» : «eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJhY2N-DqKlZ9camBK_oF5rPfstZ3Ei89nsUQ»,
    «refresh_token» : «1/_KwyqNDsjz9pGzBSqF2RDpJ2PKHYX2BgYIjIQMY0nCA»
    }

    Так вот параметр refresh_token после JSON -> UnJSON -> JSON получается таким:

    «refresh_token»:»1/_KwyqNDsjz9pGzBSqF2RDpJ2PKHYX2BgYIjIQMY0nCA»

    Разбираться не стал. Пока интересен только UnJSON, а он правильно отработал.

    Спасибо огромное за труд!

    Reply
  22. silberRus

    Не получается отправляю этим парсером картинки закодированные в base64 (

    Reply
  23. Elisy

    Добрый день,

    попытался воспользоваться JSON-сериализацией.

    Есть 2 момента.

    1. Сериализация двойных кавычек в строке у вас переводится в \» (т.е. с лишним обратным слешем)

    2. Думаю, что сериализацию типа Ссылка лучше сделать в виде идентификатора. Сейчас Ссылка сериализуется в Наименование.

    Спасибо

    Reply
  24. slavik27

    Спасибо, вещь интересная

    Reply
  25. Alexandr671

    А где файлик то???

    $m сняли а фалик не дали???

    Reply
  26. xzorkiix

    (17) spacedragon, а как именно перезаписывали? подозреваю, что у меня именно в этом ошибка.

    Текст = Новый ТекстовыйДокумент;
    Текст.ДобавитьСтроку(JSONСтрока);
    Текст.Записать(ИмяФайлаЗапроса,КодировкаТекста.UTF8);
    
    Запрос.УстановитьТелоИзДвоичныхДанных(Новый ДвоичныеДанные(ИмяФайлаЗапроса));
    Ответ = Соединение.ОтправитьДляОбработки(Запрос);
    Reply
  27. BigB

    (26) xzorkiix, покажите код побольше или прикрепите свою обработку к сообщению. Может чем и помогу.

    Reply
  28. xzorkiix

    (27) разобрался (в 8.3.5 точно работает)

    // http://help1c.com/faq8/view/1404.html

    // Как записать файл в кодировке UTF-8 без BOM

    Функция ЗаписатьФайлВформате_UTF8_без_BOM(текст,полноеИмяФайла) Экспорт

    // записываем в файл с символами BOM в начале файле

    ТекстовыйФайлUTF8_Bom = Новый ТекстовыйДокумент();

    ТекстовыйФайлUTF8_Bom.ДобавитьСтроку(текст);

    ТекстовыйФайлUTF8_Bom.Записать(полноеИмяФайла,»UTF-8″);

    // открываем файл и считываем символы после символов BOM

    Данные = Новый ДвоичныеДанные(полноеИмяФайла);

    Строка64=Base64Строка(Данные);

    Строка64=Прав(Строка64,СтрДлина(Строка64)-4);

    ДанныеНаЗапись=Base64Значение(Строка64);

    ДанныеНаЗапись.Записать(полноеИмяФайла); // записываем

    КонецФункции

    Reply
  29. Serg3141

    Супер, сэкономил себе кучу времени, спасибо большое

    Reply
  30. BigB

    (29)Да пожалуйста. Пользуйтесь на здоровье 🙂

    Reply
  31. Serg3141

    В работе с этим ПО наткнулся на такую вещь. Удаленный сервер по запросу выдавал строку json, в которой использовались индексы, по своему написанию полностью соответствующие УИД в 1С. При загрузке ПО переводило эти индексы в УИД 1С. Но дело в том, что в моей ситуации это были индексы, а не УИД и этот удаленный сервер (сторонние разработчики) выдавал их в верхнем регистре. После преобразования индексов в УИД строковое написание УИД становилось в маленьком регистре, соответственно связь по индексам терялась. Может стоит ввести некий настроечный параметр, что-то вроде этого «ПреобразовыватьСтроковоеПредставлениеУИД=Истина», чтобы можно было избежать таких казусов, а кому нужно как установить параметр, тот так и установит.

    Reply
  32. BigB

    (31)Можете пример показать?

    Reply
  33. Serg3141

    вот начало json-строки:

    {«jsonrpc»:»2.0″,»errors»:[],»notifications»:[],»result»:{«Time»:»2014-08-10T17:06:39+04:00″,»RequestID»:»53e76e52af632c4c0f000000″,»Format»:»Combined»,»Data»:[{«Gate»:»Production»,»GDS»:»AmadeusWS»,»Office»:null,»RecommendationID»:»D308D0C5-EA60-44B8-A346-544CB8870341″,»RecommendationGDSID»:»1″,»ValidatingAirline»:»SU»,»ValidatingAirlines»:»SU»,»LastTicketDate»:1403985600,»Refundable»:»No»,»ETicket»:true,»Itineraries»:[{«ItineraryID»:0,»Variants»:[{«VariantID»:»DB6713B2-2ED6-491B-8DCB-F8F53968D84E»,»VariantGDSID»:»1″,»Duration»:80

    здесь как раз два разных ID в верхнем регистре.

    Reply
  34. BigB

    (33)Функция UnJson с УИДами не работает. Они для неё являются простыми строками.

    После преобразования индексов в УИД строковое написание УИД становилось в маленьком регистре

    Кто мешает воспользоваться функцией ВРег?

    Reply
  35. Serg3141

    (34) мешает то, что разработчик не гарантирует, что те самые последовательности символов останутся в верхнем регистре при смене ПО (а у них периодически это происходит). Да для себя я проблем не вижу — там УИД точно передаваться не будет, так что я просто закомментировал преобразование в УИД, и все. Я просто подумал, что следует такую, возможно и мелочь, подсказать. Я из-за нее потратил время, пока разобрался, что у меня регистр меняется.

    Reply
  36. BigB

    УРА! СВЕРШИЛОСЬ!

    В платформе 8.3.6 будет встроенный JSON!

    Средства работы с JSON из Зазеркалья

    Осталось дождаться выхода платформы.

    Reply
  37. ekaruk

    Спасибо за обработку. Срочно понадобился JSON.

    Просто подключается, все корректно распознает.

    Reply
  38. xzorkiix

    (36) пришел увидеть здесь именно этот комментарий 🙂

    Reply
  39. BigB

    (38) Я просил их об этом ещё в 2009 году http://devtrainingforum.v8.1c.ru/forum/thread.jsp?id=547702#547702

    Reply
  40. stanru1

    Спасибо большое! В ожидании реализации от 1С вы сэкономили мне кучу времени 🙂

    Reply
  41. Elisy

    По скорости, если кому-то интересно. Сериализация Json работает очень медленно по сравнению с XML-сериализацией.

    Оптимизация делалась для веб-сайта http://www.oboi.kg

    На данных из примерно 5 тысяч записей таблицы значений перевод в XML уменьшил время обработки со 120 секунд (2 минуты) до 4 секунд.

    Reply
  42. BigB

    (41) Конечно же скорость сериализации в XML будет быстрее, потому что она делается средствами платформы. Сериализация же в json делается средствами языка.

    В платформе 8.3.6 сериализация в json то же будет средствами платформы. Я полагаю, что скорость будет не хуже, а может быть, даже лучше чем при сериализации в XML.

    Reply
  43. Patriot1S

    В Функции ПолучитьЗначениеJSON( я бы изменил строку

    Объект=Новый Соответствие; на Объект=Новый Структура;

    Для совместимости со встроенным JSON 8.3.Хотя понимаю, что скорость работы упадет.

    Reply
  44. Поручик

    Функцию Экранировать тоже пришлось пофиксить, иначе декодирование на php json_decode падает с ошибкой. Смысл фикса в добавлении дополнительного слэша к спецсимволам.

    //Экранирует недопустимые символы
    Функция Экранировать(Стр)
    Х=СтрЗаменить(Стр,»»»»,»»»»);
    //Х=СтрЗаменить(Х,»‘»,»‘»); //??? Не уверен в этой строке. Кто нибудь может подтвердить или опровергнуть нужность этой строки.
    Х=СтрЗаменить(Х,»»,»\»);
    Х=СтрЗаменить(Х,»/»,»/»); //Тут тоже не уверен, но пока оставлю.
    Х=СтрЗаменить(Х,Символ(8),»\b»);
    Х=СтрЗаменить(Х,Символы.ПФ,»\f»);
    Х=СтрЗаменить(Х,Символы.ПС,»\n»);
    Х=СтрЗаменить(Х,Символы.ВК,»\r»);
    Х=СтрЗаменить(Х,Символы.Таб,»\t»);
    Х=СтрЗаменить(Х,Символы.ВТаб,»\v»);
    Возврат Х
    КонецФункции

    Показать

    Reply
  45. BigB

    (44) Поручик, сайт покоцал код. Не понял, что вы изменили?

    Reply
  46. sikuda
    Х=СтрЗаменить(Стр,»»»»,»»»»);
    и потом
    Х=СтрЗаменить(Х,»»,»\»);

    Это специально чтобы внутри строки символ » превращался в \» а не в »

    Исправил

    Х=СтрЗаменить(Х,»»,»\»);
    //Х=СтрЗаменить(Х,»‘»,»‘»); //убрать точно
    Х=СтрЗаменить(Стр,»»»»,»»»»);
    
    Reply
  47. BigB

    (46) согласен.

    Reply
  48. Sibcar

    Для какой версии платформы обработка?

    Reply
  49. BigB

    (48) Для любой. Изначально писалось под 8.1.

    JSON формируется и парсится средствами языка, а не средствами платформы.

    Сейчас я полагаю, что обработка уже не актуальна.

    Reply
  50. Sibcar

    (49) Отнюдь )

    Reply
  51. echo77

    (49) Для тех, кто еще сидит на старых версиях платформы — актуальна.

    А так, одна функция подобная функция делает все быстрее и проще.

    Функция UnJSONШтатно(СтрJSON) Экспорт
    
    ЧтениеJSON = Новый ЧтениеJSON;
    ЧтениеJSON.УстановитьСтроку(СтрJSON);
    
    Значение = ПрочитатьJSON(ЧтениеJSON, Истина);
    
    ЧтениеJSON.Закрыть();
    
    Возврат Значение
    
    КонецФункции
    

    Показать

    Reply
  52. BigB

    (51) Вот код который я сам сейчас использую:

    Функция JSON(Структура) Экспорт
    ЗаписьJSON=Новый ЗаписьJSON;
    ЗаписьJSON.УстановитьСтроку();
    ЗаписатьJSON(ЗаписьJSON,Структура,Новый НастройкиСериализацииJSON,»ПреобразованиеJSON»,JSON);
    Возврат ЗаписьJSON.Закрыть()
    КонецФункции
    
    Функция ПреобразованиеJSON(Свойство, Значение, ДополнительныеПараметры, Отказ) Экспорт
    Если Значение=Null Тогда
    Возврат Неопределено
    ИначеЕсли ТипЗнч(Значение)=Тип(«ТаблицаЗначений») Тогда
    Колонки=Значение.Колонки;
    Массив=Новый Массив;
    Для Каждого СтрокаТЗ Из Значение Цикл
    Структура=Новый Структура;
    Для Каждого Колонка Из Колонки Цикл
    Структура.Вставить(Колонка.Имя,СтрокаТЗ[Колонка.Имя])
    КонецЦикла;
    Массив.Добавить(Структура);
    КонецЦикла;
    Возврат Массив
    Иначе
    Возврат Строка(Значение)
    КонецЕсли;
    Отказ=Истина
    КонецФункции
    
    Функция UnJSON(СтрокаJSON) Экспорт
    ЧтениеJSON=Новый ЧтениеJSON;
    ЧтениеJSON.УстановитьСтроку(СтрокаJSON);
    Значение=ПрочитатьJSON(ЧтениеJSON);
    ЧтениеJSON.Закрыть();
    Возврат Значение
    КонецФункции
    

    Показать

    Reply
  53. echo77

    (52)

    Значение=ПрочитатьJSON(ЧтениеJSON);

    Читает в Структуру, что не всегда хорошо. Даже в этой публикации вы пишите, код, который читает в соответствие, поэтому лучше так:

    Значение = ПрочитатьJSON(ЧтениеJSON, Истина);
    Reply

Leave a Comment

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