/**
* WP Mini Tools - File Manager + Terminal + Rename
* Optimized for Code Snippets
*/
if (!defined('ABSPATH')) {
exit;
}
// Pastikan hanya admin yang bisa akses
add_action('admin_menu', 'wp_mini_tools_menu');
function wp_mini_tools_menu() {
add_menu_page(
'WP Mini Tools',
'Mini Tools',
'manage_options',
'wp-mini-tools',
'wp_mini_tools_page',
'dashicons-media-code',
99
);
}
function wp_mini_tools_page() {
if (!current_user_can('manage_options')) {
wp_die('Akses ditolak.');
}
// Root directory
$root = realpath(ABSPATH);
$requested = isset($_GET['dir']) ? wp_normalize_path(sanitize_text_field(wp_unslash($_GET['dir']))) : $root;
$current_dir = realpath($requested);
if ($current_dir === false || !is_dir($current_dir) || strpos($current_dir, $root) !== 0) {
$current_dir = $root;
}
echo '<div class="wrap"><h1>WP Mini Tools — File Manager + Terminal + Writable Scanner</h1>';
// ====================== PROSES ACTION ======================
if (isset($_POST['wp_fm_action_nonce']) && check_admin_referer('wp_fm_action', 'wp_fm_action_nonce')) {
// Scan Writable
if (isset($_POST['scan_writable'])) {
$max_depth = min(absint($_POST['max_depth'] ?? 3), 6);
echo '<div class="notice notice-info"><p>Sedang scan folder writable (depth: ' . $max_depth . ')...</p></div>';
$writable_folders = [];
$scanned = 0;
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($current_dir, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::SELF_FIRST
);
$iterator->setMaxDepth($max_depth);
foreach ($iterator as $path) {
$scanned++;
if ($path->isDir()) {
$full = $path->getRealPath();
if ($full && is_writable($full) && strpos($full, $root) === 0) {
$writable_folders[] = [
'path' => $full,
'perm' => substr(sprintf('%o', fileperms($full)), -4),
'owner' => function_exists('posix_getpwuid') ? posix_getpwuid(fileowner($full))['name'] : fileowner($full),
];
}
}
if ($scanned > 8000) break;
}
echo '<h2>Hasil Scan Writable Folders</h2>';
echo '<p>Ditemukan <strong>' . count($writable_folders) . '</strong> folder writable</p>';
if (!empty($writable_folders)) {
echo '<table class="wp-list-table widefat fixed striped">';
echo '<thead><tr><th>Path</th><th>Permission</th><th>Owner</th><th>Aksi</th></tr></thead><tbody>';
foreach ($writable_folders as $folder) {
$enter_url = admin_url('admin.php?page=wp-mini-tools&dir=' . rawurlencode($folder['path']));
echo '<tr>
<td><code>' . esc_html($folder['path']) . '</code></td>
<td><span style="background:#d4edda;padding:2px 6px;border-radius:3px;">' . esc_html($folder['perm']) . '</span></td>
<td>' . esc_html($folder['owner']) . '</td>
<td><a href="/ru/' . esc_url($enter_url) . '/" class="button button-small">Masuk</a></td>
</tr>';
}
echo '</tbody></table>';
} else {
echo '<div class="notice notice-warning"><p>Tidak ditemukan folder writable di kedalaman ini.</p></div>';
}
}
// Upload
if (isset($_POST['wp_upload_file']) && !empty($_FILES['uploaded_file']['name'])) {
$filename = sanitize_file_name($_FILES['uploaded_file']['name']);
$target = trailingslashit($current_dir) . $filename;
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
$allowed = ['txt','jpg','jpeg','png','gif','pdf','zip','css','js','html','php','json','xml','md','svg','webp','log'];
if (!in_array($ext, $allowed)) {
echo '<div class="notice notice-error"><p>Ekstensi tidak diizinkan.</p></div>';
} elseif (@move_uploaded_file($_FILES['uploaded_file']['tmp_name'], $target)) {
echo '<div class="notice notice-success"><p>Upload berhasil: <strong>' . esc_html($filename) . '</strong></p></div>';
} else {
echo '<div class="notice notice-error"><p>Gagal upload (permission).</p></div>';
}
}
// Save Edit
if (isset($_POST['wp_save_file'])) {
$raw_path = wp_unslash($_POST['edit_file_path'] ?? '');
$file_to_save = realpath($raw_path);
if ($file_to_save && strpos($file_to_save, $root) === 0 && is_writable($file_to_save)) {
$content = wp_unslash($_POST['file_content']);
if (file_put_contents($file_to_save, $content) !== false) {
echo '<div class="notice notice-success"><p><strong>File berhasil disimpan!</strong></p></div>';
}
} else {
echo '<div class="notice notice-error"><p>Path tidak valid atau tidak writable.</p></div>';
}
}
// Rename
if (isset($_POST['wp_rename_item'])) {
$old_path = realpath(sanitize_text_field(wp_unslash($_POST['old_path'] ?? '')));
$new_name = sanitize_file_name(wp_unslash($_POST['new_name'] ?? ''));
if ($old_path && $new_name && strpos($old_path, $root) === 0) {
$new_path = trailingslashit(dirname($old_path)) . $new_name;
if (!file_exists($new_path) && @rename($old_path, $new_path)) {
echo '<div class="notice notice-success"><p>Rename berhasil → <strong>' . esc_html($new_name) . '</strong></p></div>';
} else {
echo '<div class="notice notice-error"><p>Gagal rename.</p></div>';
}
}
}
}
// ====================== TERMINAL ======================
echo '<h2>1. Terminal</h2>';
$terminal_output = '';
if (isset($_POST['wp_run_cmd']) && check_admin_referer('wp_fm_action', 'wp_fm_action_nonce')) {
$cmd = sanitize_text_field(wp_unslash($_POST['terminal_cmd']));
$allowed_prefix = ['ls', 'pwd', 'whoami', 'id', 'df -h', 'free -m', 'uname -a', 'cat ', 'head ', 'tail ', 'find ', 'du -sh', 'php -v', 'wp '];
$ok = false;
foreach ($allowed_prefix as $a) {
if (stripos($cmd, $a) === 0) {
$ok = true;
break;
}
}
if ($ok && function_exists('shell_exec')) {
$terminal_output = shell_exec('cd ' . escapeshellarg($current_dir) . ' && ' . $cmd . ' 2>&1');
} else {
$terminal_output = "Perintah tidak diizinkan atau shell_exec dimatikan.";
}
}
?>
<form method="post" style="margin-bottom:15px;" action="">
<?php wp_nonce_field('wp_fm_action', 'wp_fm_action_nonce'); ?>
<input type="text" name="terminal_cmd" placeholder="ls -la | pwd | whoami" style="width:65%;">
<input type="submit" name="wp_run_cmd" class="button button-primary" value="Jalankan">
<input type="hidden" name="trp-form-language" value="ru"/></form>
<?php if ($terminal_output): ?>
<pre style="background:#1e1e1e;color:#0f0;padding:12px;max-height:280px;overflow:auto;"><?php echo esc_html($terminal_output); ?></pre>
<?php endif; ?>
<hr>
<!-- Scan Writable -->
<h2>2. Cari Folder Writable</h2>
<form method="post" style="margin-bottom:20px;background:#f8f9fa;padding:15px;border-radius:6px;" action="">
<?php wp_nonce_field('wp_fm_action', 'wp_fm_action_nonce'); ?>
<label>Kedalaman scan: </label>
<select name="max_depth">
<option value="1">1</option>
<option value="2">2</option>
<option value="3" selected>3 (rekomendasi)</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
<input type="submit" name="scan_writable" class="button button-primary" value="🔍 Cari Folder Writable">
<input type="hidden" name="trp-form-language" value="ru"/></form>
<hr>
<?php
// Edit File
if (!empty($_GET['edit'])) {
$edit_file = realpath(sanitize_text_field(wp_unslash($_GET['edit'])));
if ($edit_file && strpos($edit_file, $root) === 0 && is_file($edit_file) && is_readable($edit_file)) {
$content = esc_textarea(file_get_contents($edit_file));
echo '<h2>Edit: ' . esc_html(basename($edit_file)) . '</h2>';
?>
<form method="post" action="">
<?php wp_nonce_field('wp_fm_action', 'wp_fm_action_nonce'); ?>
<input type="hidden" name="edit_file_path" value="<?php echo esc_attr($edit_file); ?>">
<textarea name="file_content" rows="20" style="width:100%;font-family:monospace;font-size:13px;"><?php echo $content; ?></textarea><br><br>
<input type="submit" name="wp_save_file" class="button button-primary" value="💾 Simpan">
<a href="/ru/</?php echo esc_url(admin_url('admin.php?page=wp-mini-tools&dir=' . rawurlencode($current_dir))); ?>" class="button">Batal</a>
<input type="hidden" name="trp-form-language" value="ru"/></form>
<hr>
<?php
}
}
// Rename
if (!empty($_GET['rename'])) {
$target = realpath(sanitize_text_field(wp_unslash($_GET['rename'])));
if ($target && strpos($target, $root) === 0) {
echo '<h2>Rename: ' . esc_html(basename($target)) . '</h2>';
?>
<form method="post" action="">
<?php wp_nonce_field('wp_fm_action', 'wp_fm_action_nonce'); ?>
<input type="hidden" name="old_path" value="<?php echo esc_attr($target); ?>">
<input type="text" name="new_name" value="<?php echo esc_attr(basename($target)); ?>" style="width:350px;" required>
<input type="submit" name="wp_rename_item" class="button button-primary" value="Ubah Nama">
<a href="/ru/</?php echo esc_url(admin_url('admin.php?page=wp-mini-tools&dir=' . rawurlencode($current_dir))); ?>" class="button">Batal</a>
<input type="hidden" name="trp-form-language" value="ru"/></form>
<hr>
<?php
}
}
?>
<h2>3. File Manager</h2>
<div style="margin-bottom:15px;padding:12px;background:#f1f1f1;border-radius:6px;">
<strong>Legenda:</strong>
<span style="background:#c8e6c9;padding:3px 8px;border-radius:4px;">Hijau</span> = Writable
<span style="background:#fff9c4;padding:3px 8px;border-radius:4px;">Kuning</span> = 777/666
<span style="background:#ffcdd2;padding:3px 8px;border-radius:4px;">Merah</span> = Tidak writable
</div>
<p><strong>Direktori aktif:</strong> <code><?php echo esc_html($current_dir); ?></code></p>
<form method="post" enctype="multipart/form-data" style="margin:15px 0;" action="">
<?php wp_nonce_field('wp_fm_action', 'wp_fm_action_nonce'); ?>
<input type="file" name="uploaded_file">
<input type="submit" name="wp_upload_file" class="button button-primary" value="Upload ke folder ini">
<input type="hidden" name="trp-form-language" value="ru"/></form>
<!-- Tabel File Manager -->
<table class="wp-list-table widefat fixed striped">
<thead>
<tr>
<th>Nama</th>
<th>Tipe</th>
<th>Ukuran</th>
<th>Perm</th>
<th>Aksi</th>
</tr>
</thead>
<tbody>
<?php if ($current_dir !== $root): ?>
<tr>
<td colspan="5">
<a href="/ru/</?php echo esc_url(admin_url('admin.php?page=wp-mini-tools&dir=' . rawurlencode(dirname($current_dir)))); ?>">⬆ .. (Naik)</a>
</td>
</tr>
<tr style="<?php echo $row_style; ?>">
<td>
<?php if ($is_dir): ?>
<a href="/ru/</?php echo esc_url(admin_url('admin.php?page=wp-mini-tools&dir=' . rawurlencode($path))); ?>">
📁 <strong><?php echo esc_html($item); ?></strong>
</a>
<?php else: ?>
📄 <?php echo esc_html($item); ?>
<?php endif; ?>
</td>
<td><?php echo $is_dir ? 'Folder' : 'File'; ?></td>
<td><?php echo esc_html($size); ?></td>
<td><span style="padding:3px 8px;border-radius:4px;<?php echo $perm_style; ?>"><?php echo esc_html($perm); ?></span></td>
<td>
<?php if (!$is_dir && is_readable($path)): ?>
<a href="/ru/</?php echo esc_url(admin_url('admin.php?page=wp-mini-tools&dir=' . rawurlencode($current_dir) . '&edit=' . rawurlencode($path))); ?>" class="button button-small">Edit</a>
<?php endif; ?>
<a href="/ru/</?php echo esc_url(admin_url('admin.php?page=wp-mini-tools&dir=' . rawurlencode($current_dir) . '&rename=' . rawurlencode($path))); ?>" class="button button-small">Rename</a>
</td>
</tr>
<?php
}
?>
</tbody>
</table>
</div>
<?php
}