利用微信jssdk上传图片,并保存到本地

项目需求:

项目一开始使用第三方cdn,七牛服务器上传图片,但是因为项目设计到很多身份证,营业执照等照片的上传,怕上传到这些cdn上面,消息泄露,所以将上传到第三方,改为上传到本地,七牛上传在之前的文章中有提到过,这里就不细说了,那么,接下了,我给大家讲一下laravel上传图片到本地的代码实现吧。

首先你需要了解plupload.js的相关知识:

define(['jquery', 'plupload', 'utils', 'locale'], function ($, plupload, utils, Locale) {
    var sdk = {};
    var defaultSetting = {
        multi_selection: false,
        file_data_name: 'image',
        flash_swf_url: '/static/libs/plupload/Moxie.swf',
        auto_start: true,
        url: '/service/cdn/upload',
        headers: {
            'X-XSRF-TOKEN': $.cookie('XSRF-TOKEN')
        }
    };


    sdk.uploader = function (settings) {
        var options = {};


        plupload.extend(options, defaultSetting, settings);


        var backupFileUploadedHandler = options.init && options.init.FileUploaded;
        if (backupFileUploadedHandler) {
            options.init.FileUploaded = function () {};
        }


        var uploadedErrorHandler = options.init && options.init.Error;
        if (uploadedErrorHandler) {
            options.init.Error = function () {};
        }


        var uploader = new plupload.Uploader(options);


        // bind 'FilesAdded' event
        uploader.bind('FilesAdded', function (up, files) {
            var autoStart = up.getOption && up.getOption('auto_start');
            autoStart = autoStart || (up.settings && up.settings.auto_start);


            if (autoStart) {
                setTimeout(function (){
                    up.start();
                }, 0);
            }


            // Reposition Flash/Silverlight
            up.refresh();
        });


        // bind 'FileUploaded' event
        uploader.bind('FileUploaded', (function (fileUploadedHandler) {
            return function (up, file, info) {
                var response = $.parseJSON(info.response);
                if (response.status == 'SUCCESS') {
                    if (fileUploadedHandler) {
                        fileUploadedHandler(up, file, response.body);
                    }
                } else {
                    utils.showMessage(Locale.t('errors.upload_image_failed'));
                }
            };
        })(backupFileUploadedHandler));


        uploader.bind('Error', (function(uploadedErrorHandler) {
            return function(up, err) {
                var errTip = '';
                var file = err.file;
                if (file) {
                    switch (err.code) {
                        case plupload.FAILED:
                            errTip = Locale.t('errors.upload_image_failed');
                            break;
                        case plupload.FILE_SIZE_ERROR:
                            var max_file_size = up.getOption && up.getOption('max_file_size');
                            max_file_size = max_file_size || (up.settings && up.settings.max_file_size);
                            errTip = Locale.t('errors.img_size_error', {size: max_file_size});
                            break;
                        case plupload.FILE_EXTENSION_ERROR:
                            errTip = Locale.t('errors.img_type_error');
                            break;
                        default:
                            errTip = Locale.t('errors.upload_image_failed');
                            break;
                    }
                }
                uploadedErrorHandler(up, err, errTip);
            };
        })(uploadedErrorHandler));


        uploader.init();


        return uploader;
    };


    return sdk;
});

该js复写了plupload.js,在qiniu上传的js基础上进行的修改,

在自定义的js文件中使用uploader.js,

var providerLicenseUpload = Uploader.uploader({
            runtimes: 'html5,flash,html4',
            browse_button: 'provider-license-upload',
            max_file_size: '1mb',
            dragdrop: false,
            auto_start: true,
            filters: {
                mime_types: [
                    {
                        title : 'Image files',
                        extensions : 'jpg,jpeg,gif,png'
                    }
                ]
            },
            init: {
                FileUploaded: function (up, file, info) {
                    $('#provider-license-img').attr('src', info.url).closest('.license-wrapper').show();
                    $('#provider-license').val(info.key);
                },
                Error: function (up, err, errTip) {
                    utils.showMessage(errTip);
                }
            }

});

后台上传图片的代码:

