Если вы хоть раз писали на PHP что-то серьёзнее «Hello world», то наверняка сталкивались с файлами: то картинку загрузить, то CSV-отчёт сгенерировать, то просто прочитать конфиг. В Yii2 для этого есть удобные инструменты, которые экономят кучу времени и нервов. В этой статье я покажу, как правильно работать с файловой системой в Yii2, чтобы код был чистым, безопасным и не разваливался при первом же переносе на другой сервер. Поехали!

Digital-студия WNDER

Почему не стоит использовать PHP-функции напрямую

Казалось бы, что сложного? Взял file_get_contents, прочитал, записал. Но в реальном проекте всё упирается в детали: пути, права доступа, обработка ошибок, совместимость с окружением. Если писать велосипеды каждый раз, код превращается в кашу.

Yii2 предоставляет компонент yii\helpers\BaseFileHelper — это набор статических методов для самых частых операций. Он уже протестирован, учитывает кучу подводных камней и работает одинаково на Linux, Windows и macOS. Плюс, если нужно что-то особенное, вы всегда можете расширить его своим классом.

Вот простой пример: создать директорию, если её нет. Напрямую это делается так:

$path = '/var/www/uploads';
if (!is_dir($path)) {
    mkdir($path, 0775, true);
}

А через Yii2 — одной строкой:

use yii\helpers\BaseFileHelper;

BaseFileHelper::createDirectory('/var/www/uploads');

Метод сам создаст все недостающие папки и выставит права. И не надо думать о мелочах.

Лайфхак: Всегда используйте BaseFileHelper::normalizePath() для приведения путей к единому виду. Это убережёт от проблем с разделителями на Windows.

Загрузка файлов через модель

Самая частая задача — дать пользователю загрузить аватарку или документ. В Yii2 это делается через модель и правило валидации. Смотрите, как элегантно.

Сначала в модели добавляем правило:

public function rules()
{
    return [
        [['avatar'], 'file', 'skipOnEmpty' => true, 'extensions' => 'png, jpg'],
    ];
}

А в контроллере обрабатываем загрузку:

public function actionUpload()
{
    $model = new UploadForm();

    if (Yii::$app->request->isPost) {
        $model->load(Yii::$app->request->post());
        $model->avatar = UploadedFile::getInstance($model, 'avatar');

        if ($model->validate()) {
            $path = Yii::getAlias('@webroot') . '/uploads/' . $model->avatar->baseName . '.' . $model->avatar->extension;
            $model->avatar->saveAs($path);
            // Дальше можно сохранить путь в БД
        }
    }

    return $this->render('upload', ['model' => $model]);
}

Обратите внимание: UploadedFile — это специальный класс Yii2, который представляет загруженный файл. Он берёт на себя всю грязную работу: проверку размера, типа, перемещение во временную папку.

Работа с директориями и путями

В Yii2 есть замечательная функция Yii::getAlias(). Она позволяет не хардкодить пути, а использовать символические имена. Например, @webroot — это корень веб-сервера, @app — корень приложения, @runtime — папка для временных файлов.

Это очень удобно: если вы переедете на другой сервер или поменяете структуру, вам не придётся переписывать код. Просто поменяете алиасы в конфиге.

Вот пример, как получить абсолютный путь до папки загрузок:

$uploadPath = Yii::getAlias('@webroot') . '/uploads';
BaseFileHelper::createDirectory($uploadPath);

А если нужно проверить, существует ли файл, и получить его размер, то:

$file = Yii::getAlias('@app/files/report.pdf');
if (file_exists($file)) {
    $size = filesize($file); // в байтах
    echo 'Размер: ' . Yii::$app->formatter->asShortSize($size);
}

Удаление и перемещение файлов

Удалять файлы тоже нужно уметь правильно. Просто unlink() — не всегда хорошая идея, потому что файл может быть занят или не существовать. Yii2 предлагает более безопасный способ.

use yii\helpers\FileHelper;

$file = Yii::getAlias('@webroot') . '/uploads/old_photo.jpg';
if (FileHelper::unlink($file)) {
    // файл удалён
} else {
    // ошибка — можно залогировать
}

Перемещение делается так же просто:

FileHelper::move($source, $destination);

Метод сам проверит, что исходный файл существует, и создаст целевую директорию, если нужно.

Советы по безопасности

Работа с файлами — это всегда риск. Вот несколько правил, которые уберегут вас от беды.

  • Никогда не доверяйте имени файла от пользователя. Вместо baseName лучше генерировать случайное имя через uniqid() или Yii::$app->security->generateRandomString().
  • Проверяйте MIME-тип — расширение могут подделать. В Yii2 для этого есть FileHelper::getMimeType().
  • Ограничивайте размер файла через правила валидации (атрибут maxSize).
  • Храните загруженные файлы вне веб-корня, если они не должны быть доступны напрямую. Тогда доступ к ним можно контролировать через контроллер.
Правило: Если файл не должен быть публичным — кладите его в @app/uploads, а не в @webroot/uploads. И отдавайте через специальный экшен с проверкой прав.

Что в итоге

Yii2 даёт удобные инструменты для работы с файлами: BaseFileHelper, алиасы, валидацию загрузок. Используйте их, чтобы не изобретать велосипеды и избежать типичных ошибок.

Главное, что стоит запомнить:

  • Всегда используйте алиасы для путей.
  • Проверяйте файлы перед сохранением.
  • Генерируйте безопасные имена.
  • Не забывайте про права доступа.

Теперь вы можете смело работать с файлами в Yii2, не боясь сюрпризов. Удачи в кодинге!

Студия WNDER