Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

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

PropertyValue
$file->nameThe original file name on the visitor's computer
$file->baseNameThe name without the extension
$file->extensionThe extension
$file->sizeThe size in bytes
$file->typeThe 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.

Thanks for reading!

Donate to the site — we work hard for you.