825 lines
46 KiB
PHP
Executable File
825 lines
46 KiB
PHP
Executable File
<?php
|
|
/**
|
|
* WEVAL - Index Complet des Pages
|
|
* Pages Natives (MVC) + Standalone
|
|
* Avec vérification status HTTP
|
|
*/
|
|
|
|
session_start();
|
|
error_reporting(E_ALL);
|
|
|
|
$serverIp = '89.167.40.150';
|
|
$port = '5821';
|
|
$baseUrl = "http://{$serverIp}:{$port}";
|
|
|
|
// =============================================
|
|
// DÉFINITION DES PAGES NATIVES (Menu Application)
|
|
// =============================================
|
|
$nativePages = [
|
|
'Dashboard' => [
|
|
'icon' => 'fa-tachometer-alt',
|
|
'color' => '#22d3ee',
|
|
'pages' => [
|
|
['url' => '/dashboard.html', 'name' => 'Dashboard Principal', 'desc' => 'Vue d\'ensemble'],
|
|
['url' => '/index.php', 'name' => 'Index', 'desc' => 'Point d\'entrée MVC'],
|
|
['url' => '/index.php?controller=Dashboard', 'name' => 'Dashboard Controller', 'desc' => 'Contrôleur dashboard'],
|
|
]
|
|
],
|
|
'Production' => [
|
|
'icon' => 'fa-paper-plane',
|
|
'color' => '#10b981',
|
|
'pages' => [
|
|
['url' => '/index.php?controller=Send', 'name' => 'Send', 'desc' => 'Envoi campagnes'],
|
|
['url' => '/index.php?controller=Tests', 'name' => 'Tests', 'desc' => 'Tests délivrabilité'],
|
|
['url' => '/index.php?controller=Processes', 'name' => 'Processes', 'desc' => 'Processus en cours'],
|
|
['url' => '/index.php?controller=Statistics', 'name' => 'Statistics', 'desc' => 'Statistiques'],
|
|
]
|
|
],
|
|
'Serveurs & MTA' => [
|
|
'icon' => 'fa-server',
|
|
'color' => '#f59e0b',
|
|
'pages' => [
|
|
['url' => '/index.php?controller=Servers', 'name' => 'Servers', 'desc' => 'Liste serveurs PMTA'],
|
|
['url' => '/index.php?controller=Servers&action=add', 'name' => 'Add Server', 'desc' => 'Ajouter serveur'],
|
|
['url' => '/index.php?controller=Domains', 'name' => 'Domains', 'desc' => 'Gestion domaines'],
|
|
['url' => '/index.php?controller=Vmtas', 'name' => 'VMTAs', 'desc' => 'Virtual MTAs'],
|
|
['url' => '/index.php?controller=IpWarmup', 'name' => 'IP Warmup', 'desc' => 'Échauffement IP'],
|
|
]
|
|
],
|
|
'Cloud Providers' => [
|
|
'icon' => 'fa-cloud',
|
|
'color' => '#ef4444',
|
|
'pages' => [
|
|
['url' => '/index.php?controller=Providers', 'name' => 'Providers', 'desc' => 'Liste providers'],
|
|
['url' => '/index.php?controller=HuaweiCloud', 'name' => 'Huawei Cloud', 'desc' => 'Gestion Huawei'],
|
|
['url' => '/index.php?controller=GoogleCloud', 'name' => 'Google Cloud', 'desc' => 'Gestion GCP'],
|
|
]
|
|
],
|
|
'Email Marketing' => [
|
|
'icon' => 'fa-envelope',
|
|
'color' => '#8b5cf6',
|
|
'pages' => [
|
|
['url' => '/index.php?controller=Lists', 'name' => 'Lists', 'desc' => 'Listes email'],
|
|
['url' => '/index.php?controller=Templates', 'name' => 'Templates', 'desc' => 'Modèles email'],
|
|
['url' => '/index.php?controller=Subjects', 'name' => 'Subjects', 'desc' => 'Objets email'],
|
|
['url' => '/index.php?controller=Headers', 'name' => 'Headers', 'desc' => 'En-têtes email'],
|
|
['url' => '/index.php?controller=Placeholders', 'name' => 'Placeholders', 'desc' => 'Variables dynamiques'],
|
|
]
|
|
],
|
|
'Affiliate' => [
|
|
'icon' => 'fa-handshake',
|
|
'color' => '#06b6d4',
|
|
'pages' => [
|
|
['url' => '/index.php?controller=Affiliate', 'name' => 'Affiliate Networks', 'desc' => 'Réseaux affiliés'],
|
|
['url' => '/index.php?controller=Offers', 'name' => 'Offers', 'desc' => 'Offres'],
|
|
['url' => '/index.php?controller=Conversions', 'name' => 'Conversions', 'desc' => 'Tracking conversions'],
|
|
]
|
|
],
|
|
'Administration' => [
|
|
'icon' => 'fa-cog',
|
|
'color' => '#64748b',
|
|
'pages' => [
|
|
['url' => '/index.php?controller=Users', 'name' => 'Users', 'desc' => 'Gestion utilisateurs'],
|
|
['url' => '/index.php?controller=Settings', 'name' => 'Settings', 'desc' => 'Paramètres'],
|
|
['url' => '/index.php?controller=Logs', 'name' => 'Logs', 'desc' => 'Journaux système'],
|
|
]
|
|
],
|
|
];
|
|
|
|
// =============================================
|
|
// SCAN DES PAGES STANDALONE
|
|
// =============================================
|
|
$excludeFiles = ['index.php', 'pages-index.php', '.htaccess'];
|
|
$standaloneCategories = [
|
|
'monitoring' => ['name' => 'Monitoring & Admin', 'icon' => 'fa-heartbeat', 'color' => '#22d3ee', 'patterns' => ['system-', 'monitoring', 'security', 'session', 'console', 'audit', 'whitelist']],
|
|
'huawei' => ['name' => 'Huawei Cloud', 'icon' => 'fa-cloud', 'color' => '#ef4444', 'patterns' => ['huawei-']],
|
|
'office' => ['name' => 'Office 365', 'icon' => 'fa-microsoft', 'color' => '#0078d4', 'patterns' => ['office-']],
|
|
'cloudflare' => ['name' => 'Cloudflare & DNS', 'icon' => 'fa-shield-alt', 'color' => '#f59e0b', 'patterns' => ['cloudflare-', 'domain', 'freedns', 'dkim', 'ptr', 'dns']],
|
|
'tracking' => ['name' => 'Tracking', 'icon' => 'fa-chart-line', 'color' => '#10b981', 'patterns' => ['tracking-']],
|
|
'chatbot' => ['name' => 'Chatbot & AI', 'icon' => 'fa-robot', 'color' => '#ec4899', 'patterns' => ['chatbot-', 'ai-', 'ollama']],
|
|
'database' => ['name' => 'Base de Données', 'icon' => 'fa-database', 'color' => '#06b6d4', 'patterns' => ['adminer', 'database', 'db-', 'sql', 'test-bd']],
|
|
's3' => ['name' => 'AWS S3', 'icon' => 'fa-aws', 'color' => '#ff9900', 'patterns' => ['s3_', 's3-', 'aws-']],
|
|
'tools' => ['name' => 'Outils', 'icon' => 'fa-tools', 'color' => '#64748b', 'patterns' => ['tool', 'util', 'helper', 'check', 'test', 'debug', 'error', 'phpinfo']],
|
|
'docs' => ['name' => 'Documentation', 'icon' => 'fa-book', 'color' => '#a855f7', 'patterns' => ['doc', 'architecture', 'help', 'guide', 'readme']],
|
|
'auth' => ['name' => 'Authentification', 'icon' => 'fa-lock', 'color' => '#eab308', 'patterns' => ['login', 'auth', 'logout', 'password']],
|
|
'demo' => ['name' => 'Démos', 'icon' => 'fa-play', 'color' => '#14b8a6', 'patterns' => ['demo', 'playground', 'sample']],
|
|
];
|
|
|
|
function scanStandaloneFiles($dir, $excludeFiles) {
|
|
$files = [];
|
|
if (!is_dir($dir)) return $files;
|
|
|
|
foreach (scandir($dir) as $item) {
|
|
if ($item[0] === '.' || in_array($item, $excludeFiles)) continue;
|
|
$path = $dir . '/' . $item;
|
|
if (is_file($path)) {
|
|
$ext = pathinfo($item, PATHINFO_EXTENSION);
|
|
if (in_array($ext, ['php', 'html'])) {
|
|
$stat = stat($path);
|
|
$files[] = [
|
|
'name' => $item,
|
|
'path' => $path,
|
|
'ext' => $ext,
|
|
'size' => filesize($path),
|
|
'created' => $stat['ctime'],
|
|
'modified' => $stat['mtime'],
|
|
];
|
|
}
|
|
}
|
|
}
|
|
return $files;
|
|
}
|
|
|
|
function categorizeFile($filename, $categories) {
|
|
$filename_lower = strtolower($filename);
|
|
foreach ($categories as $key => $cat) {
|
|
foreach ($cat['patterns'] as $pattern) {
|
|
if (strpos($filename_lower, strtolower($pattern)) !== false) {
|
|
return $key;
|
|
}
|
|
}
|
|
}
|
|
return 'other';
|
|
}
|
|
|
|
function checkUrlStatus($url) {
|
|
$ch = curl_init($url);
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_NOBODY => false,
|
|
CURLOPT_TIMEOUT => 5,
|
|
CURLOPT_FOLLOWLOCATION => true,
|
|
CURLOPT_MAXREDIRS => 3,
|
|
CURLOPT_SSL_VERIFYPEER => false,
|
|
]);
|
|
$response = curl_exec($ch);
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
$error = curl_error($ch);
|
|
$totalTime = curl_getinfo($ch, CURLINFO_TOTAL_TIME);
|
|
curl_close($ch);
|
|
|
|
$status = 'unknown';
|
|
$comment = '';
|
|
|
|
if ($error) {
|
|
$status = 'error';
|
|
$comment = 'Connection failed: ' . $error;
|
|
} elseif ($httpCode == 200) {
|
|
$status = 'ok';
|
|
$comment = 'OK (' . round($totalTime * 1000) . 'ms)';
|
|
} elseif ($httpCode == 302 || $httpCode == 301) {
|
|
$status = 'redirect';
|
|
$comment = 'Redirect ' . $httpCode;
|
|
} elseif ($httpCode == 404) {
|
|
$status = 'error';
|
|
$comment = '404 - Page non trouvée';
|
|
} elseif ($httpCode == 500) {
|
|
$status = 'error';
|
|
$comment = '500 - Erreur serveur interne';
|
|
} elseif ($httpCode == 403) {
|
|
$status = 'warning';
|
|
$comment = '403 - Accès interdit';
|
|
} elseif ($httpCode == 401) {
|
|
$status = 'warning';
|
|
$comment = '401 - Auth requise';
|
|
} elseif ($httpCode >= 400) {
|
|
$status = 'error';
|
|
$comment = $httpCode . ' - Erreur client';
|
|
} elseif ($httpCode >= 500) {
|
|
$status = 'error';
|
|
$comment = $httpCode . ' - Erreur serveur';
|
|
} else {
|
|
$status = 'warning';
|
|
$comment = 'Code: ' . $httpCode;
|
|
}
|
|
|
|
return [
|
|
'code' => $httpCode,
|
|
'status' => $status,
|
|
'comment' => $comment,
|
|
'time' => round($totalTime * 1000),
|
|
];
|
|
}
|
|
|
|
// AJAX Handler
|
|
if (isset($_GET['action'])) {
|
|
header('Content-Type: application/json');
|
|
|
|
switch ($_GET['action']) {
|
|
case 'check_url':
|
|
$url = $_GET['url'] ?? '';
|
|
if ($url) {
|
|
$fullUrl = (strpos($url, 'http') === 0) ? $url : $baseUrl . $url;
|
|
echo json_encode(checkUrlStatus($fullUrl));
|
|
} else {
|
|
echo json_encode(['status' => 'error', 'comment' => 'No URL']);
|
|
}
|
|
break;
|
|
|
|
case 'check_all':
|
|
$results = [];
|
|
// Check native pages
|
|
foreach ($nativePages as $cat => $data) {
|
|
foreach ($data['pages'] as $page) {
|
|
$fullUrl = $baseUrl . $page['url'];
|
|
$results[$page['url']] = checkUrlStatus($fullUrl);
|
|
}
|
|
}
|
|
// Check standalone
|
|
$files = scanStandaloneFiles(__DIR__, $excludeFiles);
|
|
foreach ($files as $file) {
|
|
$fullUrl = $baseUrl . '/' . $file['name'];
|
|
$results['/' . $file['name']] = checkUrlStatus($fullUrl);
|
|
}
|
|
echo json_encode($results);
|
|
break;
|
|
|
|
case 'refresh_list':
|
|
$files = scanStandaloneFiles(__DIR__, $excludeFiles);
|
|
$categorized = [];
|
|
foreach ($standaloneCategories as $key => $cat) {
|
|
$categorized[$key] = ['info' => $cat, 'files' => []];
|
|
}
|
|
$categorized['other'] = ['info' => ['name' => 'Autres', 'icon' => 'fa-folder', 'color' => '#475569'], 'files' => []];
|
|
|
|
foreach ($files as $file) {
|
|
$catKey = categorizeFile($file['name'], $standaloneCategories);
|
|
$categorized[$catKey]['files'][] = $file;
|
|
}
|
|
echo json_encode($categorized);
|
|
break;
|
|
}
|
|
exit;
|
|
}
|
|
|
|
// Scan initial
|
|
$standaloneFiles = scanStandaloneFiles(__DIR__, $excludeFiles);
|
|
$categorizedStandalone = [];
|
|
foreach ($standaloneCategories as $key => $cat) {
|
|
$categorizedStandalone[$key] = [];
|
|
}
|
|
$categorizedStandalone['other'] = [];
|
|
|
|
foreach ($standaloneFiles as $file) {
|
|
$catKey = categorizeFile($file['name'], $standaloneCategories);
|
|
$categorizedStandalone[$catKey][] = $file;
|
|
}
|
|
|
|
$totalNative = array_sum(array_map(fn($c) => count($c['pages']), $nativePages));
|
|
$totalStandalone = count($standaloneFiles);
|
|
$lastRefresh = date('d/m/Y H:i:s');
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="fr">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>WEVAL - Index Complet des Pages</title>
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
|
<style>
|
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
body { font-family: 'Segoe UI', sans-serif; background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%); min-height: 100vh; color: #e2e8f0; }
|
|
|
|
.header { background: linear-gradient(135deg, #0891b2, #0e7490); padding: 20px 30px; position: sticky; top: 0; z-index: 100; box-shadow: 0 4px 20px rgba(0,0,0,0.3); }
|
|
.header-content { max-width: 1800px; margin: 0 auto; display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 15px; }
|
|
.header h1 { font-size: 24px; display: flex; align-items: center; gap: 12px; }
|
|
.header-stats { display: flex; gap: 15px; flex-wrap: wrap; }
|
|
.stat-box { background: rgba(255,255,255,0.1); padding: 10px 20px; border-radius: 10px; text-align: center; }
|
|
.stat-number { font-size: 24px; font-weight: 700; color: #fff; }
|
|
.stat-label { font-size: 11px; color: rgba(255,255,255,0.7); margin-top: 2px; }
|
|
|
|
.header-actions { display: flex; gap: 10px; align-items: center; }
|
|
.search-input { padding: 10px 15px; border-radius: 8px; border: none; background: rgba(255,255,255,0.1); color: #fff; width: 200px; font-size: 13px; }
|
|
.search-input::placeholder { color: rgba(255,255,255,0.5); }
|
|
.search-input:focus { outline: none; background: rgba(255,255,255,0.2); }
|
|
|
|
.btn { padding: 10px 18px; border: none; border-radius: 8px; cursor: pointer; font-size: 13px; font-weight: 600; text-decoration: none; display: inline-flex; align-items: center; gap: 8px; transition: all 0.2s; }
|
|
.btn-primary { background: rgba(255,255,255,0.15); color: #fff; }
|
|
.btn-primary:hover { background: rgba(255,255,255,0.25); }
|
|
.btn-success { background: #10b981; color: #fff; }
|
|
.btn-success:hover { background: #059669; }
|
|
.btn-warning { background: #f59e0b; color: #fff; }
|
|
.btn-warning:hover { background: #d97706; }
|
|
|
|
.container { max-width: 1800px; margin: 0 auto; padding: 25px; }
|
|
|
|
.tabs { display: flex; gap: 5px; margin-bottom: 20px; background: rgba(0,0,0,0.2); padding: 5px; border-radius: 12px; }
|
|
.tab { flex: 1; padding: 15px; background: transparent; border: none; color: #94a3b8; font-size: 14px; font-weight: 600; cursor: pointer; border-radius: 8px; display: flex; align-items: center; justify-content: center; gap: 10px; transition: all 0.2s; }
|
|
.tab:hover { background: rgba(255,255,255,0.05); }
|
|
.tab.active { background: linear-gradient(135deg, #0891b2, #0e7490); color: #fff; }
|
|
.tab .badge { background: rgba(255,255,255,0.2); padding: 3px 10px; border-radius: 10px; font-size: 12px; }
|
|
|
|
.tab-content { display: none; }
|
|
.tab-content.active { display: block; }
|
|
|
|
.section { margin-bottom: 20px; }
|
|
.section-header { display: flex; align-items: center; gap: 12px; padding: 15px 20px; background: linear-gradient(135deg, #1e293b, #334155); border-radius: 12px 12px 0 0; border: 1px solid rgba(255,255,255,0.1); cursor: pointer; }
|
|
.section-header:hover { background: linear-gradient(135deg, #334155, #475569); }
|
|
.section-icon { width: 40px; height: 40px; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 18px; }
|
|
.section-title { font-size: 16px; font-weight: 600; flex: 1; }
|
|
.section-count { background: rgba(255,255,255,0.1); padding: 5px 15px; border-radius: 15px; font-size: 12px; }
|
|
.section-stats { display: flex; gap: 10px; }
|
|
.section-stat { padding: 4px 10px; border-radius: 8px; font-size: 11px; font-weight: 600; }
|
|
.section-stat.ok { background: rgba(16,185,129,0.2); color: #10b981; }
|
|
.section-stat.error { background: rgba(239,68,68,0.2); color: #ef4444; }
|
|
.section-stat.warning { background: rgba(245,158,11,0.2); color: #f59e0b; }
|
|
|
|
.section-content { background: rgba(15,23,42,0.5); border: 1px solid rgba(255,255,255,0.1); border-top: none; border-radius: 0 0 12px 12px; }
|
|
|
|
.page-table { width: 100%; border-collapse: collapse; }
|
|
.page-table th, .page-table td { padding: 12px 15px; text-align: left; border-bottom: 1px solid rgba(255,255,255,0.05); }
|
|
.page-table th { background: rgba(0,0,0,0.2); color: #94a3b8; font-size: 11px; font-weight: 600; text-transform: uppercase; }
|
|
.page-table tr:hover { background: rgba(6,182,212,0.05); }
|
|
|
|
.page-name { display: flex; align-items: center; gap: 10px; }
|
|
.page-icon { width: 32px; height: 32px; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-size: 12px; }
|
|
.page-icon.php { background: linear-gradient(135deg, #8b5cf6, #7c3aed); }
|
|
.page-icon.html { background: linear-gradient(135deg, #f59e0b, #d97706); }
|
|
.page-icon.mvc { background: linear-gradient(135deg, #22d3ee, #0891b2); }
|
|
.page-title { font-weight: 600; color: #f8fafc; font-size: 13px; }
|
|
.page-desc { font-size: 11px; color: #64748b; margin-top: 2px; }
|
|
.page-url { font-family: monospace; font-size: 11px; color: #64748b; max-width: 300px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
|
|
.status-cell { display: flex; align-items: center; gap: 8px; }
|
|
.status-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
|
|
.status-dot.ok { background: #10b981; box-shadow: 0 0 8px rgba(16,185,129,0.5); }
|
|
.status-dot.error { background: #ef4444; box-shadow: 0 0 8px rgba(239,68,68,0.5); }
|
|
.status-dot.warning { background: #f59e0b; box-shadow: 0 0 8px rgba(245,158,11,0.5); }
|
|
.status-dot.redirect { background: #3b82f6; box-shadow: 0 0 8px rgba(59,130,246,0.5); }
|
|
.status-dot.checking { background: #64748b; animation: pulse 1s infinite; }
|
|
.status-code { font-family: monospace; font-size: 12px; font-weight: 600; }
|
|
.status-code.ok { color: #10b981; }
|
|
.status-code.error { color: #ef4444; }
|
|
.status-code.warning { color: #f59e0b; }
|
|
.status-code.redirect { color: #3b82f6; }
|
|
.status-comment { font-size: 11px; color: #64748b; }
|
|
|
|
.date-cell { font-size: 11px; color: #64748b; }
|
|
.date-new { background: #ef4444; color: #fff; font-size: 9px; padding: 2px 6px; border-radius: 4px; margin-left: 5px; }
|
|
|
|
.actions-cell { display: flex; gap: 5px; }
|
|
.action-btn { width: 30px; height: 30px; border-radius: 6px; border: none; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 11px; transition: all 0.2s; }
|
|
.action-btn.open { background: #10b981; color: #fff; }
|
|
.action-btn.open:hover { background: #059669; }
|
|
.action-btn.copy { background: #3b82f6; color: #fff; }
|
|
.action-btn.copy:hover { background: #2563eb; }
|
|
.action-btn.new-tab { background: #8b5cf6; color: #fff; }
|
|
.action-btn.new-tab:hover { background: #7c3aed; }
|
|
.action-btn.check { background: #f59e0b; color: #fff; }
|
|
.action-btn.check:hover { background: #d97706; }
|
|
|
|
.progress-bar { position: fixed; top: 0; left: 0; height: 3px; background: linear-gradient(90deg, #22d3ee, #10b981); width: 0; z-index: 1000; transition: width 0.3s; }
|
|
|
|
.toast { position: fixed; bottom: 20px; right: 20px; background: #10b981; color: #fff; padding: 15px 25px; border-radius: 10px; font-size: 13px; display: none; z-index: 1000; box-shadow: 0 10px 30px rgba(0,0,0,0.3); }
|
|
.toast.show { display: flex; align-items: center; gap: 10px; animation: slideIn 0.3s ease; }
|
|
.toast.error { background: #ef4444; }
|
|
|
|
@keyframes slideIn { from { transform: translateX(100px); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
|
|
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
|
|
|
|
.summary-bar { display: grid; grid-template-columns: repeat(5, 1fr); gap: 15px; margin-bottom: 20px; }
|
|
.summary-item { background: linear-gradient(135deg, #1e293b, #334155); padding: 20px; border-radius: 12px; border: 1px solid rgba(255,255,255,0.1); }
|
|
.summary-icon { width: 50px; height: 50px; border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 22px; margin-bottom: 10px; }
|
|
.summary-value { font-size: 28px; font-weight: 700; }
|
|
.summary-label { font-size: 12px; color: #64748b; margin-top: 5px; }
|
|
|
|
.loading-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(15,23,42,0.9); display: none; align-items: center; justify-content: center; z-index: 2000; flex-direction: column; gap: 20px; }
|
|
.loading-overlay.show { display: flex; }
|
|
.loading-spinner { width: 50px; height: 50px; border: 4px solid rgba(255,255,255,0.1); border-top-color: #22d3ee; border-radius: 50%; animation: spin 1s linear infinite; }
|
|
@keyframes spin { to { transform: rotate(360deg); } }
|
|
.loading-text { font-size: 16px; color: #94a3b8; }
|
|
.loading-progress { font-size: 14px; color: #22d3ee; }
|
|
|
|
@media (max-width: 1200px) {
|
|
.summary-bar { grid-template-columns: repeat(3, 1fr); }
|
|
.header-content { flex-direction: column; }
|
|
}
|
|
@media (max-width: 768px) {
|
|
.summary-bar { grid-template-columns: 1fr 1fr; }
|
|
.tabs { flex-direction: column; }
|
|
.page-url { display: none; }
|
|
}
|
|
</style>
|
|
|
|
</head>
|
|
<body>
|
|
<div class="progress-bar" id="progressBar"></div>
|
|
|
|
<div class="loading-overlay" id="loadingOverlay">
|
|
<div class="loading-spinner"></div>
|
|
<div class="loading-text">Vérification des pages en cours...</div>
|
|
<div class="loading-progress" id="loadingProgress">0 / 0</div>
|
|
</div>
|
|
|
|
<div class="header">
|
|
<div class="header-content">
|
|
<h1><i class="fas fa-sitemap"></i> WEVAL - Index Complet</h1>
|
|
<div class="header-stats">
|
|
<div class="stat-box">
|
|
<div class="stat-number"><?= $totalNative ?></div>
|
|
<div class="stat-label">PAGES NATIVES</div>
|
|
</div>
|
|
<div class="stat-box">
|
|
<div class="stat-number"><?= $totalStandalone ?></div>
|
|
<div class="stat-label">STANDALONE</div>
|
|
</div>
|
|
<div class="stat-box">
|
|
<div class="stat-number" id="okCount">-</div>
|
|
<div class="stat-label">OK</div>
|
|
</div>
|
|
<div class="stat-box">
|
|
<div class="stat-number" id="errorCount">-</div>
|
|
<div class="stat-label">ERREURS</div>
|
|
</div>
|
|
</div>
|
|
<div class="header-actions">
|
|
<input type="text" class="search-input" id="searchInput" placeholder="Rechercher...">
|
|
<button class="btn btn-success" onclick="checkAllPages()"><i class="fas fa-sync-alt"></i> Vérifier Tout</button>
|
|
<button class="btn btn-warning" onclick="refreshList()"><i class="fas fa-redo"></i> Actualiser</button>
|
|
<a href="dashboard.html" class="btn btn-primary"><i class="fas fa-home"></i> Dashboard</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="container">
|
|
<!-- Summary -->
|
|
<div class="summary-bar">
|
|
<div class="summary-item">
|
|
<div class="summary-icon" style="background:rgba(34,211,238,0.2);color:#22d3ee"><i class="fas fa-file-code"></i></div>
|
|
<div class="summary-value"><?= $totalNative + $totalStandalone ?></div>
|
|
<div class="summary-label">Total Pages</div>
|
|
</div>
|
|
<div class="summary-item">
|
|
<div class="summary-icon" style="background:rgba(16,185,129,0.2);color:#10b981"><i class="fas fa-check-circle"></i></div>
|
|
<div class="summary-value" id="summaryOk">-</div>
|
|
<div class="summary-label">Fonctionnelles</div>
|
|
</div>
|
|
<div class="summary-item">
|
|
<div class="summary-icon" style="background:rgba(239,68,68,0.2);color:#ef4444"><i class="fas fa-times-circle"></i></div>
|
|
<div class="summary-value" id="summaryError">-</div>
|
|
<div class="summary-label">En Erreur</div>
|
|
</div>
|
|
<div class="summary-item">
|
|
<div class="summary-icon" style="background:rgba(245,158,11,0.2);color:#f59e0b"><i class="fas fa-exclamation-circle"></i></div>
|
|
<div class="summary-value" id="summaryWarning">-</div>
|
|
<div class="summary-label">Avertissements</div>
|
|
</div>
|
|
<div class="summary-item">
|
|
<div class="summary-icon" style="background:rgba(139,92,246,0.2);color:#8b5cf6"><i class="fas fa-clock"></i></div>
|
|
<div class="summary-value" id="lastCheck">-</div>
|
|
<div class="summary-label">Dernière vérif.</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tabs -->
|
|
<div class="tabs">
|
|
<button class="tab active" onclick="switchTab('native')">
|
|
<i class="fas fa-window-maximize"></i> Pages Natives (MVC)
|
|
<span class="badge"><?= $totalNative ?></span>
|
|
</button>
|
|
<button class="tab" onclick="switchTab('standalone')">
|
|
<i class="fas fa-file-code"></i> Pages Standalone
|
|
<span class="badge"><?= $totalStandalone ?></span>
|
|
</button>
|
|
<button class="tab" onclick="switchTab('errors')">
|
|
<i class="fas fa-exclamation-triangle"></i> Erreurs
|
|
<span class="badge" id="errorTabBadge">0</span>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Native Pages Tab -->
|
|
<div class="tab-content active" id="tab-native">
|
|
<?php foreach ($nativePages as $catName => $catData): ?>
|
|
<div class="section" data-category="<?= htmlspecialchars($catName) ?>">
|
|
<div class="section-header">
|
|
<div class="section-icon" style="background: <?= $catData['color'] ?>20; color: <?= $catData['color'] ?>">
|
|
<i class="fas <?= $catData['icon'] ?>"></i>
|
|
</div>
|
|
<div class="section-title"><?= htmlspecialchars($catName) ?></div>
|
|
<div class="section-count"><?= count($catData['pages']) ?> pages</div>
|
|
<div class="section-stats" id="stats-native-<?= md5($catName) ?>"></div>
|
|
</div>
|
|
<div class="section-content">
|
|
<table class="page-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Page</th>
|
|
<th>URL</th>
|
|
<th>Status</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($catData['pages'] as $page): ?>
|
|
<tr data-url="<?= htmlspecialchars($page['url']) ?>">
|
|
<td>
|
|
<div class="page-name">
|
|
<div class="page-icon mvc"><i class="fas fa-code"></i></div>
|
|
<div>
|
|
<div class="page-title"><?= htmlspecialchars($page['name']) ?></div>
|
|
<div class="page-desc"><?= htmlspecialchars($page['desc']) ?></div>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td><span class="page-url"><?= htmlspecialchars($page['url']) ?></span></td>
|
|
<td>
|
|
<div class="status-cell" id="status-<?= md5($page['url']) ?>">
|
|
<span class="status-dot checking"></span>
|
|
<span class="status-code">...</span>
|
|
<span class="status-comment">En attente</span>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<div class="actions-cell">
|
|
<a href="<?= htmlspecialchars($page['url']) ?>" class="action-btn open" title="Ouvrir"><i class="fas fa-external-link-alt"></i></a>
|
|
<button class="action-btn copy" onclick="copyUrl('<?= htmlspecialchars($page['url']) ?>')" title="Copier"><i class="fas fa-copy"></i></button>
|
|
<a href="<?= htmlspecialchars($page['url']) ?>" target="_blank" class="action-btn new-tab" title="Nouvel onglet"><i class="fas fa-plus"></i></a>
|
|
<button class="action-btn check" onclick="checkSingleUrl('<?= htmlspecialchars($page['url']) ?>')" title="Vérifier"><i class="fas fa-sync"></i></button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
|
|
<!-- Standalone Pages Tab -->
|
|
<div class="tab-content" id="tab-standalone">
|
|
<?php
|
|
$allCategories = $standaloneCategories;
|
|
$allCategories['other'] = ['name' => 'Autres', 'icon' => 'fa-folder', 'color' => '#475569'];
|
|
|
|
foreach ($allCategories as $catKey => $catInfo):
|
|
if (empty($categorizedStandalone[$catKey])) continue;
|
|
?>
|
|
<div class="section" data-category="<?= $catKey ?>">
|
|
<div class="section-header">
|
|
<div class="section-icon" style="background: <?= $catInfo['color'] ?>20; color: <?= $catInfo['color'] ?>">
|
|
<i class="fas <?= $catInfo['icon'] ?>"></i>
|
|
</div>
|
|
<div class="section-title"><?= htmlspecialchars($catInfo['name']) ?></div>
|
|
<div class="section-count"><?= count($categorizedStandalone[$catKey]) ?> fichiers</div>
|
|
<div class="section-stats" id="stats-standalone-<?= $catKey ?>"></div>
|
|
</div>
|
|
<div class="section-content">
|
|
<table class="page-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Fichier</th>
|
|
<th>URL</th>
|
|
<th>Créé le</th>
|
|
<th>Status</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($categorizedStandalone[$catKey] as $file):
|
|
$isNew = (time() - $file['created']) < 86400;
|
|
$url = '/' . $file['name'];
|
|
?>
|
|
<tr data-url="<?= htmlspecialchars($url) ?>">
|
|
<td>
|
|
<div class="page-name">
|
|
<div class="page-icon <?= $file['ext'] ?>"><i class="fas <?= $file['ext'] === 'php' ? 'fa-php' : 'fa-code' ?>"></i></div>
|
|
<div>
|
|
<div class="page-title"><?= htmlspecialchars($file['name']) ?></div>
|
|
<div class="page-desc"><?= round($file['size']/1024, 1) ?> KB</div>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td><span class="page-url"><?= htmlspecialchars($url) ?></span></td>
|
|
<td>
|
|
<div class="date-cell">
|
|
<?= date('d/m/Y H:i', $file['created']) ?>
|
|
<?php if ($isNew): ?><span class="date-new">NEW</span><?php endif; ?>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<div class="status-cell" id="status-<?= md5($url) ?>">
|
|
<span class="status-dot checking"></span>
|
|
<span class="status-code">...</span>
|
|
<span class="status-comment">En attente</span>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<div class="actions-cell">
|
|
<a href="<?= htmlspecialchars($url) ?>" class="action-btn open" title="Ouvrir"><i class="fas fa-external-link-alt"></i></a>
|
|
<button class="action-btn copy" onclick="copyUrl('<?= htmlspecialchars($url) ?>')" title="Copier"><i class="fas fa-copy"></i></button>
|
|
<a href="<?= htmlspecialchars($url) ?>" target="_blank" class="action-btn new-tab" title="Nouvel onglet"><i class="fas fa-plus"></i></a>
|
|
<button class="action-btn check" onclick="checkSingleUrl('<?= htmlspecialchars($url) ?>')" title="Vérifier"><i class="fas fa-sync"></i></button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
|
|
<!-- Errors Tab -->
|
|
<div class="tab-content" id="tab-errors">
|
|
<div class="section">
|
|
<div class="section-header">
|
|
<div class="section-icon" style="background: rgba(239,68,68,0.2); color: #ef4444">
|
|
<i class="fas fa-exclamation-triangle"></i>
|
|
</div>
|
|
<div class="section-title">Pages en Erreur</div>
|
|
<div class="section-count" id="errorListCount">0 erreurs</div>
|
|
</div>
|
|
<div class="section-content">
|
|
<table class="page-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Page</th>
|
|
<th>URL</th>
|
|
<th>Code</th>
|
|
<th>Erreur</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="errorTableBody">
|
|
<tr><td colspan="5" style="text-align:center;color:#64748b;padding:30px;">Lancez une vérification pour voir les erreurs</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="toast" id="toast"><i class="fas fa-check"></i> <span id="toastText">Message</span></div>
|
|
|
|
<script>
|
|
const baseUrl = '<?= $baseUrl ?>';
|
|
let allUrls = [];
|
|
let statusResults = {};
|
|
|
|
// Collecter toutes les URLs
|
|
document.querySelectorAll('tr[data-url]').forEach(row => {
|
|
allUrls.push(row.dataset.url);
|
|
});
|
|
|
|
function switchTab(tab) {
|
|
document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
|
|
document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
|
|
document.querySelector(`.tab:nth-child(${tab === 'native' ? 1 : tab === 'standalone' ? 2 : 3})`).classList.add('active');
|
|
document.getElementById('tab-' + tab).classList.add('active');
|
|
}
|
|
|
|
function showToast(msg, isError = false) {
|
|
const toast = document.getElementById('toast');
|
|
document.getElementById('toastText').textContent = msg;
|
|
toast.className = 'toast show' + (isError ? ' error' : '');
|
|
setTimeout(() => toast.className = 'toast', 3000);
|
|
}
|
|
|
|
function copyUrl(url) {
|
|
navigator.clipboard.writeText(baseUrl + url).then(() => {
|
|
showToast('URL copiée: ' + url);
|
|
});
|
|
}
|
|
|
|
function updateStatusCell(url, data) {
|
|
const cell = document.getElementById('status-' + MD5(url));
|
|
if (!cell) return;
|
|
|
|
cell.innerHTML = `
|
|
<span class="status-dot ${data.status}"></span>
|
|
<span class="status-code ${data.status}">${data.code || '?'}</span>
|
|
<span class="status-comment">${data.comment}</span>
|
|
`;
|
|
|
|
statusResults[url] = data;
|
|
}
|
|
|
|
async function checkSingleUrl(url) {
|
|
const cell = document.getElementById('status-' + MD5(url));
|
|
if (cell) {
|
|
cell.innerHTML = '<span class="status-dot checking"></span><span class="status-code">...</span><span class="status-comment">Vérification...</span>';
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(`?action=check_url&url=${encodeURIComponent(url)}`);
|
|
const data = await response.json();
|
|
updateStatusCell(url, data);
|
|
} catch (e) {
|
|
updateStatusCell(url, { status: 'error', code: 0, comment: 'Erreur réseau' });
|
|
}
|
|
}
|
|
|
|
async function checkAllPages() {
|
|
const overlay = document.getElementById('loadingOverlay');
|
|
const progress = document.getElementById('loadingProgress');
|
|
const progressBar = document.getElementById('progressBar');
|
|
|
|
overlay.classList.add('show');
|
|
|
|
let checked = 0;
|
|
const total = allUrls.length;
|
|
|
|
for (const url of allUrls) {
|
|
try {
|
|
const response = await fetch(`?action=check_url&url=${encodeURIComponent(url)}`);
|
|
const data = await response.json();
|
|
updateStatusCell(url, data);
|
|
} catch (e) {
|
|
updateStatusCell(url, { status: 'error', code: 0, comment: 'Erreur réseau' });
|
|
}
|
|
|
|
checked++;
|
|
progress.textContent = `${checked} / ${total}`;
|
|
progressBar.style.width = (checked / total * 100) + '%';
|
|
|
|
await new Promise(r => setTimeout(r, 50));
|
|
}
|
|
|
|
overlay.classList.remove('show');
|
|
progressBar.style.width = '0';
|
|
|
|
updateSummary();
|
|
updateErrorsTab();
|
|
showToast(`Vérification terminée: ${checked} pages`);
|
|
}
|
|
|
|
function updateSummary() {
|
|
let ok = 0, error = 0, warning = 0;
|
|
|
|
for (const url in statusResults) {
|
|
const status = statusResults[url].status;
|
|
if (status === 'ok' || status === 'redirect') ok++;
|
|
else if (status === 'error') error++;
|
|
else if (status === 'warning') warning++;
|
|
}
|
|
|
|
document.getElementById('okCount').textContent = ok;
|
|
document.getElementById('errorCount').textContent = error;
|
|
document.getElementById('summaryOk').textContent = ok;
|
|
document.getElementById('summaryError').textContent = error;
|
|
document.getElementById('summaryWarning').textContent = warning;
|
|
document.getElementById('errorTabBadge').textContent = error;
|
|
document.getElementById('lastCheck').textContent = new Date().toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' });
|
|
}
|
|
|
|
function updateErrorsTab() {
|
|
const tbody = document.getElementById('errorTableBody');
|
|
const errors = Object.entries(statusResults).filter(([url, data]) => data.status === 'error' || data.status === 'warning');
|
|
|
|
if (errors.length === 0) {
|
|
tbody.innerHTML = '<tr><td colspan="5" style="text-align:center;color:#10b981;padding:30px;"><i class="fas fa-check-circle"></i> Aucune erreur détectée!</td></tr>';
|
|
document.getElementById('errorListCount').textContent = '0 erreurs';
|
|
return;
|
|
}
|
|
|
|
document.getElementById('errorListCount').textContent = errors.length + ' erreurs';
|
|
|
|
tbody.innerHTML = errors.map(([url, data]) => `
|
|
<tr>
|
|
<td><div class="page-title">${url.split('/').pop() || url}</div></td>
|
|
<td><span class="page-url">${url}</span></td>
|
|
<td><span class="status-code ${data.status}">${data.code}</span></td>
|
|
<td><span class="status-comment">${data.comment}</span></td>
|
|
<td>
|
|
<div class="actions-cell">
|
|
<a href="${url}" class="action-btn open"><i class="fas fa-external-link-alt"></i></a>
|
|
<button class="action-btn check" onclick="checkSingleUrl('${url}')"><i class="fas fa-sync"></i></button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
`).join('');
|
|
}
|
|
|
|
function refreshList() {
|
|
location.reload();
|
|
}
|
|
|
|
// Search
|
|
document.getElementById('searchInput').addEventListener('input', function(e) {
|
|
const query = e.target.value.toLowerCase();
|
|
document.querySelectorAll('tr[data-url]').forEach(row => {
|
|
const url = row.dataset.url.toLowerCase();
|
|
const text = row.textContent.toLowerCase();
|
|
row.style.display = (url.includes(query) || text.includes(query)) ? '' : 'none';
|
|
});
|
|
});
|
|
|
|
// Simple MD5 hash for element IDs
|
|
function MD5(s){function L(k,d){return(k<<d)|(k>>>(32-d))}function K(G,k){var I,d,F,H,x;F=(G&2147483648);H=(k&2147483648);I=(G&1073741824);d=(k&1073741824);x=(G&1073741823)+(k&1073741823);if(I&d){return(x^2147483648^F^H)}if(I|d){if(x&1073741824){return(x^3221225472^F^H)}else{return(x^1073741824^F^H)}}else{return(x^F^H)}}function r(d,F,k){return(d&F)|((~d)&k)}function q(d,F,k){return(d&k)|(F&(~k))}function p(d,F,k){return(d^F^k)}function n(d,F,k){return(F^(d|(~k)))}function u(G,F,aa,Z,k,H,I){G=K(G,K(K(r(F,aa,Z),k),I));return K(L(G,H),F)}function f(G,F,aa,Z,k,H,I){G=K(G,K(K(q(F,aa,Z),k),I));return K(L(G,H),F)}function D(G,F,aa,Z,k,H,I){G=K(G,K(K(p(F,aa,Z),k),I));return K(L(G,H),F)}function t(G,F,aa,Z,k,H,I){G=K(G,K(K(n(F,aa,Z),k),I));return K(L(G,H),F)}function e(G){var Z;var F=G.length;var x=F+8;var k=(x-(x%64))/64;var I=(k+1)*16;var aa=Array(I-1);var d=0;var H=0;while(H<F){Z=(H-(H%4))/4;d=(H%4)*8;aa[Z]=(aa[Z]}|(G.charCodeAt(H)<<d));H++}Z=(H-(H%4))/4;d=(H%4)*8;aa[Z]=aa[Z]|(128<<d);aa[I-2]=F<<3;aa[I-1]=F>>>29;return aa}function B(x){var k="",F="",G,d;for(d=0;d<=3;d++){G=(x>>>(d*8))&255;F="0"+G.toString(16);k=k+F.substr(F.length-2,2)}return k}function J(k){k=k.replace(/\r\n/g,"\n");var d="";for(var F=0;F<k.length;F++){var x=k.charCodeAt(F);if(x<128){d+=String.fromCharCode(x)}else{if((x>127)&&(x<2048)){d+=String.fromCharCode((x>>6)|192);d+=String.fromCharCode((x&63)|128)}else{d+=String.fromCharCode((x>>12)}224);d+=String.fromCharCode(((x>>6)&63)|128);d+=String.fromCharCode((x&63)|128)}}}return d}var C=Array();var P,h,E,v,g,Y,X,W,V;var S=7,Q=12,N=17,M=22;var A=5,z=9,y=14,w=20;var o=4,m=11,l=16,j=23;var U=6,T=10,R=15,O=21;s=J(s);C=e(s);Y=1732584193;X=4023233417;W=2562383102;V=271733878;for(P=0;P<C.length;P+=16){h=Y;E=X;v=W;g=V;Y=u(Y,X,W,V,C[P+0],S,3614090360);V=u(V,Y,X,W,C[P+1],Q,3905402710);W=u(W,V,Y,X,C[P+2],N,606105819);X=u(X,W,V,Y,C[P+3],M,3250441966);Y=u(Y,X,W,V,C[P+4],S,4118548399);V=u(V,Y,X,W,C[P+5],Q,1200080426);W=u(W,V,Y,X,C[P+6],N,2821735955);X=u(X,W,V,Y,C[P+7],M,4249261313);Y=u(Y,X,W,V,C[P+8],S,1770035416);V=u(V,Y,X,W,C[P+9],Q,2336552879);W=u(W,V,Y,X,C[P+10],N,4294925233);X=u(X,W,V,Y,C[P+11],M,2304563134);Y=u(Y,X,W,V,C[P+12],S,1804603682);V=u(V,Y,X,W,C[P+13],Q,4254626195);W=u(W,V,Y,X,C[P+14],N,2792965006);X=u(X,W,V,Y,C[P+15],M,1236535329);Y=f(Y,X,W,V,C[P+1],A,4129170786);V=f(V,Y,X,W,C[P+6],z,3225465664);W=f(W,V,Y,X,C[P+11],y,643717713);X=f(X,W,V,Y,C[P+0],w,3921069994);Y=f(Y,X,W,V,C[P+5],A,3593408605);V=f(V,Y,X,W,C[P+10],z,38016083);W=f(W,V,Y,X,C[P+15],y,3634488961);X=f(X,W,V,Y,C[P+4],w,3889429448);Y=f(Y,X,W,V,C[P+9],A,568446438);V=f(V,Y,X,W,C[P+14],z,3275163606);W=f(W,V,Y,X,C[P+3],y,4107603335);X=f(X,W,V,Y,C[P+8],w,1163531501);Y=f(Y,X,W,V,C[P+13],A,2850285829);V=f(V,Y,X,W,C[P+2],z,4243563512);W=f(W,V,Y,X,C[P+7],y,1735328473);X=f(X,W,V,Y,C[P+12],w,2368359562);Y=D(Y,X,W,V,C[P+5],o,4294588738);V=D(V,Y,X,W,C[P+8],m,2272392833);W=D(W,V,Y,X,C[P+11],l,1839030562);X=D(X,W,V,Y,C[P+14],j,4259657740);Y=D(Y,X,W,V,C[P+1],o,2763975236);V=D(V,Y,X,W,C[P+4],m,1272893353);W=D(W,V,Y,X,C[P+7],l,4139469664);X=D(X,W,V,Y,C[P+10],j,3200236656);Y=D(Y,X,W,V,C[P+13],o,681279174);V=D(V,Y,X,W,C[P+0],m,3936430074);W=D(W,V,Y,X,C[P+3],l,3572445317);X=D(X,W,V,Y,C[P+6],j,76029189);Y=D(Y,X,W,V,C[P+9],o,3654602809);V=D(V,Y,X,W,C[P+12],m,3873151461);W=D(W,V,Y,X,C[P+15],l,530742520);X=D(X,W,V,Y,C[P+2],j,3299628645);Y=t(Y,X,W,V,C[P+0],U,4096336452);V=t(V,Y,X,W,C[P+7],T,1126891415);W=t(W,V,Y,X,C[P+14],R,2878612391);X=t(X,W,V,Y,C[P+5],O,4237533241);Y=t(Y,X,W,V,C[P+12],U,1700485571);V=t(V,Y,X,W,C[P+3],T,2399980690);W=t(W,V,Y,X,C[P+10],R,4293915773);X=t(X,W,V,Y,C[P+1],O,2240044497);Y=t(Y,X,W,V,C[P+8],U,1873313359);V=t(V,Y,X,W,C[P+15],T,4264355552);W=t(W,V,Y,X,C[P+6],R,2734768916);X=t(X,W,V,Y,C[P+13],O,1309151649);Y=t(Y,X,W,V,C[P+4],U,4149444226);V=t(V,Y,X,W,C[P+11],T,3174756917);W=t(W,V,Y,X,C[P+2],R,718787259);X=t(X,W,V,Y,C[P+9],O,3951481745);Y=K(Y,h);X=K(X,E);W=K(W,v);V=K(V,g)}return(B(Y)+B(X)+B(W)+B(V)).toLowerCase()}
|
|
|
|
// Auto-check on load (first 20)
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
const first20 = allUrls.slice(0, 20);
|
|
first20.forEach((url, i) => {
|
|
setTimeout(() => checkSingleUrl(url), i * 100);
|
|
});
|
|
setTimeout(updateSummary, first20.length * 100 + 500);
|
|
});
|
|
</script>
|
|
<?php include("includes/chatbot-widget.php"); ?>
|
|
|
|
</body>
|
|
</html>
|