Part 2 : Creating a Dynamic File Manager with PHP

0
89

In our previous article Design a Custom File Manager Using HTML and CSS , we built a file manager’s design using HTML and CSS. If you haven’t gone through that yet, feel free to check it out for a simple, visually appealing interface for your file management system. In this continuation, we’ll make the file manager dynamic by adding essential features like file upload, renaming, and deleting using PHP.

Building the Dynamic File Manager

Now that we have the visual components ready, we can use PHP to handle user interactions. These include uploading files to a directory, renaming files or folders, and deleting items when requested. In this section, we will look at the backend code that enables these functionalities.

Part 1 : Design a Custom File Manager Using HTML and CSS

Part 2 : Creating a Dynamic File Manager with PHP

Part 3 : Enhancing the File Manager with a File Upload Feature

Follow this video for complete guidance :

Complete Source Code

<?php

$directory = isset($_GET['dir']) ? $_GET['dir'] : 'uploads';

// Handle file upload
if ($_SERVER['REQUEST_METHOD'] == 'POST') {

    // Handle file/folder delete
    if (isset($_POST['delete'])) {
        $itemToDelete = $_POST['delete'];
        $pathToDelete = "$directory/$itemToDelete";
        deleteFileOrFolder($pathToDelete);
    }

    // Handle file/folder rename
    if (isset($_POST['rename'])) {
        $oldName = $_POST['oldName'];
        $newName = $_POST['newName'];
        $oldPath = "$directory/$oldName";
        $newPath = "$directory/$newName";
        
        if (renameFileOrFolder($oldPath, $newPath)) {
            echo "<p class='alert alert-success'>The item has been renamed.</p>";
        } else {
            echo "<p class='alert alert-danger'>Sorry, there was an error renaming the item.</p>";
        }
    }

    // Refresh the page to show changes
    header("Location: $_SERVER[PHP_SELF]?dir=" . urlencode($directory));
    exit();
}

function getFiles($directory)
{
    $allItems = array_diff(scandir($directory), array('.', '..'));
    $folders = array_filter($allItems, fn($item) => is_dir("$directory/$item"));
    $files = array_filter($allItems, fn($item) => !is_dir("$directory/$item"));
    
    natcasesort($folders);
    natcasesort($files);
    
    return array_merge($folders, $files);
}

function buildBreadcrumb($path)
{
    $segments = explode('/', $path);
    $breadcrumb = [];
    $currentPath = '';

    foreach ($segments as $segment) {
        if ($segment !== '') {
            $currentPath .= $segment . '/';
            $breadcrumb[] = "<a href=\"?dir=" . urlencode(rtrim($currentPath, '/')) . "\" class=\"breadcrumb-item\">" . htmlspecialchars($segment) . "</a>";
        }
    }

    return implode(' <span class="breadcrumb-separator">/</span> ', $breadcrumb);
}



function deleteFileOrFolder($path)
{
    if (is_dir($path)) {
        rmdir($path); // Delete empty folder
    } else {
        unlink($path); // Delete file
    }
}

function renameFileOrFolder($oldPath, $newPath)
{
    if (rename($oldPath, $newPath)) {
        return true;
    }
    return false;
}

$files = getFiles($directory);
$rootFolders = getFiles('uploads');