public function uploadImage(Request $request)
    {
        $this->validate($request, [
            'image' => 'required|file|image',
        ]);


        $file = $request->file('image');


        $key = $request->input('key');


        $result = app('cdn')->save($file, $key);


        if (!$result) {
            return response()->json(format_json_failed('request_failed'));
        }


        $data = [
            'url' => $result['url'],
            'key' => $result['key'],
        ];


        return response()->json(format_json_success($data));
    }


    public function save($file, $key = null)
    {
        if ($key === null) {
            $key = md5($file->path() . time() . mt_rand(1, 1000)) .'.' . $file->extension();
        }


        $path = Storage::disk($this->disk)->putFileAs($this->folder, $file, $key);


        if ($path) {
            return [
                'url' => $this->domain . '/' . $path,
                'key' => $key,
            ];
        }


        return false;
    }

当你以为这样就结束的时候,你错了,有需求需要在个人资料编辑的时候,调用微信的相机。。。微信的相机耶,好高大上的样子

显然,这里需要使用微信的jssdk,具体使用方法,请查看,微信jssdk说明文档:

https://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html

好的下面开始进入正题:

案例:图片上传到微信(该上传为临时上传,只能在微信服务器中保存3天),那么我们需要再次下载到本地,持久化存储。

ok,代码写起来:

(1)微信jssdk上传头像:

define(['jquery', 'wechat_jssdk', 'utils', 'locale'], function ($, wx, utils, Locale) {
    var shareConfig = APP_CONFIG.wechat,
        image = {};


    var _initConfig = function() {
        if (shareConfig.is_wechat == 0) {
            return;
        }


        wx.config({
            debug: (shareConfig.debug == 1) ? true : false,
            appId: shareConfig.appId,
            timestamp: shareConfig.timestamp,
            nonceStr: shareConfig.nonceStr,
            signature: shareConfig.signature,
            jsApiList: [
                'chooseImage',
                'uploadImage'
            ]
        });
    };


    var _initUpload = function(callback) {
        wx.ready(function() {
            wx.chooseImage({
                count: 1,
                sizeType: ['original', 'compressed'],
                sourceType: ['album', 'camera'],
                success: function (res) {
                    var localIds = res.localIds;
                    wx.uploadImage({
                        localId: localIds[0],
                        isShowProgressTips: 1,
                        success: function (res) {
                            var serverId = res.serverId;
                            $.ajax({
                                url: '/service/cdn/download',
                                data: {
                                    media_id: serverId
                                },
                                type: 'post'
                            }).done(function(response) {
                                if (response.status == 'SUCCESS') {
                                    var image = response.body;
                                    callback(image);
                                } else {
                                    utils.showMessage(Locale.t('errors.system_error'));
                                }
                            });
                        }
                    });
                }
            });
        });
    };


    return {
        initConfig: _initConfig,
        initUpload: _initUpload
    };
});


WeChatUpload.initConfig();
        $('#avatar').on('click', function() {
            WeChatUpload.initUpload(function(image) {
                var imageUrl = image['url'];
                var imageKey = image['key'];
                if (imageUrl && imageKey) {
                    $('#avatar-input').val(imageKey);
                    $('#avatar').attr('src', imageUrl);
                }
            });
        });

initConfig执行一次,initUpload每次点击头像时执行,jssdk是很简单的,那么这里最重要的是该如何在上传到微信服务器,然后从微信服务器下载,并且保存到本地的指定目录呢?OK,让我来用代码来征服你吧。。。让你爱上我。。。

public function downloadImage(Request $request)
    {
        $mediaId = $request->input('media_id');
        $media = app('wechat.mp')->getMedia($mediaId);

        $key = md5($mediaId . time() . mt_rand(1, 1000)) . '.jpg';

        // save image
        $filePath = config('filesystems.disks.ugc.root', base_path('www-ugc')) . '/image/' . $key;
        $file = fopen($filePath, 'w+');
        fwrite($file, $media);
        fclose($file);

        if(!file_exists($filePath))
        {
            return response()->json(format_json_failed('request_failed'));
        }

        $data = [
            'key' => $key,
            'url' => app('cdn')->getResourceUrl($key)
        ];

        return response()->json(format_json_success($data));
    }
好吧,就这样,这里要解释一下getMedia这个方法,参数是使用jssdk上传之后返回的serverId,该方法其实是请求一个微信的连接:

