Создание файлового менеджера на 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-интерфейс для мобильного клиента, интеграция с облачным диском или синхронизация нескольких серверов. Чёткое разделение контроллеров, сервисов и хранилища позволит менять внутреннюю реализацию без полной переработки административной панели.