Telegram-боты




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

51 Comments

  1. zeltyr

    Эх, эту бы статью, да неделю назад, когда я только со всем этим начал разбираться.

    Сейчас 90% статьи уже своим умом дошёл.

    Но всё равно, большое спасибо вам за труд.

    Reply
  2. eskor

    + Слежу за этим вопросом еще со времен первой публикации.

    «Телега» единственный мессенджер с вменяемым API, поэтому в корпоративных проектах ему быть.

    Мой «питомец» уже пару лет отчеты шлет 🙂

    Reply
  3. V_V_V

    Адский поток сознания, а не статья… На разделы побить бы, что-ли.

    Имею собственноручно созданного бота — вот ничем бы не помог этот набор слов.

    Reply
  4. PLAstic

    Друзья, кто скачал конфигурацию, в неё закралась ошибка. Я выложил новую версию конфигурации, но вы можете устранить ошибку и вручную: в РС «ЗапросыБоту» реквизит «ТипСообщения» должен иметь тип «Перечисление.ТипыСообщения».

    Для оперативной связи моя телега.

    Reply
  5. imedeev

    Тяжело читать — сплошной текст, но тема интересная.

    Когда то сам делал — для вечерней отправки отчета по ОРП для босса

    Reply
  6. volodya82

    {ОбщийМодуль.Боты.Модуль(72)}: Метод объекта не обнаружен (ПриПолученииСообщения)

    Reply
  7. PLAstic

    (6) Спасибо, закомментировал. Этот кусок кода относился к ботам, которым нужна дополнительная обработка при получении апдейтов. Поскольку фича мало интересная, я не стал её описывать и удалил упоминание.

    Reply
  8. more

    Хорошая информация, для первичного погружения очень хорошо.

    Reply
  9. flyer

    подскажите почему возникает ошибка для getUpdates : Conflict: can’t use getUpdates method while webhook is active?

    Reply
  10. PLAstic

    (9) У вас был установлен вебхук для получения апдейтов. В апи подробно про это было сказано: https://core.telegram.org/bots/api#making-requests-when-getting-updates

    Если его надо выключить, то надо отправить deleteWebhook.

    Reply
  11. flyer

    (10) с этим разобрался спасибо!

    еще подскажите такая ситуация. а то что то видимо делаю не так. добавил бота. test_123456789_bot я с телефона пишу ему и на компьютере вижу сообщение. попросил другого пользователя найти этого бота и ему написать но его сообщения не появляются у меня.

    Reply
  12. sdwggg

    кто-нибудь знает, как реализовать следующее?

    Бот должен ожидать от пользователя ввода даты. При этом на самом устройстве (в данном случае на iPhone) должна появиться клавиатура выбора даты, а не обычная текстовая и не циферная, чтобы в конечном итоге боту была отправлена команда вида «ДД.ММ.ГГГГ»

    Reply
  13. PLAstic

    (137) Виды клавиатур я уже описывал. Для данного случая подходит только инлайн, но делать клавиатуру для ввода времени — это весьма забавно, имхо.

    Reply
  14. Lyolik

    Интересно, а как к кнопке добавить картину — для наглядности. На пример, как на скрине…

    Reply
  15. botokash

    (14) Это эмоджи, добавляйте просто в текст кнопки

    Reply
  16. Lyolik

    (15) Что, именно, нужно добавить? У эмоджи есть какое-то текстовое представление или код? Если да, то где можна это посмотреть? Спасибо.

    Reply
  17. botokash

    (16) Эмоджи это текст. Заходишь например на emojipedia.org, находишь понравившееся, и копипастом добавляешь себе.

    Reply
  18. guy_septimiy

    Доходил аналогично автору тестовым путем в июне.

    В целом, хорошая статья, проясняющая для новичка не в теме, многие моменты.

    Автору респект

    Reply
  19. Master598

    кто может потерпеть мои вопросы новичка? в личном чате. а то запутался.

    хочу сделать бота в группе и чтобы через 1с туда напоминала и люди уже не могли отмазаться, что Почты много, затерялось письмо, или в 1с не заходил уже 3 дня.

    п.с. не халявщик, сижу читаю ваши коды, и пробую понять как это все мне под себя прикрутить.

    Reply
  20. PLAstic

    Вполне можешь задавать здесь. Ответы на вопросы могут быть полезны и остальным.

    Reply
  21. Kabz

    (17) что не все вставляеться.

    Reply
  22. taishy

    Кто знает, можно ли подключаться из 1С к телеграм от имени клиента?(не бота)

    Reply
  23. PLAstic

    (22) Теоретически это возможно. Где-то на гитхабе есть исходники tgmcli (или как-то так). Это библиотека для работы от имени пользователя телеги. Сам не сталкивался, только слышал. Думаю, ваши шансы всё равно стремятся к нулю, но удачи.

    Reply
  24. Alexey_

    (22)можно, https://core.telegram.org/#telegram-api раздел Telegram API

    Reply
  25. taishy

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

    Reply
  26. user853472
    Reply
  27. GlebBR

    полезная статья, кто нибудь решал такую проблему: режим обмена через webhook, задаю вопрос пользователю он быстро набирает много сообщений пока я не ответил. Как мне отсекать ответы пользователя которые лишние. Пример: Я задал вопрос , пользователь набрал быстро 3 ответа. Бот должен отработать только один ответ(самый первый.).Как только ответит бот, общение продолжается.

    Reply
  28. PLAstic

    (27) если ты будешь делать сессии по сообщениям с клавиатурой, то после получения ответа я их удаляю обычно. Т.е. все последующие запросы не найдут сессии и не будут обработаны.

    Reply
  29. GlebBR

    (21) решил проблему с эмоджи так. Захожу на https://apps.timwhitlock.info/emoji/tables/unicode. Беру столбец Bytes. Пример: xF0x9Fx93x9E и заменяю на %F0%9F%93%9E и вставляю в текст ,в telegram отображается эмоджи. Может кто то знает как это гуманно сделать средствами 1с, я делаю Стрзаменить.

    Reply
  30. GlebBR

    решил проблему с эмоджи так. Захожу на https://apps.timwhitlock.info/emoji/tables/unicode. Беру столбец Bytes. Пример: xF0x9Fx93x9E и заменяю на %F0%9F%93%9E и вставляю в текст ,в telegram отображается эмоджи. Может кто то знает как это гуманно сделать средствами 1с, я делаю Стрзаменить.

    Reply
  31. PLAstic

    Статья обновлена, жирным выделены дополнения.

    Reply
  32. ROM_1C

    Круто! Спасибо!

    Reply
  33. slavik_s

    Скачал конфигурацию, а в ней почти ничего нет. Очень интересует вопрос как решить перенос кнопок на другую строку, чтобы кнопки выстроились одна под другой?

    Reply
  34. slavik_s

    еще интересует как отправлять кнопки ReplyKeyboard ? В сообщении?

    Reply
  35. PLAstic

    (34) в статье про кнопки написано.

    Reply
  36. slavik_s

    (36) По этому коду

    {

    «inline_keyboard»:

    [

    [

    {«text»:»Разрешить»,»callback_data»:»%1″},

    {«text»:»Отклонить»,»callback_data»:»%2″}

    ]

    ]

    }

    Кнопки выстраиваются в одну строку [Разрешить] [Отклонить] а надо чтобы друг под другом

    [Разрешить]

    [Отклонить]

    На моем примере это так:

    {

    «inline_keyboard»: [

    [

    {

    «text»: «08:10 — Сидоров»,

    «callback_data»: «1539327600;000000002292»

    },

    {

    «text»: «10:10 — Иванов»,

    «callback_data»: «1539334800;000000003398»

    },

    {

    «text»: «10:10 — Петров»,

    «callback_data»: «1539336600;000000003404»

    },

    {

    «text»: «12:10 — Голубев»,

    «callback_data»: «1539343800;000000003397»

    }

    ]

    ]

    }

    На каждой кнопке Время и Фамилия пациента получающего услугу в указанное на кнопке время и они должны размещаться одна под другой иначе их просто не видно если в одну строку.

    Reply
  37. stako8

    Может кто сталкивался: отправляю клавиатуру «bot******/sendMessage?chat_id=******&text=Меню&reply_markup={«inline_keyboard»:[[{«text»:»1″,»callback_data»:»1″},{«text»:»2″,»callback_data»:»2″}]]}», она приходит пользователю, тот нажимает на не, но через «getUpdates» не приходит ответ что он нажал. Куда копать?

    Reply
  38. slavik_s

    (38)Через getUpdates ответ обязательно приходит, вопрос лишь в том какой ответ и кому. Может придти ошибка соединения, тогда нужно копать прокси. В ответе в реквизите Код Состояния при успешном исходе приходит код = 200. Когда пользователь нажал кнопку, то через getUpdates не ему а ВАМ (то есть БОТу) приходит КАКУЮ КНОПКУ ОН НАЖАЛ. На каком компьютере запрашиваете через getUpdates туда и приходит информация о нажатой кнопке. В вашем случает ответ будет 2 или 1. Далее вы программно обрабатываете какой ответ послать пользователю на телефон в зависимости от того какую кнопку 1 или 2 он нажал и отправляете ему ответ сформированный вашей программой или Ботом.

    Reply
  39. stako8

    (39) Это понятно, в getUpdates должно прийти CallbackQuery, но не приходит. Сообщения корректно приходят. Я вот думаю просто клавиатуру не правильно передаю. Кто то писал про кодировку и что туда передаётся какой то лишний символ и типо из-за него может telegram не понимать что отправить обратно боту в CallbackQuery(ответ от клавиатуры).

    Reply
  40. slavik_s
    Reply
  41. Hobbit_Jedi

    (26)

    IMAGE_PROCESS_FAILED

    Буквально сегодня с этим бодался. Помогло использование кодировки ANSI (без BOM) везде, где можно указать кодировку.

    Reply
  42. Hobbit_Jedi

    А можно как-то сделать так, чтобы бот сам регистрировал свои команды у БотФазера?

    А то тупо получается — их нужно и в исходном коде и в чате БотФазера дважды прописывать. И следить за синхронностью этих списков.

    Reply
  43. Hobbit_Jedi

    (43) Решил в полуавтоматическом режиме.

    Боту включил (в настройках у БотФазера) режим инлайн-бота, и добавил (уже в коде бота) обработку инлайн запроса, в ответ на который бот выбрасывает текст с описанием своих команд, в виде, пригодном для БотФазера.

    Получилось, что к БотФазеру нужно стучаться вручную. Вручную же набирать команду /setcommands. Вручную же указать имя бота, для которого устанавливаются команды. А потом делаем инлайн-запрос к нашему боту и он отдает список своих команд.

    В любом случае удобнее, чем вручную все это молотить.

    Reply
  44. user775441

    Добрый день! Два вопроса:

    1. Почему при нажатии на кнопку в боте он думает около 15 секунд — начинает крутиться колесико на кнопке. Хотя если дернуть данные сразу же, то оказывается, что ответ уже получен. То есть по факту ответ отправлен быстро, а пользователю кажется, что бот сильно тормозит. В чем может быть проблема?

    2. Почему делаете интервал обновления регзадания 3 секунды, а не 1? Так ведь бот быстрее реагирует. Есть какие то ограничения?

    Reply
  45. PLAstic

    (45) Если честно, я вообще не думал, что бот будет использоваться в режиме getUpdates. С вебхуком реакция бота сводится к малозаметному минимуму.

    Там механизм построен так, что одно рег.задание, общее для всех ботов, получает для всех сообщения, а другое — это задание самогО бота, которое анализирует наличие новых сообщений и обрабатывает их. Вроде так.

    Соответственно, разница во времени между выполнением первого и второго — это и есть 15 секунд.

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

    Reply
  46. Rollam

    Добрый день!

    Реализовал отправку сообщения с привязанной к нему Inline-клавиатурой. Ответы получаю через getUpdates.

    Всё работает, за исключением одного нюанса: ответ на нажатие (callback_query) «живёт» ровно 2 минуты с момента нажатия пользователем (засекал), после чего исчезает, даже если не вызывать getUpdates до истечения 2-х минут.

    Вам что-нибудь об этом известно? Информации по этому таймауту нигде нет.

    Reply
  47. Rollam

    (47) Пока что меня пытаются убедить в том, что такого не может быть и мне кажется.

    Reply
  48. PLAstic

    (47) Т.е. у клиента нет проблем с отправкой сообщений, он нажимает пункт, происходит регистрация на серверах телеги, но когда спустя 2 минуты мы делаем getupdates, то тычка там нет? А попробуйте нажать сначала один пункт клавиатуры, а спустя полторы минуты другой. И ещё спустя минуту проверить getupdates. В ответе будет только второй тычок или оба?

    Reply
  49. Rollam

    (49) Проверил. В ответе был лишь один «тычок», последний. Кажется, это «незадокументированная особенность».

    Reply
  50. Rollam

    (50) При этом простые текстовые сообщения, созданные менее 24 часов назад, возвращаются, как и ожидалось.

    Reply
  51. PLAstic

    (51) Да, скорее всего, есть TTL у callback_query, потому что они сами по себе не несут смысловой нагрузки и телега решила, что двух минут достаточно для получения. Иначе, если их хранить относительно долго, то весить они будут много.

    Reply

Leave a Comment

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