File uploads
Uploading a file is a common task: a post cover, an avatar, a document. In Yii a file is accepted like the rest of the form data: through a model with a validation rule. The file itself is represented by an object of the yii\web\UploadedFile class.
The form model
Create the file models/UploadForm.php by hand:
// models/UploadForm.php
namespace app\models;
use yii\base\Model;
class UploadForm extends Model
{
public $imageFile;
public function rules(): array
{
return [
['imageFile', 'file', 'skipOnEmpty' => false, 'extensions' => 'png, jpg'],
];
}
}The file rule checks that a file is uploaded and has an allowed extension. skipOnEmpty => false makes the file required.
A folder for files
Create the folder web/uploads. It is inside the site root, so the saved file web/uploads/cover.jpg opens at /uploads/cover.jpg. The web server must have write permission for it.
The controller action
// controllers/PostController.php
use app\models\UploadForm;
use yii\web\UploadedFile;
public function actionUpload()
{
$model = new UploadForm();
if (Yii::$app->request->isPost) {
$model->imageFile = UploadedFile::getInstance($model, 'imageFile');
if ($model->validate()) {
$name = uniqid() . '.' . $model->imageFile->extension;
$model->imageFile->saveAs(Yii::getAlias('@webroot/uploads/') . $name);
Yii::$app->session->setFlash('success', "File saved: $name");
return $this->refresh();
}
}
return $this->render('upload', ['model' => $model]);
}UploadedFile::getInstance() takes the file out of the request. The load() method does not work for files. saveAs() moves the file from the temporary folder to a permanent one. The @webroot alias means the web folder.
The form view
Create views/post/upload.php:
<?php
// views/post/upload.php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
?>
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]); ?>
<?= $form->field($model, 'imageFile')->fileInput() ?>
<?= Html::submitButton('Upload') ?>
<?php ActiveForm::end(); ?>Open /post/upload, choose an image and submit the form: a message with the file name appears, and the file itself is in web/uploads. If you choose a .txt file, an error about a disallowed extension appears under the field.
File properties
| Property | Value |
|---|---|
$file->name | The original file name on the visitor's computer |
$file->baseName | The name without the extension |
$file->extension | The extension |
$file->size | The size in bytes |
$file->type | The type reported by the browser |
Limits
['imageFile', 'file', 'extensions' => 'png, jpg', 'maxSize' => 2 * 1024 * 1024],maxSize limits the size, here to two megabytes. For images there is the image rule with the maxWidth and maxHeight parameters. PHP has its own limit too: the upload_max_filesize setting in php.ini.
Common mistake
Without 'enctype' => 'multipart/form-data' the browser sends only the file name, not its content. UploadedFile::getInstance() returns null, and validation reports that no file was chosen. And do not save a file under its original name $file->name: two visitors with a photo.jpg file would overwrite each other.