880 lines
37 KiB
PHP
Executable File
880 lines
37 KiB
PHP
Executable File
|
|
<?php
|
|
/**
|
|
* INTELLIGENCE API
|
|
* - Complete ISP Knowledge
|
|
* - Economic Equation
|
|
* - Anti-spam Watch
|
|
* - Advanced Learning
|
|
* - Smart Recommendations
|
|
*/
|
|
header('Content-Type: application/json');
|
|
|
|
$db = new PDO("pgsql:host=127.0.0.1;dbname=adx_system", "admin", "admin123");
|
|
|
|
// ==================== ISP COMPLETE DATABASE ====================
|
|
$ISP_DATABASE = [
|
|
// ============ MICROSOFT (Hotmail/Outlook) ============
|
|
'hotmail' => [
|
|
'names' => ['hotmail.com', 'outlook.com', 'live.com', 'msn.com'],
|
|
'filters' => [
|
|
['name' => 'SmartScreen', 'type' => 'reputation', 'severity' => 9, 'bypass' => 'Engagement-based warmup, clean IP history'],
|
|
['name' => 'Sender Reputation', 'type' => 'reputation', 'severity' => 8, 'bypass' => 'Consistent sending patterns, low complaints'],
|
|
['name' => 'Content Filtering', 'type' => 'content', 'severity' => 6, 'bypass' => 'Avoid spam words, balanced text/image ratio'],
|
|
['name' => 'Authentication Check', 'type' => 'authentication', 'severity' => 10, 'bypass' => 'SPF, DKIM, DMARC mandatory'],
|
|
],
|
|
'optimal' => [
|
|
'volume_per_hour' => 2000,
|
|
'volume_per_day' => 30000,
|
|
'warmup_days' => 21,
|
|
'best_hours' => [9, 10, 11, 14, 15, 16],
|
|
'worst_hours' => [0, 1, 2, 3, 4, 5, 22, 23],
|
|
'best_days' => ['tue', 'wed', 'thu'],
|
|
],
|
|
'requirements' => [
|
|
'dkim' => true, 'spf' => true, 'dmarc' => true, 'ptr' => true,
|
|
'list_unsubscribe' => true, 'one_click_unsubscribe' => true,
|
|
],
|
|
'weights' => ['engagement' => 0.45, 'complaints' => 0.30, 'bounces' => 0.15, 'traps' => 0.10],
|
|
'difficulty' => 8,
|
|
'countries' => ['US' => 'EST', 'UK' => 'GMT', 'DE' => 'CET', 'FR' => 'CET', 'CA' => 'EST'],
|
|
],
|
|
|
|
// ============ GOOGLE (Gmail) ============
|
|
'gmail' => [
|
|
'names' => ['gmail.com', 'googlemail.com'],
|
|
'filters' => [
|
|
['name' => 'ML Spam Filter', 'type' => 'ml', 'severity' => 10, 'bypass' => 'High engagement, personalization, legitimate content'],
|
|
['name' => 'Promotions Tab', 'type' => 'categorization', 'severity' => 5, 'bypass' => 'Personal tone, minimal marketing language'],
|
|
['name' => 'Postmaster Reputation', 'type' => 'reputation', 'severity' => 9, 'bypass' => 'Monitor via Google Postmaster Tools'],
|
|
['name' => 'User Signals', 'type' => 'engagement', 'severity' => 8, 'bypass' => 'High open rates, replies, not-spam marks'],
|
|
],
|
|
'optimal' => [
|
|
'volume_per_hour' => 3000,
|
|
'volume_per_day' => 50000,
|
|
'warmup_days' => 14,
|
|
'best_hours' => [8, 9, 10, 13, 14, 19, 20],
|
|
'worst_hours' => [0, 1, 2, 3, 4, 5],
|
|
'best_days' => ['tue', 'wed', 'thu'],
|
|
],
|
|
'requirements' => [
|
|
'dkim' => true, 'spf' => true, 'dmarc' => true, 'ptr' => true,
|
|
'list_unsubscribe' => true, 'one_click_unsubscribe' => true,
|
|
'arc' => false, 'bimi' => false,
|
|
],
|
|
'weights' => ['engagement' => 0.50, 'complaints' => 0.25, 'bounces' => 0.15, 'traps' => 0.10],
|
|
'difficulty' => 7,
|
|
'countries' => ['US' => 'PST', 'UK' => 'GMT', 'DE' => 'CET', 'FR' => 'CET'],
|
|
],
|
|
|
|
// ============ YAHOO/AOL ============
|
|
'yahoo' => [
|
|
'names' => ['yahoo.com', 'yahoo.fr', 'yahoo.co.uk', 'ymail.com', 'rocketmail.com'],
|
|
'filters' => [
|
|
['name' => 'SpamGuard', 'type' => 'reputation', 'severity' => 7, 'bypass' => 'Slow warmup, engagement focus'],
|
|
['name' => 'CFL (Complaint Feedback Loop)', 'type' => 'complaints', 'severity' => 9, 'bypass' => 'Process CFL, remove complainers immediately'],
|
|
['name' => 'Authentication', 'type' => 'authentication', 'severity' => 8, 'bypass' => 'Strict DKIM alignment'],
|
|
],
|
|
'optimal' => [
|
|
'volume_per_hour' => 2500,
|
|
'volume_per_day' => 40000,
|
|
'warmup_days' => 14,
|
|
'best_hours' => [9, 10, 11, 14, 15, 18, 19],
|
|
'worst_hours' => [0, 1, 2, 3, 4, 5],
|
|
'best_days' => ['mon', 'tue', 'wed', 'thu'],
|
|
],
|
|
'requirements' => [
|
|
'dkim' => true, 'spf' => true, 'dmarc' => true, 'ptr' => true,
|
|
'list_unsubscribe' => true,
|
|
],
|
|
'weights' => ['engagement' => 0.35, 'complaints' => 0.40, 'bounces' => 0.15, 'traps' => 0.10],
|
|
'difficulty' => 6,
|
|
'countries' => ['US' => 'PST', 'UK' => 'GMT', 'FR' => 'CET'],
|
|
],
|
|
|
|
'aol' => [
|
|
'names' => ['aol.com', 'aim.com'],
|
|
'filters' => [
|
|
['name' => 'Same as Yahoo', 'type' => 'reputation', 'severity' => 7, 'bypass' => 'Same rules as Yahoo (Verizon Media)'],
|
|
],
|
|
'optimal' => [
|
|
'volume_per_hour' => 2000,
|
|
'volume_per_day' => 30000,
|
|
'warmup_days' => 14,
|
|
'best_hours' => [9, 10, 11, 14, 15],
|
|
'worst_hours' => [0, 1, 2, 3, 4, 5],
|
|
'best_days' => ['tue', 'wed', 'thu'],
|
|
],
|
|
'requirements' => ['dkim' => true, 'spf' => true, 'dmarc' => true],
|
|
'weights' => ['engagement' => 0.35, 'complaints' => 0.40, 'bounces' => 0.15, 'traps' => 0.10],
|
|
'difficulty' => 5,
|
|
'countries' => ['US' => 'EST'],
|
|
],
|
|
|
|
// ============ GERMAN ISPs ============
|
|
'gmx' => [
|
|
'names' => ['gmx.de', 'gmx.net', 'gmx.at', 'gmx.ch'],
|
|
'filters' => [
|
|
['name' => 'UI Mail Filter', 'type' => 'content', 'severity' => 7, 'bypass' => 'German language, local sending time'],
|
|
['name' => 'Reputation System', 'type' => 'reputation', 'severity' => 8, 'bypass' => 'Consistent German IP, slow ramp'],
|
|
],
|
|
'optimal' => [
|
|
'volume_per_hour' => 1500,
|
|
'volume_per_day' => 20000,
|
|
'warmup_days' => 21,
|
|
'best_hours' => [8, 9, 10, 11, 14, 15, 16],
|
|
'worst_hours' => [0, 1, 2, 3, 4, 5, 6],
|
|
'best_days' => ['mon', 'tue', 'wed', 'thu'],
|
|
],
|
|
'requirements' => ['dkim' => true, 'spf' => true, 'dmarc' => true, 'german_ip' => true],
|
|
'weights' => ['engagement' => 0.30, 'complaints' => 0.35, 'bounces' => 0.25, 'traps' => 0.10],
|
|
'difficulty' => 8,
|
|
'countries' => ['DE' => 'CET', 'AT' => 'CET', 'CH' => 'CET'],
|
|
],
|
|
|
|
'webde' => [
|
|
'names' => ['web.de'],
|
|
'filters' => [
|
|
['name' => 'Same as GMX', 'type' => 'content', 'severity' => 7, 'bypass' => 'Same United Internet rules'],
|
|
],
|
|
'optimal' => [
|
|
'volume_per_hour' => 1500,
|
|
'volume_per_day' => 20000,
|
|
'warmup_days' => 21,
|
|
'best_hours' => [8, 9, 10, 11, 14, 15, 16],
|
|
'worst_hours' => [0, 1, 2, 3, 4, 5, 6],
|
|
'best_days' => ['mon', 'tue', 'wed', 'thu'],
|
|
],
|
|
'requirements' => ['dkim' => true, 'spf' => true, 'dmarc' => true],
|
|
'weights' => ['engagement' => 0.30, 'complaints' => 0.35, 'bounces' => 0.25, 'traps' => 0.10],
|
|
'difficulty' => 8,
|
|
'countries' => ['DE' => 'CET'],
|
|
],
|
|
|
|
'tonline' => [
|
|
'names' => ['t-online.de'],
|
|
'filters' => [
|
|
['name' => 'Deutsche Telekom Filter', 'type' => 'reputation', 'severity' => 9, 'bypass' => 'Very strict, German IP mandatory, slow warmup'],
|
|
['name' => 'Content Scan', 'type' => 'content', 'severity' => 8, 'bypass' => 'German content, no aggressive marketing'],
|
|
],
|
|
'optimal' => [
|
|
'volume_per_hour' => 1000,
|
|
'volume_per_day' => 15000,
|
|
'warmup_days' => 28,
|
|
'best_hours' => [9, 10, 11, 14, 15],
|
|
'worst_hours' => [0, 1, 2, 3, 4, 5, 6, 7, 22, 23],
|
|
'best_days' => ['tue', 'wed', 'thu'],
|
|
],
|
|
'requirements' => ['dkim' => true, 'spf' => true, 'dmarc' => true, 'german_ip' => true, 'reverse_dns' => true],
|
|
'weights' => ['engagement' => 0.25, 'complaints' => 0.40, 'bounces' => 0.25, 'traps' => 0.10],
|
|
'difficulty' => 9,
|
|
'countries' => ['DE' => 'CET'],
|
|
],
|
|
|
|
// ============ FRENCH ISPs ============
|
|
'orange_fr' => [
|
|
'names' => ['orange.fr', 'wanadoo.fr'],
|
|
'filters' => [
|
|
['name' => 'Orange Mail Filter', 'type' => 'reputation', 'severity' => 7, 'bypass' => 'French IP preferred, consistent sending'],
|
|
],
|
|
'optimal' => [
|
|
'volume_per_hour' => 2000,
|
|
'volume_per_day' => 25000,
|
|
'warmup_days' => 14,
|
|
'best_hours' => [9, 10, 11, 14, 15, 18, 19],
|
|
'worst_hours' => [0, 1, 2, 3, 4, 5, 6],
|
|
'best_days' => ['tue', 'wed', 'thu'],
|
|
],
|
|
'requirements' => ['dkim' => true, 'spf' => true],
|
|
'weights' => ['engagement' => 0.35, 'complaints' => 0.35, 'bounces' => 0.20, 'traps' => 0.10],
|
|
'difficulty' => 6,
|
|
'countries' => ['FR' => 'CET'],
|
|
],
|
|
|
|
'sfr' => [
|
|
'names' => ['sfr.fr', 'neuf.fr'],
|
|
'filters' => [
|
|
['name' => 'SFR AntiSpam', 'type' => 'content', 'severity' => 6, 'bypass' => 'Clean content, authentication'],
|
|
],
|
|
'optimal' => [
|
|
'volume_per_hour' => 2000,
|
|
'volume_per_day' => 25000,
|
|
'warmup_days' => 14,
|
|
'best_hours' => [9, 10, 11, 14, 15, 18, 19],
|
|
'worst_hours' => [0, 1, 2, 3, 4, 5, 6],
|
|
'best_days' => ['tue', 'wed', 'thu'],
|
|
],
|
|
'requirements' => ['dkim' => true, 'spf' => true],
|
|
'weights' => ['engagement' => 0.35, 'complaints' => 0.30, 'bounces' => 0.25, 'traps' => 0.10],
|
|
'difficulty' => 5,
|
|
'countries' => ['FR' => 'CET'],
|
|
],
|
|
|
|
'free_fr' => [
|
|
'names' => ['free.fr'],
|
|
'filters' => [
|
|
['name' => 'Free AntiSpam', 'type' => 'reputation', 'severity' => 6, 'bypass' => 'Standard best practices'],
|
|
],
|
|
'optimal' => [
|
|
'volume_per_hour' => 2000,
|
|
'volume_per_day' => 30000,
|
|
'warmup_days' => 10,
|
|
'best_hours' => [9, 10, 11, 14, 15, 18, 19, 20],
|
|
'worst_hours' => [0, 1, 2, 3, 4, 5],
|
|
'best_days' => ['mon', 'tue', 'wed', 'thu', 'fri'],
|
|
],
|
|
'requirements' => ['dkim' => true, 'spf' => true],
|
|
'weights' => ['engagement' => 0.40, 'complaints' => 0.30, 'bounces' => 0.20, 'traps' => 0.10],
|
|
'difficulty' => 4,
|
|
'countries' => ['FR' => 'CET'],
|
|
],
|
|
|
|
// ============ CANADIAN ISPs ============
|
|
'videotron' => [
|
|
'names' => ['videotron.ca', 'videotron.qc.ca'],
|
|
'filters' => [
|
|
['name' => 'Videotron Filter', 'type' => 'reputation', 'severity' => 6, 'bypass' => 'Canadian IP, bilingual content OK'],
|
|
],
|
|
'optimal' => [
|
|
'volume_per_hour' => 1500,
|
|
'volume_per_day' => 20000,
|
|
'warmup_days' => 14,
|
|
'best_hours' => [9, 10, 11, 14, 15, 19, 20],
|
|
'worst_hours' => [0, 1, 2, 3, 4, 5],
|
|
'best_days' => ['tue', 'wed', 'thu'],
|
|
],
|
|
'requirements' => ['dkim' => true, 'spf' => true, 'casl_compliant' => true],
|
|
'weights' => ['engagement' => 0.35, 'complaints' => 0.35, 'bounces' => 0.20, 'traps' => 0.10],
|
|
'difficulty' => 5,
|
|
'countries' => ['CA' => 'EST'],
|
|
],
|
|
|
|
// ============ APPLE ============
|
|
'icloud' => [
|
|
'names' => ['icloud.com', 'me.com', 'mac.com'],
|
|
'filters' => [
|
|
['name' => 'Apple Mail Privacy Protection', 'type' => 'privacy', 'severity' => 8, 'bypass' => 'Cannot track opens reliably since iOS 15'],
|
|
['name' => 'iCloud Filter', 'type' => 'reputation', 'severity' => 7, 'bypass' => 'Standard practices, engagement focus'],
|
|
],
|
|
'optimal' => [
|
|
'volume_per_hour' => 2000,
|
|
'volume_per_day' => 30000,
|
|
'warmup_days' => 14,
|
|
'best_hours' => [8, 9, 10, 12, 13, 18, 19, 20],
|
|
'worst_hours' => [0, 1, 2, 3, 4, 5],
|
|
'best_days' => ['tue', 'wed', 'thu'],
|
|
],
|
|
'requirements' => ['dkim' => true, 'spf' => true, 'dmarc' => true],
|
|
'weights' => ['engagement' => 0.30, 'complaints' => 0.40, 'bounces' => 0.20, 'traps' => 0.10],
|
|
'difficulty' => 6,
|
|
'countries' => ['US' => 'PST', 'UK' => 'GMT', 'DE' => 'CET', 'FR' => 'CET'],
|
|
'note' => 'Open tracking unreliable due to Mail Privacy Protection',
|
|
],
|
|
];
|
|
|
|
// ==================== ECONOMIC FORMULAS ====================
|
|
function calculateEconomicEquation($data) {
|
|
// Costs
|
|
$serverCost = $data['servers'] * $data['hours'] * 0.02; // €0.02/server/hour
|
|
$domainCost = $data['domains'] * 0.10; // €0.10/domain/day amortized
|
|
$ipCost = $data['ips'] * 0.05; // €0.05/IP/day
|
|
$listCost = $data['volume'] * 0.0001; // €0.0001/contact
|
|
$totalCost = $serverCost + $domainCost + $ipCost + $listCost;
|
|
|
|
// Revenue estimation
|
|
$inboxRate = $data['inbox_rate'] / 100;
|
|
$openRate = 0.15 * $inboxRate; // 15% of inbox
|
|
$clickRate = 0.03 * $inboxRate; // 3% of inbox
|
|
$conversionRate = 0.005 * $inboxRate; // 0.5% of inbox
|
|
|
|
$inboxCount = $data['volume'] * $inboxRate;
|
|
$openCount = $data['volume'] * $openRate;
|
|
$clickCount = $data['volume'] * $clickRate;
|
|
$conversionCount = $data['volume'] * $conversionRate;
|
|
|
|
$revenueGross = $conversionCount * ($data['payout'] ?? 5); // Default $5/conversion
|
|
$revenueNet = $revenueGross - $totalCost;
|
|
|
|
// Metrics
|
|
$costPerMail = $totalCost / max(1, $data['volume']);
|
|
$costPerInbox = $totalCost / max(1, $inboxCount);
|
|
$costPerClick = $totalCost / max(1, $clickCount);
|
|
$costPerConversion = $totalCost / max(1, $conversionCount);
|
|
|
|
$roi = $totalCost > 0 ? (($revenueNet / $totalCost) * 100) : 0;
|
|
$profitMargin = $revenueGross > 0 ? (($revenueNet / $revenueGross) * 100) : 0;
|
|
|
|
// Scores (1-100)
|
|
$profitabilityScore = min(100, max(0, 50 + $roi / 2));
|
|
$efficiencyScore = min(100, max(0, ($inboxRate * 100) * 0.5 + (100 - $costPerMail * 10000) * 0.5));
|
|
$sustainabilityScore = min(100, max(0, $data['stability_score'] ?? 50));
|
|
|
|
return [
|
|
'costs' => [
|
|
'server' => round($serverCost, 4),
|
|
'domain' => round($domainCost, 4),
|
|
'ip' => round($ipCost, 4),
|
|
'list' => round($listCost, 4),
|
|
'total' => round($totalCost, 4),
|
|
],
|
|
'metrics' => [
|
|
'inbox_count' => round($inboxCount),
|
|
'open_count' => round($openCount),
|
|
'click_count' => round($clickCount),
|
|
'conversion_count' => round($conversionCount),
|
|
],
|
|
'revenue' => [
|
|
'gross' => round($revenueGross, 2),
|
|
'net' => round($revenueNet, 2),
|
|
],
|
|
'unit_costs' => [
|
|
'per_mail' => round($costPerMail, 6),
|
|
'per_inbox' => round($costPerInbox, 6),
|
|
'per_click' => round($costPerClick, 4),
|
|
'per_conversion' => round($costPerConversion, 4),
|
|
],
|
|
'performance' => [
|
|
'roi_percent' => round($roi, 2),
|
|
'profit_margin' => round($profitMargin, 2),
|
|
'profitability_score' => round($profitabilityScore),
|
|
'efficiency_score' => round($efficiencyScore),
|
|
'sustainability_score' => round($sustainabilityScore),
|
|
],
|
|
'recommendation' => getRecommendation($roi, $inboxRate * 100, $data['stability_score'] ?? 50),
|
|
];
|
|
}
|
|
|
|
function getRecommendation($roi, $inboxRate, $stability) {
|
|
if ($roi > 200 && $inboxRate > 80 && $stability > 70) {
|
|
return ['action' => 'SCALE_UP', 'reason' => 'Excellent performance - increase volume'];
|
|
} elseif ($roi > 100 && $inboxRate > 70) {
|
|
return ['action' => 'MAINTAIN', 'reason' => 'Good performance - maintain current strategy'];
|
|
} elseif ($roi > 50 && $inboxRate > 60) {
|
|
return ['action' => 'OPTIMIZE', 'reason' => 'Acceptable performance - optimize for better results'];
|
|
} elseif ($inboxRate < 50) {
|
|
return ['action' => 'PAUSE', 'reason' => 'Poor inbox rate - investigate deliverability issues'];
|
|
} elseif ($roi < 0) {
|
|
return ['action' => 'STOP', 'reason' => 'Negative ROI - stop and reassess'];
|
|
} else {
|
|
return ['action' => 'ANALYZE', 'reason' => 'Mixed results - needs deeper analysis'];
|
|
}
|
|
}
|
|
|
|
// ==================== STABILITY EVALUATION ====================
|
|
function evaluateStability($inboxHistory) {
|
|
if (count($inboxHistory) < 3) {
|
|
return ['score' => 50, 'trend' => 'unknown', 'confidence' => 0.3];
|
|
}
|
|
|
|
$rates = array_column($inboxHistory, 'inbox_rate');
|
|
$avg = array_sum($rates) / count($rates);
|
|
|
|
// Variance
|
|
$variance = 0;
|
|
foreach ($rates as $r) {
|
|
$variance += pow($r - $avg, 2);
|
|
}
|
|
$variance /= count($rates);
|
|
$stdDev = sqrt($variance);
|
|
|
|
// Trend (linear regression)
|
|
$n = count($rates);
|
|
$sumX = $n * ($n - 1) / 2;
|
|
$sumY = array_sum($rates);
|
|
$sumXY = 0;
|
|
$sumX2 = 0;
|
|
for ($i = 0; $i < $n; $i++) {
|
|
$sumXY += $i * $rates[$i];
|
|
$sumX2 += $i * $i;
|
|
}
|
|
$slope = ($n * $sumXY - $sumX * $sumY) / ($n * $sumX2 - $sumX * $sumX);
|
|
|
|
// Stability score (lower variance = higher score)
|
|
$stabilityScore = max(0, min(100, 100 - ($stdDev * 2)));
|
|
|
|
// Trend classification
|
|
$trend = 'stable';
|
|
if ($slope > 2) $trend = 'improving';
|
|
elseif ($slope < -2) $trend = 'declining';
|
|
|
|
// Confidence based on sample size
|
|
$confidence = min(1, count($inboxHistory) / 10);
|
|
|
|
return [
|
|
'score' => round($stabilityScore),
|
|
'trend' => $trend,
|
|
'slope' => round($slope, 2),
|
|
'avg' => round($avg, 2),
|
|
'std_dev' => round($stdDev, 2),
|
|
'confidence' => round($confidence, 2),
|
|
'warning' => $trend == 'declining' ? 'Inbox rate declining - investigate' : null,
|
|
];
|
|
}
|
|
|
|
$action = $_POST['action'] ?? $_GET['action'] ?? '';
|
|
$response = ['success' => false];
|
|
|
|
switch ($action) {
|
|
|
|
// ==================== GET ISP INFO ====================
|
|
case 'get_isp_info':
|
|
$isp = $_GET['isp'] ?? '';
|
|
$country = $_GET['country'] ?? 'US';
|
|
|
|
if (isset($ISP_DATABASE[$isp])) {
|
|
$info = $ISP_DATABASE[$isp];
|
|
$info['timezone'] = $info['countries'][$country] ?? 'UTC';
|
|
$response = ['success' => true, 'isp' => $isp, 'info' => $info];
|
|
} else {
|
|
$response = ['success' => false, 'error' => 'Unknown ISP'];
|
|
}
|
|
break;
|
|
|
|
// ==================== GET ALL ISPs ====================
|
|
case 'list_all_isps':
|
|
$isps = [];
|
|
foreach ($ISP_DATABASE as $key => $data) {
|
|
$isps[] = [
|
|
'key' => $key,
|
|
'names' => $data['names'],
|
|
'difficulty' => $data['difficulty'],
|
|
'optimal_volume' => $data['optimal']['volume_per_day'],
|
|
'warmup_days' => $data['optimal']['warmup_days'],
|
|
'countries' => array_keys($data['countries']),
|
|
];
|
|
}
|
|
usort($isps, fn($a, $b) => $a['difficulty'] - $b['difficulty']);
|
|
$response = ['success' => true, 'isps' => $isps, 'count' => count($isps)];
|
|
break;
|
|
|
|
// ==================== CALCULATE ECONOMICS ====================
|
|
case 'calculate_economics':
|
|
$data = [
|
|
'volume' => intval($_POST['volume'] ?? 10000),
|
|
'servers' => intval($_POST['servers'] ?? 1),
|
|
'hours' => floatval($_POST['hours'] ?? 2),
|
|
'domains' => intval($_POST['domains'] ?? 1),
|
|
'ips' => intval($_POST['ips'] ?? 1),
|
|
'inbox_rate' => floatval($_POST['inbox_rate'] ?? 70),
|
|
'payout' => floatval($_POST['payout'] ?? 5),
|
|
'stability_score' => floatval($_POST['stability_score'] ?? 50),
|
|
];
|
|
|
|
$result = calculateEconomicEquation($data);
|
|
$response = ['success' => true, 'input' => $data, 'result' => $result];
|
|
break;
|
|
|
|
// ==================== EVALUATE STABILITY ====================
|
|
case 'evaluate_stability':
|
|
$config_id = intval($_GET['config_id'] ?? $_POST['config_id'] ?? 0);
|
|
|
|
if ($config_id) {
|
|
$history = $db->query("SELECT inbox_rate, check_time FROM admin.inbox_monitoring
|
|
WHERE send_config_id = $config_id ORDER BY check_time")->fetchAll(PDO::FETCH_ASSOC);
|
|
} else {
|
|
// Use provided data
|
|
$history = json_decode($_POST['history'] ?? '[]', true);
|
|
}
|
|
|
|
$stability = evaluateStability($history);
|
|
$response = ['success' => true, 'stability' => $stability, 'data_points' => count($history)];
|
|
break;
|
|
|
|
// ==================== WATCH ANTI-SPAM ====================
|
|
case 'antispam_watch':
|
|
$isp = $_GET['isp'] ?? '';
|
|
|
|
// Get recent send results for this ISP
|
|
$recentSends = $db->query("SELECT c.id, c.name, c.isp,
|
|
(SELECT AVG(inbox_rate) FROM admin.inbox_monitoring WHERE send_config_id = c.id) as avg_inbox,
|
|
(SELECT MIN(inbox_rate) FROM admin.inbox_monitoring WHERE send_config_id = c.id) as min_inbox,
|
|
(SELECT MAX(inbox_rate) FROM admin.inbox_monitoring WHERE send_config_id = c.id) as max_inbox,
|
|
c.created_at
|
|
FROM admin.send_configs c
|
|
WHERE c.isp = '$isp' AND c.status IN ('completed', 'running')
|
|
AND c.created_at > NOW() - INTERVAL '7 days'
|
|
ORDER BY c.created_at DESC")->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
// Detect anomalies
|
|
$alerts = [];
|
|
$avgRates = array_column($recentSends, 'avg_inbox');
|
|
|
|
if (count($avgRates) >= 3) {
|
|
$overallAvg = array_sum($avgRates) / count($avgRates);
|
|
|
|
// Check for sudden drop
|
|
if (count($avgRates) >= 2 && $avgRates[0] < $avgRates[1] * 0.7) {
|
|
$alerts[] = [
|
|
'type' => 'sudden_drop',
|
|
'severity' => 'high',
|
|
'message' => "Inbox rate dropped from {$avgRates[1]}% to {$avgRates[0]}%",
|
|
'possible_cause' => 'New filter or reputation damage',
|
|
];
|
|
}
|
|
|
|
// Check for consistent decline
|
|
if (count($avgRates) >= 3 && $avgRates[0] < $avgRates[1] && $avgRates[1] < $avgRates[2]) {
|
|
$alerts[] = [
|
|
'type' => 'declining_trend',
|
|
'severity' => 'medium',
|
|
'message' => 'Consistent decline in inbox rates detected',
|
|
'possible_cause' => 'Gradual reputation damage or filter adaptation',
|
|
];
|
|
}
|
|
|
|
// Check for below-threshold performance
|
|
if ($overallAvg < 50) {
|
|
$alerts[] = [
|
|
'type' => 'below_threshold',
|
|
'severity' => 'critical',
|
|
'message' => "Average inbox rate ({$overallAvg}%) is critically low",
|
|
'possible_cause' => 'Major deliverability issue or blacklisting',
|
|
];
|
|
}
|
|
}
|
|
|
|
// Get ISP filter info
|
|
$ispInfo = $ISP_DATABASE[$isp] ?? null;
|
|
|
|
$response = [
|
|
'success' => true,
|
|
'isp' => $isp,
|
|
'recent_sends' => $recentSends,
|
|
'alerts' => $alerts,
|
|
'filters' => $ispInfo['filters'] ?? [],
|
|
'recommendations' => $ispInfo ? [
|
|
'optimal_volume' => $ispInfo['optimal']['volume_per_day'],
|
|
'best_hours' => $ispInfo['optimal']['best_hours'],
|
|
'best_days' => $ispInfo['optimal']['best_days'],
|
|
'requirements' => $ispInfo['requirements'],
|
|
] : null,
|
|
];
|
|
break;
|
|
|
|
// ==================== LEARN FROM SEND ====================
|
|
case 'learn_from_send':
|
|
$config_id = intval($_POST['config_id']);
|
|
|
|
// Get send data
|
|
$config = $db->query("SELECT * FROM admin.send_configs WHERE id = $config_id")->fetch(PDO::FETCH_ASSOC);
|
|
$monitoring = $db->query("SELECT * FROM admin.inbox_monitoring WHERE send_config_id = $config_id ORDER BY check_time")->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
if (!$config || empty($monitoring)) {
|
|
$response = ['success' => false, 'error' => 'No data to learn from'];
|
|
break;
|
|
}
|
|
|
|
// Calculate averages
|
|
$avgInbox = array_sum(array_column($monitoring, 'inbox_rate')) / count($monitoring);
|
|
$stability = evaluateStability($monitoring);
|
|
|
|
// Determine success/failure
|
|
$success = $avgInbox >= 70 && $stability['score'] >= 60;
|
|
|
|
// Create learning entry
|
|
$learningData = [
|
|
'isp' => $config['isp'],
|
|
'country' => $config['country'],
|
|
'volume' => $config['mails_sent'],
|
|
'servers' => $config['servers_needed'],
|
|
'drops' => $config['drops_count'],
|
|
'speed' => $config['speed_per_server'],
|
|
'time_of_day' => date('H', strtotime($config['started_at'])),
|
|
'day_of_week' => date('l', strtotime($config['started_at'])),
|
|
];
|
|
|
|
$learningType = $success ? 'success_pattern' : 'failure_pattern';
|
|
|
|
$db->prepare("INSERT INTO admin.learning_history
|
|
(isp, country, send_config_id, learning_type, input_data, output_data, confidence)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?)")
|
|
->execute([
|
|
$config['isp'],
|
|
$config['country'],
|
|
$config_id,
|
|
$learningType,
|
|
json_encode($learningData),
|
|
json_encode(['avg_inbox' => $avgInbox, 'stability' => $stability]),
|
|
$stability['confidence']
|
|
]);
|
|
|
|
// Update method scores
|
|
$methodName = "{$config['isp']}_{$config['country']}_{$config['servers_needed']}srv";
|
|
|
|
$existingMethod = $db->query("SELECT * FROM admin.method_scores WHERE method_name = '$methodName'")->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if ($existingMethod) {
|
|
// Update existing
|
|
$newInboxScore = ($existingMethod['inbox_score'] * $existingMethod['total_uses'] + $avgInbox) / ($existingMethod['total_uses'] + 1);
|
|
$newStabilityScore = ($existingMethod['stability_score'] * $existingMethod['total_uses'] + $stability['score']) / ($existingMethod['total_uses'] + 1);
|
|
|
|
$db->prepare("UPDATE admin.method_scores SET
|
|
inbox_score = ?, stability_score = ?, total_uses = total_uses + 1,
|
|
success_count = success_count + ?, fail_count = fail_count + ?,
|
|
trend = ?, updated_at = NOW()
|
|
WHERE id = ?")
|
|
->execute([
|
|
$newInboxScore, $newStabilityScore,
|
|
$success ? 1 : 0, $success ? 0 : 1,
|
|
$stability['trend'],
|
|
$existingMethod['id']
|
|
]);
|
|
} else {
|
|
// Create new
|
|
$db->prepare("INSERT INTO admin.method_scores
|
|
(method_name, isp, country, inbox_score, stability_score, total_uses, success_count, fail_count, trend)
|
|
VALUES (?, ?, ?, ?, ?, 1, ?, ?, ?)")
|
|
->execute([
|
|
$methodName, $config['isp'], $config['country'],
|
|
$avgInbox, $stability['score'],
|
|
$success ? 1 : 0, $success ? 0 : 1,
|
|
$stability['trend']
|
|
]);
|
|
}
|
|
|
|
$response = [
|
|
'success' => true,
|
|
'learned' => [
|
|
'type' => $learningType,
|
|
'avg_inbox' => round($avgInbox, 2),
|
|
'stability' => $stability,
|
|
'method' => $methodName,
|
|
]
|
|
];
|
|
break;
|
|
|
|
// ==================== GET RECOMMENDATIONS ====================
|
|
case 'get_recommendations':
|
|
$isp = $_GET['isp'] ?? '';
|
|
$country = $_GET['country'] ?? '';
|
|
$volume = intval($_GET['volume'] ?? 10000);
|
|
|
|
$recommendations = [];
|
|
|
|
// 1. Best method based on learning
|
|
$bestMethod = $db->query("SELECT * FROM admin.method_scores
|
|
WHERE isp = '$isp' AND country = '$country' AND recommended = TRUE
|
|
ORDER BY (inbox_score * 0.4 + stability_score * 0.3 + cost_score * 0.3) DESC
|
|
LIMIT 1")->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if ($bestMethod) {
|
|
$recommendations[] = [
|
|
'category' => 'method',
|
|
'priority' => 'high',
|
|
'title' => 'Recommended Method',
|
|
'description' => "Use method '{$bestMethod['method_name']}' with {$bestMethod['inbox_score']}% avg inbox",
|
|
'confidence' => $bestMethod['confidence_level'],
|
|
];
|
|
}
|
|
|
|
// 2. ISP-specific recommendations
|
|
$ispInfo = $ISP_DATABASE[$isp] ?? null;
|
|
if ($ispInfo) {
|
|
// Timing
|
|
$recommendations[] = [
|
|
'category' => 'timing',
|
|
'priority' => 'medium',
|
|
'title' => 'Optimal Send Time',
|
|
'description' => "Best hours: " . implode(', ', $ispInfo['optimal']['best_hours']) . ":00",
|
|
'data' => $ispInfo['optimal'],
|
|
];
|
|
|
|
// Volume
|
|
if ($volume > $ispInfo['optimal']['volume_per_day']) {
|
|
$recommendations[] = [
|
|
'category' => 'volume',
|
|
'priority' => 'high',
|
|
'title' => 'Volume Warning',
|
|
'description' => "Requested volume ($volume) exceeds optimal ({$ispInfo['optimal']['volume_per_day']})",
|
|
'action' => 'Split into multiple days or use more IPs',
|
|
];
|
|
}
|
|
|
|
// Technical
|
|
foreach ($ispInfo['requirements'] as $req => $needed) {
|
|
if ($needed) {
|
|
$recommendations[] = [
|
|
'category' => 'technical',
|
|
'priority' => 'critical',
|
|
'title' => strtoupper($req) . ' Required',
|
|
'description' => "$isp requires $req authentication",
|
|
];
|
|
}
|
|
}
|
|
}
|
|
|
|
// 3. Recent alerts
|
|
$alerts = $db->query("SELECT * FROM admin.antispam_watch
|
|
WHERE isp = '$isp' AND resolved = FALSE
|
|
ORDER BY detected_at DESC LIMIT 3")->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
foreach ($alerts as $alert) {
|
|
$recommendations[] = [
|
|
'category' => 'alert',
|
|
'priority' => $alert['severity'],
|
|
'title' => $alert['filter_name'] ?? 'Filter Alert',
|
|
'description' => $alert['description'],
|
|
'action' => $alert['recommended_action'],
|
|
];
|
|
}
|
|
|
|
// Sort by priority
|
|
$priorityOrder = ['critical' => 0, 'high' => 1, 'medium' => 2, 'low' => 3];
|
|
usort($recommendations, fn($a, $b) => ($priorityOrder[$a['priority']] ?? 9) - ($priorityOrder[$b['priority']] ?? 9));
|
|
|
|
$response = [
|
|
'success' => true,
|
|
'isp' => $isp,
|
|
'country' => $country,
|
|
'volume' => $volume,
|
|
'recommendations' => $recommendations,
|
|
'count' => count($recommendations),
|
|
];
|
|
break;
|
|
|
|
// ==================== FULL ANALYSIS ====================
|
|
case 'full_analysis':
|
|
$config_id = intval($_POST['config_id'] ?? $_GET['config_id'] ?? 0);
|
|
|
|
$analysis = [
|
|
'config_id' => $config_id,
|
|
'timestamp' => date('Y-m-d H:i:s'),
|
|
];
|
|
|
|
// Get config
|
|
$config = $db->query("SELECT c.*, s.name as sponsor_name, o.payout, o.epc
|
|
FROM admin.send_configs c
|
|
LEFT JOIN admin.sponsors s ON c.sponsor_id = s.id
|
|
LEFT JOIN admin.offers o ON c.offer_id = o.id
|
|
WHERE c.id = $config_id")->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$config) {
|
|
$response = ['success' => false, 'error' => 'Config not found'];
|
|
break;
|
|
}
|
|
|
|
$analysis['config'] = $config;
|
|
|
|
// Get monitoring data
|
|
$monitoring = $db->query("SELECT * FROM admin.inbox_monitoring WHERE send_config_id = $config_id ORDER BY check_time")->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
// 1. Stability Analysis
|
|
$analysis['stability'] = evaluateStability($monitoring);
|
|
|
|
// 2. Economic Analysis
|
|
$econData = [
|
|
'volume' => $config['mails_sent'] ?: $config['target_volume'] * 1000,
|
|
'servers' => $config['servers_needed'],
|
|
'hours' => 2, // Estimated
|
|
'domains' => 1,
|
|
'ips' => $config['servers_needed'],
|
|
'inbox_rate' => $analysis['stability']['avg'] ?? 70,
|
|
'payout' => $config['payout'] ?? 5,
|
|
'stability_score' => $analysis['stability']['score'],
|
|
];
|
|
$analysis['economics'] = calculateEconomicEquation($econData);
|
|
|
|
// 3. ISP Analysis
|
|
$ispInfo = $ISP_DATABASE[$config['isp']] ?? null;
|
|
if ($ispInfo) {
|
|
$analysis['isp'] = [
|
|
'name' => $config['isp'],
|
|
'difficulty' => $ispInfo['difficulty'],
|
|
'filters' => $ispInfo['filters'],
|
|
'compliance' => [
|
|
'volume_ok' => $config['mails_sent'] <= $ispInfo['optimal']['volume_per_day'],
|
|
'warmup_ok' => true, // Would check warmup table
|
|
],
|
|
];
|
|
}
|
|
|
|
// 4. Recommendations
|
|
$analysis['recommendations'] = [];
|
|
|
|
// Based on economics
|
|
$rec = $analysis['economics']['recommendation'];
|
|
$analysis['recommendations'][] = [
|
|
'source' => 'economics',
|
|
'action' => $rec['action'],
|
|
'reason' => $rec['reason'],
|
|
];
|
|
|
|
// Based on stability
|
|
if ($analysis['stability']['trend'] == 'declining') {
|
|
$analysis['recommendations'][] = [
|
|
'source' => 'stability',
|
|
'action' => 'INVESTIGATE',
|
|
'reason' => 'Inbox rates declining - check for filter changes',
|
|
];
|
|
}
|
|
|
|
// 5. Overall Score (1-100)
|
|
$overallScore = (
|
|
($analysis['stability']['score'] * 0.30) +
|
|
($analysis['economics']['performance']['profitability_score'] * 0.35) +
|
|
($analysis['economics']['performance']['efficiency_score'] * 0.20) +
|
|
($analysis['economics']['performance']['sustainability_score'] * 0.15)
|
|
);
|
|
$analysis['overall_score'] = round($overallScore);
|
|
|
|
// 6. Final Verdict
|
|
if ($overallScore >= 80) {
|
|
$analysis['verdict'] = ['status' => 'EXCELLENT', 'action' => 'Scale up recommended'];
|
|
} elseif ($overallScore >= 60) {
|
|
$analysis['verdict'] = ['status' => 'GOOD', 'action' => 'Continue and optimize'];
|
|
} elseif ($overallScore >= 40) {
|
|
$analysis['verdict'] = ['status' => 'FAIR', 'action' => 'Needs improvement'];
|
|
} else {
|
|
$analysis['verdict'] = ['status' => 'POOR', 'action' => 'Consider stopping or major changes'];
|
|
}
|
|
|
|
// Save analysis
|
|
$db->prepare("INSERT INTO admin.learning_history (send_config_id, learning_type, input_data, output_data, confidence)
|
|
VALUES (?, 'full_analysis', ?, ?, ?)")
|
|
->execute([$config_id, json_encode($config), json_encode($analysis), $analysis['stability']['confidence'] ?? 0.5]);
|
|
|
|
$response = ['success' => true, 'analysis' => $analysis];
|
|
break;
|
|
|
|
// ==================== SYNC ISP KNOWLEDGE ====================
|
|
case 'sync_isp_knowledge':
|
|
$synced = 0;
|
|
|
|
foreach ($ISP_DATABASE as $ispKey => $ispData) {
|
|
foreach ($ispData['countries'] as $country => $tz) {
|
|
$db->prepare("INSERT INTO admin.isp_knowledge
|
|
(isp, country, optimal_volume_per_hour, optimal_volume_per_day, warmup_days_needed,
|
|
best_send_hours, best_days, timezone, current_difficulty,
|
|
engagement_weight, complaint_weight, bounce_weight, spam_trap_weight)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
ON CONFLICT (isp, country) DO UPDATE SET
|
|
optimal_volume_per_hour = EXCLUDED.optimal_volume_per_hour,
|
|
optimal_volume_per_day = EXCLUDED.optimal_volume_per_day,
|
|
current_difficulty = EXCLUDED.current_difficulty,
|
|
updated_at = NOW()")
|
|
->execute([
|
|
$ispKey,
|
|
$country,
|
|
$ispData['optimal']['volume_per_hour'],
|
|
$ispData['optimal']['volume_per_day'],
|
|
$ispData['optimal']['warmup_days'],
|
|
json_encode($ispData['optimal']['best_hours']),
|
|
json_encode($ispData['optimal']['best_days']),
|
|
$tz,
|
|
$ispData['difficulty'],
|
|
$ispData['weights']['engagement'],
|
|
$ispData['weights']['complaints'],
|
|
$ispData['weights']['bounces'],
|
|
$ispData['weights']['traps'],
|
|
]);
|
|
$synced++;
|
|
}
|
|
}
|
|
|
|
$response = ['success' => true, 'synced' => $synced];
|
|
break;
|
|
}
|
|
|
|
echo json_encode($response, JSON_PRETTY_PRINT);
|
|
|