Так уж получилось что мне досталась недоработанная версия интеграции с Tilda, но не напрямую, а через amoCRM (ранее, мы рассматривали опыт разработки дополнений для amoCRM).
В статье речь идет о разработке внешнего сервиса на
php
, который внутри ведет работу с Tilda посредством WebHook и самописного API для запросов к Tilda.
Tilda - конструктор сайтов. Есть возможность прикрутить каталог с товарами, корзину, сбор заявок (которые нельзя редактировать) и эквайринг.
Кроме того есть возможность интеграции с внешними сервисами, они делятся на виды, но суть интеграций одна - отправка данных из форм в интегрируемый сервис:
Tilda не поддерживает сторонние модули, на данный момент нет возможности разработки кастомных интеграций, которые можно встроить в админку.
Один из наших клиентов интегрировался с amoCRM, поэтому было решено разработать интеграция с этим продуктом, но как оказалось, в amoCRM не передается информация о статусе оплаты заказа, что было критично в нашем случае.
И тогда мы нашли способ интеграции по WebHook
...
В документации подробно описано про WebHook.
Провели эксперименты ... получилось - мы смогли получать данные из Tilda в наш сервис. Но приключения только начинались ...
Когда подъехал второй клиент на Tilda, то оказалось что отправляемый по WebHook
json
может иметь ключи в разных регистрах: у одного клиента lower-case
, у другого camel-sase
. Это решается следующим образом на php
:
$_POST = array_change_key_case($_POST);
Позже (через ~2 недели) клиенты организовали скидки по промокодам, которые распространяются на весь заказ, и как выяснилось:
Tilda не считает скидки для позиций товара, а лишь имеет данные об общей скидке (процентной или фиксированной).
Этот прикол мы разруливали (юридические консультации, возврат заказов, пересчет цен позиций заказов, создание чеков прихода) ~3 дня вперемешку с текущими задачами.
И под конец один из клиентов написал js
скрипт индивидуальной скидки, это привело к тому, что цены позиций заказа и общая сумма заказа не совпадали. Клиент был предупрежден о невозможности поддержки не стандартизированных (сервисом Tilda или нами) фич и убрал свой скрипт.
Но статус оплаты в данных WebHook
не приходил, и тогда пришлось искать другое решение ...
Теперь (31.10.2022) это неактуально, при установке WebHook есть возможность установить флаг "Отправлять после оплаты". Но ниже описан интересный опыт :)
Дела обстояли так: оформленный заказ мы получали, а статус оплаты нет. Так как статус оплаты для нас является критичным, значит мы должны сами забрать информацию о платеже ... идем снифать запросы.
Первым делом необходимо пройти авторизацию.
Не забываем подставлять нужные заголовки исходящих запросов из консоли браузера.
Идем по адресу /login/
и видим что исходящий запрос в заголовках отправляет куки вида:
Cookie: tildasid=1616609523493.626598; tildauid=1616609838237.285363; previousUrl=tilda.cc%2Fru%2F
Отправимся на предыдущю страницу сайта (она же главная). В ответ на запрос самой страницы заголовка Set-cookie
нет. Тогда идем в отладчик и пробуем найти хотя бы одну куку в одном из подгружаемых скриптов ... и находим установку куки tildasid
в файле /js/tildastat-0.2.min.js
.
Куки при входе на главную страницу Tilda.cc:
При детальном поиске обнаруживаем что tildasid
и tildauid
используют одну и ту же функцию генерации generateUniqID
:
function generateUniqID() {
var d = new Date();
var uniq = '';
var random = Math.floor(Math.random() * (999999 - 100000)) + 100000;
uniq = '' + d.getTime() + '.' + random;
return uniq
}
Теперь повторяем примерно такое же на php
:
$iTimeMls = time();
$iTimeMcsUID = random_int(500000, 1000000);
$iTimeMcsSID = $iTimeMcsUID - random_int(100000, 200000);
А кука previousUrl
у нас всегда имеет одно и тоже значение при авторизации.
Теперь пробуем авторизироваться через web-интерфейс и смотрим запросы.
Как оказалось для авторизации отправляется запрос /login/submit/
, который при успешном результате отправляет в заголовках ответа куки вида (данные подкорректированы):
Set-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, которую надо решать, иначе запрос авторизации закончится провалом. Но начнем с простейшего случая - когда капчи нет.
Опытным путем было выявлено что появление ReCaptcha имеет некие промежутки времени, и не зависит от количества неудачных авторизаций или IP адреса - она просто появляется в какие-то моменты времени, а когда-то её нет.
При отсутсвии необходимости ввода капчи запрос авторизации отправляет следующие post
данные:
email=email&password=password&csrf=239vBL6ZC9
Как видно, необходимо передавать csrf
, который можно найти в коде страницы ввода email/пароля (/login/
) так:
$sCSRF = "";
$aMatches = [];
if(preg_match("/window\.csrf\=(?:\'|\")(.*?)(?:\'|\")\;/", $sResponse, $aMatches))
$sCSRF = $aMatches[1];
Чтобы определить необходимость решения капчи нужно в коде страницы /login/
найти window.needcaptcha
так:
$needCaptcha = false;
$aMatches = [];
if(preg_match("/window\.needcaptcha\=(?:\'|\")(.*?)(?:\'|\")\;/", $sResponse, $aMatches))
$needCaptcha = ($aMatches[1] == 'y');
А ключ window.keycaptcha
для ReCaptcha находим так:
$sKeyCaptcha = "";
$aMatches = [];
if(preg_match("/window\.keycaptcha\=(?:\'|\")(.*?)(?:\'|\")\;/", $sResponse, $aMatches))
$sKeyCaptcha = $aMatches[1];
Теперь имея ключ капчи идем на сервис решения капчи rucaptcha.com, создаем акк, оплачиваем пару сотен рублей, и вызывая несколько API запросов этого сервиса получаем ключ решения капчи.
ReCaptcha может отсутсвовать при авторизации (на странице
/login/
будет отсутствоватьwindow.needcaptcha
), поэтому не на каждом запросе авторизации понадобится решение капчи.
Имея ключ решения капчи пробуем авторизироваться добавив к post
данным ключ g-recaptcha-response
:
curl_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)В ответе получаем json:
total
- общее количество заявокnext
- номер следующей страницыerrors
- количество закзов с ошибкамиleads
- массив объекта заявокcur
- текущая страницаsheetsize
- количество заявок на страницеНа данный момент Tilda имеет лимит по сроку хранения заявок, максимум 30 дней.
Смотря на опыт нескольких подключенных клиентов, на Tilda можно сделать прибыльный интернет-магазин, но назвать это полноценным интернет-магазином, сложно, это больше похоже на прототип.
В целом, интеграция с Tilda заняла около 2-х дней и оставила положиельные впечатления, как от программной работы, так и от работы с самим сервисом.