©
This document uses PHP Chinese website manual Release
在Yii里上传文件通常使用yii\web\UploadedFile类, 它把每个上传的文件封装成 UploadedFile
对象。 结合yii\widgets\ActiveForm和models,你可以轻松实现安全的上传文件机制。
和普通的文本输入框类似,当要上传一个文件时,你需要创建一个模型类并且用其中的某个属性来接收上传的文件实例。 你还需要声明一条验证规则以验证上传的文件。 举例来讲,
namespace app\models;
use yii\base\Model;
use yii\web\UploadedFile;
class UploadForm extends Model{
public $imageFile;
public function rules()
{
return [
[['imageFile'], 'file', 'skipOnEmpty' => false, 'extensions' => 'png, jpg'],
];
}
public function upload()
{
if ($this->validate()) {
$this->imageFile->saveAs('uploads/' . $this->imageFile->baseName . '.' . $this->imageFile->extension);
return true;
} else {
return false;
}
}
}
在以上代码里,imageFile
属性用于接收上传的文件实例。它对应一条file
验证规则, 该规则使用 yii\validators\FileValidator 来确保只上传扩展名为 png
或 jpg
的文件。 upload()
方法会执行该验证并且把上传的文件保存在服务器上。
通过 file
验证器,你可以检查文件的扩展名,大小,MIME类型等等。详情请查阅 Core Validatators 章节。
>提示: 如果你要上传的是一张图片,可以考虑使用image
验证器。 image
验证器是通过yii\validators\ImageValidator实现验证的,确保对应的模型属性 收到的文件是有效的图片文件,然后才保存,或者使用扩展类Imagine Extension进行处理.
接下来,在视图里创建一个文件输入控件
<?phpuse yii\widgets\ActiveForm;
?>
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]) ?>
<?= $form->field($model, 'imageFile')->fileInput() ?>
<button>Submit</button>
<?php ActiveForm::end() ?>
需要注意的是要记得在表单选项里加入 enctype
属性以确保文件能被正常上传。 fileInput()
方法会渲染一个 <input type="file">
标签,让用户可以选择一个文件上传。
现在,在控制器方法里编写连接模型和视图的代码以实现文件上传。
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()) {
// 文件上传成功
return;
}
}
return $this->render('upload', ['model' => $model]);
}
}
在上面的代码里,当提交表单的时候,yii\web\UploadedFile::getInstance()方法就被调用, 上传的文件用一个 UploadedFile
实例表示。然后,我们依靠模型的验证规则确保上传的文件是有效的, 并将文件保存在服务器上。
将前面所述的代码做一些调整,也可以一次性上传多个文件。
首先你得调整模型类,在 file
验证规则里增加一个 maxFiles
选项,用以限制一次上传文件的最大数量。 upload()
方法也得修改, 以便一个一个地保存上传的文件。
namespace app\models;
use yii\base\Model;
use yii\web\UploadedFile;
class UploadForm extends Model{
public $imageFiles;
public function rules()
{
return [
[['imageFiles'], 'file', 'skipOnEmpty' => false, 'extensions' => 'png, jpg', 'maxFiles' => 4],
];
}
public function upload()
{
if ($this->validate()) {
foreach ($this->imageFiles as $file) {
$file->saveAs('uploads/' . $file->baseName . '.' . $file->extension);
}
return true;
} else {
return false;
}
}
}
在视图文件里,你需要把 multiple
选项添加到fileInput()
函数调用里, 这样文件输入控件就可以接收多个文件。
<?phpuse yii\widgets\ActiveForm;
?>
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]) ?>
<?= $form->field($model, 'imageFiles[]')->fileInput(['multiple' => true, 'accept' => 'image
public $filename;
public $key;
protected $fileObject; // SplFileObject is very convenient for seeking to particular line in a file
public function init()
{
parent::init();
// open file
$this->fileObject = new SplFileObject($this->filename);
}
protected function prepareModels()
{
$models = [];
$pagination = $this->getPagination();
if ($pagination === false) {
// in case there's no pagination, read all lines
while (!$this->fileObject->eof()) {
$models[] = $this->fileObject->fgetcsv();
$this->fileObject->next();
}
} else {
// in case there's pagination, read only a single page
$pagination->totalCount = $this->getTotalCount();
$this->fileObject->seek($pagination->getOffset());
$limit = $pagination->getLimit();
for ($count = 0; $count < $limit; ++$count) {
$models[] = $this->fileObject->fgetcsv();
$this->fileObject->next();
}
}
return $models;
}
protected function prepareKeys($models)
{
if ($this->key !== null) {
$keys = [];
foreach ($models as $model) {
if (is_string($this->key)) {
$keys[] = $model[$this->key];
} else {
$keys[] = call_user_func($this->key, $model);
}
}
return $keys;
} else {
return array_keys($models);
}
}
protected function prepareTotalCount()
{
$count = 0;
while (!$this->fileObject->eof()) {
$this->fileObject->next();
++$count;
}
return $count;
}
}