Your IP : 216.73.217.78


Current Path : /home/seto/testhive.pm/api/
Upload File :
Current File : /home/seto/testhive.pm/api/get-link.php

<?php
require_once __DIR__ . '/../includes/db.php';
require_once __DIR__ . '/../includes/redis.php';
require_once __DIR__ . '/../includes/distribution.php';

header('Content-Type: application/json');

function respond(bool $show, string $html = '', int $linkId = 0, int $campaignId = 0, int $expiresAt = 0): void {
    if ($show) {
        echo json_encode([
            'show'        => true,
            'html'        => $html,
            'link_id'     => $linkId,
            'campaign_id' => $campaignId,
            'expires_at'  => $expiresAt,
        ]);
    } else {
        echo json_encode(['show' => false]);
    }
    exit;
}

// --- 1. Validate inputs ---
$apiKey = trim($_GET['key']    ?? '');
$domain = trim($_GET['domain'] ?? '');
$url    = trim($_GET['url']    ?? '');

if ($apiKey === '' || $domain === '' || $url === '') {
    respond(false);
}

// Normalise URL: strip query string
$url = strtok($url, '?');
if ($url === false || $url === '') $url = '/';

// --- 2. Validate global API key ---
$validKey = cache_get('global_api_key');
if ($validKey === false) {
    $validKey = db_config('global_api_key');
    cache_set('global_api_key', $validKey, 300);
}
if (!$validKey || !hash_equals($validKey, $apiKey)) respond(false);

// --- 3. Auto-register/update donor domain & page ---
$now = time();

db()->prepare(
    "INSERT OR IGNORE INTO donors (domain, api_key, created_at, last_seen_at, is_active)
     VALUES (?, '', ?, ?, 1)"
)->execute([$domain, $now, $now]);
db()->prepare(
    "UPDATE donors SET last_seen_at = ? WHERE domain = ?"
)->execute([$now, $domain]);

$donorStmt = db()->prepare("SELECT id FROM donors WHERE domain = ? LIMIT 1");
$donorStmt->execute([$domain]);
$donorId = (int)$donorStmt->fetchColumn();

// Upsert page
db()->prepare(
    "INSERT OR IGNORE INTO pages (donor_id, url, hits, first_seen_at, last_seen_at)
     VALUES (?, ?, 0, ?, ?)"
)->execute([$donorId, $url, $now, $now]);
db()->prepare(
    "UPDATE pages SET hits = hits + 1, last_seen_at = ? WHERE donor_id = ? AND url = ?"
)->execute([$now, $donorId, $url]);

$pageStmt = db()->prepare("SELECT id FROM pages WHERE donor_id = ? AND url = ? LIMIT 1");
$pageStmt->execute([$donorId, $url]);
$pageId = (int)$pageStmt->fetchColumn();

// --- 4. Blacklist check ---
$blacklist = db()->query("SELECT pattern FROM url_blacklist")->fetchAll(PDO::FETCH_COLUMN);
foreach ($blacklist as $pattern) {
    if (str_starts_with($url, $pattern)) respond(false);
}

// --- 5. Assignment lookup (Redis → DB → on-demand assign) ---
$assignKey  = 'assign:' . $pageId;
$assignment = cache_get($assignKey);

if ($assignment === false) {
    // Query DB for existing assignment
    $stmt = db()->prepare(
        "SELECT pa.link_id, pa.campaign_id, pa.expires_at,
                l.text AS link_text,
                c.target_url
         FROM page_assignments pa
         JOIN links l     ON l.id     = pa.link_id
         JOIN campaigns c ON c.id     = pa.campaign_id AND c.status = 'active'
         WHERE pa.page_id = ?
         LIMIT 1"
    );
    $stmt->execute([$pageId]);
    $row = $stmt->fetch();

    if ($row && time() <= (int)$row['expires_at']) {
        // Valid, non-expired assignment
        $assignment = [
            'link_id'     => (int)$row['link_id'],
            'campaign_id' => (int)$row['campaign_id'],
            'link_text'   => $row['link_text'],
            'target_url'  => $row['target_url'],
            'expires_at'  => (int)$row['expires_at'],
        ];
    } elseif ($row) {
        // Expired — delete and reassign on-demand
        db()->prepare("DELETE FROM page_assignments WHERE page_id = ?")->execute([$pageId]);
        $assignment = assign_page_ondemand($pageId);
    } else {
        // No assignment yet — on-demand
        $assignment = assign_page_ondemand($pageId);
    }

    // Cache for 120 seconds (assignment is sticky, so short TTL is fine)
    cache_set($assignKey, $assignment ?? 'none', 120);
} elseif ($assignment === 'none') {
    $assignment = null;
}

if (!$assignment) {
    respond(false);
}

// --- 6. Log impression (once per page per day) ---
$today = date('Y-m-d');
$ins = db()->prepare(
    "INSERT OR IGNORE INTO impressions_daily (page_id, link_id, date) VALUES (?, ?, ?)"
);
$ins->execute([$pageId, $assignment['link_id'], $today]);

if ($ins->rowCount() === 1) {
    db()->prepare(
        "UPDATE campaigns SET total_impressions = total_impressions + 1 WHERE id = ?"
    )->execute([$assignment['campaign_id']]);
}

// --- 7. Render HTML from #a#...#/a# markup ---
$targetUrl = htmlspecialchars($assignment['target_url'], ENT_QUOTES, 'UTF-8');
$html = preg_replace_callback(
    '/#a#(.+?)#\/a#/u',
    fn($m) => '<a href="' . $targetUrl . '">' . htmlspecialchars($m[1], ENT_QUOTES, 'UTF-8') . '</a>',
    $assignment['link_text']
);

// --- 8. Probabilistic cleanup (1% chance) ---
if (mt_rand(1, 100) === 1) {
    db()->exec("DELETE FROM impressions_daily WHERE date < date('now', '-30 days')");
}

respond(true, $html, $assignment['link_id'], $assignment['campaign_id'], $assignment['expires_at']);