Содержание
По работе, наконец-то, моя сфера была четко определена и меня перекинули на внешние интеграции. И так уж получилось что мне досталась недоработанная версия интеграции с Tilda, но не напрямую, а через amoCRM (ранее, мы рассматривали опыт разработки дополнений для amoCRM).
php
, который внутри ведет работу с Tilda посредством WebHook и самописного API для запросов к TildaКроме того есть возможность интеграции с внешними сервисами, они делятся на виды, но суть интеграций одна - отправка данных из форм в интегрируемый сервис:
Один из наших клиентов интегрировался с amoCRM, поэтому было решено разработать интеграция с этим продуктом, но как оказалось, в amoCRM не передается информация о статусе оплаты заказа, что было критично в нашем случае.
И тогда мы нашли способ интеграции по WebHook
...
В документации подробно описано про WebHook.
Провели эксперименты ... получилось - мы смогли получать данные из Tilda в наш сервис. Но приключения только начинались ...
Когда подъехал второй клиент на Tilda, то оказалось что отправляемый по WebHook
json
может иметь ключи в разных регистрах: у одного клиента lower-case
, у другого camel-sase
. Это решается следующим образом на php
:
php$_POST = array_change_key_case($_POST);
Позже (через ~2 недели) клиенты организовали скидки по промокодам, которые распространяются на весь заказ, и как выяснилось:
Этот прикол мы разруливали (юридические консультации, возврат заказов, пересчет цен позиций заказов, создание чеков прихода) ~3 дня вперемешку с текущими задачами.
И под конец один из клиентов написал js
скрипт индивидуальной скидки, это привело к тому, что цены позиций заказа и общая сумма заказа не совпадали. Клиент был предупрежден о невозможности поддержки не стандартизированных (сервисом Tilda или нами) фич и убрал сиё творение.
Но статус оплаты в данных WebHook
не приходил, и тогда пришлось искать другое решение ...
Дела обстояли так: оформленный заказ мы получали, а статус оплаты нет. Так как статус оплаты для нас является критичным, значит мы должны сами забрать информацию о платеже ... идем снифать запросы.
Первым делом необходимо пройти авторизацию.
Идем по адресу /login/
и видим что исходящий запрос в заголовках отправляет куки вида:
plaintextCookie: tildasid=1616609523493.626598; tildauid=1616609838237.285363; previousUrl=tilda.cc%2Fru%2F
Отправимся на предыдущю страницу сайта (она же главная). В ответ на запрос самой страницы заголовка Set-cookie
нет. Тогда идем в отладчик и пробуем найти хотя бы одну куку в одном из подгружаемых скриптов ... и находим установку куки tildasid
в файле /js/tildastat-0.2.min.js
.
При детальном поиске обнаруживаем что tildasid
и tildauid
используют одну и ту же функцию генерации generateUniqID
:
jsfunction generateUniqID() { var d = new Date(); var uniq = ''; var random = Math.floor(Math.random() * (999999 - 100000)) + 100000; uniq = '' + d.getTime() + '.' + random; return uniq }
Теперь повторяем примерно такое же на php
:
php$iTimeMls = time(); $iTimeMcsUID = random_int(500000, 1000000); $iTimeMcsSID = $iTimeMcsUID - random_int(100000, 200000);
А кука previousUrl
у нас всегда имеет одно и тоже значение при авторизации.
Теперь пробуем авторизироваться через web-интерфейс и смотрим запросы.
Как оказалось для авторизации отправляется запрос /login/submit/
, который при успешном результате отправляет в заголовках ответа куки вида (данные подкорректированы):
plaintextSet-Cookie: PHPSESSID=dc2kseiqlfpcv85dfe3578hk94; path=/; secure; HttpOnly Set-Cookie: userid=1092881; expires=Wed, 07-Apr-2021 18:36:44 GMT; path=/; secure; httponly Set-Cookie: hash=01a14f9a4d8cc987e08f0ad9353aec5d; expires=Wed, 07-Apr-2021 18:36:44 GMT; path=/; secure; httponly Set-Cookie: registered=yes; expires=Thu, 24-Mar-2022 18:36:44 GMT; path=/; secure Set-Cookie: tildacommonsessid=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.tilda.cc; secure; httponly Set-Cookie: lang=RU; expires=Wed, 07-Apr-2021 18:36:44 GMT; path=/; secure
/login/submit/
и установить куки полученные ранее (tildasid
, tildauid
), то при запросе /login/
будет получен 302 код ответа - редирект на страницу проектов /projects/
. В ином случае код ответа 200.
Настало время авторизироваться через скрипт. Однако, на странице авторизации иногда появляется ReCaptcha, которую надо решать, иначе запрос авторизации закончится провалом. Но начнем с простейшего случая - когда капчи нет.
При отсутсвии необходимости ввода капчи запрос авторизации отправляет следующие post
данные:
plaintextemail=email&password=password&csrf=239vBL6ZC9
Как видно, необходимо передавать csrf
, который можно найти в коде страницы ввода email/пароля (/login/
) так:
php$sCSRF = ""; $aMatches = []; if(preg_match("/window\.csrf\=(?:\'|\")(.*?)(?:\'|\")\;/", $sResponse, $aMatches)) $sCSRF = $aMatches[1];
Чтобы определить необходимость решения капчи нужно в коде страницы /login/
найти window.needcaptcha
так:
php$needCaptcha = false; $aMatches = []; if(preg_match("/window\.needcaptcha\=(?:\'|\")(.*?)(?:\'|\")\;/", $sResponse, $aMatches)) $needCaptcha = ($aMatches[1] == 'y');
А ключ window.keycaptcha
для ReCaptcha находим так:
phpsKeyCaptcha = ""; $aMatches = []; if(preg_match("/window\.keycaptcha\=(?:\'|\")(.*?)(?:\'|\")\;/", $sResponse, $aMatches)) $sKeyCaptcha = $aMatches[1];
Теперь имея ключ капчи идем на сервис решения капчи rucaptcha.com, создаем акк, оплачиваем пару сотен рублей, и вызывая несколько API запросов этого сервиса получаем ключ решения капчи.
/login/
будет отсутствовать window.needcaptcha
), поэтому не на каждом запросе авторизации понадобится решение капчи.Имея ключ решения капчи пробуем авторизироваться добавив к post
данным ключ g-recaptcha-response
:
phpcurl_setopt($this->m_hCurl, CURLOPT_POSTFIELDS, "email=".$this->m_sTildaLogin."&password=".$this->m_sTildaPass."&csrf=".$sCSRF.($needCaptcha ? "&g-recaptcha-response=$sReCaptchaResponse" : ""));
Здесь уже намного проще. Заходим на страницу заявок проекта и смотрим запросы:
Всего 3 запроса:
/projects/leads/?projectid=id
- html страница проекта, /projects/get/getleads/
- получение информации о количестве заявок и названии проекта, /projects/submit/leads/
- сами заявки.json
, хотя в заголовках ответа Content-Type: text/html; charset=utf-8
У последних двух запросов адреса и ответы немного соответствуют друг другу.
Запрос получения заявок требует post
параметров:
comm
- совершаемая операция, в случае запроса списка заявок надо указывать getleads
c
- unixtime
в милисекундахprojectid
- идентификатор проектаsheet
- номер текущей страницы (default: 1)sheetsize
- количество заявок на странице (default: 50)total
- общее количество заявокnext
- номер следующей страницыerrors
- количество закзов с ошибкамиleads
- массив объекта заявокcur
- текущая страницаsheetsize
- количество заявок на страницеСмотря на опыт нескольких подключенных клиентов, на Tilda можно сделать прибыльный интернет-магазин, но назвать это полноценным интернет-магазином, сложно, это больше похоже на прототип.
В целом, интеграция с Tilda заняла около 2-х дней и оставила положиельные впечатления, как от программной работы, так и от работы с самим сервисом.