<?php
/**
 * WordPress Auto Cleanup Script - Eksekusi via Browser
 * -----------------------------------------------------------------
 * Adaptasi dari script cleanup Joomla, disesuaikan untuk struktur
 * WordPress (wp-admin, wp-content, wp-includes, dst).
 *
 * PERBEDAAN PENTING vs versi Joomla aslinya:
 * - Default-nya DRY RUN (tidak menghapus apa pun), harus dikonfirmasi
 *   eksplisit lewat parameter &confirm=yes sebelum benar-benar menghapus.
 *   Ini supaya script tidak langsung menghapus isi situs hanya karena
 *   URL-nya diakses / ke-crawl / ke-cache oleh bot.
 *
 * CARA PAKAI:
 * 1. Upload ke ROOT WordPress (sejajar dengan wp-config.php).
 * 2. GANTI $security_password di bawah dengan password acak Anda sendiri.
 * 3. Akses: https://domainanda.com/cleanup-wp-full.php?key=PASSWORD_ANDA
 *    -> Ini hanya menampilkan simulasi (DRY RUN), TIDAK menghapus apa pun.
 * 4. Setelah Anda BACKUP FULL dan yakin daftarnya benar, akses:
 *    https://domainanda.com/cleanup-wp-full.php?key=PASSWORD_ANDA&confirm=yes
 *    -> Ini baru benar-benar menghapus.
 * 5. HAPUS FILE INI dari server setelah selesai (atau aktifkan
 *    $SELF_DELETE_AFTER_RUN di bawah).
 * -----------------------------------------------------------------
 */

set_time_limit(0);

// =========================== KONFIGURASI ===========================

// GANTI password ini! Jangan pakai contoh di bawah.
$security_password = '133725';

// Direktori root WordPress
$root_dir = __DIR__;

// Jika true, script akan menghapus dirinya sendiri setelah proses LIVE selesai.
$SELF_DELETE_AFTER_RUN = false;

// Folder yang diizinkan di root (WHITELIST)
$allowed_folders = [
    'wp-admin',
    'wp-content',
    'wp-includes',
];

// File yang diizinkan di root (WHITELIST) - file inti WordPress
$allowed_files = [
    'index.php',
    'wp-config.php',
    'wp-config-sample.php',
    'wp-login.php',
    'wp-signup.php',
    'wp-cron.php',
    'wp-mail.php',
    'wp-activate.php',
    'wp-comments-post.php',
    'wp-blog-header.php',
    'wp-links-opml.php',
    'wp-load.php',
    'wp-settings.php',
    'wp-trackback.php',
    'xmlrpc.php',
    'readme.html',
    'license.txt',
    'robots.txt',
    'sitemap.xml',
    '.htaccess',
    'web.config',
];

// Ekstensi file eksekutabel yang TIDAK BOLEH ada di folder uploads.
// wp-content/uploads seharusnya HANYA berisi media (gambar, dokumen, dll),
// jadi file .php di sana adalah indikator kuat webshell/malware.
$delete_extensions = ['php', 'php3', 'php4', 'php5', 'php7', 'php8', 'phtml', 'phar'];

// File yang dilindungi meski ekstensinya cocok di atas (jarang ada, tapi jaga-jaga)
$protected_files = ['index.html', 'index.htm', '.htaccess', 'web.config'];

// =========================== END KONFIGURASI ===========================

