ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## kartik-v/yii2-widget-fileinput 上传插件使用小结   使用Yii2开发项目的时候不免要用到文件上传,这里小结一下 [kartik-v/yii2-widget-fileinput](https://github.com/kartik-v/yii2-widget-fileinput) 插件的一些使用过程,以备查阅。   思路:图片上传使用统一的图片表关联存储图片在服务器上的相关信息,使用一个model子类渲染一个上传的视图,上传成功后利用回调函数将数据写入到隐藏域。 ### 安装插件 这里使用**composer**命令安装 [kartik-v/yii2-widget-fileinput](https://github.com/kartik-v/yii2-widget-fileinput)。 ``` composer require kartik-v/yii2-widget-fileinput "@dev" ``` ### 模型 #### 图片模型 ``` <?php namespace backend\models; use Yii; use yii\db\ActiveRecord; /** * This is the model class for table "{{%images}}". * * @property integer $id * @property string $url * @property integer $create_time * @property string $module * @property integer $status */ class Images extends ActiveRecord { // public $imageFile; /** * @inheritdoc */ public static function tableName() { return '{{%images}}'; } /** * @inheritdoc */ public function rules() { return [ [['url', 'create_time', 'module'], 'required'], [['created_at', 'status'], 'integer'], [['url'], 'string', 'max' => 255], [['module'], 'string', 'max' => 15], ]; } /** * @inheritdoc */ public function attributeLabels() { return [ 'id' => 'ID', 'url' => '图片路径', 'create_time' => '创建时间', 'module' => '模块', 'status' => '数据状态', ]; } } ``` #### 上传模型 ``` <?php namespace backend\models; use Yii; use yii\base\Model; /** * 上传文件必须配置两个参数 * * 1. 在 `/common/config/bootstrap.php` 文件中,配置`@uploadPath`的值,例如:`dirname(dirname(__DIR__)) . '/frontend/web/uploads'` * * 2. 在 `/backend/config/params.php` 文件中,配置`assetDomain`的值,例如:`http://localhost/yii2/advanced/frontend/web/uploads` * * Class UploadForm * @package backend\models */ class UploadForm extends Model { public $imageFile; public function rules() { return [ //数据验证这里可自己做 [['imageFile'], 'file', 'skipOnEmpty' => true, 'extensions' => 'png, jpg'], ]; } public function upload() { if ($this->validate()) { $path = Yii::getAlias('@uploadPath') . '/' . date("Ymd"); if (!is_dir($path) || !is_writable($path)) { \yii\helpers\FileHelper::createDirectory($path, 0777, true); } $filePath = $path . '/' . Yii::$app->request->post('model', '') . '_' . md5(uniqid() . mt_rand(10000, 99999999)) . '.' . $this->imageFile->extension; if ($this->imageFile->saveAs($filePath)) { //这里将上传成功后的图片信息保存到数据库 $imageUrl = $this->parseImageUrl($filePath); $imageModel = new Images(); $imageModel->url = $imageUrl; $imageModel->created_at = time(); $imageModel->status = 0; $imageModel->module = Yii::$app->request->post('model', ''); $imageModel->save(false); $imageId = Yii::$app->db->getLastInsertID(); return ['imageUrl' => $imageUrl, 'imageId' => $imageId]; } } return false; } /** * 这里在upload中定义了上传目录根目录别名,以及图片域名 * 将/var/www/html/advanced/frontend/web/uploads/20160626/file.png 转化为 http://statics.gushanxia.com/uploads/20160626/file.png * format:http://domain/path/file.extension * @param $filePath * @return string */ private function parseImageUrl($filePath) { if (strpos($filePath, Yii::getAlias('@uploadPath')) !== false) { return Yii::$app->params['assetDomain'] . str_replace(Yii::getAlias('@uploadPath'), '', $filePath); } else { return $filePath; } } } ``` ### 视图文件 ``` <?php $form = ActiveForm::begin([ 'options' => [ 'class' => 'form-horizontal', ], 'fieldConfig' => [ // 'template' => "<div class='row'><div class='col-lg-1 text-right text-fixed'>{label}</div><div class='col-lg-9'>{input}</div><div class='col-lg-2 errors'>{error}</div></div>", ] ]); ?> <?= $form->field($model, 'image_id')->hiddenInput()->label(false); ?> <?= $form->field($upload, 'imageFile')->widget(\kartik\file\FileInput::className(), [ 'options' => [ 'accept' => 'images/*', 'module' => 'Goods', 'multipe' => false, ], 'pluginOptions' => [ // 异步上传的接口地址设置 'uploadUrl' => \yii\helpers\Url::to(['upload']), 'uploadAsync' => true, // 异步上传需要携带的其他参数,比如商品id等,可选 'uploadExtraData' => [ 'model' => 'goods' ], // 需要预览的文件格式 'previewFileType' => 'image', // 预览的文件 'initialPreview' => $p1 ?: '', // 需要展示的图片设置,比如图片的宽度等 'initialPreviewConfig' => $p2 ?: '', // 是否展示预览图 'initialPreviewAsData' => true, // 最少上传的文件个数限制 'minFileCount' => 1, // 最多上传的文件个数限制,需要配置`'multipe'=>true`才生效 'maxFileCount' => 10, // 是否显示移除按钮,指input上面的移除按钮,非具体图片上的移除按钮 'showRemove' => false, // 是否显示上传按钮,指input上面的上传按钮,非具体图片上的上传按钮 'showUpload' => true, //是否显示[选择]按钮,指input上面的[选择]按钮,非具体图片上的上传按钮 'showBrowse' => true, // 展示图片区域是否可点击选择多文件 'browseOnZoneClick' => true, // 如果要设置具体图片上的移除、上传和展示按钮,需要设置该选项 'fileActionSettings' => [ // 设置具体图片的查看属性为false,默认为true 'showZoom' => true, // 设置具体图片的上传属性为true,默认为true 'showUpload' => true, // 设置具体图片的移除属性为true,默认为true 'showRemove' => true, ], ], //网上很多地方都没详细说明回调触发事件,其实fileupload为上传成功后触发的,三个参数,主要是第二个,有formData,jqXHR以及response参数,上传成功后返回的ajax数据可以在response获取 'pluginEvents' => [ 'fileuploaded' => "function (object,data){ $('.field-goods-name').show().find('input').val(data.response.imageId); }", //错误的冗余机制 'error' => "function (){ alert('图片上传失败'); }" ] ]); ?> <div class="form-group"> <?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?> </div> <?php ActiveForm::end(); ?> ``` ### 控制器渲染页面效果 ``` public function actionCreate() { $model = new Goods(); if ($model->load(Yii::$app->request->post()) && $model->save()) { return $this->redirect(['view', 'id' => $model->id]); } else { return $this->render('create', [ 'model' => $model, 'upload' => new UploadForm() ]); } } /** * Updates an existing Goods model. * If update is successful, the browser will be redirected to the 'view' page. * @param integer $id * @return mixed */ public function actionUpdate($id) { $model = $this->findModel($id); $upload = new UploadForm(); $relationImage = Images::find()->where(['id' => $model->name])->one(); $p1 = $p2 = []; if ($relationImage) { $p1 = $relationImage->url; $p2 = [ 'url' => Url::to(['delete']), 'key' => $relationImage->id, ]; } if ($model->load(Yii::$app->request->post()) && $model->save()) { return $this->redirect(['view', 'id' => $model->id]); } else { return $this->render('update', [ 'model' => $model, 'upload' => $upload, 'p1' => $p1, 'p2' => $p2, ]); } } public function actionUpload() { $uploadForm = new UploadForm(); if(Yii::$app->request->isPost){ $uploadForm->imageFile = UploadedFile::getInstance($uploadForm, 'imageFile'); if($imageUrl = $uploadForm->upload()){ echo Json::encode([ 'imageUrl' => $imageUrl, 'error' => '' //上传的error字段,如果没有错误就返回空字符串,否则返回错误信息,客户端会自动判定该字段来认定是否有错 ]); }else{ echo Json::encode([ 'imageUrl' => '', 'error' => '文件上传失败' ]); } } } ``` 附上`goods`和`images`表结构: ```sql CREATE TABLE `rotatain` ( `id` int(11) NOT NULL AUTO_INCREMENT, `image_id` int(11) NOT NULL COMMENT '图片id', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; CREATE TABLE `images` ( `id` int(11) NOT NULL AUTO_INCREMENT, `url` varchar(255) NOT NULL COMMENT '图片路径', `created_at` int(11) unsigned NOT NULL COMMENT '创建时间', `module` char(15) NOT NULL COMMENT '模块', `status` smallint(6) NOT NULL DEFAULT '0' COMMENT '数据状态', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCsaREMENT=1 DEFAULT CHARSET=utf8; ```