Skip to content

Instantly share code, notes, and snippets.

@lord-alfred
Last active November 5, 2020 21:55
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save lord-alfred/d52f8d975ee103be143bf8fe14110b24 to your computer and use it in GitHub Desktop.
Save lord-alfred/d52f8d975ee103be143bf8fe14110b24 to your computer and use it in GitHub Desktop.
Запрос к API Keitaro TDS v6 с запасным URL, в случае если TDS недоступна (позволяет не терять трафик)
<?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