laravel如何异步上传图片并重命名?

本来是一个同步上传的功能,后来需求变化,只能改成异步,
前端页面长酱紫的:

{{-- Upload File Modal --}}
<div class="modal fade" id="modal-file-upload">
  <div class="modal-dialog">
    <div class="modal-content">
      <form  id="file-upload-form" method="POST" action="/admin/upload/file"
            class="form-horizontal" enctype="multipart/form-data">
        <input type="hidden" id="file-upload" name="_token" value="{{ csrf_token() }}">
        <input type="hidden" id="file-upload" name="folder" value="{{ $folder }}">
        <div class="modal-header">
          <button type="button" class="close" data-dismiss="modal">
            &times;
          </button>
          <h4 class="modal-title">上传新的文件</h4>
        </div>
        <div class="modal-body">
          <div class="form-group">
            <label for="file" class="col-sm-3 control-label">
              文件
            </label>
            <div class="col-sm-8">
              <input type="file" id="file" name="file">
            </div>
          </div>
          <div class="form-group">
            <label for="file_name" class="col-sm-3 control-label">
              选择上传到的文件夹/命名并上传或直接命名并上传
            </label>
            <div class="col-sm-4">
              <input type="text" id="file_name" name="file_name"
                     class="form-control">
            </div>
          </div>
        </div>
        <div class="modal-footer">
          <button type="button" class="btn btn-default" data-dismiss="modal">
            取消
          </button>
          <button type="submit" class="btn btn-primary" onclick="handle_upload_image()" >
            上传文件
          </button>
        </div>
      </form>

    </div>
  </div>
</div>

其中别的都不重要的,主要是id=file id=file_name 这两个,还有最后的submit的按钮,原先重命名是在后端的控制器在存储过程中进行的:

 public function uploadFile(UploadFileRequest $request)
    {
        $file = $_FILES['file'];
        $fileName = $request->get('file_name');
        $fileName = $fileName ?: $file['name'];
        $path = str_finish($request->get('folder'), '/') . $fileName;
        $content = File::get($file['tmp_name']);
        $homes = home::where('image_name',$fileName)->get();
        if($homes->count())
        {
            $error =  "File already exists";
            return redirect()
                ->back()
                ->withErrors([$error]);
        }
        $syncfileditle = home::create(  [
        'image_name'=>$fileName,
        'show_image'=>0,
            'webPath'=>$path
    ]);
        $result = $this->manager->saveFile($path, $content);
        if ($result === true) {
            return redirect()
                ->back()
                ->withSuccess("文件 '$syncfileditle->image_name' 已上传");
        }

        $error = $result ? : "上传文件引发了一个错误";
        return redirect()
            ->back()
            ->withErrors([$error]);
    }

现在怕是只能再重新写一个控制函数,并且注册路由去实现一遍,问题是怎样实现异步上传图片呢?(AJAX具体怎么用,完全没有头绪QAQ)

阅读 4.3k
1 个回答

使用canvas压缩图片然后ajax上传(这可是扒了生产上在跑的代码。。效果就是点击上传按钮--选择完图片--确定--图片开始上传至服务器--完成后返回图片路径到隐藏域中--最后将该隐藏域的路径保存到数据库即可):

// 前端:
<div id="photo1">
    <input type="file" id="icon_pic" data-path="user/level" onClick="uploadPhoto('#icon_pic','photo1')"/>
    <!-- 上传过的就话就读取出来 -->
    <img src="">
    <input type="hidden" name="icon_pic" value="{{ $icon_pic }}">
</div>
<script>
// todo.. 可优化成无需传js参数即可上传
//AJAX上传base64
function base64_uploading(base64, nameid, target) {
    $.ajax({
        type: 'POST',
        url: upload_route(),
        data: {
            '_token': csrf_token(),
            'base64': base64,
            'path': $("#" + nameid).data('path') || 'goods'
        },
        dataType: 'json',
        timeout: 50000,
        success: function(data) {
            // 如果有-表示是多个图
            if(nameid.indexOf('-') != -1){
                var temp = nameid.split('-');
                nameid = temp[0] + '[' + temp[1] + ']';
            }
            if (data.status == 1) {
                var submit_input = $("input[name='" + nameid + "']");

                if (submit_input.length == 1) {
                    submit_input.val(data.url);
                } else {
                    var inputs = document.createElement('input');
                    inputs.setAttribute('type', 'hidden');
                    inputs.setAttribute('name', nameid);
                    inputs.value = data.url;
                    document.getElementById(target).appendChild(inputs);
                }
            }
        },
        error: function(req, msg) {
            log_system('上传图片失败:' + msg);
        }
    })
}

