🐘
explorer.php
← Back
šŸ“ Php ⚔ Executable Ctrl+S: Save • Ctrl+R: Run • Ctrl+F: Find
<?php // PHP File Explorer with Add/Delete/Move Functionality // Security: Define the root directory to prevent directory traversal attacks $rootDir = __DIR__; // Changed from __DIR__ . '/apps' to __DIR__ (current directory) $currentDir = isset($_GET['dir']) ? $_GET['dir'] : ''; // Configure your domain - CHANGE THIS to your actual domain $baseDomain= 'http://108.61.85.3'; // Change this to your domain $webPath = ''; // Changed from '/apps' to '' (root web path) // Sanitize the directory path $currentDir = str_replace(['../', '..\\'], '', $currentDir); $fullPath = realpath($rootDir . '/' . $currentDir); // Security check: Ensure we're still within the root directory if (!$fullPath || strpos($fullPath, realpath($rootDir)) !== 0) { $fullPath = realpath($rootDir); $currentDir = ''; } $message = ''; $messageType = ''; // Handle form submissions (create, upload, delete, move) if ($_SERVER['REQUEST_METHOD'] === 'POST') { if (isset($_POST['action'])) { switch ($_POST['action']) { case 'create_file': $fileName = trim($_POST['file_name']); if ($fileName && !preg_match('/[<>:"|?*]/', $fileName)) { $newFilePath = $fullPath . '/' . $fileName; if (!file_exists($newFilePath)) { if (file_put_contents($newFilePath, '') !== false) { setPermissions($newFilePath); $message = "File '$fileName' created successfully with 777 permissions!"; $messageType = 'success'; } else { $message = "Failed to create file '$fileName'."; $messageType = 'error'; } } else { $message = "File '$fileName' already exists."; $messageType = 'error'; } } else { $message = "Invalid file name."; $messageType = 'error'; } break; case 'create_folder': $folderName = trim($_POST['folder_name']); if ($folderName && !preg_match('/[<>:"|?*]/', $folderName)) { $newFolderPath = $fullPath . '/' . $folderName; if (!file_exists($newFolderPath)) { umask(0000); // Ensure proper permissions for new directories if (mkdir($newFolderPath, 0777)) { setPermissions($newFolderPath); $message = "Folder '$folderName' created successfully with 777 permissions!"; $messageType = 'success'; } else { $message = "Failed to create folder '$folderName'."; $messageType = 'error'; } } else { $message = "Folder '$folderName' already exists."; $messageType = 'error'; } } else { $message = "Invalid folder name."; $messageType = 'error'; } break; case 'upload_file': if (isset($_FILES['file']) && $_FILES['file']['error'] === UPLOAD_ERR_OK) { $fileName = basename($_FILES['file']['name']); $targetPath = $fullPath . '/' . $fileName; if (move_uploaded_file($_FILES['file']['tmp_name'], $targetPath)) { setPermissions($targetPath); $message = "File '$fileName' uploaded successfully with 777 permissions!"; $messageType = 'success'; } else { $message = "Failed to upload file '$fileName'."; $messageType = 'error'; } } else { $message = "No file selected or upload error."; $messageType = 'error'; } break; case 'delete_items': if (isset($_POST['selected_items']) && is_array($_POST['selected_items'])) { $deletedCount = 0; foreach ($_POST['selected_items'] as $item) { $itemPath = $fullPath . '/' . basename($item); if (file_exists($itemPath)) { if (is_dir($itemPath)) { if (rmdir_recursive($itemPath)) { $deletedCount++; } } else { if (unlink($itemPath)) { $deletedCount++; } } } } if ($deletedCount > 0) { $message = "$deletedCount item(s) deleted successfully!"; $messageType = 'success'; } else { $message = "No items were deleted."; $messageType = 'error'; } } else { $message = "No items selected for deletion."; $messageType = 'error'; } break; case 'move_items': if (isset($_POST['selected_items']) && is_array($_POST['selected_items']) && isset($_POST['destination_folder'])) { $destinationDir = trim($_POST['destination_folder']); // Handle moving to parent directory if ($destinationDir === '..') { if ($currentDir) { $pathParts = explode('/', $currentDir); array_pop($pathParts); $destinationDir = implode('/', $pathParts); } else { $destinationDir = ''; } } // Sanitize destination path $destinationDir = str_replace(['../', '..\\'], '', $destinationDir); $destinationFullPath = realpath($rootDir . '/' . $destinationDir); // Security check for destination if ($destinationFullPath && strpos($destinationFullPath, realpath($rootDir)) === 0 && is_dir($destinationFullPath)) { $movedCount = 0; $errors = []; foreach ($_POST['selected_items'] as $item) { $itemName = basename($item); $sourcePath = $fullPath . '/' . $itemName; $destinationPath = $destinationFullPath . '/' . $itemName; if (file_exists($sourcePath)) { // Check if destination already exists if (file_exists($destinationPath)) { $errors[] = "Item '$itemName' already exists in destination folder."; continue; } // Attempt to move the item if (rename($sourcePath, $destinationPath)) { setPermissions($destinationPath); $movedCount++; } else { $errors[] = "Failed to move '$itemName'."; } } else { $errors[] = "Item '$itemName' not found."; } } if ($movedCount > 0) { $message = "$movedCount item(s) moved successfully!"; if (!empty($errors)) { $message .= " Errors: " . implode(', ', $errors); } $messageType = 'success'; } else { $message = "No items were moved. " . implode(', ', $errors); $messageType = 'error'; } } else { $message = "Invalid destination folder."; $messageType = 'error'; } } else { $message = "No items selected for moving or no destination specified."; $messageType = 'error'; } break; case 'change_permissions': if (isset($_POST['selected_items']) && is_array($_POST['selected_items']) && isset($_POST['new_permissions'])) { $newPermissions = trim($_POST['new_permissions']); // Validate octal permission format if (preg_match('/^[0-7]{3,4}$/', $newPermissions)) { $octalPermissions = octdec($newPermissions); $changedCount = 0; $errors = []; foreach ($_POST['selected_items'] as $item) { $itemName = basename($item); $itemPath = $fullPath . '/' . $itemName; if (file_exists($itemPath)) { if (chmod($itemPath, $octalPermissions)) { $changedCount++; } else { $errors[] = "Failed to change permissions for '$itemName'."; } } else { $errors[] = "Item '$itemName' not found."; } } if ($changedCount > 0) { $message = "$changedCount item(s) permissions changed to $newPermissions successfully!"; if (!empty($errors)) { $message .= " Errors: " . implode(', ', $errors); } $messageType = 'success'; } else { $message = "No permissions were changed. " . implode(', ', $errors); $messageType = 'error'; } } else { $message = "Invalid permission format. Use 3 or 4 digit octal format (e.g., 755, 644)."; $messageType = 'error'; } } else { $message = "No items selected or no permissions specified."; $messageType = 'error'; } break; } } } // Recursive directory removal function function rmdir_recursive($dir) { if (!is_dir($dir)) return false; $files = array_diff(scandir($dir), ['.', '..']); foreach ($files as $file) { $filePath = $dir . '/' . $file; if (is_dir($filePath)) { rmdir_recursive($filePath); } else { unlink($filePath); } } return rmdir($dir); } // Helper function to ensure proper permissions function setPermissions($path) { if (file_exists($path)) { chmod($path, 0777); // Also try to set umask to ensure new files get proper permissions umask(0000); return true; } return false; } // Helper function to get file permissions in octal format function getFilePermissions($path) { if (file_exists($path)) { return substr(sprintf('%o', fileperms($path)), -4); } return '0000'; } // Get directory contents $items = []; if (is_dir($fullPath)) { $files = scandir($fullPath); foreach ($files as $file) { if ($file !== '.' && $file !== '..') { $filePath = $fullPath . '/' . $file; $relativePath = $currentDir ? $currentDir . '/' . $file : $file; $items[] = [ 'name' => $file, 'path' => $relativePath, 'is_dir' => is_dir($filePath), 'size' => is_file($filePath) ? filesize($filePath) : 0, 'modified' => filemtime($filePath), 'permissions' => getFilePermissions($filePath) ]; } } } // Sort items: directories first, then files, alphabetically usort($items, function($a, $b) { if ($a['is_dir'] !== $b['is_dir']) { return $b['is_dir'] - $a['is_dir']; } return strcasecmp($a['name'], $b['name']); }); // Get available folders for move operation function getAvailableFolders($rootDir, $currentDir, $excludeItems = []) { $folders = []; // Add parent directory option if not in root if ($currentDir) { $folders[] = ['name' => '.. (Parent Directory)', 'path' => '..', 'display' => 'šŸ“ .. (Parent Directory)']; } // Add root directory if not already there if ($currentDir) { $folders[] = ['name' => 'root', 'path' => '', 'display' => 'šŸ“ root']; } // Get all subdirectories recursively $getAllFolders = function($dir, $prefix = '') use (&$getAllFolders, $rootDir, $excludeItems) { $result = []; $fullDir = $rootDir . '/' . $dir; if (is_dir($fullDir)) { $files = scandir($fullDir); foreach ($files as $file) { if ($file !== '.' && $file !== '..' && is_dir($fullDir . '/' . $file)) { $relativePath = $dir ? $dir . '/' . $file : $file; // Skip if this folder is in the exclude list if (!in_array($file, $excludeItems)) { $displayName = $prefix . 'šŸ“ ' . $file; $result[] = ['name' => $file, 'path' => $relativePath, 'display' => $displayName]; // Recursively get subfolders $subFolders = $getAllFolders($relativePath, $prefix . ' '); $result = array_merge($result, $subFolders); } } } } return $result; }; // Get all folders except current directory $allFolders = $getAllFolders(''); // Filter out current directory foreach ($allFolders as $folder) { if ($folder['path'] !== $currentDir) { $folders[] = $folder; } } return $folders; } // Helper function to format file sizes function formatBytes($size, $precision = 2) { $units = ['B', 'KB', 'MB', 'GB', 'TB']; for ($i = 0; $size > 1024 && $i < count($units) - 1; $i++) { $size /= 1024; } return round($size, $precision) . ' ' . $units[$i]; } // Helper function to get breadcrumb navigation function getBreadcrumbs($currentDir) { $breadcrumbs = [['name' => 'root', 'path' => '']]; // Changed from 'apps' to 'root' if ($currentDir) { $parts = explode('/', $currentDir); $path = ''; foreach ($parts as $part) { $path .= ($path ? '/' : '') . $part; $breadcrumbs[] = ['name' => $part, 'path' => $path]; } } return $breadcrumbs; } // Helper function to check if file is viewable function isViewableFile($filename) { $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); $editableExts = ['txt', 'php', 'html', 'css', 'js', 'json', 'xml', 'md', 'py', 'java', 'cpp', 'c', 'h', 'sql', 'yml', 'yaml']; $imageExts = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg']; return in_array($ext, $editableExts) || in_array($ext, $imageExts); } // Helper function to check if file can be opened in browser function isWebAccessible($filename) { $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); $webExts = ['html', 'htm', 'php', 'css', 'js', 'json', 'xml', 'txt', 'svg', 'jpg', 'jpeg', 'png', 'gif', 'pdf']; return in_array($ext, $webExts); } // Helper function to generate web URL for file function getWebUrl($currentDir, $filename, $baseDomain, $webPath) { $path = $currentDir ? $currentDir . '/' . $filename : $filename; return $baseDomain . $webPath . '/' . $path; } $availableFolders = getAvailableFolders($rootDir, $currentDir); ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>PHP File Explorer</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background-color: #f5f5f5; color: #333; line-height: 1.6; } .container { max-width: 1400px; margin: 0 auto; padding: 20px; } .navigation { background: white; padding: 15px 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); margin-bottom: 20px; } .breadcrumb { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; } .breadcrumb a { color: #3498db; text-decoration: none; padding: 4px 8px; border-radius: 4px; transition: background-color 0.2s; } .breadcrumb a:hover { background-color: #ecf0f1; } .breadcrumb span { color: #7f8c8d; } .message { padding: 12px 20px; border-radius: 6px; margin-bottom: 20px; } .message.success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; } .message.error { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; } .main-content { display: block; } .file-browser { background: white; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); margin-bottom: 20px; } .toolbar { padding: 20px; border-top: 1px solid #ecf0f1; display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; } .toolbar-section { display: flex; flex-direction: column; gap: 8px; } .toolbar-section h3 { color: #2c3e50; font-size: 14px; margin-bottom: 5px; } .form-group { display: flex; gap: 8px; align-items: center; } .form-group input[type="text"], .form-group input[type="file"], .form-group select { flex: 1; padding: 6px 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 13px; } .btn { padding: 6px 12px; border: none; border-radius: 4px; font-size: 13px; cursor: pointer; transition: background-color 0.2s; text-decoration: none; display: inline-block; text-align: center; } .btn-primary { background-color: #3498db; color: white; } .btn-primary:hover { background-color: #2980b9; } .btn-success { background-color: #27ae60; color: white; } .btn-success:hover { background-color: #229954; } .btn-danger { background-color: #e74c3c; color: white; } .btn-danger:hover { background-color: #c0392b; } .btn:disabled { background-color: #bdc3c7; cursor: not-allowed; } .file-list { max-height: 500px; overflow-y: auto; } .file-item { display: flex; align-items: center; padding: 8px 20px; border-bottom: 1px solid #ecf0f1; transition: background-color 0.2s; } .file-item:hover { background-color: #f8f9fa; } .file-item:last-child { border-bottom: none; } .file-checkbox { margin-right: 8px; } .file-icon { width: 20px; height: 20px; margin-right: 8px; display: flex; align-items: center; justify-content: center; font-size: 16px; } .file-name { flex: 1; min-width: 0; } .file-name a { color: #2c3e50; text-decoration: none; font-weight: 500; } .file-name a:hover { color: #3498db; } .file-actions { margin-left: 8px; } .file-actions a { color: #7f8c8d; text-decoration: none; font-size: 12px; padding: 2px 6px; border-radius: 3px; margin-left: 4px; } .file-actions a:hover { background-color: #ecf0f1; } .file-info { display: flex; gap: 15px; color: #7f8c8d; font-size: 12px; margin-left: auto; } .file-permissions { min-width: 40px; text-align: center; font-family: 'Courier New', monospace; background-color: #ecf0f1; padding: 2px 6px; border-radius: 3px; } .file-size { min-width: 60px; text-align: right; } .empty-folder { padding: 40px 20px; text-align: center; color: #7f8c8d; font-style: italic; } .select-all { padding: 10px 20px; background: #f8f9fa; border-bottom: 1px solid #ecf0f1; } .footer { background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); text-align: center; } .footer h1 { color: #2c3e50; margin: 0; } .move-section { display: flex; flex-direction: column; gap: 8px; } .move-form { display: flex; flex-direction: column; gap: 8px; } @media (max-width: 1024px) { .toolbar { grid-template-columns: 1fr; } } </style> </head> <body> <div class="container"> <!-- Navigation at the top --> <div class="navigation"> <nav class="breadcrumb"> <?php $breadcrumbs = getBreadcrumbs($currentDir); foreach ($breadcrumbs as $index => $crumb): ?> <?php if ($index > 0): ?> <span>/</span> <?php endif; ?> <?php if ($index === count($breadcrumbs) - 1): ?> <span><?= htmlspecialchars($crumb['name']) ?></span> <?php else: ?> <a href="?dir=<?= urlencode($crumb['path']) ?>"> <?= htmlspecialchars($crumb['name']) ?> </a> <?php endif; ?> <?php endforeach; ?> </nav> </div> <?php if ($message): ?> <div class="message <?= $messageType ?>"> <?= htmlspecialchars($message) ?> </div> <?php endif; ?> <!-- File Explorer --> <div class="main-content"> <div class="file-browser"> <div class="file-list"> <?php if (empty($items)): ?> <div class="empty-folder"> This folder is empty </div> <?php else: ?> <div class="select-all"> <label> <input type="checkbox" id="selectAll"> Select All </label> </div> <?php foreach ($items as $item): ?> <div class="file-item"> <input type="checkbox" class="file-checkbox" name="selected_items[]" value="<?= htmlspecialchars($item['name']) ?>" form="deleteForm"> <div class="file-icon"> <?= $item['is_dir'] ? 'šŸ“' : 'šŸ“„' ?> </div> <div class="file-name"> <?php if ($item['is_dir']): ?> <a href="?dir=<?= urlencode($item['path']) ?>"> <?= htmlspecialchars($item['name']) ?> </a> <?php else: ?> <span><?= htmlspecialchars($item['name']) ?></span> <?php endif; ?> </div> <?php if (!$item['is_dir']): ?> <div class="file-actions"> <?php if (isViewableFile($item['name'])): ?> <a href="editor.php?dir=<?= urlencode($currentDir) ?>&view=<?= urlencode($item['name']) ?>">Edit</a> <?php endif; ?> <?php if (isWebAccessible($item['name'])): ?> <a href="<?= getWebUrl($currentDir, $item['name'], $baseDomain, $webPath) ?>" target="_blank">Open</a> <?php endif; ?> </div> <?php endif; ?> <div class="file-info"> <div class="file-permissions" title="File permissions"> <?= htmlspecialchars($item['permissions']) ?> </div> <div class="file-size"> <?= $item['is_dir'] ? '-' : formatBytes($item['size']) ?> </div> </div> </div> <?php endforeach; ?> <?php endif; ?> </div> <div class="toolbar"> <div class="toolbar-section"> <h3>šŸ”’ Change Permissions</h3> <form method="post" id="permissionsForm" class="form-group"> <input type="hidden" name="action" value="change_permissions"> <input type="text" name="new_permissions" placeholder="755" pattern="[0-7]{3,4}" maxlength="4" title="Enter 3 or 4 digit octal permissions (e.g., 755, 644)"> <button type="submit" class="btn btn-primary" id="permissionsBtn" disabled onclick="return confirmPermissions()"> Change </button> </form> </div> <div class="toolbar-section"> <h3>šŸ“„ Create File</h3> <form method="post" class="form-group"> <input type="hidden" name="action" value="create_file"> <input type="text" name="file_name" placeholder="filename.ext" required> <button type="submit" class="btn btn-primary">Create</button> </form> </div> <div class="toolbar-section"> <h3>šŸ“ Create Folder</h3> <form method="post" class="form-group"> <input type="hidden" name="action" value="create_folder"> <input type="text" name="folder_name" placeholder="Folder name" required> <button type="submit" class="btn btn-primary">Create</button> </form> </div> <div class="toolbar-section"> <h3>šŸ“„ Upload File</h3> <form method="post" enctype="multipart/form-data" class="form-group"> <input type="hidden" name="action" value="upload_file"> <input type="file" name="file" required> <button type="submit" class="btn btn-primary">Upload</button> </form> </div> <div class="toolbar-section move-section"> <h3>šŸ“¦ Move Selected</h3> <form method="post" id="moveForm" class="move-form"> <input type="hidden" name="action" value="move_items"> <select name="destination_folder" id="destinationFolder" required> <option value="">Select destination folder...</option> <?php foreach ($availableFolders as $folder): ?> <option value="<?= htmlspecialchars($folder['path']) ?>"> <?= htmlspecialchars($folder['display']) ?> </option> <?php endforeach; ?> </select> <button type="submit" class="btn btn-success" id="moveBtn" disabled onclick="return confirmMove()"> Move </button> </form> </div> <div class="toolbar-section"> <h3>šŸ—‘ļø Delete Selected</h3> <form method="post" id="deleteForm" class="form-group"> <input type="hidden" name="action" value="delete_items"> <button type="submit" class="btn btn-danger" id="deleteBtn" disabled onclick="return confirmDelete()"> Delete </button> </form> </div> </div> </div> </div> <!-- Title at the bottom --> <div class="footer"> <h1>šŸ“ File Explorer</h1> </div> </div> <script> // Handle select all functionality const selectAllCheckbox = document.getElementById('selectAll'); const fileCheckboxes = document.querySelectorAll('.file-checkbox'); const deleteBtn = document.getElementById('deleteBtn'); const moveBtn = document.getElementById('moveBtn'); const permissionsBtn = document.getElementById('permissionsBtn'); const destinationFolder = document.getElementById('destinationFolder'); const permissionsInput = document.querySelector('input[name="new_permissions"]'); function updateButtons() { const checkedBoxes = document.querySelectorAll('.file-checkbox:checked'); const hasSelection = checkedBoxes.length > 0; const hasDestination = destinationFolder.value !== ''; const hasPermissions = permissionsInput.value !== '' && /^[0-7]{3,4}$/.test(permissionsInput.value); deleteBtn.disabled = !hasSelection; moveBtn.disabled = !hasSelection || !hasDestination; permissionsBtn.disabled = !hasSelection || !hasPermissions; } if (selectAllCheckbox) { selectAllCheckbox.addEventListener('change', function() { fileCheckboxes.forEach(checkbox => { checkbox.checked = this.checked; }); updateButtons(); }); } fileCheckboxes.forEach(checkbox => { checkbox.addEventListener('change', function() { const allChecked = Array.from(fileCheckboxes).every(cb => cb.checked); const noneChecked = Array.from(fileCheckboxes).every(cb => !cb.checked); if (selectAllCheckbox) { selectAllCheckbox.checked = allChecked; selectAllCheckbox.indeterminate = !allChecked && !noneChecked; } updateButtons(); }); }); // Update buttons when destination or permissions change destinationFolder.addEventListener('change', function() { updateButtons(); }); permissionsInput.addEventListener('input', function() { updateButtons(); }); function confirmPermissions() { const checkedBoxes = document.querySelectorAll('.file-checkbox:checked'); const permissionsValue = permissionsInput.value; if (checkedBoxes.length === 0) { alert('No items selected for permission change.'); return false; } if (!permissionsValue || !/^[0-7]{3,4}$/.test(permissionsValue)) { alert('Please enter valid octal permissions (e.g., 755, 644).'); return false; } const itemNames = Array.from(checkedBoxes).map(cb => cb.value); const itemList = itemNames.join('\n• '); return confirm(`Are you sure you want to change permissions to ${permissionsValue} for the following ${itemNames.length} item(s):\n\n• ${itemList}`); } // Smart confirmation functions function confirmDelete() { const checkedBoxes = document.querySelectorAll('.file-checkbox:checked'); if (checkedBoxes.length === 0) { alert('No items selected for deletion.'); return false; } const itemNames = Array.from(checkedBoxes).map(cb => cb.value); const itemList = itemNames.join('\n• '); return confirm(`Are you sure you want to delete the following ${itemNames.length} item(s)?\n\n• ${itemList}\n\nThis action cannot be undone.`); } function confirmMove() { const checkedBoxes = document.querySelectorAll('.file-checkbox:checked'); const destinationSelect = document.getElementById('destinationFolder'); if (checkedBoxes.length === 0) { alert('No items selected for moving.'); return false; } if (destinationSelect.value === '') { alert('Please select a destination folder.'); return false; } const itemNames = Array.from(checkedBoxes).map(cb => cb.value); const itemList = itemNames.join('\n• '); const destinationText = destinationSelect.options[destinationSelect.selectedIndex].text; return confirm(`Are you sure you want to move the following ${itemNames.length} item(s):\n\n• ${itemList}\n\nTo: ${destinationText}`); } // Add selected items to forms when submitting document.getElementById('moveForm').addEventListener('submit', function() { const checkedBoxes = document.querySelectorAll('.file-checkbox:checked'); checkedBoxes.forEach(checkbox => { const hiddenInput = document.createElement('input'); hiddenInput.type = 'hidden'; hiddenInput.name = 'selected_items[]'; hiddenInput.value = checkbox.value; this.appendChild(hiddenInput); }); }); document.getElementById('permissionsForm').addEventListener('submit', function() { const checkedBoxes = document.querySelectorAll('.file-checkbox:checked'); checkedBoxes.forEach(checkbox => { const hiddenInput = document.createElement('input'); hiddenInput.type = 'hidden'; hiddenInput.name = 'selected_items[]'; hiddenInput.value = checkbox.value; this.appendChild(hiddenInput); }); }); // Initial state updateButtons(); </script> </body> </html>