因爲如今手頭的項目中有一個上傳證件照認證的功能(手機端),以前的思路是直接點擊上傳,而後直接將圖片上傳到服務器去,這篇文章有講到(http://www.cnblogs.com/it-cen/p/4535219.html),但在微信裏打開網頁去上傳,速度並不快,並且,假如我上傳一張2M大的圖片,也沒有對其進行壓縮處理,這樣很影響上傳和下載的速度。php
因此,我這裏藉助微信JSSDK的圖像接口對其進行開發實現圖片上傳的功能,爲什麼我選擇此接口?第一,目前的項目是在微信中打開的網頁,利用此接口,性能確定是好一點的啦,畢竟是微信本身的東西;第二,用此接口,開發效率更高嘛;第三,最重要的一點,就是它能對圖片進行壓縮,假如一張2M的圖片,經過微信圖片上傳接口能夠將圖片壓縮成幾百K的大小,這對網站的性能是頗有幫助的。html
1、個人思路是:web
先調用「拍照或從手機相冊選擇圖片接口」—>選擇成功圖片後—>調用「上傳圖片接口」—>上傳成功後(也就是圖片上傳到了微信服務器上)—>調用「下載圖片接口」—>將圖片下載到本身的服務器存儲。ajax
2、JSSDK的使用步驟redis
一、概述 算法
微信JS-SDK是微信公衆平臺面向網頁開發者提供的基於微信內的網頁開發工具包。數據庫
經過使用微信JS-SDK,網頁開發者可藉助微信高效地使用拍照、選圖、語音、位置等手機系統的能力,同時能夠直接使用微信分享、掃一掃、卡券、支付等微信特有的能力,爲微信用戶提供更優質的網頁體驗。json
二、使用步驟api
步驟一:綁定域名緩存
先登陸微信公衆平臺進入「公衆號設置」的「功能設置」裏填寫「JS接口安全域名」。
備註:登陸後可在「開發者中心」查看對應的接口權限。
步驟二:引入JS文件
在須要調用JS接口的頁面引入以下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.0.0.js
步驟三:經過config接口注入權限驗證配置
全部須要使用JS-SDK的頁面必須先注入配置信息,不然將沒法調用(同一個url僅需調用一次,對於變化url的SPA的web app可在每次url變化時進行調用)
1 wx.config({ 2 debug: true, // 開啓調試模式,調用的全部api的返回值會在客戶端alert出來,若要查看傳入的參數,能夠在pc端打開,參數信息會經過log打出,僅在pc端時纔會打印。 3 appId: '', // 必填,公衆號的惟一標識 4 timestamp: , // 必填,生成簽名的時間戳 5 nonceStr: '', // 必填,生成簽名的隨機串 6 signature: '',// 必填,簽名,見附錄1 7 jsApiList: [] // 必填,須要使用的JS接口列表,全部JS接口列表見附錄2 8 });
1 wx.ready(function(){ 2 3 // config信息驗證後會執行ready方法,全部接口調用都必須在config接口得到結果以後,config是一個客戶端的異步操做,因此若是須要在頁面加載時就調用相關接口,則須把相關接口放在ready函數中調用來確保正確執行。對於用戶觸發時才調用的接口,則能夠直接調用,不須要放在ready函數中。 4 });
1 wx.error(function(res){ 2 3 // config信息驗證失敗會執行error函數,如簽名過時致使驗證失敗,具體錯誤信息能夠打開config的debug模式查看,也能夠在返回的res參數中查看,對於SPA能夠在這裏更新簽名。 4 5 });
全部接口經過wx對象(也可以使用jWeixin對象)來調用,參數是一個對象,除了每一個接口自己須要傳的參數以外,還有如下通用參數:
備註:不要嘗試在trigger中使用ajax異步請求修改本次分享的內容,由於客戶端分享操做是一個同步操做,這時候使用ajax的回包會尚未返回。
以上幾個函數都帶有一個參數,類型爲對象,其中除了每一個接口自己返回的數據以外,還有一個通用屬性errMsg,其值格式以下:
3、開發及代碼分析詳解(用的是CI框架,只要是MVC模式均可以)
一、先在服務器端取到:公衆號的惟一標識appId、生成簽名的時間戳timestamp、生成簽名的隨機串nonceStr、簽名signature。
wx_upload.php
1 <?php 2 class wx_upload extends xx_Controller { 3 public function __construct() { 4 parent::__construct(); 5 } 6 7 public function wxUploadImg() { 8 //在模板裏引入jssdk的js文件 9 $this->addResLink('http://res.wx.qq.com/open/js/jweixin-1.0.0.js'); 10 //取得:公衆號的惟一標識appId、生成簽名的時間戳timestamp、生成簽名的隨機串nonceStr、簽名signature這些值,並以json形式傳到模板頁面 11 $this->smartyData['wxJsApi'] = json_encode(array('signPackage' => $this->model->weixin->signPackage())); 12 }
WeixinModel.php
1 <?php 2 class WxModel extends ModelBase{ 3 public $appId; 4 public $appSecret; 5 public $token; 6 7 public function __construct() { 8 parent::__construct(); 9 10 //審覈經過的移動應用所給的AppID和AppSecret 11 $this->appId = 'wx0000000000000000'; 12 $this->appSecret = '00000000000000000000000000000'; 13 $this->token = '00000000'; 14 } 15 16 /** 17 * 獲取jssdk所需參數的全部值 18 * @return array 19 */ 20 public function signPackage() { 21 $protocol = (!empty($_SERVER['HTTPS'] && $_SERVER['HTTPS'] == 'off' || $_SERVER['port'] == 443)) ? 'https://' : 'http://'; 22 //當前網頁的URL 23 $url = "$protocol$_SERVER['host']$_SERVER['REQUEST_URI']"; 24 //生成簽名的時間戳 25 $timestamp = time(); 26 //生成簽名的隨機串 27 $nonceStr = $this->createNonceStr(); 28 //獲取公衆號用於調用微信JS接口的臨時票據 29 $jsApiTicket = $this->getJsApiTicket(); 30 //對全部待簽名參數按照字段名的ASCII 碼從小到大排序(字典序)後, 31 //使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字符串$str。 32 //這裏須要注意的是全部參數名均爲小寫字符 33 $str = "jsapi_ticket=$jsApiTicket&noncestr=$nonceStr×tamp=$timestamp&url=$url"; 34 //對$str進行sha1簽名,獲得signature: 35 $signature = sha1($str); 36 $signPackage = array( 37 "appId" => $this->AppId, 38 "nonceStr" => $nonceStr, 39 "timestamp" => $timestamp, 40 "url" => $url, 41 "signature" => $signature, 42 "rawString" => $string 43 ); 44 return $signPackage; 45 } 46 47 /** 48 * 建立簽名的隨機字符串 49 * @param int $length 字符串長度 50 * @return string 隨機字符串 51 */ 52 private function createNonceStr($length == 16) { 53 $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; 54 $str = ''; 55 for ($i=0; $i < $length; $i++) { 56 $str .= substr(mt_rand(0, strlen($chars)), 1); 57 } 58 return $str; 59 } 60 61 /** 62 * 獲取公衆號用於調用微信JS接口的臨時票據 63 * @return string 64 */ 65 private function getJsApiTicket() { 66 //先查看redis裏是否存了jsapi_ticket此值,假若有,就直接返回 67 $jsApiTicket = $this->library->redisCache->get('weixin:ticket'); 68 if (!$jsApiTicket) { 69 //先獲取access_token(公衆號的全局惟一票據) 70 $accessToken = $this->getApiToken(); 71 //經過access_token 採用http GET方式請求得到jsapi_ticket 72 $result = $this->callApi("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=$accessToken&type=jsapi"); 73 //獲得了jsapi_ticket 74 $jsApiTicket = $result['ticket']; 75 //將jsapi_ticket緩存到redis裏面,下次就不用再請求去取了 76 $expire = max(1, intval($result['expire']) - 60); 77 $this->library->redisCache->set('weixin:ticket', $jsApiTicket, $expire); 78 } 79 return $jsApiTicket; 80 } 81 82 /** 83 * 獲取衆號的全局惟一票據access_token 84 * @param boolean $forceRefresh 是否強制刷新 85 * @return string 返回access_token 86 */ 87 private function getApiToken($forceRefresh = false) { 88 //先查看redis是否存了accessToken,若是有了,就不用再去微信server去請求了(提升效率) 89 $accessToken = $this->library->redisCache->get('weixin:accessToken'); 90 //強制刷新accessToken或者accessToken爲空時就去請求accessToken 91 if ($forceRefresh || empty($accessToken)) { 92 //請求獲得accessToken 93 $result = $this->callApi("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$this->appId}&secret={$this->appSecret}"); 94 $accessToken = $result['access_token']; 95 $expire = max(1, intval($result['expire']) - 60); 96 //將其存進redis裏面去 97 $this->library->redisCache->set('weixin:accessToken', $accessToken, $expire); 98 } 99 return $accessToken; 100 }
這裏要補充一些 JS-SDK使用權限簽名算法 的思路和注意點(這裏我直接複製官網文檔給你們看看)
jsapi_ticket
生成簽名以前必須先了解一下jsapi_ticket,jsapi_ticket是公衆號用於調用微信JS接口的臨時票據。正常狀況下,jsapi_ticket的有效期爲7200秒,經過access_token來獲取。因爲獲取jsapi_ticket的api調用次數很是有限,頻繁刷新jsapi_ticket會致使api調用受限,影響自身業務,開發者必須在本身的服務全局緩存jsapi_ticket 。
一、獲取access_token(有效期7200秒,開發者必須在本身的服務全局緩存access_token)
二、用第一步拿到的access_token 採用http GET方式請求得到jsapi_ticket(有效期7200秒,開發者必須在本身的服務全局緩存jsapi_ticket)
https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
成功返回以下JSON:
1 { 2 "errcode":0, 3 "errmsg":"ok", 4 "ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA", 5 "expires_in":7200 6 }
得到jsapi_ticket以後,就能夠生成JS-SDK權限驗證的簽名了。
簽名算法
簽名生成規則以下:參與簽名的字段包括noncestr(隨機字符串), 有效的jsapi_ticket, timestamp(時間戳), url(當前網頁的URL,不包含#及其後面部分) 。對全部待簽名參數按照字段名的ASCII 碼從小到大排序(字典序)後,使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字符串string1。這裏須要注意的是全部參數名均爲小寫字符。對string1做sha1加密,字段名和字段值都採用原始值,不進行URL 轉義。
即signature=sha1(string1)。 示例:
步驟1. 對全部待簽名參數按照字段名的ASCII 碼從小到大排序(字典序)後,使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字符串string1:
jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW×tamp=1414587457&url=http://mp.weixin.qq.com?params=value
步驟2. 對string1進行sha1簽名,獲得signature:
0f9de62fce790f9a083d5c99e95740ceb90c27ed
注意事項
1.簽名用的noncestr和timestamp必須與wx.config中的nonceStr和timestamp相同。
2.簽名用的url必須是調用JS接口頁面的完整URL。
3.出於安全考慮,開發者必須在服務器端實現簽名的邏輯。
二、取到咱們所須要的值後,就在js文件裏面開始使用了
uploadImg.tpl
<script> $(function(){ $.util.wxMenuImage('{$wxJsApi|default:""}') }); </script>
uploadImg.js
1 if(typeof($util)=='undefined')$util={}; 2 3 $.util.wxMenuImage = function(json) { 4 if (json.length == 0) return; 5 //解析json變成js對象 6 wxJsApi = JSON.parse(json); 7 8 //經過config接口注入權限驗證配置 9 wx.config({ 10 debug: false, //開啓調試模式,調用的全部api的返回值會在客戶端alert出來 11 appId: wxJsApi.signPackage.appId, //公衆號的惟一標識 12 timestamp: wxJsApi.signPackage.timestamp, //生成簽名的時間戳 13 nonceStr: wxJsApi.signPackage.nonceStr, //生成簽名的隨機串 14 signature: wxJsApi.signPackage.signature, //簽名 15 jsApiList: ['chooseImage', 'uploadImage'] //須要使用的JS接口列表 這裏我用了選擇圖片和上傳圖片接口 16 }); 17 18 //經過ready接口處理成功驗證,config信息驗證後會執行ready方法,全部接口調用都必須在config接口得到結果以後 19 wx.ready(function(){ 20 //獲得上傳圖片按鈕 21 document.querySelector('#uploadImage').onclick = function() { 22 var images = {localId:[],serverId:[]}; 23 //調用 拍照或從手機相冊中選圖接口 24 wx.chooseImage({ 25 success: function(res) { 26 if (res.localIds.length != 1) { 27 alert('只能上傳一張圖片'); 28 return; 29 } 30 //返回選定照片的本地ID列表 31 iamges.localId = res.localIds; 32 images.serverId = []; 33 //上傳圖片函數 34 function upload() { 35 //調用上傳圖片接口 36 wx.uploadImage({ 37 localId: images.localId[0], // 須要上傳的圖片的本地ID,由chooseImage接口得到 38 isShowProcess: 1, // 默認爲1,顯示進度提示 39 success: function(res) { 40 //返回圖片的服務器端ID res.serverId,而後調用wxImgCallback函數進行下載圖片操做 41 wxImgCallback(res.serverId); 42 }, 43 fail: function(res) { 44 alert('上傳失敗'); 45 } 46 }); 47 } 48 upload(); 49 } 50 }); 51 } 52 }); 53 } 54 55 56 function wxImgCallback(serverId) { 57 //將serverId傳給wx_upload.php的upload方法 58 var url = 'wx_upload/upload/'+serverId; 59 $.getJSON(url, function(data){ 60 if (data.code == 0) { 61 alert(data.msg); 62 } else if (data.code == 1) { 63 //存儲到服務器成功後的處理 64 // 65 } 66 }); 67 }
三、圖片上傳完成後會返回一個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
1 /*********************圖片下載到本地服務器****************************************/ 2 //從微信服務器讀取圖片,而後下載到本地服務器 3 public function upload($media_id) { 4 //圖片文件名 5 $fileName = md5($this->wxId."/$media_id"); 6 //調用下載圖片接口,返回路徑 7 $path = $this->weixin->wxDownImg($media_id, sys_get_temp_dir()."$fileName"); 8 if ($path != false) { 9 //將圖片的路徑插入數據庫去存儲 10 if ($this->model->weixin->updateByWxid($this->wxId, array('img_path'=>$path))) { 11 $this->output->_display(json_encode( 12 array( 13 'code'=>1, 14 'msg'=>'上傳成功', 15 'fileUrl' =>$path; 16 ) 17 )); 18 } else { 19 $this->output->_display(json_encode2(array('code'=>0,'msg' => '上傳失敗','err'=>'1'))); 20 } 21 } else { 22 $this->output->_display(json_encode2(array('code'=>0,'msg' => '上傳失敗','err'=>'2'))); 23 } 24 25 }
WeixinModel.php
1 //從微信服務器端下載圖片到本地服務器 2 public function wxDownImg($media_id, $path) { 3 //調用 多媒體文件下載接口 4 $url = "https://api.weixin.qq.com/cgi-bin/media/get?access_token={$this->model->weixin->_getApiToken()}&media_id=$media_id"; 5 //用curl請求,返回文件資源和curl句柄的信息 6 $info = $this->curl_request($url); 7 //文件類型 8 $types = array('image/bmp'=>'.bmp', 'image/gif'=>'.gif', 'image/jpeg'=>'.jpg', 'image/png'=>'.png'); 9 //判斷響應首部裏的的content-type的值是不是這四種圖片類型 10 if (isset($types[$info['header']['content_type']])) { 11 //文件的uri 12 $path = $path.$types[$info['header']['content_type']]; 13 } else { 14 return false; 15 } 16 17 //將資源寫入文件裏 18 if ($this->saveFile($path, $info['body'])) { 19 //將文件保存在本地目錄 20 $imgPath = rtrim(base_url(), '/').'/img'.date('Ymd').'/'.md5($this->controller->wxId.$media_id).$types[$info['header'['content_type']]]; 21 if (!is_dir($imgPath)) { 22 if(mkdir($imgPath)) { 23 if (false !== rename($path, $imgPath) { 24 return $imgPath; 25 } 26 } 27 } 28 return $path; 29 } 30 31 return false; 32 33 } 34 35 /** 36 * curl請求資源 37 * @param string $url 請求url 38 * @return array 39 */ 40 private function curl_request($url = '') { 41 if ($url == '') return; 42 $ch = curl_init(); 43 //這裏返回響應報文時,只要body的內容,其餘的都不要 44 curl_setopt($ch, CURLOPT_HEADER, 0); 45 curl_setopt($ch, CURLOPT_NOBODY, 0); 46 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 47 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); 48 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 49 $package = curl_exec($ch); 50 //獲取curl鏈接句柄的信息 51 $httpInfo = curl_getinfo($ch); 52 curl_close($ch); 53 54 $info = array_merge(array($package), array($httpInfo)); 55 56 return $info; 57 58 } 59 60 /** 61 * 將資源寫入文件 62 * @param string 資源uri 63 * @param source 資源 64 * @return boolean 65 */ 66 private function saveFile($path, $fileContent) { 67 $fp = fopen($path, 'w'); 68 if (false !== $localFile) { 69 if (false !== fwrite($fp, $fileContent)) { 70 fclose($fp); 71 return true; 72 } 73 } 74 return false; 75 }
到這裏,已經完成了:
先調用「拍照或從手機相冊選擇圖片接口」—>選擇成功圖片後—>調用「上傳圖片接口」—>上傳成功後(也就是圖片上傳到了微信服務器上)—>調用「下載圖片接口」—>將圖片下載到本身的服務器存儲。
這一思路的實現。咱們用到了微信的選擇圖片接口、上傳圖片接口和下載媒體資源接口。
下面我附上這一接口開發的所有代碼:
1 <?php 2 class wx_upload extends xx_Controller { 3 public function __construct() { 4 parent::__construct(); 5 } 6 7 public function wxUploadImg() { 8 //在模板裏引入jssdk的js文件 9 $this->addResLink('http://res.wx.qq.com/open/js/jweixin-1.0.0.js'); 10 //取得:公衆號的惟一標識appId、生成簽名的時間戳timestamp、生成簽名的隨機串nonceStr、簽名signature這些值,並以json形式傳到模板頁面 11 $this->smartyData['wxJsApi'] = json_encode(array('signPackage' => $this->model->weixin->signPackage())); 12 } 13 14 /*********************圖片下載到本地服務器****************************************/ 15 //從微信服務器讀取圖片,而後下載到本地服務器 16 public function upload($media_id) { 17 //圖片文件名 18 $fileName = md5($this->wxId."/$media_id"); 19 //調用下載圖片接口,返回路徑 20 $path = $this->weixin->wxDownImg($media_id, sys_get_temp_dir()."$fileName"); 21 if ($path != false) { 22 //將圖片的路徑插入數據庫去存儲 23 if ($this->model->weixin->updateByWxid($this->wxId, array('img_path'=>$path))) { 24 $this->output->_display(json_encode( 25 array( 26 'code'=>1, 27 'msg'=>'上傳成功', 28 'fileUrl' =>$path; 29 ) 30 )); 31 } else { 32 $this->output->_display(json_encode2(array('code'=>0,'msg' => '上傳失敗','err'=>'1'))); 33 } 34 } else { 35 $this->output->_display(json_encode2(array('code'=>0,'msg' => '上傳失敗','err'=>'2'))); 36 } 37 38 } 39 } 40 41 42 43 44 45 46 47 48 49 50 51 ?>
1 <?php 2 class WxModel extends ModelBase{ 3 public $appId; 4 public $appSecret; 5 public $token; 6 7 public function __construct() { 8 parent::__construct(); 9 10 //審覈經過的移動應用所給的AppID和AppSecret 11 $this->appId = 'wx0000000000000000'; 12 $this->appSecret = '00000000000000000000000000000'; 13 $this->token = '00000000'; 14 } 15 16 /** 17 * 獲取jssdk所需參數的全部值 18 * @return array 19 */ 20 public function signPackage() { 21 $protocol = (!empty($_SERVER['HTTPS'] && $_SERVER['HTTPS'] == 'off' || $_SERVER['port'] == 443)) ? 'https://' : 'http://'; 22 //當前網頁的URL 23 $url = "$protocol$_SERVER['host']$_SERVER['REQUEST_URI']"; 24 //生成簽名的時間戳 25 $timestamp = time(); 26 //生成簽名的隨機串 27 $nonceStr = $this->createNonceStr(); 28 //獲取公衆號用於調用微信JS接口的臨時票據 29 $jsApiTicket = $this->getJsApiTicket(); 30 //對全部待簽名參數按照字段名的ASCII 碼從小到大排序(字典序)後, 31 //使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字符串$str。 32 //這裏須要注意的是全部參數名均爲小寫字符 33 $str = "jsapi_ticket=$jsApiTicket&noncestr=$nonceStr×tamp=$timestamp&url=$url"; 34 //對$str進行sha1簽名,獲得signature: 35 $signature = sha1($str); 36 $signPackage = array( 37 "appId" => $this->AppId, 38 "nonceStr" => $nonceStr, 39 "timestamp" => $timestamp, 40 "url" => $url, 41 "signature" => $signature, 42 "rawString" => $string 43 ); 44 return $signPackage; 45 } 46 47 /** 48 * 建立簽名的隨機字符串 49 * @param int $length 字符串長度 50 * @return string 隨機字符串 51 */ 52 private function createNonceStr($length == 16) { 53 $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; 54 $str = ''; 55 for ($i=0; $i < $length; $i++) { 56 $str .= substr(mt_rand(0, strlen($chars)), 1); 57 } 58 return $str; 59 } 60 61 /** 62 * 獲取公衆號用於調用微信JS接口的臨時票據 63 * @return string 64 */ 65 private function getJsApiTicket() { 66 //先查看redis裏是否存了jsapi_ticket此值,假若有,就直接返回 67 $jsApiTicket = $this->library->redisCache->get('weixin:ticket'); 68 if (!$jsApiTicket) { 69 //先獲取access_token(公衆號的全局惟一票據) 70 $accessToken = $this->getApiToken(); 71 //經過access_token 採用http GET方式請求得到jsapi_ticket 72 $result = $this->callApi("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=$accessToken&type=jsapi"); 73 //獲得了jsapi_ticket 74 $jsApiTicket = $result['ticket']; 75 //將jsapi_ticket緩存到redis裏面,下次就不用再請求去取了 76 $expire = max(1, intval($result['expire']) - 60); 77 $this->library->redisCache->set('weixin:ticket', $jsApiTicket, $expire); 78 } 79 return $jsApiTicket; 80 } 81 82 /** 83 * 獲取衆號的全局惟一票據access_token 84 * @param boolean $forceRefresh 是否強制刷新 85 * @return string 返回access_token 86 */ 87 private function getApiToken($forceRefresh = false) { 88 //先查看redis是否存了accessToken,若是有了,就不用再去微信server去請求了(提升效率) 89 $accessToken = $this->library->redisCache->get('weixin:accessToken'); 90 //強制刷新accessToken或者accessToken爲空時就去請求accessToken 91 if ($forceRefresh || empty($accessToken)) { 92 //請求獲得accessToken 93 $result = $this->callApi("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$this->appId}&secret={$this->appSecret}"); 94 $accessToken = $result['access_token']; 95 $expire = max(1, intval($result['expire']) - 60); 96 //將其存進redis裏面去 97 $this->library->redisCache->set('weixin:accessToken', $accessToken, $expire); 98 } 99 return $accessToken; 100 } 101 102 //從微信服務器端下載圖片到本地服務器 103 public function wxDownImg($media_id, $path) { 104 //調用 多媒體文件下載接口 105 $url = "https://api.weixin.qq.com/cgi-bin/media/get?access_token={$this->model->weixin->_getApiToken()}&media_id=$media_id"; 106 //用curl請求,返回文件資源和curl句柄的信息 107 $info = $this->curl_request($url); 108 //文件類型 109 $types = array('image/bmp'=>'.bmp', 'image/gif'=>'.gif', 'image/jpeg'=>'.jpg', 'image/png'=>'.png'); 110 //判斷響應首部裏的的content-type的值是不是這四種圖片類型 111 if (isset($types[$info['header']['content_type']])) { 112 //文件的uri 113 $path = $path.$types[$info['header']['content_type']]; 114 } else { 115 return false; 116 } 117 118 //將資源寫入文件裏 119 if ($this->saveFile($path, $info['body'])) { 120 //將文件保存在本地目錄 121 $imgPath = rtrim(base_url(), '/').'/img'.date('Ymd').'/'.md5($this->controller->wxId.$media_id).$types[$info['header'['content_type']]]; 122 if (!is_dir($imgPath)) { 123 if(mkdir($imgPath)) { 124 if (false !== rename($path, $imgPath) { 125 return $imgPath; 126 } 127 } 128 } 129 return $path; 130 } 131 132 return false; 133 134 } 135 136 /** 137 * curl請求資源 138 * @param string $url 請求url 139 * @return array 140 */ 141 private function curl_request($url = '') { 142 if ($url == '') return; 143 $ch = curl_init(); 144 //這裏返回響應報文時,只要body的內容,其餘的都不要 145 curl_setopt($ch, CURLOPT_HEADER, 0); 146 curl_setopt($ch, CURLOPT_NOBODY, 0); 147 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 148 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); 149 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 150 $package = curl_exec($ch); 151 //獲取curl鏈接句柄的信息 152 $httpInfo = curl_getinfo($ch); 153 curl_close($ch); 154 155 $info = array_merge(array($package), array($httpInfo)); 156 157 return $info; 158 159 } 160 161 /** 162 * 將資源寫入文件 163 * @param string 資源uri 164 * @param source 資源 165 * @return boolean 166 */ 167 private function saveFile($path, $fileContent) { 168 $fp = fopen($path, 'w'); 169 if (false !== $localFile) { 170 if (false !== fwrite($fp, $fileContent)) { 171 fclose($fp); 172 return true; 173 } 174 } 175 return false; 176 } 177 178 } 179 180 181 182 183 184 185 186 187 ?>
1 <html> 2 <head> 3 4 </head> 5 <body> 6 <button id="uploadImage">點擊上傳圖片</button> 7 <script> 8 $(function(){ 9 $.util.wxMenuImage('{$wxJsApi|default:""}') 10 }); 11 </script> 12 </body> 13 </html>
1 if(typeof($util)=='undefined')$util={}; 2 3 $.util.wxMenuImage = function(json) { 4 if (json.length == 0) return; 5 //解析json變成js對象 6 wxJsApi = JSON.parse(json); 7 8 //經過config接口注入權限驗證配置 9 wx.config({ 10 debug: false, //開啓調試模式,調用的全部api的返回值會在客戶端alert出來 11 appId: wxJsApi.signPackage.appId, //公衆號的惟一標識 12 timestamp: wxJsApi.signPackage.timestamp, //生成簽名的時間戳 13 nonceStr: wxJsApi.signPackage.nonceStr, //生成簽名的隨機串 14 signature: wxJsApi.signPackage.signature, //簽名 15 jsApiList: ['chooseImage', 'uploadImage'] //須要使用的JS接口列表 這裏我用了選擇圖片和上傳圖片接口 16 }); 17 18 //經過ready接口處理成功驗證,config信息驗證後會執行ready方法,全部接口調用都必須在config接口得到結果以後 19 wx.ready(function(){ 20 //獲得上傳圖片按鈕 21 document.querySelector('#uploadImage').onclick = function() { 22 var images = {localId:[],serverId:[]}; 23 //調用 拍照或從手機相冊中選圖接口 24 wx.chooseImage({ 25 success: function(res) { 26 if (res.localIds.length != 1) { 27 alert('只能上傳一張圖片'); 28 return; 29 } 30 //返回選定照片的本地ID列表 31 iamges.localId = res.localIds; 32 images.serverId = []; 33 //上傳圖片函數 34 function upload() { 35 //調用上傳圖片接口 36 wx.uploadImage({ 37 localId: images.localId[0], // 須要上傳的圖片的本地ID,由chooseImage接口得到 38 isShowProcess: 1, // 默認爲1,顯示進度提示 39 success: function(res) { 40 //返回圖片的服務器端ID res.serverId,而後調用wxImgCallback函數進行下載圖片操做 41 wxImgCallback(res.serverId); 42 }, 43 fail: function(res) { 44 alert('上傳失敗'); 45 } 46 }); 47 } 48 upload(); 49 } 50 }); 51 } 52 }); 53 } 54 55 56 function wxImgCallback(serverId) { 57 //將serverId傳給wx_upload.php的upload方法 58 var url = 'wx_upload/upload/'+serverId; 59 $.getJSON(url, function(data){ 60 if (data.code == 0) { 61 alert(data.msg); 62 } else if (data.code == 1) { 63 //存儲到服務器成功後的處理 64 // 65 } 66 }); 67 }
代碼中有些方法沒有貼出來,你們要是想看看,能夠到http://www.cnblogs.com/it-cen/p/4535219.html 這篇博文去看。
本次講解就到此,這篇博文是給對微信接口開發有興趣的朋友參考,若是你是高手,徹底能夠繞道。
若是此博文中有哪裏講得讓人難以理解,歡迎留言交流,如有講解錯的地方歡迎指出。
若是您以爲您能在此博文學到了新知識,請爲我頂一個,如文章中有解釋錯的地方,歡迎指出。
互相學習,共同進步!