setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // Drill-down API if (isset($_GET['drill'])) { header('Content-Type: application/json'); $data = []; try { switch($_GET['drill']) { // Infrastructure case 'servers': $data = $pdo->query("SELECT id, name, main_ip, host_name, status, created_date FROM admin.mta_servers ORDER BY id DESC LIMIT 20")->fetchAll(PDO::FETCH_ASSOC); break; case 'vmtas': $data = $pdo->query("SELECT v.id, v.name, v.domain, v.ip, v.status, m.name as server FROM admin.servers_vmtas v JOIN admin.mta_servers m ON v.mta_server_id = m.id LIMIT 20")->fetchAll(PDO::FETCH_ASSOC); break; // Campaigns case 'campaigns': $data = $pdo->query("SELECT id, name, status, total_sent, total_opens, total_clicks FROM admin.campaigns ORDER BY id DESC LIMIT 20")->fetchAll(PDO::FETCH_ASSOC); break; case 'campaigns_active': $data = $pdo->query("SELECT id, name, status, total_sent FROM admin.campaigns WHERE status IN ('sending','active') LIMIT 20")->fetchAll(PDO::FETCH_ASSOC); break; // Office 365 case 'office_accounts': $data = $pdo->query("SELECT id, admin_email, status, created_at FROM admin.office_accounts ORDER BY id DESC LIMIT 20")->fetchAll(PDO::FETCH_ASSOC); break; case 'office_domains': $data = $pdo->query("SELECT id, domain_name, verification_status, account_id FROM admin.office_domains ORDER BY id DESC LIMIT 20")->fetchAll(PDO::FETCH_ASSOC); break; // Security case 'security_events': $data = $pdo->query("SELECT * FROM admin.security_events ORDER BY created_at DESC LIMIT 20")->fetchAll(PDO::FETCH_ASSOC); break; case 'blacklist': $data = $pdo->query("SELECT * FROM admin.blacklist_checks ORDER BY checked_at DESC LIMIT 20")->fetchAll(PDO::FETCH_ASSOC); break; // Brain case 'brain_tests': $data = $pdo->query("SELECT * FROM admin.brain_test_results ORDER BY id DESC LIMIT 20")->fetchAll(PDO::FETCH_ASSOC); break; case 'brain_winners': $data = $pdo->query("SELECT * FROM admin.brain_winners ORDER BY id DESC LIMIT 20")->fetchAll(PDO::FETCH_ASSOC); break; } } catch(Exception $e) { $data = [['error' => $e->getMessage()]]; } echo json_encode($data); exit; } // Stats $stats = [ 'servers' => $pdo->query("SELECT COUNT(*) FROM admin.mta_servers WHERE status='Activated'")->fetchColumn(), 'vmtas' => $pdo->query("SELECT COUNT(*) FROM admin.servers_vmtas")->fetchColumn(), 'campaigns_active' => $pdo->query("SELECT COUNT(*) FROM admin.campaigns WHERE status IN ('sending','active')")->fetchColumn(), 'emails_sent' => $pdo->query("SELECT COALESCE(SUM(total_sent),0) FROM admin.campaigns")->fetchColumn(), 'opens' => $pdo->query("SELECT COALESCE(SUM(total_opens),0) FROM admin.campaigns")->fetchColumn(), 'clicks' => $pdo->query("SELECT COALESCE(SUM(total_clicks),0) FROM admin.campaigns")->fetchColumn(), 'office_accounts' => $pdo->query("SELECT COUNT(*) FROM admin.office_accounts")->fetchColumn(), 'office_verified' => $pdo->query("SELECT COUNT(*) FROM admin.office_domains WHERE verification_status='Verified'")->fetchColumn(), 'security_events' => $pdo->query("SELECT COUNT(*) FROM admin.security_events")->fetchColumn(), ]; // Security Check $security = ['status' => 'OK', 'score' => 100, 'alerts' => []]; $brute = shell_exec("grep 'Failed password' /var/log/auth.log 2>/dev/null | awk '{print \$(NF-3)}' | sort | uniq -c | sort -rn | head -3"); if ($brute) { foreach (array_filter(explode("\n", trim($brute))) as $line) { if (preg_match('/^\s*(\d+)\s+(.+)$/', $line, $m) && intval($m[1]) >= 10) { $security['alerts'][] = ['type' => 'BRUTE_FORCE', 'ip' => $m[2], 'attempts' => $m[1]]; $security['score'] -= 20; } } } if ($security['score'] < 80) $security['status'] = 'WARNING'; if ($security['score'] < 50) $security['status'] = 'CRITICAL'; ?>
Fail2ban config: port 49222. Vérifier que SSH utilise ce port.
Tenant recovery → License test → Azure credentials
FreeDNS creation → Add to O365 → DNS verification
Huawei provisioning → PMTA install → VMTA config
Config testing → ISP analysis → Winner selection
Send list → Creative → PMTA routing → Tracking
Opens: =number_format($stats['opens'])?> | Clicks: =number_format($stats['clicks'])?> | Rate: =$stats['emails_sent']>0?round($stats['opens']/$stats['emails_sent']*100,1):0?>%
• Campagnes avec 0 envois = pas de send queue
• Fail2ban port 49222 ≠ SSH réel ?
• daily_stats vide → utiliser campaigns