Home  >  Article  >  WeChat Applet  >  WeChat JS-SDK image interface development

WeChat JS-SDK image interface development

高洛峰
高洛峰Original
2017-03-01 09:29:511788browse

I use the image interface of WeChat JSSDK to develop it to implement the image upload function. Why did I choose this interface? First, the current project is a web page opened in WeChat. Using this interface, the performance will definitely be better. After all, it is WeChat’s own thing; second, using this interface, the development efficiency will be higher; third, finally The important point is that it can compress images. For example, if a 2M image is used, the image can be compressed into a size of several hundred K through the WeChat image upload interface, which is very helpful for the performance of the website.

1. My idea is:

First call the "photograph or select a picture from the mobile phone album interface" -> After selecting a successful picture -> call the 'upload picture interface' -> After the upload is successful (that is, the image is uploaded to the WeChat server) -> Call the "Download Image Interface" -> Download the image to your own server for storage.

2. Steps for using JSSDK

1. Overview

WeChat JS-SDK is a WeChat-based WeChat public platform for web developers. web development toolkit.

By using WeChat JS-SDK, web developers can use WeChat to efficiently use the capabilities of mobile phone systems such as taking pictures, selecting pictures, voice, and location. At the same time, they can directly use WeChat to share, scan, and coupons. WeChat’s unique capabilities such as payment provide WeChat users with a better web experience.

2. Steps to use

Step 1: Bind domain name

First log in to the WeChat public platform and enter the "Function Settings" of "Official Account Settings" to fill in "JS Interface Security" domain name".

Note: After logging in, you can view the corresponding interface permissions in the "Developer Center".

Step 2: Import JS files

Import the following JS files on the page that needs to call the JS interface (https is supported): http://res.wx.qq.com/open/js /jweixin-1.0.0.js

Step 3: Inject permission verification configuration through the config interface

All pages that need to use JS-SDK must first inject configuration information, otherwise it will not be called (same as A URL only needs to be called once, and the SPA web app that changes the URL can be called every time the URL changes)

wx.config({
    debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
    appId: '', // 必填,公众号的唯一标识
    timestamp: , // 必填,生成签名的时间戳
    nonceStr: '', // 必填,生成签名的随机串
    signature: '',// 必填,签名,见附录1
    jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});

Step 4: Process successful verification through the ready interface

wx.ready(function(){

    // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
});

Step 5 : Handling failed verification through error interface

wx.error(function(res){

    // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。

});

Interface calling instructions

All interfaces are called through wx objects (jWeixin objects can also be used). The parameter is an object, except that each interface itself needs to be passed In addition to the parameters, there are the following general parameters:

  1. success: the callback function executed when the interface call is successful.

  2. fail: The callback function executed when the interface call fails.

  3. complete: The callback function executed when the interface call is completed, regardless of success or failure.

  4. cancel: The callback function when the user clicks cancel. It is only used by some APIs where the user cancels the operation.

  5. trigger: A method that is triggered when a button in the Menu is clicked. This method only supports related interfaces in the Menu.

Note: Do not try to use ajax asynchronous request in the trigger to modify the content of this share, because the client sharing operation is a synchronous operation, and the return packet using ajax will not be available at this time. return.


The above functions all have one parameter, which is of type object. In addition to the data returned by each interface itself, there is also a general attribute errMsg, whose value format is as follows:

    1. When the call is successful: "xxx:ok", where xxx is the interface name of the call

    2. When the user cancels: "xxx:cancel" , where xxx is the name of the called interface

    3. When the call fails: its value is the specific error message

 

3. Detailed explanation of development and code analysis (CI framework is used, as long as it is MVC mode)

1. First obtain on the server side: the unique identifier appId of the public account, and the timestamp of the generated signature , generate a signed random string nonceStr and signature signature.

<?php
class wx_upload extends xx_Controller {
    public function __construct() {
        parent::__construct();
    }
 