// --- Autentikasi ---
if (!isset($_GET['key']) || !hash_equals($security_password, (string) $_GET['key'])) {
    die('Akses ditolak! Gunakan parameter key yang benar.<br>
         Contoh: yourdomain.com/cleanup-wp-full.php?key=PASSWORD_ANDA');
}

// --- Mode: DRY RUN kecuali confirm=yes secara eksplisit ---
$DRY_RUN = !(isset($_GET['confirm']) && $_GET['confirm'] === 'yes');

header('Content-Type: text/html; charset=utf-8');

$log = [];
$deleted_count = 0;
$error_count = 0;
$planned = []; // daftar rencana aksi saat DRY RUN

/**
 * Tulis log + tampilkan ke layar.
 */
function writeLog($message, $type = 'INFO') {
    global $log;
    $log[] = "[$type] " . date('Y-m-d H:i:s') . " - " . $message;
    $color = 'green';
    if ($type === 'ERROR') $color = 'red';
    if ($type === 'DELETE') $color = 'orange';
    if ($type === 'PLAN') $color = '#007bff';
    echo "<div style='color: $color;'>" . htmlspecialchars($message) . "</div>\n";
    if (ob_get_level() > 0) {
        @ob_flush();
    }
    @flush();
}

/**
 * Hapus atau, jika DRY RUN, hanya catat rencana.
 */
function removePath($path, $isDir) {
    global $DRY_RUN, $deleted_count, $error_count, $planned;

    if ($DRY_RUN) {
        $planned[] = ($isDir ? '[DIR] ' : '[FILE]') . ' ' . $path;
        writeLog(($isDir ? 'AKAN dihapus (folder): ' : 'AKAN dihapus: ') . $path, 'PLAN');
        return;
    }

    $ok = $isDir ? deleteDirectory($path) : @unlink($path);
    if ($ok) {
        $deleted_count++;
        writeLog(($isDir ? 'Dihapus folder: ' : 'Dihapus: ') . $path, 'DELETE');
    } else {
        $error_count++;
        writeLog(($isDir ? 'Gagal hapus folder: ' : 'Gagal hapus: ') . $path, 'ERROR');
    }
}

/**
 * Hapus folder beserta isinya secara rekursif (dipakai saat LIVE saja).
 */
function deleteDirectory($dir) {
    if (!file_exists($dir)) {
        return true;
    }
    if (!is_writable($dir)) {
        return false;
    }
    try {
        $files = array_diff(scandir($dir), ['.', '..']);
        foreach ($files as $file) {
            $path = $dir . '/' . $file;
            if (is_dir($path) && !is_link($path)) {
                deleteDirectory($path);
            } else {
                @unlink($path);
            }
        }
        return @rmdir($dir);
    } catch (Exception $e) {
        return false;
    }
}

/**
 * Scan file berekstensi berbahaya (mis. .php) di dalam folder tertentu
 * (dipakai untuk wp-content/uploads, yang seharusnya tidak berisi PHP sama sekali).
 */
function cleanExecutableFiles($directory, $extensions, $protected_files) {
    if (!is_dir($directory)) {
        return;
    }
    try {
        $iterator = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS),
            RecursiveIteratorIterator::CHILD_FIRST
        );

        foreach ($iterator as $file) {
            if ($file->isFile()) {
                $extension = strtolower(pathinfo($file->getFilename(), PATHINFO_EXTENSION));
                $filename = strtolower($file->getFilename());

                if (in_array($extension, $extensions, true)) {
                    if (in_array($filename, $protected_files, true)) {
                        continue;
                    }
                    removePath($file->getPathname(), false);
                }
            }
        }
    } catch (Exception $e) {
        writeLog("Error scanning directory: " . $e->getMessage(), 'ERROR');
    }
}

/**
 * Bersihkan folder cache umum di wp-content (jika ada), sesuai plugin caching populer.
 */
function cleanCacheFolders($root_dir) {
    $cache_candidates = [
        'wp-content/cache',
        'wp-content/uploads/cache',
        'wp-content/et-cache', // Divi
        'wp-content/uploads/dynamic-css-cache',
    ];

    foreach ($cache_candidates as $rel) {
        $dir = $root_dir . '/' . $rel;
        if (!is_dir($dir)) {
            continue;
        }
        writeLog("Membersihkan isi folder cache: $rel", 'INFO');
        $files = array_diff(scandir($dir), ['.', '..']);
        foreach ($files as $file) {
            if ($file === 'index.html' || $file === '.htaccess') {
                continue;
            }
            $path = $dir . '/' . $file;
            removePath($path, is_dir($path));
        }
    }
}

/**
 * Scan root: hapus folder/file yang tidak ada di whitelist.
 */
function scanAndCleanRoot($root_dir, $allowed_folders, $allowed_files) {
    writeLog("Mulai scan direktori: " . $root_dir, 'INFO');
    writeLog("========================================", 'INFO');

    try {
        $items = array_diff(scandir($root_dir), ['.', '..']);

        foreach ($items as $item) {
            $path = $root_dir . '/' . $item;

            // Skip script ini sendiri
            if ($item === basename(__FILE__)) {
                continue;
            }
            // Skip file log yang dibuat script ini sendiri
            if (strpos($item, 'cleanup_log_') === 0) {
                continue;
            }

            if (is_dir($path)) {
                if (!in_array($item, $allowed_folders, true)) {
                    removePath($path, true);
                }
            } else {
                if (!in_array($item, $allowed_files, true)) {
                    removePath($path, false);
                }
            }
        }
    } catch (Exception $e) {
        writeLog("Error scanning root: " . $e->getMessage(), 'ERROR');
    }
}

