Как формируется GUID?




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

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

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

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

    Малаца!

    Reply
  2. Идальго

    Красавчик ваще!

    Reply
  3. NoRazum

    как долго шел к сути ответа.

    Отличная статья.

    Reply
  4. baton_pk

    (4) знать, не задавать вопросов и давать ссылку тем, кто не знает и задаёт вопросы.

    Reply
  5. dgolovanov

    «Надеюсь, теперь мысль о том, чтобы «упорядочить по ссылке», я из вас вытряхнул окончательно.»

    Ну или ставить галку «Автоупорядочивание» ))

    Reply
  6. NN2P

    Так держать, Николай! Отличная статья!

    Reply
  7. panvartan

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

    Reply
  8. корум

    (8) а почему решил, что нельзя?

    Записывай как строку и вперёд.

    Reply
  9. panvartan

    (8) а почему решил, что нельзя?

    Записывай как строку и вперёд.

    Поэтому и спрашиваю — почему отсутствует нативный способ выбора типа «уникальный идентификатор», в регистре сведений он же присутствует. Может причина в нежелательности его использования.

    Reply
  10. bforce

    Не думал, что будет интересно. Но автору удалось. Узнал новые аспекты и позаимствовал себе

    СмещениеСтандартногоВремени() + СмещениеЛетнегоВремени()

    Спасибо!

    Reply
  11. PerlAmutor

    Если кому интересно почему дата 15.10.1582. В этот день Папа Римский ввел Григорианский календарь взамен Юлианского.

    использовалось 2 варианта: для вередачи по сети

    Поправьте опечатку.

    Есть вопрос. MAC адрес берется клиента или сервера?

    Упорядочивать по времени не будем, а вот отсечь какие-нибудь элементы справочника на основе времени полученного из UUIDA все-таки можно.

    Reply
  12. starik-2005

    Блин, хотел как в (1), но уже )))

    Reply
  13. Region102

    А можно как-то сформировать GUID на php? Просто пишу front для 1С и охота чтобы при отсутствии связи с 1С можно было создавать элементы в MySQL, а потом синхронить их с 1С с готовыми GUID.

    Reply
  14. starik-2005

    (14)

    А можно как-то сформировать GUID на php?

    Так.

    Reply
  15. Region102

    (15) Спасибо, слона то я и не заметил )

    Reply
  16. Aprobator

    Вот спасибо! Теперь буду знать, что гуид уникален не в рамках одной базы 1с. А то по дурости (незнанию — эти понятия недалеко друг от друга ушли), в правилах конвертации отключал поиск по уникальному идентификатору. Надо было, реально, самому погуглить, а что же такое GUID.

    Reply
  17. baclanov

    Замечательная статья! Считаю, что тема раскрыта не полностью, скромно опущен «идентификатор метаданных» ({«#»,643bfde6-77a8-4438-874d-733071adf65e,373:a2b40050569302c311e73a3f23930d2d}), а об этом хотелось бы узнать по-подробнее.

    Reply
  18. Трактор

    (17)

    Теперь буду знать, что гуид уникален не в рамках одной базы 1с.

    Всё несколько печальнее. Гуид МОЖЕТ быть уникален не в пределах одной базы. Практически же в одной базе может существовать несколько объектов с одинаковым гуид. В разных таблицах.

    Я столкнулся с этим, когда пользовал конвертацию данных. Конвертация данных сохраняет идентификатор объекта при передаче его в другую базу. Если одному источнику соответствует несколько получателей, то мы получим в одной базе несколько объектов с одинаковы гуид.

    Например, при переходе с УТ10 на УТ11 справочник контрагенты передаётся в справочники контрагенты и партнёры. При этом гуиды у контрагента и партнёра получаются одинаковыми.

    Reply
  19. Aprobator

    (19) интересно однако. Но, я так понимаю, на перенос данных через конвертацию это не особо повлияло, поскольку поиск по идентификатору должен идти в рамках определенного объекта метаданных?

    Reply
  20. vladismi

    Полезная статья

    Reply
  21. Трактор

    (20) верно.

    Reply
  22. brr

    (18) рандомный гуид же

    Reply
  23. Altair777

    (19) не так давно встретился с ситуацией когда гуиды были не уникальны в разных базах. Когда нужно было по-быстрому развернуть новую базу — скопировали старую. Грохнули документы, а справочники оставили. Вместе с их гуидами

    Reply
  24. AlexGroovy

    Очень мощная и полезная статья.Автору большой респект!

    Reply
  25. sdv91

    (8)В измерениях регистра использовать строки — это треш.

    Reply
  26. koshak84

    Как-то была задача во все документы добавить реквизит «Дата создания документа». Для всех существующих документов заполнить эту дату автоматически на основании GUID. Документов было более миллиона. У всех дата из GUID сформировалась в принципе правильно. Т.е. можно сделать вывод, что в 1С (по крайней мере на платформе 8.1) используется Time-Based GUIDs.

    Reply
  27. Irwin
    Reply
  28. TIS_08

    (28) Отличное дополнение.

    Reply
  29. kuzyara

    (30) В принципе верно, только не зашит, а подставляется, не в GUID, а в представление ссылки, не код, а номер таблицы sql, не уникальный, а порядковый 😉

    Reply
  30. red80

    А у кого нибудь были одинаковые GUID разных объектов? У меня — да.

    Reply
  31. Arxxximed

    (32) Брехня )))) Наверняка объекты в разных таблицах и получены переносом данных или конвертации ….

    В (19) уже это рассмотрели.

    Reply
  32. red80

    (33) Одинаковые GUID в разных таблицах одной базы. Были выявлены при выгрузке из нескольких типов документов (Реализация, Авансовый, РозничныеПродажи, ЧекККМ, ОтчетКомиссионера,…) одной базы в документы ВводОстатков другой базы с сохранением GUID документа-источника в документе-приемнике. Что в базе делали до меня — хз.

    Reply
  33. anatoliy.kichuk

    Въедлив — крут! Статья интересная!

    Reply
  34. Поручик

    (15) Надо же, я тоже не знал. А вещь в моём деле нужная.

    Reply
  35. tormozit
    Надеюсь, теперь мысль о том, чтобы «упорядочить по ссылке», я из вас вытряхнул окончательно.

    Рекомендую явно указать, что имеется ввиду «упорядочить по ссылке для получения порядка создания». Иначе неподготовленный читатель может сделать неправильный вывод.

    Reply
  36. tormozit

    (38) Не соглашусь.

    1. Если надо упорядочить по моменту времени, то я использую дату + ссылку (ГУИД).

    2. Если надо получить стабильный порядок ссылок, то я сделаю упорядочивание по ссылке (ГУИД).

    Reply
  37. kuzyara

    (39) Спасибо, меня смутила формулировка. Упорядочивание по ссылке в пределах секунды действительно имеет смысл для работы с моментом времени. А по второму пункту?

    Reply
  38. tormozit

    (40) Что по второму пункту?

    Reply
  39. PerlAmutor

    (40) Нашел интересное, на мой взгляд, применение вашим изысканиям.

    В БСП есть механизм регламентного удаления помеченных на удаление объектов.

    В обработке идет вызов стандартной функции НайтиПомеченныеНаУдаление(), которая возвращает массив ссылок.

    Проход по этому массиву идет с обратным индексом, с конца к началу. Ваша функция получения времени из ссылки помогла определить как именно распределяются объекты в этом массиве по дате создания. И я пришел к выводу, что ссылки в этом массиве располагаются в последовательности прохождения по дереву метаданных, т.к. типы ссылок сгруппированы. Соответственно объекты в этом массиве разбросаны по датам создания и вот чем это плохо:

    — У меня больше 50 000 помеченных на удаление объектов, большая часть из которых Ключи Аналитики Учета Номенклатуры.

    При каждом запуске удаления до «свежепомеченных» объектов дело почти никогда не доходит, т.к. регламентое задание может выполняться больше недели в поисках всех ссылок на эти ключи и это ненормально

    — Регламентное задание каждый раз перелопачивает одни и те же данные снова и снова, хотя заранее и так понятно, что объекты эти не будут удалены никогда, период закрыт. Некоторые объекты полуинформативные, и к сожалению заменить их тоже не чем.

    В общем есть мысль пересортировать массив помеченных таким образом, чтобы объекты помеченные в последнее время удалялись первыми, а старье и объекты с программно установленным Уникальным Идентификатором без даты оказывались в конце списка.

    Reply
  40. Shaka13

    а как, например «b0d27f78-dc86-11e6-898b-bcaec5369a36» преобразовать в бинарник и наоборот из бинарника сделать «b0d27f78-dc86-11e6-898b-bcaec5369a36»?

    Reply
  41. kuzyara

    (43)

    // Преобразует ГУИД из формата 1С в формат SQL

    Функция ГУИДдляSQL(Строка) Экспорт
    Если ПустаяСтрока(Строка) Тогда
    Возврат Строка;
    КонецЕсли;
    Результат = «»;
    Строка = СтрЗаменить(СтрЗаменить(СтрЗаменить(Строка, «-«,»»), «{«, «»), «}», «»);
    СтрокаПозиций = «23211917272531291315091101030507»;
    Для к = 0 По 15 Цикл
    ИсхПозиция = Число(Сред(СтрокаПозиций, к*2+1,2));
    Результат = Результат + Сред(Строка, ИсхПозиция, 2);
    КонецЦикла;
    Возврат Врег(Сред(Результат, 1, 8)+»-«+Сред(Результат, 9, 4)+»-«+Сред(Результат, 13, 4)+»-«+Сред(Результат, 17, 4)+»-«+Сред(Результат, 21, 12));
    КонецФункции // ГУИДдляSQL() 

    Показать

    // Преобразует ГУИД из формата SQL в формат 1С

    Функция ГУИДдля1С(Строка) Экспорт
    Если ПустаяСтрока(Строка) Тогда
    Возврат Строка;
    КонецЕсли;
    Результат = «»;
    Строка = СтрЗаменить(СтрЗаменить(СтрЗаменить(Строка, «-«,»»), «{«, «»), «}», «»);
    СтрокаПозиций = «25272931212317190705030111091513»;
    Для к = 0 По 15 Цикл
    ИсхПозиция = Число(Сред(СтрокаПозиций, к*2+1,2));
    Результат = Результат + Сред(Строка, ИсхПозиция, 2);
    КонецЦикла;
    Возврат Врег(Сред(Результат, 1, 8)+»-«+Сред(Результат, 9, 4)+»-«+Сред(Результат, 13, 4)+»-«+Сред(Результат, 17, 4)+»-«+Сред(Результат, 21, 12));
    КонецФункции 

    Показать

    http://forum.infostart.ru/forum105/topic34914/message385150/#message385150

     г = Справочники.Валюты.ПолучитьСсылку();
    р=ГУИДдляSQL(XMLСтрока(г));
    а=»80B7001517A39B3511E0F63522D8E339″;
    п=ГУИДдля1С(а);
    Reply
  42. Plotks2017

    (26)

    8)В измерениях регистра использовать строки — это треш.

    почему?

    Reply
  43. Shmell

    Работа проделана колоссальная! Молодец. Статья в фаворитах )

    Reply
  44. MrTom

    Для тех, у кого с типами и версиями GUID картинка не сошлась (как у меня), можно посмотреть вот здесь:

    http://guid.one/guid

    Кратко: типов (они же версия, хотя странная путаница здесь) на самом деле 5.

    Reply
  45. MrTom

    (28) Я думаю это знает любой, кто работал с битыми ссылками.

    Битая ссылка имеет вид <Объект не найден> (77:805f000c291e652311e0ad237dea6181). Здесь 77 — это номер таблицы, т.е. тип объекта, об этом уже говорили выше. А строка после двоеточия — это и есть ссылка.

    Если получить ссылку в УФ-базе по кнопке «Получить ссылку», то она будет вот такой:

    e1cib/data/Справочник.Контрагенты?ref=80c574d43512a57311e5ffc8937f5c0f

    Здесь тип указан строкой, а ссылка идет после «ref=»

    Вот код, который получает GUID из ссылки (писал очень давно и для себя 🙂 )

      Поз = Найти(СсылкаУИД, «ref=»);
    Если Поз=0 Тогда
    Поз = Найти(СсылкаУИД, «:»);
    Поз = ?(Поз=0, 0, Поз+1);
    Иначе
    Поз = Поз+4;
    КонецЕсли;
    
    Если Поз=0 Тогда
    Предупреждение(«Ссылка имеет неизвестный формат»);
    Иначе
    Стр = Сред(СсылкаУИД, Поз, 32);
    УИД = Прав(Стр,8)+»-«+Сред(Стр,21,4)+»-«+Сред(Стр,17,4)+»-«+Лев(Стр,4)+»-«+Сред(Стр,5,12);
    КонецЕсли;
    

    Показать

    Одинаковые ссылки с разными типами встречаются не так уж редко даже в одной базе.

    Reply
  46. SerGeoSik

    Хорошо написал. давно искал нечто подобное

    Reply
  47. d4rkmesa

    Спасибо. Однако, вот это утверждение:

    В-третьих, гуид случаен по своему стандарту и время в нем это лишь способ сгруппировать первичные ключи для уменьшения ширины В-дерева и ускорения операций вставки в кластерный индекс!

    ИМХО, это спорно. Т.к. УИД ссылки упаковывается в бинарник, то это почти нивелирует этот эфффект. Я сам как то думал, что рандомные УИД’ы — зло для ссылок в 1С, спорил по этому поводу на форуме. Делал опыт, программно создавал несколько сот элементов справочника Номенклатура в УТ, как вручную назначая УИД («random»), так и нет (чтобы УИД’ы брались из пула сеанса, псевдоупорядочивание).

    Запускал dm_db_index_physical_stats в SQL и никакой разницы не было, индекс не фрагментировался от «рандомных» УИД’ов. Не знаю, может на миллионах записей это имеет значение.

    Reply
  48. frkbvfnjh

    UUID_Node возвращает каждый раз разное значение если передавать ГУИД в виде

    Строка(Новый УникальныйИдентификатор());

    Какой версии должен быть UUID, что бы всегда МАС возвращался?

    Reply
  49. frkbvfnjh

    Что за тайные знаки?

    Reply
  50. frkbvfnjh

    И как в 1С можно сгенерировать time based uuid? Может кто нибудь придумает? У меня вот что то не выходит 🙁

    Reply
  51. kuzyara

    (51-52-53)

    — первой

    — я мясоед)

    — xmlстрока(документы.перемещениетоваров.ПолучитьСсылку())

    Reply
  52. kuzyara

    (18) baclanov, это идентификатор типа ссылки. Сравните:

    _а1 = значениевстрокувнутр(Тип(«Массив»));
    _а2 = значениевстрокувнутр(новый(«Массив»));
    //{«T»,51e7a0d2-530b-11d4-b98a-008048da3034}
    //{«#»,51e7a0d2-530b-11d4-b98a-008048da3034,{0}}
    _б1 = значениевстрокувнутр(Тип(«ТекстовыйДокумент»));
    _б2 = значениевстрокувнутр(новый(«ТекстовыйДокумент»));
    //{«T»,ebf766b1-f32c-11d3-9851-008048da1252}
    //{«#»,ebf766b1-f32c-11d3-9851-008048da1252,{0,{#base64:77u/}}}
    _в1 = значениевстрокувнутр(Тип(«СправочникСсылка.Справочник1»));
    _в2 = значениевстрокувнутр(справочники.справочник1.пустаяссылка());
    _в3 = значениевстрокувнутр(справочники.справочник1.первый);
    //{«T»,03f456d1-078b-47bd-821e-1d16c25cdd8d}
    //{«#»,03f456d1-078b-47bd-821e-1d16c25cdd8d,10:00000000000000000000000000000000}
    //{«#»,03f456d1-078b-47bd-821e-1d16c25cdd8d,10:9db766f0d06c0eb24ef19d0bbdc5c7af}

    Показать

    _Все_ внутренние типы данных имеют идентификатор, в том числе и объекты типа ссылка. Любая ссылка состоит из идентификатора типа, и, собственно, самой ссылки. https://infostart.ru/public/196623/

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

    Reply
  53. lame

    Пользуюсь вот такой вот процедуркой — для получения времени создания объекта по гуид

    Функция ДатаСозданияСсылки(Ссылка)

    //Ссылка- любая ссылка конфигурации на документ или справочник

    ГУИД = Ссылка.УникальныйИдентификатор();

    Строка16 = Сред(ГУИД, 16, 3) + Сред(ГУИД, 10, 4) + Сред(ГУИД, 1, 8);

    Разрядность = СтрДлина(Строка16);

    ЧислоСек = 0;

    Для Позиция = 1 По Разрядность Цикл

    ЧислоСек = ЧислоСек + Найти(«123456789abcdef»,Сред(Строка16,Позиция,1))*Pow(16,Разрядность — Позиция);

    КонецЦикла;

    ЧислоСек = ЧислоСек / 10000000;

    Возврат Дата(1582, 10, 15, 00, 00, 00) + ЧислоСек + СмещениеСтандартногоВремени() + СмещениеЛетнегоВремени();

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

    Reply

Leave a Comment

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