Maison >Applet WeChat >Développement WeChat >Développement d'interface d'image WeChat JS-SDK

Développement d'interface d'image WeChat JS-SDK

高洛峰
高洛峰original
2017-03-01 09:29:511841parcourir

Ici, j'utilise l'interface image de WeChat JSSDK pour la développer afin d'implémenter la fonction de téléchargement d'images. Pourquoi ai-je choisi cette interface ? Premièrement, le projet actuel est une page Web ouverte dans WeChat. En utilisant cette interface, les performances seront certainement meilleures. Après tout, c'est l'affaire de WeChat. Deuxièmement, en utilisant cette interface, l'efficacité du développement sera plus élevée. Le point important est qu'il peut compresser les images. Par exemple, si une image de 2 Mo est utilisée, l'image peut être compressée dans une taille de plusieurs centaines de Ko via l'interface de téléchargement d'images WeChat, ce qui est très utile pour les performances du site Web.

1. Mon idée est la suivante :

Appelez d'abord "photographier ou sélectionnez une photo dans l'interface de l'album du téléphone mobile" -> Après avoir sélectionné une photo réussie -> interface' -> Une fois le téléchargement réussi (c'est-à-dire que l'image est téléchargée sur le serveur WeChat) -> Appelez « l'interface de téléchargement d'image » -> Téléchargez l'image sur votre propre serveur pour le stockage.

2. Étapes pour utiliser JSSDK

1. Présentation

WeChat JS-SDK est fourni par la plateforme publique WeChat pour les développeurs Web basés sur le Web WeChat boîte à outils de développement.

En utilisant WeChat JS-SDK, les développeurs Web peuvent utiliser WeChat pour utiliser efficacement les capacités des systèmes de téléphonie mobile telles que la prise de photos, la sélection d'images, la voix et la localisation. En même temps, ils peuvent utiliser directement WeChat. pour partager, numériser, coupon, etc. Les capacités uniques de WeChat telles que le paiement offrent aux utilisateurs de WeChat une meilleure expérience Web.

2. Étapes d'utilisation

Étape 1 : lier le nom de domaine

Connectez-vous d'abord à la plateforme publique WeChat et entrez dans les « Paramètres de fonction » des « Paramètres du compte officiel » pour renseigner le nom de domaine "JS Interface Security".

Remarque : Après vous être connecté, vous pouvez afficher les autorisations d'interface correspondantes dans le "Centre des développeurs".

Étape 2 : Introduire les fichiers JS

Introduisez les fichiers JS suivants sur la page qui doit appeler l'interface JS (https est pris en charge) : http://res.wx.qq.com /open/js /jweixin-1.0.0.js

Étape 3 : Injecter la configuration de vérification des autorisations via l'interface de configuration

Toutes les pages qui doivent utiliser JS-SDK doivent d'abord injecter des informations de configuration, sinon, elle ne sera pas appelée (comme pour une URL qui ne doit être appelée qu'une seule fois, et l'application Web SPA qui modifie l'URL peut être appelée à chaque fois que l'URL change)

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

Étape 4 : Processus réussi vérification via l'interface prête

wx.ready(function(){

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

Étape 5 : Gérer l'échec de la vérification via l'interface d'erreur

wx.error(function(res){

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

});

Instructions d'appel d'interface

Toutes les interfaces sont appelées via des objets wx (jWeixin des objets peuvent également être utilisés), et le paramètre est un objet, sauf En plus des paramètres que chaque interface doit transmettre, il existe également les paramètres communs suivants :

  1. succès : le fonction de rappel exécutée lorsque l’appel d’interface réussit.

  2. fail : La fonction de rappel exécutée lorsque l'appel d'interface échoue.

  3. complete : la fonction de rappel exécutée lorsque l'appel d'interface est terminé, quel que soit le succès ou l'échec.

  4. cancel : La fonction de rappel lorsque l'utilisateur clique sur Annuler. Elle n'est utilisée que par certaines API où l'utilisateur annule l'opération.

  5. déclencheur : une méthode qui est déclenchée lorsqu'un bouton du menu est cliqué. Cette méthode ne prend en charge que les interfaces associées dans le menu.

Remarque : n'essayez pas d'utiliser une requête asynchrone ajax dans le déclencheur pour modifier le contenu de ce partage, car l'opération de partage client est une opération synchrone et le paquet de retour utilisant ajax le fera ne sera pas disponible pour le moment.


Les fonctions ci-dessus ont toutes un paramètre de type objet. En plus des données renvoyées par chaque interface elle-même, il existe également un attribut général errMsg, dont le format de valeur est le suivant :

    1. Lorsque l'appel réussit : "xxx:ok", où xxx est le nom de l'interface appelée

    2. Lorsque l'utilisateur annule : "xxx : Cancel" , où xxx est le nom de l'interface appelée

    3. Lorsque l'appel échoue : sa valeur est le message d'erreur spécifique

 

3. Explication détaillée du développement et analyse du code (le framework CI est utilisé, à condition qu'il soit en mode MVC)

1. Obtenez d'abord côté serveur : l'identifiant unique appId de le compte officiel et l'horodatage de la signature générée génèrent une chaîne aléatoire signée nonceStr et une signature de 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()));
    }

Contrôleur de téléchargement d'images

<?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;
        }

Obtenir appId, nonceStr, timestamp, signature model

Ici, nous devons ajouter quelques informations sur l'algorithme de signature d'autorisation utilisé par JS-SDK Idées et points à noter (je copierai le document du site officiel directement pour que tout le monde puisse le voir)

jsapi_ticket

Avant de générer une signature, vous devez d'abord comprendre que jsapi_ticket est temporaire. fonction utilisée par les comptes publics pour appeler la facture WeChat JS. Dans des circonstances normales, la période de validité de jsapi_ticket est de 7 200 secondes, obtenue via access_token. Étant donné que le nombre d'appels d'API pour obtenir jsapi_ticket est très limité, l'actualisation fréquente de jsapi_ticket entraînera un nombre limité d'appels d'API et affectera leur propre activité. Les développeurs doivent mettre en cache jsapi_ticket globalement dans leurs propres services.

1. Obtenez access_token (valable 7200 secondes, les développeurs doivent mettre en cache access_token globalement dans leurs propres services)

2. Utilisez l'access_token obtenu lors de la première étape pour demander jsapi_ticket en utilisant la méthode http GET ( La période de validité est de 7 200 secondes, les développeurs doivent mettre en cache jsapi_ticket globalement dans leurs propres 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中文网!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn