rzaripov.kz

Создание файлового менеджера на PHP с админ-панелью

Файловый менеджер на PHP — удачный учебный проект, в котором объединяются работа с каталогами, загрузка документов, права доступа и базовая веб-безопасность. Его можно использовать как внутренний инструмент для управления файлами сайта, небольшой медиатекой или закрытым хранилищем документов.

Простая версия не требует сложного фреймворка. Достаточно PHP, веб-сервера Apache или Nginx, базы данных для пользователей и аккуратно организованной файловой структуры. При этом проект легко расширяется: к нему можно добавить поиск, журнал действий, предпросмотр изображений и разграничение ролей.

Административная панель должна скрывать технические детали от пользователя. В ней отображаются папки и файлы, доступны загрузка, скачивание, переименование, удаление и создание каталогов. Все операции выполняются через сервер, поэтому проверку пути и прав нельзя оставлять на стороне браузера.

Такой проект хорошо показывает практические навыки PHP-разработчика. Он затрагивает обработку HTTP-запросов, HTML-формы, сессии, SQL-запросы, работу с файловой системой и защиту от типичных атак. Для портфолио можно оформить его как самостоятельное кроссплатформенное веб-приложение с понятной демонстрацией функций.

Архитектура приложения и структура каталогов

Удобно разделить файловый менеджер на несколько слоёв. Маршрутизатор принимает запрос, контроллер определяет действие, сервис проверяет права и работает с файловой системой, а шаблон формирует HTML-страницу. Для небольшого проекта допустима упрощённая MVC-структура, но даже она лучше набора несвязанных PHP-файлов.

Пример структуры может выглядеть так:

project/
├── public/
│   ├── index.php
│   └── assets/
├── app/
│   ├── Controllers/
│   ├── Services/
│   ├── Views/
│   └── Database/
├── storage/
│   └── files/
├── config/
└── vendor/

Каталог public должен быть единственной веб-доступной директорией. Загруженные документы лучше хранить в storage/files, закрыв прямой доступ к нему настройками веб-сервера. Скачивание в таком случае выполняется отдельным PHP-обработчиком после проверки авторизации.

Для взаимодействия отдельных компонентов можно использовать JSON-эндпоинты. Подход к проектированию таких маршрутов и обработке HTTP-запросов подробно разобран в материале о REST API. Даже если панель работает через обычные формы, подобная архитектура пригодится для асинхронной загрузки и мобильного клиента.

Подготовка базы данных и авторизации

База данных не обязана хранить содержимое файлов. Для начала достаточно таблицы пользователей и журнала операций. В таблице users можно разместить поля id, login, password_hash, role, created_at. Журнал file_actions будет содержать пользователя, тип действия, относительный путь, IP-адрес и дату события.

Пароли сохраняются только через password_hash():

$hash = password_hash($_POST['password'], PASSWORD_DEFAULT);

При входе используется password_verify(). После успешной авторизации необходимо вызвать session_regenerate_id(true), чтобы снизить риск фиксации сессии. Проверку пользователя удобно вынести в middleware или отдельную функцию, которая вызывается перед каждым административным действием.

Роли могут быть минимальными: администратор управляет файлами и пользователями, редактор работает с содержимым, а наблюдатель имеет доступ только к просмотру и скачиванию. Проверка роли должна выполняться на сервере, поскольку скрытая кнопка в HTML не является ограничением доступа.

Навигация по файлам и операции с каталогами

Основой менеджера становится передача относительного пути, например documents/reports. Сервер объединяет его с корневой директорией хранилища, после чего нормализует результат. Нельзя без проверки передавать пользовательскую строку в scandir(), unlink() или rename().

Безопасная схема включает несколько шагов: удалить лишние разделители, привести путь к каноническому виду, проверить отсутствие выхода выше корня и убедиться, что итоговый путь начинается с разрешённой директории. В PHP для этого применяют realpath(), basename() и сравнение префикса:

$root = realpath(__DIR__ . '/../../storage/files');
$requested = $root . '/' . ltrim($_GET['path'] ?? '', '/');
$target = realpath($requested);

if ($target === false || !str_starts_with($target, $root)) {
    http_response_code(403);
    exit('Недопустимый путь');
}

Для создания папки имя также нужно ограничить допустимыми символами. Лучше запретить управляющие символы, обратные слеши и специальные значения . и ... Переименование выполняется только внутри того же разрешённого каталога, а удаление папок должно требовать отдельного подтверждения.

Загрузка, скачивание и отображение данных

Форма загрузки должна использовать method="post" и enctype="multipart/form-data". Сервер проверяет код ошибки, размер, расширение, MIME-тип и фактическое содержимое файла. Расширение нельзя считать достаточной проверкой: злоумышленник может переименовать исполняемый скрипт в изображение.

Файл желательно сохранять под случайным именем, созданным через random_bytes() или bin2hex(). Исходное имя хранится отдельно в базе и выводится только после экранирования:

$safeName = bin2hex(random_bytes(16)) . '.bin';
$destination = $root . '/' . $safeName;

if (is_uploaded_file($_FILES['upload']['tmp_name'])) {
    move_uploaded_file($_FILES['upload']['tmp_name'], $destination);
}

Список разрешённых форматов зависит от назначения приложения. Для документов можно оставить PDF, DOCX и TXT, для изображений — JPEG, PNG и WebP. Исполняемые файлы, архивы с потенциально опасным содержимым и серверные скрипты лучше запрещать или помещать в изолированное хранилище.

Скачивание проходит через контроллер: он проверяет сессию, находит файл, задаёт корректные заголовки Content-Type и Content-Disposition, а затем передаёт данные через readfile(). Имя в заголовке нужно кодировать безопасно, чтобы исключить внедрение управляющих символов.

Интерфейс административной панели

Панель должна показывать текущую папку, хлебные крошки, список объектов и доступные действия. Для каждого файла полезно выводить размер, дату изменения и тип. Кнопки удаления и переименования лучше открывать через диалог подтверждения, а результаты операций показывать понятными уведомлениями.

HTML-вывод необходимо экранировать с помощью htmlspecialchars($value, ENT_QUOTES, 'UTF-8'). Это особенно важно для исходных имён файлов и названий каталогов, поскольку они могут содержать HTML-код. Для форм, изменяющих состояние, добавляется CSRF-токен, связанный с текущей сессией.

Адаптивная вёрстка позволяет пользоваться панелью с ноутбука, планшета и телефона. Для портфолио можно подготовить отдельный демонстрационный экран с тестовыми файлами и описанием стека. Ссылку на готовый веб-пример уместно разместить рядом с проектом, например как отдельный веб-проект, если он используется для показа практических навыков разработки.

AJAX-запросы пригодятся для удаления и загрузки без полной перезагрузки страницы. Однако клиентский JavaScript должен лишь улучшать интерфейс: все проверки сессии, параметров, прав и содержимого файлов остаются в PHP-коде.

Защита данных и развитие проекта

Минимальный набор защиты включает HTTPS, CSRF-токены, строгую проверку путей, ограничение размера загрузки и безопасные HTTP-заголовки. В конфигурации PHP следует настроить upload_max_filesize и post_max_size, а веб-серверу запретить выполнение скриптов внутри каталога хранилища.

Журнал действий помогает расследовать ошибки и подозрительную активность. В него записываются загрузка, скачивание, удаление, перемещение и изменение имени. Для крупных файлов можно добавить потоковую передачу, контроль свободного места и фоновое создание миниатюр.

Функция Базовая реализация Вариант для расширения
Авторизация Сессии и роли Двухфакторная аутентификация
Хранение Локальный каталог S3-совместимое облако
Загрузка Ограничение MIME и размера Очередь и возобновление
Поиск Фильтрация текущей папки Полнотекстовый индекс
Аудит Журнал в базе данных Отчёты и уведомления
Интерфейс HTML и формы AJAX или отдельное мобильное приложение

Следующим этапом может стать REST-интерфейс для мобильного клиента, интеграция с облачным диском или синхронизация нескольких серверов. Чёткое разделение контроллеров, сервисов и хранилища позволит менять внутреннюю реализацию без полной переработки административной панели.