本书未发布

69. 上传图片

未匹配的标注

简介

我们在本节完成 Simditor 编辑器里的上传图片功能。

需求分解

在编辑个人资料页面我们已经实现了上传图片功能,所以在本节我们将基于这个实现编辑器里的上传图片。

首先因为我们之前在编辑用户信息页面已经实现上传图片功能,所以我们打算尽量通过优化之前已有方法实现编辑器上传图片功能。

通过查询 编辑器上传图片文档 我们发现编辑器上传图片要求返回的数据格式必须是 JSON 格式,但它需要的 JSON 数据结构和控制器的 successerror 方法返回的结构不一样,所以我们在新增加一个控制器行为处理方法来处理编辑器上传图片功能。

Simditor 编辑器上传返回数据示例

{
  "success": true/false,
  "msg": "error message", # optional
  "file_path": "[real file path]"
}

数据模型

首先,我们优化一下 Upload::saveImage 使这个方法支持多种图片上传。

application/common/model/Upload.php

<?php

namespace app\common\model;

use think\Image;
use app\common\validate\Avatar as AvatarValidate;
use app\common\exception\ValidateException;

class Upload
{
   /**
    * 保存上传图片
    * @Author   zhanghong(Laifuzi)
    * @DateTime 2019-02-21
    * @param    File               $file         上传文件
    * @param    string             $type         文件类型
    * @param    string             $max_width    最大宽度
    * @return   object                           FunctionResult
    */
    public static function saveImage($file, $type, $max_width = 0){
        if($type == 'avatar'){
            $validate = new AvatarValidate;
            if(!$validate->batch(true)->check(['file' => $file])){
                $e = new ValidateException('上传图片失败');
                $e->setData($validate->getError());
                throw $e;
            }
        }

        $local_dir = 'uploads';
        $ds = DIRECTORY_SEPARATOR;
        $info = $file->rule('md5')->move($local_dir);
        $save_name = $info->getSaveName();
        $save_path = $ds.$local_dir.$ds.$save_name;

        $image = Image::open('.'.$save_path);
        //直接覆盖原图
        if($max_width > 0){
            //直接覆盖原图
            $image->thumb($max_width, $max_width)->save('.'.$save_path);
        }

        return [
            'ext' => $info->getExtension(),
            'save_path' => $save_path,
            'sha1' => $info->hash("sha1"),
            'md5' => $info->hash("md5"),
            'size' => $info->getSize(),
            'origin_name' => $file->getInfo('name'),
        ];
    }
}

代码解读

  • 我们给 Upload::saveImage 添加了一个新参数 $type,我们通过该参数来区分上传图片类型。只有当 $type=='avatar' 时才会调用使用 AvatarValidate 来验证上传的头像头片是否符合我们限制的条件;
  • 因为 $type 的参数值直接影响到方法里的处理逻辑(是否调用验证器),所以我们把这个参数添加到 $max_width 前面并不设置默认值。

控制器

因为 Simditor 编辑器上传图片要求后端程序返回的数据格式和我们之前完成的上传图片返回格式结构不同,所以我们首先在 Upload 控制器里添加一个新的控制( action )方法来处理编辑器上传图片功能并按编辑器需要的格式返回响应数据。

另外,因为我们给 Upload::saveImage 方法添加了参数 $type 所以,我们也需要修改一下 save_image 里的调用。

application/index/controller/Upload.php

<?php

namespace app\index\controller;

use think\Request;
use app\common\model\Upload as UploadModel;
use app\common\exception\ValidateException;

class Upload extends Base
{
    .
    .
    .
    private function save_image($request)
    {
        .
        .
        .

        if($request->isPost()){
            $file = $request->file('image');
            try{
                $upload_info = UploadModel::saveImage($file, 'avatar', 416);
                $image = $upload_info['save_path'];
            }catch(ValidateException $e){
                $errors = $e->getData();
                $error_msg = $errors['file'];
            }
        }

        .
        .
        .
    }

    public function simditor(Request $request)
    {
        $file = $this->request->file('upfile');
        try{
            $upload_info = UploadModel::saveImage($file, 'content', 1024);
            $data = [
                'status' => true,
                'msg' => '上传成功',
                'file_path' => $upload_info['save_path'],
            ];
        }catch(\Expection $e){
            $data = [
                'status' => false,
                'msg' => $e->getMessage(),
            ];
        }

        // 变量$data值已经是Simditor编辑器需要返回的格式了
        // 所以直接调用json()方法返回该数据
        return json($data);
    }
}

路由

在路由配置文件里定义新增控制器方法。

route/route.php

<?php
.
.
.
// 上传图片
Route::post('upload/simditor', 'upload/simditor')->name('upload.simditor');
Route::get('upload', 'upload/create')->name('upload.create');
Route::post('upload', 'upload/save')->name('upload.save');
.
.
.
  • 注意,upload.simditor 要定义在 upload.create 之前。

视图模板

最后,我们在表单页面里调用 upload.simditor 来上传图片:

application/index/view/topic/form.html

.
.
.
<script type="text/javascript">
    jQuery(function($){
        var editor = new Simditor({
            textarea: $('#body-field'),
            upload: {
              url: "{:url('[upload.simditor]')}",
              fileKey: 'upfile',
              connectionCount: 3,
              leaveConfirm: '文件上传中,关闭此页面将取消上传。'
            },
            pasteImage: true,
        });

        validAndSubmitForm(
            .
            .
            .
        );
    });
</script>
.
.
.

参数解释:

  • pasteImage —— 设定是否支持图片黏贴上传,这里我们使用 true 进行开启;
  • url —— 处理上传图片的 URL;
  • fileKey —— 是服务器端获取图片的键值,我们设置为 upload_file;
  • connectionCount —— 最多只能同时上传 3 张图片;
  • leaveConfirm —— 上传过程中,用户关闭页面时的提醒。

效果预览

Git 版本控制

--- delete ---
同头像上传类似的,我们在上传图片的时候,程序自动创建了 public/uploads/images/topics/ 目录,此文件夹下的图片文件都是用户上传的话题图片,我们需要防止这些文件被纳入 Git 版本控制器中,在该目录里创建 .gitignore 文件并让 Git 忽略该目录里的所有文件。

public/uploads/images/topics/.gitignore

*
!.gitignore

--- delete ---

下面把代码纳入到版本管理:

$ git add -A
$ git commit -m "用户可以上传话题图片"

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 只看当前版本


暂无话题~