http请求方式: GET
http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID
请求示例(示例为通过curl命令获取多媒体文件)
curl -I -G "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID"
这个在微信jssdk文档中有提过,记住一定要先看该文档哟,一定,一定,一定哟~~~该方法神奇的给你下载图片,但是在代码里是给你返回的二进制流,这个时候,寡人百度了又百度,谷歌了又谷歌,找到了php写入文件流的方法,保存图片,那就是神奇的:

fopen+fwrite+fclose,ok就这样,可以将二进制数据,保存到本地,(其实图片就是二进制数据,只是变现格式不一样,你把图片用sublime打开,就是一串字符集编码)。


好吧,到这里也许已经很多人爱上了我,但是,但是,此时此刻,我爱上了我的leader,(本人大学刚毕业。。。leader已n年工作经验),好吧,不得不爱上他,来开开他的后台下载微信图片,并保存到本地的方法吧。。。

    if (!function_exists('mime_type_to_image_type')) {
        function mime_type_to_image_type($mimeType)
        {
            $mimeTypes = [
                'image/gif' => IMAGETYPE_GIF,
                'image/jpeg' => IMAGETYPE_JPEG,
                'image/png' => IMAGETYPE_PNG,
                'application/x-shockwave-flash' => IMAGETYPE_SWF,
                'image/psd' => IMAGETYPE_PSD,
                'image/bmp' => IMAGETYPE_BMP,
                'image/tiff' => IMAGETYPE_TIFF_II,
                'image/jp2' => IMAGETYPE_JP2,
                'image/iff' => IMAGETYPE_IFF,
                'image/vnd.wap.wbmp' => IMAGETYPE_WBMP,
                'image/xbm' => IMAGETYPE_XBM,
                'image/vnd.microsoft.icon' => IMAGETYPE_ICO,
            ];
            return array_get($mimeTypes, $mimeType, false);
        }
    }

//复写了wechat.class.php中的getMedia方法

public function getImage($mediaId)
    {
        if (!$this->access_token && !$this->checkAuth()) {
            return false;
        }


        $url = self::API_URL_PREFIX . self::MEDIA_GET_URL;
        $query = [
            'access_token' => $this->access_token,
            'media_id' => $mediaId,
        ];


        $client = new Client();
        $response = $client->get($url, [
            'query' => $query,
        ]);


        if ($response->getStatusCode() != 200) {
            return false;
        }


        $result = [];


        $contentType = $response->getHeader('Content-Type');
        $imageType = mime_type_to_image_type(array_shift($contentType));
        if ($imageType !== false) {
            $result['image_type'] = $imageType;
        }


        $result['data'] = $response->getBody();


        return $result;
    }


    public function downloadImage(Request $request)
    {
        $mediaId = $request->input('media_id');
        // $mediaId = '_Eb3yhich_NAfrE10lhEmuLl6WCU2ICTD7SRZGFtNP2FY4kX63Q-QLWi1tJ7aVdz';
        $imageResult = app('wechat.mp')->getImage($mediaId);
        if ($imageResult === false) {
            return response()->json(format_json_failed('request_failed'));
        }


        $imageType = array_get($imageResult, 'image_type');
        $extension = '.jpg';
        if ($imageType) {
            $extension = image_type_to_extension($imageType);
        }


        $key = md5($mediaId . time() . mt_rand(1, 1000)) . $extension;
        $path = 'temp/' . $key;


        // save image to temp folder
        $result = Storage::disk('local')->put($path, $imageResult['data']);


        if (!$result) {
            return response()->json(format_json_failed('request_failed'));
        }


        // save image to cdn
        $filePath = rtrim(config('filesystems.disks.local.root'), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $path;
        $file = new File($filePath);
        $cdn = app('cdn');
        $data = $cdn->save($file, $key);


        if ($data) {
            return response()->json(format_json_success($data));
        } else {
            return response()->json(format_json_failed('request_failed'));
        }
    }


这里和上面的upload使用了同一套save方法,个人觉得并没有什么不同,都是保存图片到本地,这样非得作,但是我还是深深的爱上了他。。。好吧,也许看了这么多代码,很多小朋友也不是很了解,如果有疑问,欢迎线下来找,我们互相探讨,不行我还有我leader,哈哈哈!!!


你可能感兴趣的:(php,php之laravel,js前台知识,服务器)