9.0 KiB
Загрузка файлов
Загрузка файлов в Yii выполняется с помощью модели-формы, её правил валидации и некоторого кода в контроллере. Давайте посмотрим подробнее, что необходимо для загрузки файлов.
Загрузка одного файла
Для начала требуется создать модель, которая будет обрабатывать загрузку файлов. Создайте models/UploadForm.php
со
следующим содержанием:
namespace app\models;
use yii\base\Model;
use yii\web\UploadedFile;
/**
* UploadForm is the model behind the upload form.
*/
class UploadForm extends Model
{
/**
* @var UploadedFile file attribute
*/
public $file;
/**
* @return array the validation rules.
*/
public function rules()
{
return [
[['file'], 'file'],
];
}
}
В коде что выше, мы создали модель UploadForm
с свойством file
, которое станет в HTML форме <input type="file">
.
В правилах валидации это свойство описывается правилом file
, которое используется yii\validators\FileValidator.
Вид формы
Далее создайте вид, который будет выводить форму:
<?php
use yii\widgets\ActiveForm;
?>
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]) ?>
<?= $form->field($model, 'file')->fileInput() ?>
<button>Отправить</button>
<?php ActiveForm::end() ?>
'enctype' => 'multipart/form-data'
необходимо для того, чтобы форма поддерживала отправку файлов. fileInput()
формирует файловый элемент формы.
Контроллер
Теперь создайте контроллер, который соединит вид формы и модель:
namespace app\controllers;
use Yii;
use yii\web\Controller;
use app\models\UploadForm;
use yii\web\UploadedFile;
class SiteController extends Controller
{
public function actionUpload()
{
$model = new UploadForm();
if (Yii::$app->request->isPost) {
$model->file = UploadedFile::getInstance($model, 'file');
if ($model->file && $model->validate()) {
$model->file->saveAs('uploads/' . $model->file->baseName . '.' . $model->file->extension);
}
}
return $this->render('upload', ['model' => $model]);
}
}
Вместо model->load(...)
мы используем UploadedFile::getInstance(...)
. Так как \yii\web\UploadedFile
не запускает процесс валидации модели, а только предоставляет информацию о загруженном файле. Поэтому необходимо
произвести валидацию самостоятельно, через $model->validate()
, которая вызовет yii\validators\FileValidator.
Валидатор ожидает свойство, которое содержит информацию о загружаемом файле - вы это можете увидеть во внутреннем коде этого
валидатора:
if (!$file instanceof UploadedFile || $file->error == UPLOAD_ERR_NO_FILE) {
return [$this->uploadRequired, []];
}
Если валидация пройдена успешна, то сохраняем файл:
$model->file->saveAs('uploads/' . $model->file->baseName . '.' . $model->file->extension);
Если вы используете "basic" шаблона приложения, то директория uploads
должна быть создана внутри web
.
Всё. Откройте форму и попробуйте загрузить файл. Он должен загрузиться в basic/web/uploads
.
Валидация
Очень часто требуется разрешить загрузку только определённых файлов или установить обязательную загрузку. Ниже мы
рассмотрим некоторые общие настройки правила file
.
Обязательная загрузка файла
Если требуется обязательная загрузка файла, используйте skipOnEmpty
:
public function rules()
{
return [
[['file'], 'file', 'skipOnEmpty' => false],
];
}
тип MIME
Разумно проверять тип загружаемого файла. Для этого FileValidator имеет свойство $extensions
:
public function rules()
{
return [
[['file'], 'file', 'extensions' => 'gif, jpg'],
];
}
По-умолчанию, эта проверка будет также проверять MIME-тип данных, в соответствии с расширением. Для gif это будет
image/gif
, для jpg
- image/jpeg
.
Обратите внимание, что некоторые MIME-типы могут быть определены неверно через fileinfo, расширение PHP, которое
использует FileValidator. Например, csv
файлы будут определены как text/plain
вместо корректного text/csv
.
Вы можете отключить такое поведение через установку свойства checkExtensionByMimeType
в false
и указать
корректный MIME-тип вручную:
public function rules()
{
return [
[['file'], 'file', 'checkExtensionByMimeType' => false, 'extensions' => 'csv', 'mimeTypes' => 'text/plain'],
];
}
Свойства изображений
Для загрузки изображений вам может пригодиться валидатор yii\validators\ImageValidator. Он проверяет является ли файл изображением, которое затем может быть обработано или сохранено с помощью Imagine Extension.
Загрузка нескольких файлов
Если вам нужно загрузить несколько файлов одновременно, то необходимо внести некоторые корректировки.
В модель:
class UploadForm extends Model
{
/**
* @var UploadedFile|Null file attribute
*/
public $file;
/**
* @return array the validation rules.
*/
public function rules()
{
return [
[['file'], 'file', 'maxFiles' => 10], // <--- здесь!
];
}
}
В виде:
<?php
use yii\widgets\ActiveForm;
$form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]);
?>
<?= $form->field($model, 'file[]')->fileInput(['multiple' => true]) ?>
<button>Отправить</button>
<?php ActiveForm::end(); ?>
Изменения внесены в строку
<?= $form->field($model, 'file[]')->fileInput(['multiple' => true]) ?>
В контроллере:
namespace app\controllers;
use Yii;
use yii\web\Controller;
use app\models\UploadForm;
use yii\web\UploadedFile;
class SiteController extends Controller
{
public function actionUpload()
{
$model = new UploadForm();
if (Yii::$app->request->isPost) {
$model->file = UploadedFile::getInstances($model, 'file');
if ($model->file && $model->validate()) {
foreach ($model->file as $file) {
$file->saveAs('uploads/' . $file->baseName . '.' . $file->extension);
}
}
}
return $this->render('upload', ['model' => $model]);
}
}
Есть два отличия в контроллере от загрузки одного файла. Во-первых используется UploadedFile::getInstances($model, 'file');
вместо UploadedFile::getInstance($model, 'file');
. Первый возвратит информацию обо всех загруженных файлах, в то
время как, как второй вернёт информацию только об одном загруженном файле. Во-вторых отличие в том, что применяется
foreach
для сохранения каждого файла.