addEmptyDir($zip_base); $entries = scandir($src_path); if ($entries === false) { return; } foreach ($entries as $entry_name) { if ($entry_name === '.' || $entry_name === '..') { continue; } $entry_path = $src_path . DIRECTORY_SEPARATOR . $entry_name; // Sembolik linkleri atla — traversal güvenliği. if (is_link($entry_path)) { continue; } // ZIP içindeki yol her zaman / ayracı kullanır. $zip_entry = $zip_base . $entry_name; if (is_dir($entry_path)) { // Alt klasörü "/" ile sonlandırarak özyinelemeli ekle. // Boş olsa bile zip_add_dir içinde addEmptyDir çağrılır. zip_add_dir($zip, $entry_path, $zip_entry . '/'); } else { $zip->addFile($entry_path, $zip_entry); } } } // ============================================================================= // --- Authentication --- // ============================================================================= // Set secure cookie parameters BEFORE session_start(). // session_set_cookie_params() array form and 'samesite' key are PHP 7.3+ only. // Use ini_set() for full PHP 7.0–8.4 compatibility. ini_set('session.cookie_httponly', '1'); ini_set('session.cookie_lifetime', '0'); ini_set('session.cookie_path', '/'); if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') { ini_set('session.cookie_secure', '1'); } // SameSite via ini_set is supported from PHP 7.3+; silently ignored on older. ini_set('session.cookie_samesite', 'Strict'); session_start(); // Security headers — sent early, before any output. header('X-Frame-Options: SAMEORIGIN'); header('X-Content-Type-Options: nosniff'); header('Referrer-Policy: no-referrer'); // Per-session CSRF token — embedded in every form, validated on every POST. if (empty($_SESSION['csrf_token'])) { $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); } if (isset($_GET['logout'])) { session_destroy(); header('Location: ' . basename(__FILE__)); exit; } // --- Simple session-based brute-force rate limiting --- if (!isset($_SESSION['login_attempts'])) { $_SESSION['login_attempts'] = 0; $_SESSION['login_last'] = 0; } if (isset($_POST['password'])) { $locked = $_SESSION['login_attempts'] >= 5 && (time() - (int) $_SESSION['login_last']) < 300; if ($locked) { $wait = 300 - (time() - (int) $_SESSION['login_last']); http_response_code(429); die('

Too many failed attempts. Please wait ' . $wait . ' seconds.

'); } if (password_verify($_POST['password'], PASSWORD_HASH)) { // Regenerate session ID on successful login to prevent session fixation. session_regenerate_id(true); $_SESSION['auth'] = true; $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); $_SESSION['login_attempts'] = 0; header('Location: ' . basename(__FILE__)); exit; } $_SESSION['login_attempts']++; $_SESSION['login_last'] = time(); } if (!isset($_SESSION['auth'])) { http_response_code(401); die('Login

Login

'); } // ============================================================================= // --- Current Directory Resolution --- // ============================================================================= // Navigation is unrestricted across the filesystem. // Individual file operations are each guarded by safe_item_path(), // which ensures every action stays within $current_dir. $current_dir = isset($_GET['path']) ? realpath($_GET['path']) : false; if ($current_dir === false || !is_dir($current_dir)) { $current_dir = realpath(__DIR__); } // ============================================================================= // --- CSRF Verification --- // ============================================================================= function verify_csrf(): void { if (!hash_equals($_SESSION['csrf_token'] ?? '', $_POST['csrf_token'] ?? '')) { http_response_code(403); exit('Forbidden: invalid or missing CSRF token.'); } } // ============================================================================= // --- Flash Message --- // ============================================================================= // Messages are stored raw in the session; escaping happens at render time. $message = $_SESSION['message'] ?? ''; unset($_SESSION['message']); // ============================================================================= // --- POST Action Handlers --- // ============================================================================= if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) { verify_csrf(); $action = (string) ($_POST['action'] ?? ''); // ------------------------------------------------------------------------- // Bulk: Create ZIP from selected items // ------------------------------------------------------------------------- if ($action === 'zip_selected') { if (empty($_POST['selected_items'])) { $_SESSION['message'] = 'No items selected.'; } elseif (!class_exists('ZipArchive')) { $_SESSION['message'] = 'Error: ZipArchive extension is not available on this server.'; } else { // Remove execution time limit for large backups. set_time_limit(0); $zip_filename = 'archive-' . date('Y-m-d-His') . '.zip'; $zip_filepath = $current_dir . DIRECTORY_SEPARATOR . $zip_filename; $zip = new ZipArchive(); if ($zip->open($zip_filepath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) { $_SESSION['message'] = 'Error: Could not create the archive file. Check directory permissions.'; } else { $items_added = 0; foreach ($_POST['selected_items'] as $raw_item) { $item = basename((string) $raw_item); $item_path = safe_item_path($current_dir, $item); if ($item_path === false) continue; if (is_file($item_path)) { // Single file — add directly with forward-slash name. $zip->addFile($item_path, $item); $items_added++; } elseif (is_dir($item_path)) { // Directory — recurse, including empty sub-dirs. // Boş klasörler de geçerli öğedir: addEmptyDir içinde çağrılır. // Symlinks inside are skipped for security (see zip_add_dir). zip_add_dir($zip, $item_path, $item . '/'); $items_added++; } } if ($items_added === 0) { // Seçilen tüm öğeler geçersiz veya erişilemez — temizlik yap. $zip->close(); if (file_exists($zip_filepath)) { @unlink($zip_filepath); } $_SESSION['message'] = 'Error: No valid items could be added to the archive. Check permissions.'; } elseif ($zip->close() === false) { // close() başarısız — arşiv bozuk olabilir — temizlik yap. if (file_exists($zip_filepath)) { @unlink($zip_filepath); } $_SESSION['message'] = 'Error: Failed to finalize the archive. The file has been removed.'; } else { $_SESSION['message'] = 'Archive "' . $zip_filename . '" created successfully.'; } } } // ------------------------------------------------------------------------- // Bulk: Delete selected items // ------------------------------------------------------------------------- } elseif ($action === 'delete_selected') { if (empty($_POST['selected_items'])) { $_SESSION['message'] = 'No items selected for deletion.'; } else { $total = count($_POST['selected_items']); $deleted_count = 0; foreach ($_POST['selected_items'] as $raw_item) { $item_path = safe_item_path($current_dir, (string) $raw_item); if ($item_path === false) continue; if (is_dir($item_path)) { if (recursive_delete($item_path)) $deleted_count++; } elseif (is_file($item_path)) { if (unlink($item_path)) $deleted_count++; } } if ($deleted_count === 0) { $_SESSION['message'] = 'Error: No items could be deleted. Check permissions.'; } elseif ($deleted_count < $total) { // Partial failure — shown as error (red) $_SESSION['message'] = 'Error: Only ' . $deleted_count . ' of ' . $total . ' item(s) deleted. Some could not be removed.'; } else { $_SESSION['message'] = $deleted_count . ' item(s) deleted successfully.'; } } // ------------------------------------------------------------------------- // Upload // ------------------------------------------------------------------------- } elseif ($action === 'upload' && isset($_FILES['file'])) { if ($_FILES['file']['error'] !== UPLOAD_ERR_OK) { $upload_errors = [ UPLOAD_ERR_INI_SIZE => 'File exceeds the server size limit (php.ini)', UPLOAD_ERR_FORM_SIZE => 'File exceeds the form size limit', UPLOAD_ERR_PARTIAL => 'File was only partially uploaded', UPLOAD_ERR_NO_FILE => 'No file was sent', UPLOAD_ERR_NO_TMP_DIR => 'Temporary upload folder is missing', UPLOAD_ERR_CANT_WRITE => 'Failed to write file to disk', UPLOAD_ERR_EXTENSION => 'A PHP extension stopped the upload', ]; $code = $_FILES['file']['error']; $_SESSION['message'] = 'Upload error: ' . ($upload_errors[$code] ?? 'Unknown error (code ' . $code . ')'); } else { // Upload hedefi: dosya yöneticisindeki aktif dizin ($current_dir). // İzin kontrolü aynı dizine karşı yapılır. // Dosya türü / uzantı kısıtlaması yoktur — genel amaçlı dosya yöneticisi. $dest = $current_dir . DIRECTORY_SEPARATOR . basename($_FILES['file']['name']); if (file_exists($dest) && !is_writable($dest)) { $_SESSION['message'] = 'Error: Destination file exists and is not writable.'; } elseif (!is_writable($current_dir)) { $_SESSION['message'] = 'Error: No write permission for this directory.'; } elseif (move_uploaded_file($_FILES['file']['tmp_name'], $dest)) { $_SESSION['message'] = 'File uploaded successfully.'; } elseif (copy($_FILES['file']['tmp_name'], $dest)) { unlink($_FILES['file']['tmp_name']); $_SESSION['message'] = 'File uploaded successfully (via copy).'; } else { $err = error_get_last(); $_SESSION['message'] = 'Upload failed. System error: ' . ($err['message'] ?? 'Unknown'); } } // ------------------------------------------------------------------------- // Delete (single item) // ------------------------------------------------------------------------- } elseif ($action === 'delete') { $target = safe_item_path($current_dir, (string) ($_POST['target'] ?? '')); if ($target === false) { $_SESSION['message'] = 'Error: Item not found or access denied.'; } else { $name = basename($target); $deleted = is_dir($target) ? recursive_delete($target) : unlink($target); $_SESSION['message'] = $deleted ? '"' . $name . '" deleted successfully.' : 'Error: Could not delete "' . $name . '".'; } // ------------------------------------------------------------------------- // Rename // ------------------------------------------------------------------------- } elseif ($action === 'rename') { $target = safe_item_path($current_dir, (string) ($_POST['target'] ?? '')); $new_name = basename(trim((string) ($_POST['new_name'] ?? ''))); if ($target === false) { $_SESSION['message'] = 'Error: Item not found or access denied.'; } elseif ($new_name === '' || $new_name === '.' || $new_name === '..') { $_SESSION['message'] = 'Error: Invalid new name.'; } else { $old_name = basename($target); $new_path = $current_dir . DIRECTORY_SEPARATOR . $new_name; if (file_exists($new_path)) { // Hedef isim zaten var — sessiz üzerine yazma yerine açık hata ver. $_SESSION['message'] = 'Error: "' . h($new_name) . '" already exists. Rename aborted.'; } elseif (rename($target, $new_path)) { $_SESSION['message'] = 'Renamed "' . $old_name . '" to "' . $new_name . '".'; } else { $_SESSION['message'] = 'Error: Rename failed.'; } } // ------------------------------------------------------------------------- // Chmod // ------------------------------------------------------------------------- } elseif ($action === 'chmod') { $target = safe_item_path($current_dir, (string) ($_POST['target'] ?? '')); $new_perms = trim((string) ($_POST['new_perms'] ?? '')); if ($target === false) { $_SESSION['message'] = 'Error: Item not found or access denied.'; } elseif (!preg_match('/^[0-7]{3,4}$/', $new_perms)) { $_SESSION['message'] = 'Error: Invalid permission code "' . h($new_perms) . '".'; } elseif (chmod($target, octdec($new_perms))) { $_SESSION['message'] = 'Permissions for "' . basename($target) . '" set to ' . $new_perms . '.'; } else { $_SESSION['message'] = 'Error: Could not change permissions (check OS support).'; } // ------------------------------------------------------------------------- // Save (file editor) // ------------------------------------------------------------------------- } elseif ($action === 'save') { $filename = basename((string) ($_POST['target'] ?? '')); $target = safe_item_path($current_dir, $filename); $content = (string) ($_POST['content'] ?? ''); if ($target === false || !is_file($target)) { $_SESSION['message'] = 'Error: File not found or access denied.'; header('Location: ' . basename(__FILE__) . '?path=' . urlencode($current_dir)); } elseif (!is_writable($target)) { $_SESSION['message'] = 'Error: File is not writable. Check permissions.'; header('Location: ' . basename(__FILE__) . '?path=' . urlencode($current_dir) . '&edit=' . urlencode($filename)); } elseif (file_put_contents($target, $content, LOCK_EX) !== false) { $_SESSION['message'] = '"' . $filename . '" saved successfully.'; header('Location: ' . basename(__FILE__) . '?path=' . urlencode($current_dir) . '&edit=' . urlencode($filename)); } else { $_SESSION['message'] = 'Error: Could not save "' . $filename . '".'; header('Location: ' . basename(__FILE__) . '?path=' . urlencode($current_dir) . '&edit=' . urlencode($filename)); } exit; } header('Location: ' . basename(__FILE__) . '?path=' . urlencode($current_dir)); exit; } // ============================================================================= // --- Download Handler --- // ============================================================================= if (isset($_GET['download'])) { $file = safe_item_path($current_dir, (string) $_GET['download']); if ($file !== false && is_file($file) && is_readable($file)) { $file_size = filesize($file); // Clean any open output buffers to avoid buffering large files in RAM. if (ob_get_level()) { ob_end_clean(); } header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); // Escape any double-quotes in the filename for the Content-Disposition header. header('Content-Disposition: attachment; filename="' . str_replace('"', '\\"', basename($file)) . '"'); if ($file_size !== false) { header('Content-Length: ' . $file_size); } readfile($file); exit; } } // ============================================================================= // --- File Editor --- // ============================================================================= if (isset($_GET['edit'])) { $edit_file = safe_item_path($current_dir, (string) $_GET['edit']); if ($edit_file !== false && is_file($edit_file)) { $edit_name = basename($edit_file); $edit_readable = is_readable($edit_file); $edit_writable = is_writable($edit_file); $edit_size = filesize($edit_file); $edit_content = $edit_readable ? file_get_contents($edit_file) : ''; $edit_csrf = h($_SESSION['csrf_token']); $edit_is_err = str_starts_with($message, 'Error:'); ?> Edit: <?php echo h($edit_name); ?> — <?php echo h(PAGE_TITLE); ?>
← Back
⚠ This file is not readable.
⚠ This file is read-only. You can view but not save changes.
File: Size: Modified: Permissions: ✓ Editable Ctrl+S to save
<?php echo h(PAGE_TITLE); ?>

Logout
Name Size Permissions Modified Actions
.. Parent Directory
-

Upload File

No file selected