| Current Path : /home/seto/testhive.pm/api/ |
| 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']);