    public function wxUploadImg() {
        //在模板里引入jssdk的js文件
        $this->addResLink('http://res.wx.qq.com/open/js/jweixin-1.0.0.js');
        //取得:公众号的唯一标识appId、生成签名的时间戳timestamp、生成签名的随机串nonceStr、签名signature这些值,并以json形式传到模板页面
        $this->smartyData['wxJsApi'] = json_encode(array('signPackage' => $this->model->weixin->signPackage()));
    }

Image upload controller

<?php
    class WxModel extends ModelBase{
        public $appId;
        public $appSecret;
        public $token;

        public function __construct() {
            parent::__construct();

            //审核通过的移动应用所给的AppID和AppSecret
            $this->appId = 'wx0000000000000000';
            $this->appSecret = '00000000000000000000000000000';
            $this->token = '00000000';
        }

        /**
         * 获取jssdk所需参数的所有值
         * @return array
         */
        public function signPackage() {
            $protocol = (!empty($_SERVER['HTTPS'] && $_SERVER['HTTPS'] == 'off' || $_SERVER['port'] == 443)) ? 'https://' : 'http://';
            //当前网页的URL
            $url = "$protocol$_SERVER['host']$_SERVER['REQUEST_URI']";
            //生成签名的时间戳
            $timestamp = time();
            //生成签名的随机串
            $nonceStr = $this->createNonceStr();
            //获取公众号用于调用微信JS接口的临时票据
            $jsApiTicket = $this->getJsApiTicket();
            //对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,
            //使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串$str。
            //这里需要注意的是所有参数名均为小写字符
            $str = "jsapi_ticket=$jsApiTicket&noncestr=$nonceStr&timestamp=$timestamp&url=$url";
            //对$str进行sha1签名,得到signature:
            $signature = sha1($str);
            $signPackage = array(
                "appId"     => $this->AppId,
                "nonceStr"  => $nonceStr,
                "timestamp" => $timestamp,
                "url"       => $url,
                "signature" => $signature,
                "rawString" => $string
                );
            return $signPackage;
        }

        /**
         * 创建签名的随机字符串
         * @param  int $length 字符串长度
         * @return string      随机字符串
         */
        private function createNonceStr($length == 16) {
            $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
            $str = '';
            for ($i=0; $i < $length; $i++) { 
                $str .= substr(mt_rand(0, strlen($chars)), 1);
            }
            return $str;
        }

        /**
         * 获取公众号用于调用微信JS接口的临时票据
         * @return string 
         */
        private function getJsApiTicket() {
            //先查看redis里是否存了jsapi_ticket此值,假如有,就直接返回
            $jsApiTicket = $this->library->redisCache->get('weixin:ticket');
            if (!$jsApiTicket) {
                //先获取access_token(公众号的全局唯一票据)
                $accessToken = $this->getApiToken();
                //通过access_token 采用http GET方式请求获得jsapi_ticket
                $result = $this->callApi("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=$accessToken&type=jsapi");
                //得到了jsapi_ticket
                $jsApiTicket = $result['ticket'];
                //将jsapi_ticket缓存到redis里面,下次就不用再请求去取了
                $expire = max(1, intval($result['expire']) - 60);
                $this->library->redisCache->set('weixin:ticket', $jsApiTicket, $expire);
            }
            return $jsApiTicket;
        }

