Uploading Files =============== > Note: This section is under development. Uploading files in Yii is done via form model, its validation rules and some controller code. Let's review what's needed to handle uploads properly. Form model ---------- First of all, you need to create a model that will handle file upload. Create `models/UploadForm.php` with the following content: ```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|Null file attribute */ public $file; /** * @return array the validation rules. */ public function rules() { return [ [['file'], 'file'], ]; } } ``` In the code above, we created a model `UploadForm` with an attribute `$file` that will become `` in the HTML form. The attribute has the validation rule named `file` that uses [[yii\validators\FileValidator|FileValidator]]. Form view --------- Next create a view that will render the form. ```php ['enctype' => 'multipart/form-data']]); ?> field($model, 'file')->fileInput() ?> ``` The `'enctype' => 'multipart/form-data'` is important since it allows file uploads. `fileInput()` represents a form input field. Controller ---------- Now create the controller that connects form and model together: ```php 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->validate()) { $model->file->saveAs('uploads/' . $model->file->baseName . '.' . $model->file->extension); } } return $this->render('upload', ['model' => $model]); } } ``` Instead of `model->load(...)` we are using `UploadedFile::getInstance(...)`. [[\yii\web\UploadedFile|UploadedFile]] does not run the model validation. It only provides information about the uploaded file. Therefore, you need to run validation manually via `$model->validate()`. This triggers the [[yii\validators\FileValidator|FileValidator]] that expects a file: ```php $file instanceof UploadedFile || $file->error == UPLOAD_ERR_NO_FILE //in code framework ``` If validation is successful, then we're saving the file: ```php $model->file->saveAs('uploads/' . $model->file->baseName . '.' . $model->file->extension); ``` If you're using "basic" application template then folder `uploads` should be created under `web`. That's it. Load the page and try uploading. Uplaods should end up in `basic/web/uploads`. Additional information ---------------------- ### Required rule If you need to make file upload mandatory use `skipOnEmpty` like the following: ```php public function rules() { return [ [['file'], 'file', 'skipOnEmpty' => false], ]; } ``` ### MIME type It is wise to validate type of the file uploaded. FileValidator has property `$types` for the purpose: ```php public function rules() { return [ [['file'], 'file', 'types' => 'gif, jpg',], ]; } ``` The thing is that it validates only file extension and not the file content. In order to validate content as well use `mimeTypes` property of `ImageValidator`: ```php public function rules() { return [ [['file'], 'image', 'mimeTypes' => 'image/jpeg, image/png',], ]; } ``` ### Uploading multiple files If you need download multiple files at once some adjustments are required. View: ```php ['enctype' => 'multipart/form-data']]); if ($model->hasErrors()) { //it is necessary to see all the errors for all the files. echo '
';
    print_r($model->getErrors());
    echo '
'; } ?> field($model, 'file[]')->fileInput(['multiple' => '']) ?> ``` The difference is the following line: ```php field($model, 'file[]')->fileInput(['multiple' => '']) ?> ``` Controller: ```php 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) { $files = UploadedFile::getInstances($model, 'file'); foreach ($files as $file) { $_model = new UploadForm(); $_model->file = $file; if ($_model->validate()) { $_model->file->saveAs('uploads/' . $_model->file->baseName . '.' . $_model->file->extension); } else { foreach ($_model->getErrors('file') as $error) { $model->addError('file', $error); } } } if ($model->hasErrors('file')){ $model->addError( 'file', count($model->getErrors('file')) . ' of ' . count($files) . ' files not uploaded' ); } } return $this->render('upload', ['model' => $model]); } } ``` The difference is `UploadedFile::getInstances($model, 'file');` instead of `UploadedFile::getInstance($model, 'file');`. Former returns instances for **all** uploaded files while the latter gives you only a single instance.