Uploading Files =============== Uploading files in Yii is usually done with the help of [[yii\web\UploadedFile]] which encapsulates each uploaded file as an `UploadedFile` object. Combined with [[yii\widgets\ActiveForm]] and [models](structure-models.md), you can easily implement a secure file uploading mechanism. ## Creating Models Like working with plain text inputs, to upload a single file you would create a model class and use an attribute of the model to keep the uploaded file instance. You should also declare a validation rule to validate the file upload. For example, ```php namespace app\models; use yii\base\Model; use yii\web\UploadedFile; class UploadForm extends Model { /** * @var UploadedFile */ public $imageFile; public function rules() { return [ [['imageFile'], 'file', 'skipOnEmpty' => false, 'fileExtension' => 'png, jpg'], ]; } public function upload() { if ($this->validate()) { $this->imageFile->saveAs('uploads/' . $model->imageFile->baseName . '.' . $model->imageFile->extension); return true; } else { return false; } } } ``` In the code above, the `imageFile` attribute is used to keep the uploaded file instance. It is associated with a `file` validation rule which uses [[yii\validators\FileValidator]] to ensure a file with extension name `png` or `jpg` is uploaded. The `upload()` method will perform the validation and save the uploaded file on the server. The `file` validator allows you to check file extensions, size, MIME type, etc. For more details, please refer to the [Core Validators](tutorial-core-validators.md#file) section for more details. > Tip: If you are uploading an image, you may consider using the `image` validator instead. The `image` validator is implemented via [[yii\validators\ImageValidator]] which verifies if an attribute has received a valid image that can be then either saved or processed using the [Imagine Extension](https://github.com/yiisoft/yii2-imagine). ## Rendering File Input Next, create a file input in a view: ```php ['enctype' => 'multipart/form-data']]) ?> field($model, 'imageFile')->fileInput() ?> ``` It is important to remember that you add the `enctype` option to the form so that the file can be properly uploaded. The `fileInput()` call will render a `` tag which will allow users to select a file to upload. ## Wiring Up Now in a controller action, write the code to wire up the model and the view to implement file uploading: ```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->imageFile = UploadedFile::getInstance($model, 'imageFile'); if ($model->upload()) { // file is uploaded successfully return; } } return $this->render('upload', ['model' => $model]); } } ``` In the above code, when the form is submitted, the [[yii\web\UploadedFile::getInstance()]] method is called to represent the uploaded file as an `UploadedFile` instance. We then rely on the model validation to make sure the uploaded file is valid and save the file on the server. ## Uploading Multiple Files If you need to upload multiple files at once, some adjustments are required. Model: ```php class UploadForm extends Model { /** * @var UploadedFile|Null file attribute */ public $file; /** * @return array the validation rules. */ public function rules() { return [ [['file'], 'file', 'maxFiles' => 10], // <--- here! ]; } } ``` View: ```php ['enctype' => 'multipart/form-data']]); ?> field($model, 'file[]')->fileInput(['multiple' => true]) ?> ``` The difference is the following line: ```php field($model, 'file[]')->fileInput(['multiple' => true]) ?> ``` 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) { $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]); } } ``` There are two differences from single file upload. First is that `UploadedFile::getInstances($model, 'file');` is used instead of `UploadedFile::getInstance($model, 'file');`. The former returns instances for **all** uploaded files while the latter gives you only a single instance. The second difference is that we're doing `foreach` and saving each file.