Files
wevads-platform/scripts/api_master-monitor-api.php
2026-02-26 04:53:11 +01:00

911 lines
36 KiB
PHP
Executable File

<?php
/**
* MASTER MONITOR API
* - ALL AI Providers (Free + Paid) with dynamic update
* - Error detection (500, 404, regressions)
* - Cache cleaner
* - Zombie killer (PMTA servers)
* - Tracking system monitor
* - URL/Send validation matrix
*/
header('Content-Type: application/json');
error_reporting(E_ALL);
$db = new PDO("pgsql:host=127.0.0.1;dbname=adx_system", "admin", "admin123");
// ==================== COMPLETE AI PROVIDERS DATABASE ====================
$ALL_AI_PROVIDERS = [
// ============ FREE TIER ============
'groq' => [
'name' => 'Groq',
'type' => 'free',
'endpoint' => 'https://api.groq.com/openai/v1/chat/completions',
'models' => ['llama-3.3-70b-versatile', 'llama-3.1-8b-instant', 'llama-3.2-90b-vision-preview', 'mixtral-8x7b-32768', 'gemma2-9b-it', 'whisper-large-v3'],
'capabilities' => ['text', 'code', 'vision', 'voice_transcription'],
'rate_limit' => '30 req/min, 14400/day',
'cost' => 'FREE',
'speed' => 'ultra_fast',
'quality' => 8,
'signup' => 'https://console.groq.com'
],
'cerebras' => [
'name' => 'Cerebras',
'type' => 'free',
'endpoint' => 'https://api.cerebras.ai/v1/chat/completions',
'models' => ['llama3.1-8b', 'llama3.1-70b'],
'capabilities' => ['text', 'code'],
'rate_limit' => '30 req/min',
'cost' => 'FREE',
'speed' => 'ultra_fast',
'quality' => 7,
'signup' => 'https://cloud.cerebras.ai'
],
'sambanova' => [
'name' => 'SambaNova',
'type' => 'free',
'endpoint' => 'https://api.sambanova.ai/v1/chat/completions',
'models' => ['Meta-Llama-3.1-8B-Instruct', 'Meta-Llama-3.1-70B-Instruct', 'Meta-Llama-3.1-405B-Instruct'],
'capabilities' => ['text', 'code'],
'rate_limit' => '10 req/min',
'cost' => 'FREE',
'speed' => 'fast',
'quality' => 8,
'signup' => 'https://cloud.sambanova.ai'
],
'hyperbolic' => [
'name' => 'Hyperbolic',
'type' => 'free',
'endpoint' => 'https://api.hyperbolic.xyz/v1/chat/completions',
'models' => ['meta-llama/Llama-3.2-3B-Instruct', 'Qwen/Qwen2.5-72B-Instruct', 'deepseek-ai/DeepSeek-V2.5'],
'capabilities' => ['text', 'code', 'image_gen'],
'rate_limit' => 'Generous free tier',
'cost' => 'FREE',
'speed' => 'fast',
'quality' => 8,
'signup' => 'https://hyperbolic.xyz'
],
'glhf' => [
'name' => 'GLHF Chat',
'type' => 'free',
'endpoint' => 'https://glhf.chat/api/openai/v1/chat/completions',
'models' => ['hf:meta-llama/Llama-3.1-405B-Instruct', 'hf:mistralai/Mistral-7B-Instruct-v0.3'],
'capabilities' => ['text', 'code'],
'rate_limit' => 'Free',
'cost' => 'FREE',
'speed' => 'medium',
'quality' => 9,
'signup' => 'https://glhf.chat'
],
'openrouter_free' => [
'name' => 'OpenRouter (Free)',
'type' => 'free',
'endpoint' => 'https://openrouter.ai/api/v1/chat/completions',
'models' => ['meta-llama/llama-3.1-8b-instruct:free', 'google/gemma-2-9b-it:free', 'mistralai/mistral-7b-instruct:free', 'huggingfaceh4/zephyr-7b-beta:free'],
'capabilities' => ['text', 'aggregator'],
'rate_limit' => '20 req/min free models',
'cost' => 'FREE',
'speed' => 'medium',
'quality' => 7,
'signup' => 'https://openrouter.ai'
],
'gemini' => [
'name' => 'Google Gemini',
'type' => 'free',
'endpoint' => 'https://generativelanguage.googleapis.com/v1beta/models',
'models' => ['gemini-1.5-flash', 'gemini-1.5-flash-8b', 'gemini-1.5-pro', 'gemini-2.0-flash-exp', 'gemini-exp-1206'],
'capabilities' => ['text', 'image', 'video', 'audio', 'code', 'function_calling'],
'rate_limit' => '60 req/min, 1500/day',
'cost' => 'FREE (generous)',
'speed' => 'fast',
'quality' => 9,
'signup' => 'https://aistudio.google.com'
],
'cloudflare_ai' => [
'name' => 'Cloudflare Workers AI',
'type' => 'free',
'endpoint' => 'https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/run',
'models' => ['@cf/meta/llama-3.1-8b-instruct', '@cf/mistral/mistral-7b-instruct-v0.1', '@cf/qwen/qwen1.5-14b-chat-awq'],
'capabilities' => ['text', 'image_gen', 'embeddings'],
'rate_limit' => '10000 neurons/day free',
'cost' => 'FREE',
'speed' => 'fast',
'quality' => 7,
'signup' => 'https://dash.cloudflare.com'
],
'huggingface_inference' => [
'name' => 'HuggingFace Inference',
'type' => 'free',
'endpoint' => 'https://api-inference.huggingface.co/models',
'models' => ['meta-llama/Llama-3.2-3B-Instruct', 'mistralai/Mistral-7B-Instruct-v0.3', 'google/gemma-2-2b-it'],
'capabilities' => ['text', 'image_gen', 'embeddings', 'audio'],
'rate_limit' => 'Rate limited free',
'cost' => 'FREE',
'speed' => 'slow',
'quality' => 7,
'signup' => 'https://huggingface.co'
],
// ============ FREE TRIAL / CREDITS ============
'mistral' => [
'name' => 'Mistral AI',
'type' => 'free_trial',
'endpoint' => 'https://api.mistral.ai/v1/chat/completions',
'models' => ['mistral-large-latest', 'mistral-small-latest', 'codestral-latest', 'pixtral-12b-2409', 'mistral-embed'],
'capabilities' => ['text', 'code', 'vision', 'embeddings'],
'rate_limit' => '€5 free credit',
'cost' => '€5 FREE then paid',
'speed' => 'fast',
'quality' => 9,
'signup' => 'https://console.mistral.ai'
],
'cohere' => [
'name' => 'Cohere',
'type' => 'free_trial',
'endpoint' => 'https://api.cohere.ai/v1/chat',
'models' => ['command-r-plus', 'command-r', 'command-light', 'embed-english-v3.0'],
'capabilities' => ['text', 'rag', 'embeddings', 'rerank'],
'rate_limit' => '1000 req/month free',
'cost' => 'FREE trial then paid',
'speed' => 'medium',
'quality' => 8,
'signup' => 'https://dashboard.cohere.com'
],
'together' => [
'name' => 'Together AI',
'type' => 'free_trial',
'endpoint' => 'https://api.together.xyz/v1/chat/completions',
'models' => ['meta-llama/Llama-3.2-90B-Vision-Instruct-Turbo', 'meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo', 'mistralai/Mixtral-8x22B-Instruct-v0.1', 'Qwen/Qwen2.5-72B-Instruct-Turbo'],
'capabilities' => ['text', 'code', 'vision', 'image_gen'],
'rate_limit' => '$25 free credit',
'cost' => '$25 FREE then paid',
'speed' => 'fast',
'quality' => 9,
'signup' => 'https://api.together.xyz'
],
'fireworks' => [
'name' => 'Fireworks AI',
'type' => 'free_trial',
'endpoint' => 'https://api.fireworks.ai/inference/v1/chat/completions',
'models' => ['accounts/fireworks/models/llama-v3p1-405b-instruct', 'accounts/fireworks/models/llama-v3p2-90b-vision-instruct', 'accounts/fireworks/models/mixtral-8x22b-instruct'],
'capabilities' => ['text', 'code', 'vision', 'function_calling'],
'rate_limit' => '$1 free credit',
'cost' => '$1 FREE then cheap',
'speed' => 'fast',
'quality' => 9,
'signup' => 'https://fireworks.ai'
],
'novita' => [
'name' => 'Novita AI',
'type' => 'free_trial',
'endpoint' => 'https://api.novita.ai/v3/openai/chat/completions',
'models' => ['meta-llama/llama-3.1-70b-instruct', 'meta-llama/llama-3.1-405b-instruct', 'mistralai/mistral-nemo'],
'capabilities' => ['text', 'image_gen', 'video_gen'],
'rate_limit' => '$0.5 free credit',
'cost' => '$0.5 FREE then paid',
'speed' => 'medium',
'quality' => 8,
'signup' => 'https://novita.ai'
],
'lepton' => [
'name' => 'Lepton AI',
'type' => 'free_trial',
'endpoint' => 'https://llama3-1-405b.lepton.run/api/v1/chat/completions',
'models' => ['llama3-1-405b', 'llama3-1-70b', 'mixtral-8x7b'],
'capabilities' => ['text', 'code'],
'rate_limit' => 'Free trial',
'cost' => 'FREE trial',
'speed' => 'fast',
'quality' => 9,
'signup' => 'https://www.lepton.ai'
],
'anyscale' => [
'name' => 'Anyscale',
'type' => 'free_trial',
'endpoint' => 'https://api.endpoints.anyscale.com/v1/chat/completions',
'models' => ['meta-llama/Llama-3-70b-chat-hf', 'mistralai/Mixtral-8x7B-Instruct-v0.1'],
'capabilities' => ['text', 'code'],
'rate_limit' => '$10 free credit',
'cost' => '$10 FREE then paid',
'speed' => 'fast',
'quality' => 8,
'signup' => 'https://www.anyscale.com'
],
'replicate' => [
'name' => 'Replicate',
'type' => 'free_trial',
'endpoint' => 'https://api.replicate.com/v1/predictions',
'models' => ['meta/llama-2-70b-chat', 'mistralai/mixtral-8x7b-instruct-v0.1', 'stability-ai/sdxl'],
'capabilities' => ['text', 'image_gen', 'video_gen', 'audio'],
'rate_limit' => 'Pay per use',
'cost' => 'Free trial then paid',
'speed' => 'slow',
'quality' => 8,
'signup' => 'https://replicate.com'
],
// ============ CHEAP / VALUE ============
'deepseek' => [
'name' => 'DeepSeek',
'type' => 'cheap',
'endpoint' => 'https://api.deepseek.com/chat/completions',
'models' => ['deepseek-chat', 'deepseek-coder', 'deepseek-reasoner'],
'capabilities' => ['text', 'code', 'reasoning', 'analysis'],
'rate_limit' => 'High limits',
'cost' => '$0.14/1M input, $0.28/1M output',
'speed' => 'fast',
'quality' => 9,
'signup' => 'https://platform.deepseek.com'
],
'openrouter' => [
'name' => 'OpenRouter (Paid)',
'type' => 'aggregator',
'endpoint' => 'https://openrouter.ai/api/v1/chat/completions',
'models' => ['anthropic/claude-3.5-sonnet', 'openai/gpt-4o', 'google/gemini-pro-1.5', 'meta-llama/llama-3.1-405b-instruct'],
'capabilities' => ['text', 'image', 'code', 'all_models'],
'rate_limit' => 'Per model',
'cost' => 'Variable (often cheaper)',
'speed' => 'medium',
'quality' => 10,
'signup' => 'https://openrouter.ai'
],
// ============ PREMIUM / PAID ============
'anthropic' => [
'name' => 'Anthropic Claude',
'type' => 'paid',
'endpoint' => 'https://api.anthropic.com/v1/messages',
'models' => ['claude-3-5-sonnet-20241022', 'claude-3-5-haiku-20241022', 'claude-3-opus-20240229'],
'capabilities' => ['text', 'image', 'code', 'analysis', 'reasoning', 'computer_use'],
'rate_limit' => '4000 req/min',
'cost' => '$3-15/1M tokens',
'speed' => 'medium',
'quality' => 10,
'signup' => 'https://console.anthropic.com'
],
'openai' => [
'name' => 'OpenAI',
'type' => 'paid',
'endpoint' => 'https://api.openai.com/v1/chat/completions',
'models' => ['gpt-4o', 'gpt-4o-mini', 'gpt-4-turbo', 'o1-preview', 'o1-mini', 'dall-e-3', 'whisper-1', 'tts-1'],
'capabilities' => ['text', 'image', 'vision', 'voice', 'tts', 'code', 'reasoning'],
'rate_limit' => 'Tier based',
'cost' => '$2.50-60/1M tokens',
'speed' => 'fast',
'quality' => 10,
'signup' => 'https://platform.openai.com'
],
'perplexity' => [
'name' => 'Perplexity',
'type' => 'paid',
'endpoint' => 'https://api.perplexity.ai/chat/completions',
'models' => ['llama-3.1-sonar-large-128k-online', 'llama-3.1-sonar-small-128k-online', 'llama-3.1-sonar-huge-128k-online'],
'capabilities' => ['text', 'search', 'rag', 'citations'],
'rate_limit' => 'Per subscription',
'cost' => '$0.20-5/1M tokens',
'speed' => 'medium',
'quality' => 9,
'signup' => 'https://www.perplexity.ai/settings/api'
],
'azure_openai' => [
'name' => 'Azure OpenAI',
'type' => 'paid',
'endpoint' => 'https://{resource}.openai.azure.com/openai/deployments/{deployment}/chat/completions',
'models' => ['gpt-4o', 'gpt-4-turbo', 'gpt-35-turbo'],
'capabilities' => ['text', 'image', 'voice', 'code'],
'rate_limit' => 'Quota based',
'cost' => 'Similar to OpenAI',
'speed' => 'fast',
'quality' => 10,
'signup' => 'https://azure.microsoft.com/en-us/products/ai-services/openai-service'
],
'aws_bedrock' => [
'name' => 'AWS Bedrock',
'type' => 'paid',
'endpoint' => 'https://bedrock-runtime.{region}.amazonaws.com',
'models' => ['anthropic.claude-3-5-sonnet', 'meta.llama3-1-405b-instruct', 'amazon.titan-text-premier'],
'capabilities' => ['text', 'image', 'code', 'embeddings'],
'rate_limit' => 'Quota based',
'cost' => 'Per model pricing',
'speed' => 'fast',
'quality' => 10,
'signup' => 'https://aws.amazon.com/bedrock/'
],
'vertex_ai' => [
'name' => 'Google Vertex AI',
'type' => 'paid',
'endpoint' => 'https://{region}-aiplatform.googleapis.com/v1/projects/{project}/locations/{region}/publishers/google/models',
'models' => ['gemini-1.5-pro', 'gemini-1.5-flash', 'text-bison', 'code-bison'],
'capabilities' => ['text', 'image', 'video', 'code', 'embeddings'],
'rate_limit' => 'Quota based',
'cost' => 'Per model pricing',
'speed' => 'fast',
'quality' => 9,
'signup' => 'https://console.cloud.google.com/vertex-ai'
],
// ============ SPECIALIZED ============
'eleven_labs' => [
'name' => 'ElevenLabs',
'type' => 'specialized',
'endpoint' => 'https://api.elevenlabs.io/v1',
'models' => ['eleven_multilingual_v2', 'eleven_turbo_v2'],
'capabilities' => ['tts', 'voice_clone', 'audio'],
'rate_limit' => '10000 chars/month free',
'cost' => 'FREE tier then paid',
'speed' => 'fast',
'quality' => 10,
'signup' => 'https://elevenlabs.io'
],
'stability' => [
'name' => 'Stability AI',
'type' => 'specialized',
'endpoint' => 'https://api.stability.ai/v1/generation',
'models' => ['stable-diffusion-xl-1024-v1-0', 'stable-image-ultra', 'stable-video-diffusion'],
'capabilities' => ['image_gen', 'video_gen', 'image_edit'],
'rate_limit' => '25 credits free',
'cost' => 'Credits based',
'speed' => 'medium',
'quality' => 10,
'signup' => 'https://platform.stability.ai'
],
'assemblyai' => [
'name' => 'AssemblyAI',
'type' => 'specialized',
'endpoint' => 'https://api.assemblyai.com/v2',
'models' => ['best', 'nano'],
'capabilities' => ['transcription', 'speaker_diarization', 'sentiment'],
'rate_limit' => '5 hours free',
'cost' => '$0.37/hour',
'speed' => 'medium',
'quality' => 10,
'signup' => 'https://www.assemblyai.com'
]
];
$action = $_POST['action'] ?? $_GET['action'] ?? '';
$response = ['success' => false];
switch ($action) {
// ==================== LIST ALL PROVIDERS ====================
case 'list_all_providers':
$byType = [
'free' => [],
'free_trial' => [],
'cheap' => [],
'paid' => [],
'specialized' => [],
'aggregator' => []
];
foreach ($ALL_AI_PROVIDERS as $key => $p) {
$byType[$p['type']][] = array_merge(['key' => $key], $p);
}
$response = [
'success' => true,
'providers' => $ALL_AI_PROVIDERS,
'by_type' => $byType,
'total' => count($ALL_AI_PROVIDERS),
'free_count' => count($byType['free']) + count($byType['free_trial'])
];
break;
// ==================== SYNC PROVIDERS TO DB ====================
case 'sync_providers':
$synced = 0;
foreach ($ALL_AI_PROVIDERS as $key => $p) {
$stmt = $db->prepare("INSERT INTO admin.ai_providers
(name, provider_key, endpoint, model, capabilities, rate_limit, cost, speed_rating, quality_rating, provider_type, signup_url)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT (provider_key) DO UPDATE SET
name = EXCLUDED.name,
endpoint = EXCLUDED.endpoint,
model = EXCLUDED.model,
capabilities = EXCLUDED.capabilities,
rate_limit = EXCLUDED.rate_limit,
cost = EXCLUDED.cost");
$stmt->execute([
$p['name'],
$key,
$p['endpoint'],
$p['models'][0],
json_encode($p['capabilities']),
$p['rate_limit'],
$p['cost'],
$p['speed'] == 'ultra_fast' ? 10 : ($p['speed'] == 'fast' ? 8 : 5),
$p['quality'],
$p['type'],
$p['signup']
]);
$synced++;
}
$response = ['success' => true, 'synced' => $synced];
break;
// ==================== ERROR DETECTION & AUTO-REPAIR ====================
case 'check_errors':
$errors = [];
// Check Apache error log for 500s
$apacheErrors = shell_exec("grep -c '500' /var/log/apache2/error.log 2>/dev/null || echo 0");
$errors['apache_500'] = intval(trim($apacheErrors));
// Check for 404s in access log
$notFound = shell_exec("grep -c ' 404 ' /var/log/apache2/access.log 2>/dev/null | tail -1000 || echo 0");
$errors['apache_404'] = intval(trim($notFound));
// Check PHP fatal errors
$phpFatal = shell_exec("grep -c 'Fatal error' /var/log/apache2/error.log 2>/dev/null || echo 0");
$errors['php_fatal'] = intval(trim($phpFatal));
// Check specific WEVAL endpoints
$endpoints = [
'wevads_main' => 'http://127.0.0.1:5821/',
'hamid_api' => 'http://127.0.0.1:5821/hamid-api.php?action=health',
'send_control' => 'http://127.0.0.1:5821/deliverads/send-control.php',
'ceo_pilotage' => 'http://127.0.0.1:5821/ceo-pilotage.php',
'tracking_58421' => 'http://127.0.0.1:58421/',
'n8n' => 'http://127.0.0.1:5678/'
];
$endpointStatus = [];
foreach ($endpoints as $name => $url) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$endpointStatus[$name] = [
'url' => $url,
'status' => $httpCode,
'ok' => ($httpCode >= 200 && $httpCode < 400)
];
if ($httpCode >= 500) {
$errors['endpoint_' . $name] = $httpCode;
}
}
$response = [
'success' => true,
'errors' => $errors,
'endpoints' => $endpointStatus,
'total_errors' => array_sum($errors),
'critical' => array_sum($errors) > 10
];
break;
// ==================== AUTO-REPAIR ERRORS ====================
case 'auto_repair':
$repairs = [];
// 1. Clear OPcache
if (function_exists('opcache_reset')) {
opcache_reset();
$repairs[] = 'OPcache cleared';
}
// 2. Restart PHP-FPM if many errors
$phpErrors = shell_exec("grep -c 'Fatal error' /var/log/apache2/error.log 2>/dev/null || echo 0");
if (intval(trim($phpErrors)) > 10) {
shell_exec('systemctl restart php7.4-fpm 2>&1');
$repairs[] = 'PHP-FPM restarted';
}
// 3. Check and restart Apache if needed
$apacheStatus = trim(shell_exec('systemctl is-active apache2'));
if ($apacheStatus !== 'active') {
shell_exec('systemctl restart apache2 2>&1');
$repairs[] = 'Apache restarted';
}
// 4. Clear APC cache
if (function_exists('apc_clear_cache')) {
apc_clear_cache();
apc_clear_cache('user');
$repairs[] = 'APC cache cleared';
}
// 5. Clear Redis cache if saturated
$redisInfo = shell_exec('redis-cli info memory 2>/dev/null | grep used_memory_human');
if (strpos($redisInfo, 'G') !== false) { // If using GB
shell_exec('redis-cli FLUSHDB 2>&1');
$repairs[] = 'Redis cache cleared';
}
// 6. Log repair
$db->prepare("INSERT INTO admin.orchestrator_log (source, action, data, status) VALUES ('auto-repair', 'repair_executed', ?, 'success')")
->execute([json_encode($repairs)]);
$response = ['success' => true, 'repairs' => $repairs];
break;
// ==================== CLEAR ALL CACHES ====================
case 'clear_all_caches':
$cleared = [];
// OPcache
if (function_exists('opcache_reset')) {
opcache_reset();
$cleared[] = 'OPcache';
}
// Redis
shell_exec('redis-cli FLUSHALL 2>&1');
$cleared[] = 'Redis';
// APCu
if (function_exists('apcu_clear_cache')) {
apcu_clear_cache();
$cleared[] = 'APCu';
}
// PHP session files (old ones)
shell_exec('find /var/lib/php/sessions -type f -mtime +1 -delete 2>&1');
$cleared[] = 'Old PHP sessions';
// Temp files
shell_exec('rm -rf /tmp/wevads_* 2>&1');
$cleared[] = 'Temp files';
// Apache logs rotation
shell_exec('logrotate -f /etc/logrotate.d/apache2 2>&1');
$cleared[] = 'Apache logs rotated';
$response = ['success' => true, 'cleared' => $cleared];
break;
// ==================== ZOMBIE KILLER ====================
case 'kill_zombies':
$killed = [];
// 1. Find zombie PMTA servers (in DB as running but actually stopped)
$runningInDb = $db->query("SELECT id, name, ip_address, cloud_instance_id, cloud_provider
FROM mta.servers WHERE provider_status = 'running'")->fetchAll(PDO::FETCH_ASSOC);
foreach ($runningInDb as $srv) {
// Check if really running (port 25)
$conn = @fsockopen($srv['ip_address'], 25, $errno, $errstr, 3);
if ($conn === false) {
// It's a zombie!
$db->prepare("UPDATE mta.servers SET provider_status = 'zombie_detected' WHERE id = ?")
->execute([$srv['id']]);
$killed[] = ['type' => 'pmta_zombie', 'server' => $srv['name'], 'ip' => $srv['ip_address']];
// Try to stop at cloud level
// (would call Huawei/Scaleway API here)
} else {
fclose($conn);
}
}
// 2. Find zombie processes on this server
$zombieProcesses = shell_exec("ps aux | grep -E 'Z|defunct' | grep -v grep | wc -l");
if (intval(trim($zombieProcesses)) > 0) {
// Kill parent processes of zombies
shell_exec("ps -ef | grep defunct | grep -v grep | awk '{print $3}' | xargs -r kill -9 2>/dev/null");
$killed[] = ['type' => 'local_zombie', 'count' => intval(trim($zombieProcesses))];
}
// 3. Find stuck PHP processes
$stuckPhp = shell_exec("ps aux | grep 'php' | grep -v grep | awk '\$10 > 300 {print \$2}'");
$stuckPids = array_filter(explode("\n", trim($stuckPhp)));
foreach ($stuckPids as $pid) {
shell_exec("kill -9 $pid 2>/dev/null");
$killed[] = ['type' => 'stuck_php', 'pid' => $pid];
}
// 4. Find orphan Apache workers
$orphanApache = shell_exec("ps aux | grep apache2 | grep -v grep | awk '\$6 > 500000 {print \$2}'"); // >500MB
$orphanPids = array_filter(explode("\n", trim($orphanApache)));
foreach ($orphanPids as $pid) {
shell_exec("kill -9 $pid 2>/dev/null");
$killed[] = ['type' => 'orphan_apache', 'pid' => $pid];
}
// Log
$db->prepare("INSERT INTO admin.orchestrator_log (source, action, data, status) VALUES ('zombie-killer', 'kill_zombies', ?, 'success')")
->execute([json_encode($killed)]);
$response = ['success' => true, 'killed' => $killed, 'count' => count($killed)];
break;
// ==================== TRACKING SYSTEM MONITOR ====================
case 'check_tracking':
$trackingServers = [
['name' => 'OVH Tracking 1', 'ip' => '151.80.235.110', 'port' => 80],
['name' => 'OVH Tracking 2', 'ip' => '151.80.235.111', 'port' => 80],
['name' => 'Local Tracking', 'ip' => '127.0.0.1', 'port' => 58421],
];
$results = [];
foreach ($trackingServers as $srv) {
$conn = @fsockopen($srv['ip'], $srv['port'], $errno, $errstr, 5);
$isUp = ($conn !== false);
if ($conn) fclose($conn);
// Test tracking endpoint
$testUrl = "http://{$srv['ip']}:{$srv['port']}/track/test";
$ch = curl_init($testUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$trackResponse = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$results[] = [
'name' => $srv['name'],
'ip' => $srv['ip'],
'port' => $srv['port'],
'port_open' => $isUp,
'http_code' => $httpCode,
'healthy' => $isUp && $httpCode < 400
];
}
$unhealthy = array_filter($results, fn($r) => !$r['healthy']);
$response = [
'success' => true,
'servers' => $results,
'all_healthy' => empty($unhealthy),
'unhealthy_count' => count($unhealthy)
];
break;
// ==================== REPAIR TRACKING ====================
case 'repair_tracking':
$server = $_POST['server'] ?? 'local';
$repairs = [];
if ($server == 'local' || $server == 'all') {
// Restart local tracking
shell_exec('systemctl restart apache2 2>&1');
$repairs[] = 'Apache restarted (local tracking)';
// Check nginx for tracking
$nginxStatus = trim(shell_exec('systemctl is-active nginx 2>/dev/null'));
if ($nginxStatus !== 'active') {
shell_exec('systemctl start nginx 2>&1');
$repairs[] = 'Nginx started';
}
}
$response = ['success' => true, 'repairs' => $repairs];
break;
// ==================== URL VALIDATION MATRIX ====================
case 'validate_send_urls':
$config_id = intval($_POST['config_id'] ?? $_GET['config_id'] ?? 0);
if (!$config_id) {
$response = ['success' => false, 'error' => 'config_id required'];
break;
}
$config = $db->query("SELECT c.*, s.image_base_url, s.tracking_domain, o.offer_url
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);
$validation = [
'config_id' => $config_id,
'tests' => []
];
// 1. Test Image URL
if ($config['image_url']) {
$ch = curl_init($config['image_url']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
curl_close($ch);
$validation['tests']['image'] = [
'url' => $config['image_url'],
'status' => $httpCode,
'content_type' => $contentType,
'ok' => $httpCode == 200 && strpos($contentType, 'image') !== false
];
}
// 2. Test Tracking Domain
if ($config['tracking_domain']) {
$trackUrl = "https://{$config['tracking_domain']}/health";
$ch = curl_init($trackUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$validation['tests']['tracking_domain'] = [
'url' => $trackUrl,
'status' => $httpCode,
'ok' => $httpCode >= 200 && $httpCode < 400
];
}
// 3. Test Tracking Link Redirect
if ($config['tracking_domain'] && $config['offer_url']) {
$trackLink = "https://{$config['tracking_domain']}/c/test123";
$ch = curl_init($trackLink);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$redirectUrl = curl_getinfo($ch, CURLINFO_REDIRECT_URL);
curl_close($ch);
$validation['tests']['tracking_redirect'] = [
'url' => $trackLink,
'status' => $httpCode,
'redirect_to' => $redirectUrl,
'ok' => $httpCode == 301 || $httpCode == 302
];
}
// 4. Test Offer URL
if ($config['offer_url']) {
$ch = curl_init($config['offer_url']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$finalUrl = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
curl_close($ch);
$validation['tests']['offer_url'] = [
'url' => $config['offer_url'],
'final_url' => $finalUrl,
'status' => $httpCode,
'ok' => $httpCode >= 200 && $httpCode < 400
];
}
// Overall status
$allOk = true;
foreach ($validation['tests'] as $test) {
if (!$test['ok']) $allOk = false;
}
$validation['all_ok'] = $allOk;
$response = ['success' => true, 'validation' => $validation];
break;
// ==================== FULL SEND TEST ====================
case 'full_send_test':
$config_id = intval($_POST['config_id'] ?? 0);
$results = [
'config_id' => $config_id,
'timestamp' => date('Y-m-d H:i:s'),
'tests' => []
];
// 1. URL Validation
$urlValidation = json_decode(file_get_contents("http://127.0.0.1:5821/api/master-monitor-api.php?action=validate_send_urls&config_id=$config_id"), true);
$results['tests']['urls'] = $urlValidation['validation'] ?? ['ok' => false];
// 2. Seed Test (if seeds available)
$seedCount = $db->query("SELECT COUNT(*) FROM admin.seed_accounts WHERE status = 'active'")->fetchColumn();
$results['tests']['seeds'] = [
'available' => $seedCount,
'ok' => $seedCount > 0
];
// 3. Server Availability
$config = $db->query("SELECT server_ids FROM admin.send_configs WHERE id = $config_id")->fetch(PDO::FETCH_ASSOC);
$serverIds = trim($config['server_ids'] ?? '', '{}');
if ($serverIds) {
$servers = $db->query("SELECT id, ip_address, provider_status FROM mta.servers WHERE id IN ($serverIds)")->fetchAll(PDO::FETCH_ASSOC);
$serversOk = 0;
foreach ($servers as $s) {
if ($s['provider_status'] == 'running') {
$conn = @fsockopen($s['ip_address'], 25, $errno, $errstr, 3);
if ($conn) {
fclose($conn);
$serversOk++;
}
}
}
$results['tests']['servers'] = [
'total' => count($servers),
'running' => $serversOk,
'ok' => $serversOk > 0
];
}
// 4. Suppression Check
$suppressionDone = $db->query("SELECT suppression_done FROM admin.send_configs WHERE id = $config_id")->fetchColumn();
$results['tests']['suppression'] = [
'done' => (bool)$suppressionDone,
'ok' => (bool)$suppressionDone
];
// Overall
$allOk = true;
foreach ($results['tests'] as $test) {
if (!($test['ok'] ?? false)) $allOk = false;
}
$results['all_ok'] = $allOk;
$results['ready_to_send'] = $allOk;
$response = ['success' => true, 'results' => $results];
break;
// ==================== REGRESSION DETECTION ====================
case 'detect_regressions':
$regressions = [];
// Compare current error counts with yesterday
$todayErrors = intval(shell_exec("grep -c 'error' /var/log/apache2/error.log 2>/dev/null || echo 0"));
$yesterdayErrors = intval(shell_exec("grep -c 'error' /var/log/apache2/error.log.1 2>/dev/null || echo 0"));
if ($todayErrors > $yesterdayErrors * 2 && $todayErrors > 10) {
$regressions[] = [
'type' => 'error_spike',
'today' => $todayErrors,
'yesterday' => $yesterdayErrors,
'increase' => round(($todayErrors / max(1, $yesterdayErrors)) * 100 - 100, 1) . '%'
];
}
// Check for new 500 errors in last hour
$recent500 = shell_exec("grep '500' /var/log/apache2/error.log 2>/dev/null | tail -100 | grep -c \"$(date '+%b %d %H')\" || echo 0");
if (intval(trim($recent500)) > 5) {
$regressions[] = [
'type' => '500_errors',
'count' => intval(trim($recent500)),
'period' => 'last_hour'
];
}
// Check for new PHP files with syntax errors
$syntaxErrors = shell_exec("find /opt/wevads/public -name '*.php' -mmin -60 -exec php -l {} \; 2>&1 | grep -c 'Parse error' || echo 0");
if (intval(trim($syntaxErrors)) > 0) {
$regressions[] = [
'type' => 'php_syntax_error',
'count' => intval(trim($syntaxErrors))
];
}
// Check AI provider health
$failedProviders = $db->query("SELECT COUNT(*) FROM admin.ai_providers WHERE status = 'error'")->fetchColumn();
if ($failedProviders > 3) {
$regressions[] = [
'type' => 'ai_providers_down',
'count' => $failedProviders
];
}
$response = [
'success' => true,
'regressions' => $regressions,
'count' => count($regressions),
'critical' => count($regressions) > 2
];
break;
}
echo json_encode($response, JSON_PRETTY_PRINT);