        /**
         * 获取众号的全局唯一票据access_token
         * @param  boolean $forceRefresh 是否强制刷新
         * @return string                返回access_token
         */
        private function getApiToken($forceRefresh = false) {
            //先查看redis是否存了accessToken,如果有了,就不用再去微信server去请求了(提高效率)
            $accessToken = $this->library->redisCache->get('weixin:accessToken');
            //强制刷新accessToken或者accessToken为空时就去请求accessToken
            if ($forceRefresh || empty($accessToken)) {
                //请求得到accessToken
                $result = $this->callApi("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$this->appId}&secret={$this->appSecret}");
                $accessToken = $result['access_token'];
                $expire = max(1, intval($result['expire']) - 60);
                //将其存进redis里面去
                $this->library->redisCache->set('weixin:accessToken', $accessToken, $expire);
            }
            return $accessToken;
        }

Get appId, nonceStr, timestamp, signature model

Here are some ideas and points to pay attention to when using the permission signature algorithm of JS-SDK (Here I directly copy the official website document for everyone to see)

jsapi_ticket

Before generating a signature, you must first understand jsapi_ticket. jsapi_ticket is a temporary ticket used by public accounts to call the WeChat JS interface. Under normal circumstances, the validity period of jsapi_ticket is 7200 seconds and is obtained through access_token. Since the number of api calls to obtain jsapi_ticket is very limited, frequent refresh of jsapi_ticket will result in limited api calls and affect their own business. Developers must cache jsapi_ticket globally in their own services.

1. Obtain access_token (valid for 7200 seconds, developers must cache access_token globally in their own services)

2. Use the access_token obtained in the first step to request jsapi_ticket using http GET method ( Validity period is 7200 seconds, developers must cache jsapi_ticket globally in their own services)

      https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi

    成功返回如下JSON:

{
"errcode":0,
"errmsg":"ok",
"ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA",
"expires_in":7200
}

    获得jsapi_ticket之后,就可以生成JS-SDK权限验证的签名了。

    

    签名算法