?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Modern File Manager</title>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.1/css/all.min.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <style>
        body {
            font-family: 'Arial', sans-serif;
            background-color: #f7f7f7;
        }
        .container {
            max-width: 1200px;
        }
        .breadcrumb {
            background-color: transparent;
            padding: 0;
            margin-bottom: 20px;
        }
        .breadcrumb a {
            color: #007bff;
            text-decoration: none;
            font-weight: bold;
            font-size: 16px;
            transition: color 0.3s ease;
        }
        .breadcrumb a:hover {
            color: #0056b3;
            text-decoration: underline;
        }
        .breadcrumb i {
            color: #6c757d;
        }
        .breadcrumb-item {
            font-size: 16px;
            color: #6c757d;
        }
        .breadcrumb-separator {
            color: #6c757d;
            padding: 0 8px;
        }
        .sidebar {
            background-color: #343a40;
            color: #fff;
            padding: 20px;
            height: 100vh;
            position: fixed;
            top: 0;
            left: 0;
            width: 250px;
        }
        .sidebar-item {
            margin-bottom: 10px;
            cursor: pointer;
            font-size: 16px;
        }
        .sidebar-item:hover {
            background-color: #495057;
            padding-left: 10px;
            transition: padding 0.3s;
        }
        .content {
            margin-left: 270px;
            padding: 20px;
        }
        .file-item {
            background-color: #fff;
            border-radius: 5px;
            padding: 15px;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
            margin-bottom: 15px;
            text-align: center;
        }
        .file-item:hover {
            background-color: #e9ecef;
        }
        .file-icon i {
            font-size: 40px;
            color: #6c757d;
            margin-bottom: 10px;
        }
        .file-name {
            font-size: 14px;
            color: #495057;
        }
        .file-actions {
            margin-top: 10px;
        }
        #contextMenu {
            display: none;
            position: absolute;
            background-color: #ffffff;
            border: 1px solid #ccc;
            box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
            border-radius: 4px;
            z-index: 1000;
        }
        #contextMenu .menu-item {
            padding: 8px 12px;
            cursor: pointer;
        }
        #contextMenu .menu-item:hover {
            background-color: #f1f1f1;
        }
        .upload-area {
            width: 400px; height: 200px;
            border: 2px dashed #ccc; border-radius: 10px;
            text-align: center; line-height: 200px;
            margin: 50px auto; cursor: pointer;
            color: #333; font-size: 18px;
        }
        .upload-area.hover { background: #f0f0f0; }
        #fileInput { display: none; }
    </style>
</head>
<body>
    <div class="sidebar">
        <h4 class="text-center">File Manager</h4>
        <hr class="text-white">
        <div class="sidebar-item">
          <strong>Quick Access</strong>
        </div>
        <?php foreach ($rootFolders as $folder){ ?>
            <?php $folderPath = "uploads/$folder"; ?>
            <?php if (is_dir($folderPath)){ ?>
                <div class="sidebar-item">
                    <a href="?dir=<?php echo urlencode($folderPath) ?>" class="text-white"><?php echo htmlspecialchars($folder) ?></a>
                </div>
            <?php } ?>
        <?php } ?>
    </div>

    <div class="content">
        <div class="container">
            <nav aria-label="breadcrumb">
                <ol class="breadcrumb">
                    <li class="breadcrumb-item"><a href="?dir=uploads">Home</a></li>
                    <?php echo buildBreadcrumb($directory); ?>
                </ol>
            </nav>

      <div class="upload-area" id="uploadfile">Drag & Drop Files Here</div>
      <input type="file" id="fileInput">

            <div class="row mt-5">
                <?php foreach ($files as $file){ ?>
                    <?php 
                    $filePath = "$directory/$file";
                    $fileType = pathinfo($filePath, PATHINFO_EXTENSION);
                    $iconClass = match (strtolower($fileType)) {
                        'png', 'jpg', 'jpeg', 'gif' => 'fa-image',
                        'mp3' => 'fa-play',
                        'mp4' => 'fa-video',
                        'pdf' => 'fa-file',
                        default => is_dir($filePath) ? 'fa-folder' : 'fa-file'
                    };
                ?>
                    <div class="col-md-2" id="file-<?php echo $file;?>">
                        <div class="file-item" oncontextmenu="showContextMenu(event, '<?php echo $file;?>')">
                            <?php if (is_dir($filePath)){ ?>
                                <a href="?dir=<?= urlencode($filePath) ?>" class="text-decoration-none text-dark">
                            <?php } ?>
                                <div class="file-icon">
                                    <i class="fa <?php echo $iconClass;?>"></i>
                                </div>
                                <div class="file-name"><?php echo htmlspecialchars($file);?></div>
                            <?php if (is_dir($filePath)){ ?>
                                </a>
                            <?php } ?>
                        </div>
                    </div>
                <?php } ?>
            </div>

            <div id="contextMenu" class="context-menu">
                <div class="menu-item" onclick="renameItem()">Rename</div>
                <div class="menu-item" onclick="deleteItem()">Delete</div>
            </div>
        </div>
    </div>

    <script>
        function showContextMenu(event, file) {
            event.preventDefault();
            currentItem = file;
            const contextMenu = document.getElementById('contextMenu');
            contextMenu.style.display = 'block';
            contextMenu.style.left = `${event.pageX}px`;
            contextMenu.style.top = `${event.pageY}px`;
        }

        function hideContextMenu() {
            document.getElementById('contextMenu').style.display = 'none';
        }

        window.addEventListener('click', hideContextMenu);   

        function deleteItem() {
            if (confirm('Are you sure you want to delete this item?')) {
                const form = document.createElement('form');
                form.method = 'POST';
                form.innerHTML = `<input type="hidden" name="delete" value="${currentItem}">`;
                document.body.appendChild(form);
                form.submit();
            }
        }

        function renameItem() {
            const newName = prompt("Enter the new name:", currentItem);
            if (newName && newName !== currentItem) {
                const form = document.createElement('form');
                form.method = 'POST';
                form.innerHTML = `
                    <input type="hidden" name="rename" value="true">
                    <input type="hidden" name="oldName" value="${currentItem}">
                    <input type="hidden" name="newName" value="${newName}">
                `;
                document.body.appendChild(form);
                form.submit();
            }
        }
    </script>
</body>
</html>

File Upload

The file upload functionality allows users to easily add files to the current directory. This is handled by detecting when a POST request is made and verifying that a file has been uploaded. The uploaded file is then moved to the selected directory using PHP’s move_uploaded_file() function.

ALSO READ  How to add Facebook Login to Your Website

The user can either drag and drop the file into the designated upload area or select a file manually via a file input field. Once uploaded, the page refreshes to show the updated list of files and folders.

File Renaming

To enhance the user experience, we’ve implemented a renaming feature. Right-clicking a file or folder opens a context menu with the option to rename the selected item. The user can provide a new name for the item, which will be processed via PHP’s rename() function.

The renameFileOrFolder() function checks if the renaming operation is successful and displays an appropriate success or failure message.

File Deletion

The delete option is accessible via the context menu as well. After confirming the deletion, the selected file or folder is removed from the directory using PHP’s unlink() for files or rmdir() for empty directories.

Dynamic Interaction with the Frontend

For a smooth and user-friendly experience, the PHP backend is complemented by JavaScript. The front-end code provides drag-and-drop functionality for uploading files, along with context menus for file operations like renaming and deleting. When an item is renamed or deleted, the changes are instantly reflected on the page without requiring a page reload.

Additionally, the context menu is shown when a user right-clicks on any file or folder. The rename and delete options are triggered by respective functions that send the necessary data to the server for processing.

With these dynamic features—file upload, renaming, and deletion—we now have a fully functional file manager in PHP. The interface we previously built with HTML and CSS has come to life, enabling users to manage files more efficiently. By implementing these backend functionalities, we’ve made the file manager interactive, allowing for a seamless experience in handling files and folders.

ALSO READ  10 Funny PHP APIs

Stay tuned for future tutorials where we will continue enhancing this file manager with additional features such as file previews, search functionality, and more!

Comments are closed.