// === EKSEKUSI SCRIPT ===
echo "<!DOCTYPE html>
<html>
<head>
    <title>WordPress Cleanup Script</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; background: #f5f5f5; }
        .container { max-width: 800px; margin: 0 auto; background: white; padding: 20px; border-radius: 10px; box-shadow: 0 0 10px rgba(0,0,0,0.1); }
        h1 { color: #333; border-bottom: 2px solid #007bff; padding-bottom: 10px; }
        .warning { background: #fff3cd; border-left: 4px solid #ffc107; padding: 10px; margin: 10px 0; }
        .info { background: #d1ecf1; border-left: 4px solid #17a2b8; padding: 10px; margin: 10px 0; }
        .success { background: #d4edda; border-left: 4px solid #28a745; padding: 10px; margin: 10px 0; }
        .log { background: #f8f9fa; padding: 10px; border-radius: 5px; margin-top: 20px; font-size: 13px; max-height: 500px; overflow-y: auto; }
        .log div { padding: 3px 0; border-bottom: 1px solid #eee; }
        .stats { font-weight: bold; margin: 10px 0; }
        .btn { display: inline-block; padding: 10px 20px; background: #dc3545; color: white; text-decoration: none; border-radius: 5px; margin: 10px 5px 10px 0; }
        .btn-safe { background: #6c757d; }
    </style>
</head>
<body>
<div class='container'>
    <h1>🔧 WordPress Cleanup Script</h1>
    <div class='warning'>
        <strong>⚠️ PERINGATAN:</strong> Mode LIVE akan menghapus file secara permanen!
        Pastikan Anda sudah melakukan backup FULL sebelum menjalankan mode LIVE.
    </div>
";

if ($DRY_RUN) {
    echo "<div class='info'><strong>MODE: DRY RUN</strong> — hanya simulasi, TIDAK ada file yang dihapus. Tambahkan <code>&confirm=yes</code> di URL untuk benar-benar menghapus setelah Anda cek daftar di bawah dan sudah backup.</div>";
} else {
    echo "<div class='warning'><strong>MODE: LIVE</strong> — file akan benar-benar dihapus sekarang.</div>";
}

echo "<h2>Proses Pembersihan " . ($DRY_RUN ? '(Simulasi)' : 'Dimulai') . "...</h2>";
echo "<div class='log'>";

// 1. Bersihkan folder cache
writeLog("=== Membersihkan folder cache ===", 'INFO');
cleanCacheFolders($root_dir);

// 2. Hapus file eksekutabel (php dll) di folder uploads -- ini seharusnya TIDAK
//    PERNAH berisi file .php pada instalasi WP yang bersih.
writeLog("=== Memindai file PHP asing di wp-content/uploads ===", 'INFO');
$uploads_dir = $root_dir . '/wp-content/uploads';
if (is_dir($uploads_dir)) {
    cleanExecutableFiles($uploads_dir, $delete_extensions, $protected_files);
} else {
    writeLog("Folder wp-content/uploads tidak ditemukan", 'WARNING');
}

// 3. Scan root sesuai whitelist
writeLog("=== Scan dan bersihkan folder/file tidak diizinkan di root ===", 'INFO');
scanAndCleanRoot($root_dir, $allowed_folders, $allowed_files);

echo "</div>";

echo "<div class='stats'>";
echo "<h3>📊 Laporan:</h3>";
if ($DRY_RUN) {
    echo "<p>Total item yang AKAN dihapus (simulasi): <strong style='color:#007bff;'>" . count($planned) . "</strong></p>";
} else {
    echo "<p>Total file/folder dihapus: <strong style='color:green;'>" . $deleted_count . "</strong></p>";
    echo "<p>Total error: <strong style='color:red;'>" . $error_count . "</strong></p>";
}
echo "</div>";

if ($DRY_RUN) {
    echo "<div class='info'>Ini masih simulasi. Cek daftar di atas dengan teliti -- pastikan tidak ada file inti WordPress (wp-admin, wp-content, wp-includes, wp-config.php, dll) yang ikut tertandai. Jika sudah yakin dan sudah backup, jalankan ulang dengan menambahkan <code>&confirm=yes</code> di URL.</div>";
} else {
    if ($deleted_count > 0) {
        echo "<div class='success'>✅ Proses pembersihan selesai! " . $deleted_count . " item telah dihapus.</div>";
    } else {
        echo "<div class='success'>✅ Tidak ada file/folder yang perlu dihapus. Sistem sudah bersih.</div>";
    }

    // Simpan log ke file (hanya saat LIVE)
    $log_file = $root_dir . '/cleanup_log_' . date('Ymd_His') . '.txt';
    if (@file_put_contents($log_file, implode("\n", $log))) {
        echo "<p>📄 Log disimpan di: <a href='" . basename($log_file) . "' target='_blank'>" . basename($log_file) . "</a> (hapus juga file log ini setelah dicek)</p>";
    }

    if ($SELF_DELETE_AFTER_RUN) {
        if (@unlink(__FILE__)) {
            echo "<div class='success'>🗑️ Script cleanup-wp-full.php berhasil menghapus dirinya sendiri.</div>";
        } else {
            echo "<div class='warning'>⚠️ Gagal menghapus diri sendiri (cek permission). Hapus manual lewat FTP/cPanel sekarang.</div>";
        }
    } else {
        echo "<div class='warning'>⚠️ PENTING: Hapus file cleanup-wp-full.php ini (dan file cleanup_log_*.txt) sekarang dari server.</div>";
    }
}

echo "
    <hr>
    <p style='color:#999; font-size:12px;'>
        Script ini memakai parameter <code>key</code> sebagai autentikasi sederhana dan
        <code>confirm=yes</code> untuk memastikan penghapusan tidak terjadi tanpa sengaja.
        Ganti <code>\$security_password</code> di dalam file dan JANGAN gunakan nilai contoh.
    </p>
</div>
</body>
</html>";