    签名生成规则如下:参与签名的字段包括noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳), url(当前网页的URL,不包含#及其后面部分) 。对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1。这里需要注意的是所有参数名均为小写字符。对string1作sha1加密,字段名和字段值都采用原始值,不进行URL 转义。
    即signature=sha1(string1)。 示例:


    • noncestr=Wm3WZYTPz0wzccnW

    • jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg

    • timestamp=1414587457

    • url=http://mp.weixin.qq.com?params=value

    步骤1. 对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1:

      jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW&timestamp=1414587457&url=http://www.php.cn/

    步骤2. 对string1进行sha1签名,得到signature:

      0f9de62fce790f9a083d5c99e95740ceb90c27ed

    注意事项

      1.签名用的noncestr和timestamp必须与wx.config中的nonceStr和timestamp相同。

      2.签名用的url必须是调用JS接口页面的完整URL。

      3.出于安全考虑,开发者必须在服务器端实现签名的逻辑。

 

   2、取到我们所需要的值后,就在js文件里面开始使用了

  uploadImg.tpl

<script>
        $(function(){
            $.util.wxMenuImage('{$wxJsApi|default:""}')
        });
</script>

   uploadImg.js

if(typeof($util)=='undefined')$util={};

$.util.wxMenuImage = function(json) {
    if (json.length == 0) return; 
    //解析json变成js对象
    wxJsApi = JSON.parse(json);

    //通过config接口注入权限验证配置
    wx.config({
        debug: false,   //开启调试模式,调用的所有api的返回值会在客户端alert出来
        appId: wxJsApi.signPackage.appId,   //公众号的唯一标识
        timestamp: wxJsApi.signPackage.timestamp,   //生成签名的时间戳
        nonceStr: wxJsApi.signPackage.nonceStr, //生成签名的随机串
        signature: wxJsApi.signPackage.signature,   //签名
        jsApiList: ['chooseImage', 'uploadImage']   //需要使用的JS接口列表 这里我用了选择图片和上传图片接口
    });

    //通过ready接口处理成功验证,config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后
    wx.ready(function(){
        //得到上传图片按钮
        document.querySelector('#uploadImage').onclick = function() {
            var images = {localId:[],serverId:[]};
            //调用 拍照或从手机相册中选图接口
            wx.chooseImage({
                success: function(res) {
                    if (res.localIds.length != 1) {
                        alert('只能上传一张图片');
                        return;
                    }
                    //返回选定照片的本地ID列表
                    iamges.localId = res.localIds;
                    images.serverId = [];
                    //上传图片函数
                    function upload() {
                        //调用上传图片接口
                        wx.uploadImage({
                            localId: images.localId[0], // 需要上传的图片的本地ID,由chooseImage接口获得
                            isShowProcess: 1,   // 默认为1,显示进度提示
                            success: function(res) {
                                //返回图片的服务器端ID res.serverId,然后调用wxImgCallback函数进行下载图片操作
                                wxImgCallback(res.serverId);
                            },
                            fail: function(res) {
                                alert('上传失败');
                            }
                        });
                    }
                    upload();
                }
            });
        }
    });
}


function wxImgCallback(serverId) {
    //将serverId传给wx_upload.php的upload方法
    var url = 'wx_upload/upload/'+serverId;
    $.getJSON(url, function(data){
        if (data.code == 0) {
            alert(data.msg);
        } else if (data.code == 1) {
            //存储到服务器成功后的处理
            //
        }
    });
}

图片选择和图片上传接口调用

图片选择和图片上传接口调用

   

  3、图片上传完成后会返回一个serverId,然后通过这个来下载图片到本地服务器

  这里先补充下如何调用下载图片接口(我直接复制官方文档的说明了)

    公众号可调用本接口来获取多媒体文件。请注意,视频文件不支持下载,调用该接口需http协议。

    接口调用请求说明

    http请求方式: GET
     http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID

    参数说明

参数 是否必须 说明
access_token 调用接口凭证
media_id 媒体文件ID

    返回说明

    正确情况下的返回HTTP头如下:

      HTTP/1.1 200 OK
      Connection: close
      Content-Type: image/jpeg 
      Content-disposition: attachment; filename="MEDIA_ID.jpg"
      Date: Sun, 06 Jan 2013 10:20:18 GMT
      Cache-Control: no-cache, must-revalidate
      Content-Length: 339721
      curl -G "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID"

    错误情况下的返回JSON数据包示例如下(示例为无效媒体ID错误)::

      {"errcode":40007,"errmsg":"invalid media_id"}


 接下来看自己写的代码
 wx_upload.php
/*********************图片下载到本地服务器****************************************/
    //从微信服务器读取图片,然后下载到本地服务器
    public function upload($media_id) {
        //图片文件名
        $fileName = md5($this->wxId."/$media_id");
        //调用下载图片接口,返回路径
        $path = $this->weixin->wxDownImg($media_id, sys_get_temp_dir()."$fileName");
        if ($path != false) {
            //将图片的路径插入数据库去存储
            if ($this->model->weixin->updateByWxid($this->wxId, array('img_path'=>$path))) {
                $this->output->_display(json_encode(
                    array(
                            'code'=>1,
                            'msg'=>'上传成功',
                            'fileUrl' =>$path;
                        )
                ));
            } else {
                $this->output->_display(json_encode2(array('code'=>0,'msg' => '上传失败','err'=>'1')));
            }
        } else {
            $this->output->_display(json_encode2(array('code'=>0,'msg' => '上传失败','err'=>'2')));
        }
        
    }

从微信服务器下载图片到本地存储

//从微信服务器端下载图片到本地服务器
        public function wxDownImg($media_id, $path) {
            //调用 多媒体文件下载接口
            $url = "https://api.weixin.qq.com/cgi-bin/media/get?access_token={$this->model->weixin->_getApiToken()}&media_id=$media_id";
            //用curl请求,返回文件资源和curl句柄的信息
            $info = $this->curl_request($url);
            //文件类型
            $types = array('image/bmp'=>'.bmp', 'image/gif'=>'.gif', 'image/jpeg'=>'.jpg', 'image/png'=>'.png');
            //判断响应首部里的的content-type的值是否是这四种图片类型
            if (isset($types[$info['header']['content_type']])) {
                //文件的uri
                $path = $path.$types[$info['header']['content_type']];
            } else {
                return false;
            }

            //将资源写入文件里
            if ($this->saveFile($path, $info['body'])) {
                //将文件保存在本地目录
                $imgPath = rtrim(base_url(), '/').'/img'.date('Ymd').'/'.md5($this->controller->wxId.$media_id).$types[$info['header'['content_type']]];
                if (!is_dir($imgPath)) {
                    if(mkdir($imgPath)) {
                        if (false !== rename($path, $imgPath) {
                            return $imgPath;
                        }
                    }
                }
                return $path;
            }

            return false;

        }

        /**
         * curl请求资源
         * @param  string $url 请求url
         * @return array 
         */
        private function curl_request($url = '') {
            if ($url == '') return;
            $ch = curl_init();
            //这里返回响应报文时,只要body的内容,其他的都不要
            curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_NOBODY, 0);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            $package = curl_exec($ch);
            //获取curl连接句柄的信息
            $httpInfo = curl_getinfo($ch);
            curl_close($ch);

            $info = array_merge(array($package), array($httpInfo));

            return $info;

        }

        /**
         * 将资源写入文件
         * @param  string 资源uri
         * @param  source 资源
         * @return boolean 
         */
        private function saveFile($path, $fileContent) {
            $fp = fopen($path, 'w');
            if (false !== $localFile) {
                if (false !== fwrite($fp, $fileContent)) {
                    fclose($fp);
                    return true;
                }
            }
            return false;
        }

从微信服务器下载图片到本地存储接口

  到这里,已经完成了:

    先调用“拍照或从手机相册选择图片接口”—>选择成功图片后—>调用“上传图片接口”—>上传成功后(也就是图片上传到了微信服务器上)—>调用“下载图片接口”—>将图片下载到自己的服务器存储。

  这一思路的实现。我们用到了微信的选择图片接口、上传图片接口和下载媒体资源接口。

  下面我附上这一接口开发的全部代码:

<?php
class wx_upload extends xx_Controller {
    public function __construct() {
        parent::__construct();
    }
 
    public function wxUploadImg() {
        //在模板里引入jssdk的js文件
        $this->addResLink('http://res.wx.qq.com/open/js/jweixin-1.0.0.js');
        //取得:公众号的唯一标识appId、生成签名的时间戳timestamp、生成签名的随机串nonceStr、签名signature这些值,并以json形式传到模板页面
        $this->smartyData['wxJsApi'] = json_encode(array('signPackage' => $this->model->weixin->signPackage()));
    }

    /*********************图片下载到本地服务器****************************************/
    //从微信服务器读取图片,然后下载到本地服务器
    public function upload($media_id) {
        //图片文件名
        $fileName = md5($this->wxId."/$media_id");
        //调用下载图片接口,返回路径
        $path = $this->weixin->wxDownImg($media_id, sys_get_temp_dir()."$fileName");
        if ($path != false) {
            //将图片的路径插入数据库去存储
            if ($this->model->weixin->updateByWxid($this->wxId, array('img_path'=>$path))) {
                $this->output->_display(json_encode(
                    array(
                            'code'=>1,
                            'msg'=>'上传成功',
                            'fileUrl' =>$path;
                        )
                ));
            } else {
                $this->output->_display(json_encode2(array('code'=>0,'msg' => '上传失败','err'=>'1')));
            }
        } else {
            $this->output->_display(json_encode2(array('code'=>0,'msg' => '上传失败','err'=>'2')));
        }
        
    }
}



?>
<?php
    class WxModel extends ModelBase{
        public $appId;
        public $appSecret;
        public $token;

        public function __construct() {
            parent::__construct();

            //审核通过的移动应用所给的AppID和AppSecret
            $this->appId = 'wx0000000000000000';
            $this->appSecret = '00000000000000000000000000000';
            $this->token = '00000000';
        }

        /**
         * 获取jssdk所需参数的所有值
         * @return array
         */
        public function signPackage() {
            $protocol = (!empty($_SERVER['HTTPS'] && $_SERVER['HTTPS'] == 'off' || $_SERVER['port'] == 443)) ? 'https://' : 'http://';
            //当前网页的URL
            $url = "$protocol$_SERVER['host']$_SERVER['REQUEST_URI']";
            //生成签名的时间戳
            $timestamp = time();
            //生成签名的随机串
            $nonceStr = $this->createNonceStr();
            //获取公众号用于调用微信JS接口的临时票据
            $jsApiTicket = $this->getJsApiTicket();
            //对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,
            //使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串$str。
            //这里需要注意的是所有参数名均为小写字符
            $str = "jsapi_ticket=$jsApiTicket&noncestr=$nonceStr&timestamp=$timestamp&url=$url";
            //对$str进行sha1签名,得到signature:
            $signature = sha1($str);
            $signPackage = array(
                "appId"     => $this->AppId,
                "nonceStr"  => $nonceStr,
                "timestamp" => $timestamp,
                "url"       => $url,
                "signature" => $signature,
                "rawString" => $string
                );
            return $signPackage;
        }

        /**
         * 创建签名的随机字符串
         * @param  int $length 字符串长度
         * @return string      随机字符串
         */
        private function createNonceStr($length == 16) {
            $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
            $str = '';
            for ($i=0; $i < $length; $i++) { 
                $str .= substr(mt_rand(0, strlen($chars)), 1);
            }
            return $str;
        }

        /**
         * 获取公众号用于调用微信JS接口的临时票据
         * @return string 
         */
        private function getJsApiTicket() {
            //先查看redis里是否存了jsapi_ticket此值,假如有,就直接返回
            $jsApiTicket = $this->library->redisCache->get('weixin:ticket');
            if (!$jsApiTicket) {
                //先获取access_token(公众号的全局唯一票据)
                $accessToken = $this->getApiToken();
                //通过access_token 采用http GET方式请求获得jsapi_ticket
                $result = $this->callApi("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=$accessToken&type=jsapi");
                //得到了jsapi_ticket
                $jsApiTicket = $result['ticket'];
                //将jsapi_ticket缓存到redis里面,下次就不用再请求去取了
                $expire = max(1, intval($result['expire']) - 60);
                $this->library->redisCache->set('weixin:ticket', $jsApiTicket, $expire);
            }
            return $jsApiTicket;
        }

        /**
         * 获取众号的全局唯一票据access_token
         * @param  boolean $forceRefresh 是否强制刷新
         * @return string                返回access_token
         */
        private function getApiToken($forceRefresh = false) {
            //先查看redis是否存了accessToken,如果有了,就不用再去微信server去请求了(提高效率)
            $accessToken = $this->library->redisCache->get('weixin:accessToken');
            //强制刷新accessToken或者accessToken为空时就去请求accessToken
            if ($forceRefresh || empty($accessToken)) {
                //请求得到accessToken
                $result = $this->callApi("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$this->appId}&secret={$this->appSecret}");
                $accessToken = $result['access_token'];
                $expire = max(1, intval($result['expire']) - 60);
                //将其存进redis里面去
                $this->library->redisCache->set('weixin:accessToken', $accessToken, $expire);
            }
            return $accessToken;
        }

        //从微信服务器端下载图片到本地服务器
        public function wxDownImg($media_id, $path) {
            //调用 多媒体文件下载接口
            $url = "https://api.weixin.qq.com/cgi-bin/media/get?access_token={$this->model->weixin->_getApiToken()}&media_id=$media_id";
            //用curl请求,返回文件资源和curl句柄的信息
            $info = $this->curl_request($url);
            //文件类型
            $types = array('image/bmp'=>'.bmp', 'image/gif'=>'.gif', 'image/jpeg'=>'.jpg', 'image/png'=>'.png');
            //判断响应首部里的的content-type的值是否是这四种图片类型
            if (isset($types[$info['header']['content_type']])) {
                //文件的uri
                $path = $path.$types[$info['header']['content_type']];
            } else {
                return false;
            }

            //将资源写入文件里
            if ($this->saveFile($path, $info['body'])) {
                //将文件保存在本地目录
                $imgPath = rtrim(base_url(), '/').'/img'.date('Ymd').'/'.md5($this->controller->wxId.$media_id).$types[$info['header'['content_type']]];
                if (!is_dir($imgPath)) {
                    if(mkdir($imgPath)) {
                        if (false !== rename($path, $imgPath) {
                            return $imgPath;
                        }
                    }
                }
                return $path;
            }

            return false;

        }

        /**
         * curl请求资源
         * @param  string $url 请求url
         * @return array 
         */
        private function curl_request($url = '') {
            if ($url == '') return;
            $ch = curl_init();
            //这里返回响应报文时,只要body的内容,其他的都不要
            curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_NOBODY, 0);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            $package = curl_exec($ch);
            //获取curl连接句柄的信息
            $httpInfo = curl_getinfo($ch);
            curl_close($ch);

            $info = array_merge(array($package), array($httpInfo));

            return $info;

        }

        /**
         * 将资源写入文件
         * @param  string 资源uri
         * @param  source 资源
         * @return boolean 
         */
        private function saveFile($path, $fileContent) {
            $fp = fopen($path, 'w');
            if (false !== $localFile) {
                if (false !== fwrite($fp, $fileContent)) {
                    fclose($fp);
                    return true;
                }
            }
            return false;
        }

    }


?>
<html>
    <head>
        
    </head>
    <body>
        <button id="uploadImage">点击上传图片</button>
        <script>
        $(function(){
            $.util.wxMenuImage('{$wxJsApi|default:""}')
        });
        </script>
    </body>
</html>
if(typeof($util)=='undefined')$util={};

$.util.wxMenuImage = function(json) {
    if (json.length == 0) return; 
    //解析json变成js对象
    wxJsApi = JSON.parse(json);

    //通过config接口注入权限验证配置
    wx.config({
        debug: false,   //开启调试模式,调用的所有api的返回值会在客户端alert出来
        appId: wxJsApi.signPackage.appId,   //公众号的唯一标识
        timestamp: wxJsApi.signPackage.timestamp,   //生成签名的时间戳
        nonceStr: wxJsApi.signPackage.nonceStr, //生成签名的随机串
        signature: wxJsApi.signPackage.signature,   //签名
        jsApiList: ['chooseImage', 'uploadImage']   //需要使用的JS接口列表 这里我用了选择图片和上传图片接口
    });

    //通过ready接口处理成功验证,config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后
    wx.ready(function(){
        //得到上传图片按钮
        document.querySelector('#uploadImage').onclick = function() {
            var images = {localId:[],serverId:[]};
            //调用 拍照或从手机相册中选图接口
            wx.chooseImage({
                success: function(res) {
                    if (res.localIds.length != 1) {
                        alert('只能上传一张图片');
                        return;
                    }
                    //返回选定照片的本地ID列表
                    iamges.localId = res.localIds;
                    images.serverId = [];
                    //上传图片函数
                    function upload() {
                        //调用上传图片接口
                        wx.uploadImage({
                            localId: images.localId[0], // 需要上传的图片的本地ID,由chooseImage接口获得
                            isShowProcess: 1,   // 默认为1,显示进度提示
                            success: function(res) {
                                //返回图片的服务器端ID res.serverId,然后调用wxImgCallback函数进行下载图片操作
                                wxImgCallback(res.serverId);
                            },
                            fail: function(res) {
                                alert('上传失败');
                            }
                        });
                    }
                    upload();
                }
            });
        }
    });
}


function wxImgCallback(serverId) {
    //将serverId传给wx_upload.php的upload方法
    var url = 'wx_upload/upload/'+serverId;
    $.getJSON(url, function(data){
        if (data.code == 0) {
            alert(data.msg);
        } else if (data.code == 1) {
            //存储到服务器成功后的处理
            //
        }
    });
}

本次讲解就到此,这篇博文是给对微信接口开发有兴趣的朋友参考,如果你是高手,完全可以绕道。

 更多微信JS-SDK之图像接口开发相关文章请关注PHP中文网!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn