Upload File with Yii2
First you need to create a model that will handle the form of download the file.
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 this code, we created a model UploadForm
with an attribute $file
that will be is <input type="file">
in upload form and pointed out to him validation rule file
. This rule is [[yii\validators\FileValidator|FileValidator]]
Secondly create a view for our model.
<?php
use yii\widgets\ActiveForm;
$form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]); ?>
<?= $form->field($model, 'file')->fileInput() ?>
<button>Submit</button>
<?php ActiveForm::end(); ?>
It is different attribute 'enctype' => 'multipart/form-data'
from the standard form. This value is required when you are using forms that have a file upload control. fileInput()
represents a form input field.
Thirdly, that create the controller that will connect our form and model.
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]);
}
}
The difference here from the standard crud action, so use UploadedFile::getInstance(...)
instead model->load(...)
. [[\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 $model->validate()
. This triggers the [[yii\validators\FileValidator|FileValidator]] that expects a file
$file instanceof UploadedFile || $file->error == UPLOAD_ERR_NO_FILE //in code framework
If validation done without errors, then save the file
$model->file->saveAs('uploads/' . $model->file->baseName . '.' . $model->file->extension);
If you use "basic" application then forlder uploads
should be create inside web
folder.
Everything is ready, now run the page and download the file. Check the folder basic/web/uploads
to make sure that you have downloaded.
Additional information.
Required rule
If you need to check the mandatory download the file, then use skipOnEmpty
.
public function rules()
{
return [
[['file'], 'file', 'skipOnEmpty' => false],
];
}
Path upload folder
Folder to download the file can be installed using Yii::getAlias('@app/uploads')
. This base path of currently running application and folder `uploads
MIME type
FileValidator have property $types
public function rules()
{
return [
[['file'], 'file', 'types' => 'gif, jpg',],
];
}
it pulls
in_array(strtolower(pathinfo($file->name, PATHINFO_EXTENSION)), $this->types, true))
As you can see, the name of the expansion may be one and the file type - other, actually.
UploadedFile::getInstance()->type
` also do not take this value for granted.
Instead, use [[\yii\helpers\BaseFileHelper|FileHelper]] and his [[FileHelper::getMimeType()]] to determine the exact MIME type.
If allowed to load only the images, using [[\yii\validators\ImageValidator|ImageValidator]] instead [[yii\validators\FileValidator|FileValidator]].
public function rules()
{
return [
[['file'], 'image', 'mimeTypes' => 'image/jpeg, image/png',],
];
}
ImageValidator
use use yii\helpers\FileHelper;
for check mime types.
List Mime types
Multiple files uploader
If you need download multiple files, you will need to alter slightly the controller and view. At first view:
<?php
use yii\widgets\ActiveForm;
$form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]);
if ($model->hasErrors()) { //it is necessary to see all the errors for all the files.
echo '<pre>';
print_r($model->getErrors());
echo '</pre>';
}
?>
<?= $form->field($model, 'file[]')->fileInput(['multiple' => '']) ?>
<button>Submit</button>
<?php ActiveForm::end(); ?>
In fact the only difference is in the one row.
<?= $form->field($model, 'file[]')->fileInput(['multiple' => '']) ?>
instead
<?= $form->field($model, 'file')->fileInput() ?>
-
['multiple' => '']
- HTML multiple Attribute -
file[]
vs `file
- need, otherwise UploadedFile sees only one file
We now turn to the controller
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]);
}
}
Here the differences in:
-
UploadedFile::getInstances($model, 'file');
insteadUploadedFile::getInstance($model, 'file');
. First returns all uploaded files for the given model attribute, second - one. - All other differences follow from the first.