Last active
November 5, 2020 21:55
-
-
Save lord-alfred/d52f8d975ee103be143bf8fe14110b24 to your computer and use it in GitHub Desktop.
Запрос к API Keitaro TDS v6 с запасным URL, в случае если TDS недоступна (позволяет не терять трафик)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// пример работы с Keitaro TDS v6 по API (написан на PHP 7 (!) из-за Throwable) | |
// запрет кэширования этой страницы в CloudFlare/браузере | |
header("Cache-Control: private"); | |
// сюда можно воткнуть какой-то свой антибот, чтоб он отрабатывал до запуска общения с API | |
// примерно как-то так: | |
// require_once(__DIR__ . '/antibot.php'); | |
// немного важных переменных | |
// (которые обычно выносятся в конфиг, но тут удобнее показать так) | |
$FALLBACK_URL = 'https://tglink.ru/Lord_Alfred'; // запасной URL в случае если TDS лежит (план Б) | |
$TDS_DOMAIN = 'http://tds_domain.com'; // домен TDS (с keitaro v6 для примера) | |
$TDS_APIKEY = '1234567'; // API-ключ к keitaro (берётся у неё со настроек) | |
$TDS_GROUP = 'niagra'; // группа из TDS | |
// получение данных о визите | |
// скорее всего вам нужно будет что-то править под себя | |
$keyword = filter_input(INPUT_GET, 'keyword', FILTER_SANITIZE_STRING); // ключевик из GET параметра keyword | |
$host = filter_input(INPUT_SERVER, 'HTTP_HOST'); // текущий домен | |
$link = ''; // переменная, где в итоге будет URL для редиректа (из TDS или fallback - план Б) | |
// несколько полезных функций, по хорошему они тоже должны быть где-то отдельно | |
// получение реального IP юзера | |
function get_user_IP($user_agent) { | |
$real_ip = ''; | |
// вначале проверяем заголовки, которые передаёт CloudFlare, а потом всё остальное | |
$headers = ['HTTP_CF_CONNECTING_IP', 'HTTP_TRUE_CLIENT_IP', 'HTTP_X_REAL_IP', 'HTTP_FORWARDED', | |
'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_CLIENT_IP', | |
'REMOTE_ADDR']; | |
foreach ($headers as $header) { | |
$header_value = filter_input(INPUT_SERVER, $header); | |
if (!empty($header_value)) { | |
$real_ip = $header_value; | |
break; | |
} | |
} | |
if (strstr($real_ip, ',')) { | |
$tmp = explode(',', $real_ip); | |
$tmp_size = sizeof($tmp); | |
if ((stristr($user_agent, 'mini') !== false) && ($tmp_size >= 2)) { | |
$real_ip = trim($tmp[$tmp_size - 2]); // https://dev.opera.com/articles/opera-mini-request-headers/ | |
} else { | |
$real_ip = trim($tmp[0]); | |
} | |
} | |
return $real_ip; | |
} | |
// get-запрос с лимитированием времени соединения и отключенной верификацией SSL соединения | |
function request_get_content($url) { | |
if (function_exists('curl_init')) { // если установлен curl, то отдаём приоритет именно ему | |
$options = @array( // собачка - плохо, тут она только из-за того что в вашем php может не быть каких-то опций для curl | |
CURLOPT_RETURNTRANSFER => true, | |
CURLOPT_HEADER => false, | |
CURLOPT_FOLLOWLOCATION => true, | |
CURLOPT_ENCODING => '', // Accept-Encoding | |
CURLOPT_CONNECTTIMEOUT => 2, | |
CURLOPT_TIMEOUT => 2, | |
CURLOPT_MAXREDIRS => 3, | |
CURLOPT_SSL_VERIFYPEER => false, | |
CURLOPT_SSL_VERIFYHOST => false, | |
); | |
$ch = curl_init($url); | |
foreach($options as $option => $value) { | |
curl_setopt($ch, $option, $value); | |
} | |
$output = curl_exec($ch); | |
$error = curl_error($ch); | |
$errorno = curl_errno($ch); | |
curl_close($ch); | |
if ($errorno !== 0) { | |
throw new Exception('Failed curl #' . $errorno . ': ' . $error); | |
} | |
return $output; | |
} else { | |
if (!ini_get('allow_url_fopen')) { // если перекрыт кислород, то бросаем исключение | |
throw new Exception('disabled allow_url_fopen'); | |
} else { // или выполняем запрос через file_get_contents с контекстом | |
$options = array( | |
'http' => array( | |
'method' => 'GET', | |
'ignore_errors' => true, | |
'follow_location' => true, | |
'max_redirects' => 3, | |
'timeout' => 2, | |
), | |
'ssl' => array( | |
'verify_peer' => false, | |
'verify_peer_name' => false | |
) | |
); | |
$context = stream_context_create($options); | |
$result = file_get_contents($url, false, $context); | |
if ($result === FALSE) { | |
throw new Exception('Failed file_get_contents'); | |
} | |
return $result; | |
} | |
} | |
} | |
// оборачиваем общение с API в try-catch, чтоб отлавливать падения и запускать план "Б" (fallback url) | |
// внутри блока try - вся логика запроса к Keitaro TDS v6, её можно легко поменять на другую (для других TDS) | |
try { | |
$lang = filter_input(INPUT_SERVER, 'HTTP_ACCEPT_LANGUAGE'); // язык браузера | |
$user_agent = filter_input(INPUT_SERVER, 'HTTP_USER_AGENT'); // юзер агент | |
$ip = get_user_IP($user_agent); // корректный IP пользователя | |
// параметры запроса | |
$params = [ | |
'action' => 'get_link', | |
'charset' => 'utf-8', | |
'api_key' => $TDS_APIKEY, | |
'group' => $TDS_GROUP, | |
'lang' => $lang, | |
'ip' => $ip, | |
'source' => $host, | |
'ua' => $user_agent, | |
'keyword' => $keyword, | |
]; | |
$get_params = http_build_query($params); | |
$url = sprintf('%s/api.php?%s', trim($TDS_DOMAIN, '/'), $get_params); | |
// выполняем запрос к TDS и декодируем полученный JSON | |
$content = request_get_content($url); | |
$data = json_decode($content); | |
// если в результирующих данных есть это свойство, то значит запрос от бота (так определила keitaro) | |
// эта настройка должна идти всегда в самом начале, потому что в настройках группы может стоять "пропусткать ботов" | |
if (isset($data->bot_action)) { | |
$link = ''; | |
} | |
// проверяем что в результирующих данных есть нужные свойства, означающие url для редиректа | |
if (isset($data->stream) && isset($data->stream->url) && !empty($data->stream->url)) { | |
$link = $data->stream->url; | |
} | |
} catch (\Throwable $e) { // в случае если произошла ошибка или вылетел Exception | |
// проверяем подключен ли у нас Sentry, и если да - то вначале передаём ошибку в него | |
if (function_exists('\Sentry\captureException')) { | |
\Sentry\captureException($e); | |
} | |
// ну и в итоге выставляем в link - запасной URL, чтоб трафик не шёл в никуда | |
$link = $FALLBACK_URL; | |
} | |
// если в итоговой переменной будет пусто, то идём на запасной URL | |
// но возможно если вы хотите скрыть ссылки от ботов - | |
// вам тогда стоит закомментировать это условие и просто сделать exit(); | |
if (empty($link)) { | |
$link = $FALLBACK_URL; | |
} | |
// далее какая-то логика передачи ссылки в шаблон или просто редирект | |
// пример - 302 редирект, но его я закомментирую | |
// (перед header не должно быть echo или другого вывода в браузер, а то будет ругаться на уже отправленные заголовки) | |
// header("Location: " . $link); | |
// и ещё один пример - просто вывод ссылки в браузер: | |
echo $link; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment