Files
wevads-platform/scripts/api_adversarial-sandbox.php
2026-02-26 04:53:11 +01:00

160 lines
9.5 KiB
PHP
Executable File

<?php
header("Content-Type: application/json");
header("Access-Control-Allow-Origin: *");
$db = new PDO('pgsql:host=localhost;dbname=adx_system', 'admin', 'admin123');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$action = $_GET["action"] ?? $_POST["action"] ?? "status";
// ISP filter rules engine
function analyzeTemplate($subject, $html, $fromDomain) {
$issues = []; $scores = ["gmail"=>100,"outlook"=>100,"yahoo"=>100,"gmx"=>100];
// 1. Spam trigger words
$spamWords = ["free","winner","congratulations","click here","act now","limited time","buy now","cheap","discount","offer expires","100%","guarantee","no obligation","risk free","urgent","casino","viagra","crypto","bitcoin","earn money","work from home","lose weight"];
$subjectLower = strtolower($subject); $htmlLower = strtolower(strip_tags($html));
$found = [];
foreach($spamWords as $w) {
if(strpos($subjectLower, $w) !== false || strpos($htmlLower, $w) !== false) $found[] = $w;
}
if(count($found) > 0) {
$penalty = min(count($found) * 5, 40);
foreach($scores as $k=>&$v) $v -= $penalty;
$issues[] = ["severity"=>"high","rule"=>"spam_words","detail"=>"Found ".count($found)." spam triggers: ".implode(", ",$found),"penalty"=>$penalty];
}
// 2. HTML ratio
$textLen = strlen(strip_tags($html)); $htmlLen = strlen($html);
$ratio = $htmlLen > 0 ? $textLen / $htmlLen : 0;
if($ratio < 0.2) {
foreach($scores as $k=>&$v) $v -= 15;
$issues[] = ["severity"=>"medium","rule"=>"html_ratio","detail"=>"Text/HTML ratio too low: ".round($ratio*100)."%","penalty"=>15];
}
// 3. Too many links
$linkCount = substr_count(strtolower($html), '<a ') + substr_count(strtolower($html), 'href=');
if($linkCount > 5) {
$p = min(($linkCount - 5) * 3, 20);
foreach($scores as $k=>&$v) $v -= $p;
$issues[] = ["severity"=>"medium","rule"=>"too_many_links","detail"=>"$linkCount links found (max recommended: 5)","penalty"=>$p];
}
// 4. Image-only email
$imgCount = substr_count(strtolower($html), '<img');
if($imgCount > 0 && $textLen < 100) {
foreach($scores as $k=>&$v) $v -= 25;
$issues[] = ["severity"=>"high","rule"=>"image_only","detail"=>"Image-heavy email with $imgCount images and only $textLen chars of text","penalty"=>25];
}
// 5. Subject line issues
if(strlen($subject) > 80) {
$scores["gmail"] -= 5; $scores["outlook"] -= 3;
$issues[] = ["severity"=>"low","rule"=>"subject_long","detail"=>"Subject too long: ".strlen($subject)." chars","penalty"=>5];
}
if(preg_match('/[A-Z]{5,}/', $subject)) {
foreach($scores as $k=>&$v) $v -= 10;
$issues[] = ["severity"=>"medium","rule"=>"caps_subject","detail"=>"Excessive caps in subject","penalty"=>10];
}
if(preg_match('/[!]{2,}|[$]{2,}|[*]{3,}/', $subject)) {
foreach($scores as $k=>&$v) $v -= 8;
$issues[] = ["severity"=>"medium","rule"=>"special_chars","detail"=>"Excessive special characters in subject","penalty"=>8];
}
// 6. Missing unsubscribe
if(stripos($html, 'unsubscribe') === false && stripos($html, 'désabonner') === false) {
$scores["gmail"] -= 15; $scores["outlook"] -= 10; $scores["yahoo"] -= 10;
$issues[] = ["severity"=>"high","rule"=>"no_unsubscribe","detail"=>"No unsubscribe link found","penalty"=>15];
}
// 7. Domain reputation check
if(strpos($fromDomain, '.charity') !== false || strpos($fromDomain, '.xyz') !== false || strpos($fromDomain, '.top') !== false) {
foreach($scores as $k=>&$v) $v -= 10;
$issues[] = ["severity"=>"medium","rule"=>"suspicious_tld","detail"=>"TLD '$fromDomain' has lower trust","penalty"=>10];
}
// 8. JavaScript detection
if(stripos($html, '<script') !== false || stripos($html, 'javascript:') !== false) {
foreach($scores as $k=>&$v) $v -= 30;
$issues[] = ["severity"=>"critical","rule"=>"javascript","detail"=>"JavaScript detected - will be blocked by all ISPs","penalty"=>30];
}
// 9. Base64 encoded content
if(preg_match('/base64[,;]/', $html)) {
$scores["gmail"] -= 15; $scores["outlook"] -= 20;
$issues[] = ["severity"=>"medium","rule"=>"base64_content","detail"=>"Base64 encoded content detected","penalty"=>15];
}
// 10. URL shorteners
$shorteners = ["bit.ly","tinyurl","goo.gl","t.co","ow.ly","is.gd","buff.ly"];
foreach($shorteners as $s) {
if(stripos($html, $s) !== false) {
foreach($scores as $k=>&$v) $v -= 20;
$issues[] = ["severity"=>"high","rule"=>"url_shortener","detail"=>"URL shortener '$s' detected - major spam signal","penalty"=>20];
break;
}
}
// Clamp scores
foreach($scores as $k=>&$v) $v = max(0, min(100, $v));
$overall = round(array_sum($scores) / count($scores));
$recommendations = [];
if($overall < 60) $recommendations[] = "CRITICAL: Template needs major revision before sending";
if($overall < 80) $recommendations[] = "Consider A/B testing with a small segment first";
foreach($issues as $i) {
if($i["severity"] == "critical") $recommendations[] = "FIX IMMEDIATELY: ".$i["detail"];
elseif($i["severity"] == "high") $recommendations[] = "Fix: ".$i["detail"];
}
if(empty($recommendations)) $recommendations[] = "Template looks good for sending";
return ["scores"=>$scores,"overall"=>$overall,"issues"=>$issues,"recommendations"=>$recommendations,"grade"=>$overall>=90?"A":($overall>=75?"B":($overall>=60?"C":($overall>=40?"D":"F")))];
}
try {
switch($action) {
case "status":
$total = $db->query("SELECT count(*) FROM admin.adversarial_tests")->fetchColumn();
echo json_encode(["status"=>"success","service"=>"adversarial-sandbox","tests_run"=>$total,"rules_active"=>10,"isps_simulated"=>["gmail","outlook","yahoo","gmx"],"actions"=>["status","test","history","stats","rules"]]);
break;
case "test":
$d = json_decode(file_get_contents("php://input"), true) ?: $_POST;
$subject = $d["subject"] ?? "Test Subject";
$html = $d["html"] ?? $d["body"] ?? "<p>Test email body</p>";
$from = $d["from_domain"] ?? "culturellemejean.charity";
$result = analyzeTemplate($subject, $html, $from);
// Save to DB
$stmt = $db->prepare("INSERT INTO admin.adversarial_tests (template_name,subject,html_content,test_results,gmail_score,outlook_score,yahoo_score,overall_score,issues,recommendations) VALUES (?,?,?,?,?,?,?,?,?,?) RETURNING id");
$stmt->execute([$d["name"]??"unnamed",$subject,$html,json_encode($result),$result["scores"]["gmail"],$result["scores"]["outlook"],$result["scores"]["yahoo"],$result["overall"],json_encode($result["issues"]),implode("\n",$result["recommendations"])]);
$id = $stmt->fetch(PDO::FETCH_ASSOC)["id"];
$result["test_id"] = $id;
$result["status"] = "success";
echo json_encode($result);
break;
case "history":
$rows = $db->query("SELECT id,template_name,subject,gmail_score,outlook_score,yahoo_score,overall_score,created_at FROM admin.adversarial_tests ORDER BY created_at DESC LIMIT 50")->fetchAll(PDO::FETCH_ASSOC);
echo json_encode(["status"=>"success","data"=>$rows]);
break;
case "stats":
$avg = $db->query("SELECT ROUND(AVG(gmail_score),1) as gmail, ROUND(AVG(outlook_score),1) as outlook, ROUND(AVG(yahoo_score),1) as yahoo, ROUND(AVG(overall_score),1) as overall, count(*) as total FROM admin.adversarial_tests")->fetch(PDO::FETCH_ASSOC);
$best = $db->query("SELECT template_name, overall_score FROM admin.adversarial_tests ORDER BY overall_score DESC LIMIT 5")->fetchAll(PDO::FETCH_ASSOC);
$worst = $db->query("SELECT template_name, overall_score FROM admin.adversarial_tests ORDER BY overall_score ASC LIMIT 5")->fetchAll(PDO::FETCH_ASSOC);
echo json_encode(["status"=>"success","averages"=>$avg,"best"=>$best,"worst"=>$worst]);
break;
case "rules":
echo json_encode(["status"=>"success","rules"=>[
["id"=>1,"name"=>"spam_words","description"=>"Detects common spam trigger words in subject and body","severity"=>"high","penalty"=>"5 per word, max 40"],
["id"=>2,"name"=>"html_ratio","description"=>"Checks text/HTML ratio (min 20%)","severity"=>"medium","penalty"=>"15"],
["id"=>3,"name"=>"too_many_links","description"=>"Flags emails with more than 5 links","severity"=>"medium","penalty"=>"3 per extra link"],
["id"=>4,"name"=>"image_only","description"=>"Detects image-heavy emails with little text","severity"=>"high","penalty"=>"25"],
["id"=>5,"name"=>"subject_length","description"=>"Subject line over 80 chars","severity"=>"low","penalty"=>"5"],
["id"=>6,"name"=>"caps_subject","description"=>"Excessive capitals in subject","severity"=>"medium","penalty"=>"10"],
["id"=>7,"name"=>"no_unsubscribe","description"=>"Missing unsubscribe/désabonner link","severity"=>"high","penalty"=>"15"],
["id"=>8,"name"=>"suspicious_tld","description"=>"Low-trust TLDs (.charity, .xyz, .top)","severity"=>"medium","penalty"=>"10"],
["id"=>9,"name"=>"javascript","description"=>"JavaScript in email body","severity"=>"critical","penalty"=>"30"],
["id"=>10,"name"=>"url_shortener","description"=>"URL shorteners (bit.ly, etc)","severity"=>"high","penalty"=>"20"]
]]);
break;
default:
echo json_encode(["error"=>"Unknown action"]);
}
} catch(Exception $e) { echo json_encode(["error"=>$e->getMessage()]); }