function uploadPhoto(input, target) {
    document.querySelector(input).onchange = function(evt) {
        var files = evt.target.files;
        var nameid = evt.target.id;

        $("#"+target).find('img').hide();
        
        for (var i = 0, f; f = files[i]; i++) {
            if (!f.type.match('image.*')) continue;

            var reader = new FileReader();
            reader.onload = (function(theFile) {
                return function(e) {
                    var img = document.createElement('img');
                    img.title = theFile.name;
                    img.src = e.target.result;
                    img.setAttribute('data-img', 'uploadImg');
                    document.getElementById(target).appendChild(img);

                    compressImg(reader.result, 800, theFile.type, function(data) { //压缩完成后执行的callback
                        base64_uploading(data, nameid, target);

                    });
                }
            })(f);
            reader.readAsDataURL(f);
            $(this).parent().prev().show();
        }
    }
}

function compressImg(imgData, maxHeight, img_type, onCompress) {
    if (!imgData) return;
    onCompress = onCompress || function() {};
    maxHeight = maxHeight || 800; //默认最大高度200px

    var canvas = document.createElement('canvas');
    var img = new Image();
    // 记住必须先绑定事件,才能设置src属性,否则img没内容可以画到canvas
    img.src = imgData;
    img.onload = function() {
        var cw = img.width;
        var ch = img.height;
        var w = img.width;
        var h = img.height;
        canvas.width = w;
        canvas.height = h;
        if (cw > 1000 && cw > ch) {
            w = 1000;
            h = (1000 * ch) / cw;
            canvas.width = w;
            canvas.height = h;
        }
        if (ch > 1000 && ch > cw) {
            h = 1000;
            w = (1000 * cw) / ch;
            canvas.width = w;
            canvas.height = h;
        }
        var ctx = canvas.getContext("2d");
        //重置canvans宽高 canvas.width = img.width; canvas.height = img.height;
        ctx.clearRect(0, 0, canvas.width, canvas.height); // canvas清屏
        ctx.drawImage(img, 0, 0, w, h); // 将图像绘制到canvas上 

        onCompress(canvas.toDataURL(img_type)); //必须等压缩完才读取canvas值,否则canvas内容是黑帆布
    };
}
</script>

// 后端:
/**
 * 上传图片接收地址
 * @param Request $request
 */
public function uploadPhoto (Request $request, PhotoRepository $photo)
{
    $base64 = $request->input('base64');  //图片文件
    $path = $request->input('path');  //图片路径

    $md5_file = md5_file($base64);

    $photo_info = $photo->findWithoutFail($md5_file);
    if (!empty($photo_info)) {
        $ary['status'] = 1;
        $ary['info'] = '图片已存在';
        $ary['url'] = $photo_info->url;
        return $ary;
    }
    $ary = base64imgsave($base64,$path);
    if ($ary['status'] == 1 ){
        $photo->insert($md5_file, $ary['url']);
    }
    return $ary;
}

/**
 * base64上传的图片储存到服务器本地
 * @param  base64 $img
 * @param string $path_name
 * @return multitype:number string |string
 */
function base64imgsave($img,$path_name = ''){

    $ymd = date("Ymd"); //图片路径地址
    if (!empty($path_name)) {
        $basedir = 'uploads/'.$path_name.'/'.$ymd.'';
    }else{
        $basedir = 'uploads/base64/'.$ymd.'';
    }

    $fullpath = $basedir;
    if(!is_dir($fullpath)){
        mkdir($fullpath,0777,true);
    }
    $types = empty($types)? array('jpg', 'gif', 'png', 'jpeg'):$types;

    $img = str_replace(array('_','-'), array('/','+'), $img);

    $b64img = substr($img, 0,100);

    if(preg_match('/^(data:\s*image\/(\w+);base64,)/', $b64img, $matches)){
         
        $type = $matches[2];
        if(!in_array($type, $types)){
            return array('status'=>1,'info'=>'图片格式不正确,只支持 jpg、gif、png、jpeg哦!','url'=>'');
        }
        $img = str_replace($matches[1], '', $img);
        $img = base64_decode($img);
        $photo = '/'.md5(date('YmdHis').rand(1000, 9999)).'.'.$type;
        file_put_contents($fullpath.$photo, $img);
         
        $ary['status'] = 1;
        $ary['info'] = '保存图片成功';
        $ary['url'] = $basedir.$photo;
         
        return $ary;

    }

    $ary['status'] = 0;
    $ary['info'] = '请选择要上传的图片';
     
    return $ary;
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题