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




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