mirror of
https://github.com/yiisoft/yii2.git
synced 2025-08-14 14:28:27 +08:00
247 lines
6.1 KiB
Markdown
247 lines
6.1 KiB
Markdown
Uploading Files
|
|
===============
|
|
|
|
Uploading files in Yii is done via the a form model, its validation rules and some controller code. Let's review what's
|
|
required to handle uploads properly.
|
|
|
|
|
|
Uploading single file
|
|
---------------------
|
|
|
|
First of all, you need to create a model that will handle file uploads. 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 file attribute
|
|
*/
|
|
public $file;
|
|
|
|
/**
|
|
* @return array the validation rules.
|
|
*/
|
|
public function rules()
|
|
{
|
|
return [
|
|
[['file'], 'file'],
|
|
];
|
|
}
|
|
}
|
|
```
|
|
|
|
In the code above, we've created a model `UploadForm` with an attribute `$file` that will become `<input type="file">` 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
|
|
<?php
|
|
use yii\widgets\ActiveForm;
|
|
?>
|
|
|
|
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]) ?>
|
|
|
|
<?= $form->field($model, 'file')->fileInput() ?>
|
|
|
|
<button>Submit</button>
|
|
|
|
<?php ActiveForm::end() ?>
|
|
```
|
|
|
|
The `'enctype' => 'multipart/form-data'` is necessary because it allows file uploads. `fileInput()` represents a form
|
|
input field.
|
|
|
|
### Controller
|
|
|
|
Now create the controller that connects the 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->file && $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, rather it only provides information about the uploaded file. Therefore, you need to run the validation manually via `$model->validate()` to trigger the [[yii\validators\FileValidator|FileValidator]] that expects a file:
|
|
|
|
```php
|
|
$file instanceof UploadedFile || $file->error == UPLOAD_ERR_NO_FILE //in the 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 the "basic" application template, then folder `uploads` should be created under `web`.
|
|
|
|
That's it. Load the page and try uploading. Uploads should end up in `basic/web/uploads`.
|
|
|
|
Validation
|
|
----------
|
|
|
|
It's often required to adjust validation rules to accept certain files only or require uploading. Below we'll review
|
|
some common rule configurations.
|
|
|
|
### Required
|
|
|
|
If you need to make the file upload mandatory, use `skipOnEmpty` like the following:
|
|
|
|
```php
|
|
public function rules()
|
|
{
|
|
return [
|
|
[['file'], 'file', 'skipOnEmpty' => false],
|
|
];
|
|
}
|
|
```
|
|
|
|
### MIME type
|
|
|
|
It is wise to validate the type of file uploaded. FileValidator has the property `$extensions` for this purpose:
|
|
|
|
```php
|
|
public function rules()
|
|
{
|
|
return [
|
|
[['file'], 'file', 'extensions' => 'gif, jpg',],
|
|
];
|
|
}
|
|
```
|
|
|
|
Keep in mind that only the file extension will be validated, but not the actual file content. In order to validate the content as well, use the `mimeTypes` property of `FileValidator`:
|
|
|
|
```php
|
|
public function rules()
|
|
{
|
|
return [
|
|
[['file'], 'file', 'extensions' => 'jpg, png', 'mimeTypes' => 'image/jpeg, image/png',],
|
|
];
|
|
}
|
|
```
|
|
|
|
[List of common media types](http://en.wikipedia.org/wiki/Internet_media_type#List_of_common_media_types)
|
|
|
|
### Image properties
|
|
|
|
If you upload an image, [[yii\validators\ImageValidator|ImageValidator]] may come in handy. It verifies if an attribute
|
|
received a valid image that can be then either saved or processed using the [Imagine Extension](https://github.com/yiisoft/yii2/tree/master/extensions/imagine).
|
|
|
|
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
|
|
<?php
|
|
use yii\widgets\ActiveForm;
|
|
|
|
$form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]);
|
|
?>
|
|
|
|
<?= $form->field($model, 'file[]')->fileInput(['multiple' => true]) ?>
|
|
|
|
<button>Submit</button>
|
|
|
|
<?php ActiveForm::end(); ?>
|
|
```
|
|
|
|
The difference is the following line:
|
|
|
|
```php
|
|
<?= $form->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');` 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.
|