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




Принцип обмена данными из 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='\

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 не будет опубликован. Обязательные поля помечены *