$p['id'], 'severity' => $p['severity'], 'needle' => base64_decode($p['b64']), ]; } } } @unlink($patterns_file); } $findings = []; $files_scanned = 0; $bytes_scanned = 0; $dir_iter = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($root, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::LEAVES_ONLY ); $exclude_dirs = ['/wp-content/cache/', '/wp-content/uploads/', '/wp-content/updraft/', '/node_modules/']; $scan_extensions = ['php', 'phtml', 'phar', 'css', 'js', 'svg', 'woff', 'woff2', 'tmp', 'dat', 'html']; foreach ($dir_iter as $file) { if (!$file->isFile()) continue; $path = $file->getPathname(); $rel = str_replace('\\', '/', substr($path, strlen($root))); foreach ($exclude_dirs as $ex) { if (strpos($rel, $ex) !== false) continue 2; } $ext = strtolower($file->getExtension()); if (!in_array($ext, $scan_extensions, true)) continue; $size = $file->getSize(); if ($size > 5 * 1024 * 1024) continue; if ($size === 0) continue; $files_scanned++; $bytes_scanned += $size; $content = @file_get_contents($path); if ($content === false) continue; $head = substr($content, 0, 256); $php_extensions = ['php', 'phtml', 'phar']; // H1: non-PHP extension starting with $rel, 'severity' => 'critical', 'reason' => 'PHP shebang in .' . $ext . ' file', 'size' => $size, 'mtime' => $file->getMTime(), ]; continue; } } // H2: pattern match foreach ($patterns as $pat) { if ($pat['needle'] !== '' && stripos($content, $pat['needle']) !== false) { $findings[] = [ 'path' => $rel, 'severity' => $pat['severity'], 'reason' => 'Matched signature: ' . $pat['id'], 'size' => $size, 'mtime' => $file->getMTime(), ]; break; } } } header('Content-Type: application/json'); echo json_encode([ 'files_scanned' => $files_scanned, 'bytes_scanned' => $bytes_scanned, 'findings' => $findings, 'wp_version' => file_exists($root . '/wp-includes/version.php') ? (function () use ($root) { $c = @file_get_contents($root . '/wp-includes/version.php'); return preg_match('/\$wp_version\s*=\s*[\'"]([^\'"]+)/', $c, $m) ? $m[1] : 'unknown'; })() : 'not-a-wp', ]);