我這里借助微信JSSDK的圖像接口對其進行開發(fā)實現(xiàn)圖片上傳的功能,為何我選擇此接口?第一,目前的項目是在微信中打開的網(wǎng)頁,利用此接口,性能肯定是好一點的啦,畢竟是微信自己的東西;第二,用此接口,開發(fā)效率更高嘛;第三,最重要的一點,就是它能對圖片進行壓縮,假如一張2M的圖片,通過微信圖片上傳接口可以將圖片壓縮成幾百K的大小,這對網(wǎng)站的性能是很有幫助的。
一、我的思路是:
先調(diào)用“拍照或從手機相冊選擇圖片接口”—>選擇成功圖片后—>調(diào)用“上傳圖片接口”—>上傳成功后(也就是圖片上傳到了微信服務(wù)器上)—>調(diào)用“下載圖片接口”—>將圖片下載到自己的服務(wù)器存儲。
?
二、JSSDK的使用步驟
1、概述
微信JS-SDK是微信公眾平臺面向網(wǎng)頁開發(fā)者提供的基于微信內(nèi)的網(wǎng)頁開發(fā)工具包。
通過使用微信JS-SDK,網(wǎng)頁開發(fā)者可借助微信高效地使用拍照、選圖、語音、位置等手機系統(tǒng)的能力,同時可以直接使用微信分享、掃一掃、卡券、支付等微信特有的能力,為微信用戶提供更優(yōu)質(zhì)的網(wǎng)頁體驗。
2、使用步驟
步驟一:綁定域名
先登錄微信公眾平臺進入“公眾號設(shè)置”的“功能設(shè)置”里填寫“JS接口安全域名”。
備注:登錄后可在“開發(fā)者中心”查看對應(yīng)的接口權(quán)限。
步驟二:引入JS文件
在需要調(diào)用JS接口的頁面引入如下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.0.0.js
步驟三:通過config接口注入權(quán)限驗證配置
所有需要使用JS-SDK的頁面必須先注入配置信息,否則將無法調(diào)用(同一個url僅需調(diào)用一次,對于變化url的SPA的web app可在每次url變化時進行調(diào)用)
wx.config({
????debug:?true,?//?開啟調(diào)試模式,調(diào)用的所有api的返回值會在客戶端alert出來,若要查看傳入的參數(shù),可以在pc端打開,參數(shù)信息會通過log打出,僅在pc端時才會打印。
????appId:?'',?//?必填,公眾號的唯一標識
????timestamp:?,?//?必填,生成簽名的時間戳
????nonceStr:?'',?//?必填,生成簽名的隨機串
????signature:?'',//?必填,簽名,見附錄1
????jsApiList:?[]?//?必填,需要使用的JS接口列表,所有JS接口列表見附錄2
});
步驟四:通過ready接口處理成功驗證
wx.ready(function(){
????//?config信息驗證后會執(zhí)行ready方法,所有接口調(diào)用都必須在config接口獲得結(jié)果之后,config是一個客戶端的異步操作,所以如果需要在頁面加載時就調(diào)用相關(guān)接口,則須把相關(guān)接口放在ready函數(shù)中調(diào)用來確保正確執(zhí)行。對于用戶觸發(fā)時才調(diào)用的接口,則可以直接調(diào)用,不需要放在ready函數(shù)中。
});
步驟五:通過error接口處理失敗驗證
wx.error(function(res){
????//?config信息驗證失敗會執(zhí)行error函數(shù),如簽名過期導(dǎo)致驗證失敗,具體錯誤信息可以打開config的debug模式查看,也可以在返回的res參數(shù)中查看,對于SPA可以在這里更新簽名。
});
接口調(diào)用說明
所有接口通過wx對象(也可使用jWeixin對象)來調(diào)用,參數(shù)是一個對象,除了每個接口本身需要傳的參數(shù)之外,還有以下通用參數(shù):
success:接口調(diào)用成功時執(zhí)行的回調(diào)函數(shù)。
fail:接口調(diào)用失敗時執(zhí)行的回調(diào)函數(shù)。
complete:接口調(diào)用完成時執(zhí)行的回調(diào)函數(shù),無論成功或失敗都會執(zhí)行。
cancel:用戶點擊取消時的回調(diào)函數(shù),僅部分有用戶取消操作的api才會用到。
trigger: 監(jiān)聽Menu中的按鈕點擊時觸發(fā)的方法,該方法僅支持Menu中的相關(guān)接口。
備注:不要嘗試在trigger中使用ajax異步請求修改本次分享的內(nèi)容,因為客戶端分享操作是一個同步操作,這時候使用ajax的回包會還沒有返回。
以上幾個函數(shù)都帶有一個參數(shù),類型為對象,其中除了每個接口本身返回的數(shù)據(jù)之外,還有一個通用屬性errMsg,其值格式如下:
調(diào)用成功時:"xxx:ok" ,其中xxx為調(diào)用的接口名
用戶取消時:"xxx:cancel",其中xxx為調(diào)用的接口名
調(diào)用失敗時:其值為具體錯誤信息
三、開發(fā)及代碼分析詳解(用的是CI框架,只要是MVC模式都可以)
1、先在服務(wù)器端取到:公眾號的唯一標識appId、生成簽名的時間戳timestamp、生成簽名的隨機串nonceStr、簽名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()));
????}
圖片上傳控制器
<?php
class WxModel extends ModelBase{
public $appId;
public $appSecret;
public $token;
public function __construct() {
parent::__construct();
//審核通過的移動應(yīng)用所給的AppID和AppSecret
$this->appId?=?'wx0000000000000000';
????????????$this->appSecret?=?'00000000000000000000000000000';
????????????$this->token?=?'00000000';
????????}
????????/**
?????????*?獲取jssdk所需參數(shù)的所有值
?????????*?@return?array
?????????*/
????????public?function?signPackage()?{
????????????$protocol?=?(!empty($_SERVER['HTTPS']?&&?$_SERVER['HTTPS']?==?'off'?||?$_SERVER['port']?==?443))???'https://'?:?'http://';
????????????//當前網(wǎng)頁的URL
????????????$url?=?"$protocol$_SERVER['host']$_SERVER['REQUEST_URI']";
????????????//生成簽名的時間戳
????????????$timestamp?=?time();
????????????//生成簽名的隨機串
????????????$nonceStr?=?$this->createNonceStr();
????????????//獲取公眾號用于調(diào)用微信JS接口的臨時票據(jù)
????????????$jsApiTicket?=?$this->getJsApiTicket();
????????????//對所有待簽名參數(shù)按照字段名的ASCII?碼從小到大排序(字典序)后,
????????????//使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字符串$str。
????????????//這里需要注意的是所有參數(shù)名均為小寫字符
????????????$str?=?"jsapi_ticket=$jsApiTicket&noncestr=$nonceStr×tamp=$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;
????????}
????????/**
?????????*?創(chuàng)建簽名的隨機字符串
?????????*?@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;
}
/**
* 獲取公眾號用于調(diào)用微信JS接口的臨時票據(jù)
* @return string
*/
private function getJsApiTicket() {
//先查看redis里是否存了jsapi_ticket此值,假如有,就直接返回
$jsApiTicket = $this->library->redisCache->get('weixin:ticket');
????????????if?(!$jsApiTicket)?{
????????????????//先獲取access_token(公眾號的全局唯一票據(jù))
????????????????$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;
????????}
????????/**
?????????*?獲取眾號的全局唯一票據(jù)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;
????????}
獲取到appId、nonceStr、timestamp、signature模型
這里要補充一些 JS-SDK使用權(quán)限簽名算法 的思路和注意點(這里我直接復(fù)制官網(wǎng)文檔給大家看看)
jsapi_ticket
生成簽名之前必須先了解一下jsapi_ticket,jsapi_ticket是公眾號用于調(diào)用微信JS接口的臨時票據(jù)。正常情況下,jsapi_ticket的有效期為7200秒,通過access_token來獲取。由于獲取jsapi_ticket的api調(diào)用次數(shù)非常有限,頻繁刷新jsapi_ticket會導(dǎo)致api調(diào)用受限,影響自身業(yè)務(wù),開發(fā)者必須在自己的服務(wù)全局緩存jsapi_ticket?。
1、獲取access_token(有效期7200秒,開發(fā)者必須在自己的服務(wù)全局緩存access_token)
2、用第一步拿到的access_token 采用http GET方式請求獲得jsapi_ticket(有效期7200秒,開發(fā)者必須在自己的服務(wù)全局緩存jsapi_ticket)
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權(quán)限驗證的簽名了。
簽名算法
簽名生成規(guī)則如下:參與簽名的字段包括noncestr(隨機字符串), 有效的jsapi_ticket, timestamp(時間戳), url(當前網(wǎng)頁的URL,不包含#及其后面部分) 。對所有待簽名參數(shù)按照字段名的ASCII 碼從小到大排序(字典序)后,使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字符串string1。這里需要注意的是所有參數(shù)名均為小寫字符。對string1作sha1加密,字段名和字段值都采用原始值,不進行URL 轉(zhuǎn)義。
即signature=sha1(string1)。 示例:
noncestr=Wm3WZYTPz0wzccnW
jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg
timestamp=1414587457
url=http://mp.weixin.qq.com?params=value
步驟1. 對所有待簽名參數(shù)按照字段名的ASCII 碼從小到大排序(字典序)后,使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字符串string1:
jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW×tamp=1414587457&url=http://m.miracleart.cn/
步驟2. 對string1進行sha1簽名,得到signature:
0f9de62fce790f9a083d5c99e95740ceb90c27ed
注意事項
1.簽名用的noncestr和timestamp必須與wx.config中的nonceStr和timestamp相同。
2.簽名用的url必須是調(diào)用JS接口頁面的完整URL。
3.出于安全考慮,開發(fā)者必須在服務(wù)器端實現(xiàn)簽名的邏輯。
?
? 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接口注入權(quán)限驗證配置
????wx.config({
????????debug:?false,???//開啟調(diào)試模式,調(diào)用的所有api的返回值會在客戶端alert出來
????????appId:?wxJsApi.signPackage.appId,???//公眾號的唯一標識
????????timestamp:?wxJsApi.signPackage.timestamp,???//生成簽名的時間戳
????????nonceStr:?wxJsApi.signPackage.nonceStr,?//生成簽名的隨機串
????????signature:?wxJsApi.signPackage.signature,???//簽名
????????jsApiList:?['chooseImage',?'uploadImage']???//需要使用的JS接口列表?這里我用了選擇圖片和上傳圖片接口
????});
????//通過ready接口處理成功驗證,config信息驗證后會執(zhí)行ready方法,所有接口調(diào)用都必須在config接口獲得結(jié)果之后
????wx.ready(function(){
????????//得到上傳圖片按鈕
????????document.querySelector('#uploadImage').onclick?=?function()?{
????????????var?images?=?{localId:[],serverId:[]};
????????????//調(diào)用?拍照或從手機相冊中選圖接口
????????????wx.chooseImage({
????????????????success:?function(res)?{
????????????????????if?(res.localIds.length?!=?1)?{
????????????????????????alert('只能上傳一張圖片');
????????????????????????return;
????????????????????}
????????????????????//返回選定照片的本地ID列表
????????????????????iamges.localId?=?res.localIds;
????????????????????images.serverId?=?[];
????????????????????//上傳圖片函數(shù)
????????????????????function?upload()?{
????????????????????????//調(diào)用上傳圖片接口
????????????????????????wx.uploadImage({
????????????????????????????localId:?images.localId[0],?//?需要上傳的圖片的本地ID,由chooseImage接口獲得
????????????????????????????isShowProcess:?1,???//?默認為1,顯示進度提示
????????????????????????????success:?function(res)?{
????????????????????????????????//返回圖片的服務(wù)器端ID?res.serverId,然后調(diào)用wxImgCallback函數(shù)進行下載圖片操作
????????????????????????????????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)?{
????????????//存儲到服務(wù)器成功后的處理
????????????//
????????}
????});
}
圖片選擇和圖片上傳接口調(diào)用
圖片選擇和圖片上傳接口調(diào)用
?
3、圖片上傳完成后會返回一個serverId,然后通過這個來下載圖片到本地服務(wù)器
這里先補充下如何調(diào)用下載圖片接口(我直接復(fù)制官方文檔的說明了)
公眾號可調(diào)用本接口來獲取多媒體文件。請注意,視頻文件不支持下載,調(diào)用該接口需http協(xié)議。
接口調(diào)用請求說明
http請求方式:?GET
http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID
參數(shù)說明
參數(shù) |
是否必須 |
說明 |
access_token |
是 |
調(diào)用接口憑證 |
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數(shù)據(jù)包示例如下(示例為無效媒體ID錯誤)::
{"errcode":40007,"errmsg":"invalid?media_id"}
接下來看自己寫的代碼
wx_upload.php
/*********************圖片下載到本地服務(wù)器****************************************/
????//從微信服務(wù)器讀取圖片,然后下載到本地服務(wù)器
????public?function?upload($media_id)?{
????????//圖片文件名
????????$fileName?=?md5($this->wxId."/$media_id");
????????//調(diào)用下載圖片接口,返回路徑
????????$path?=?$this->weixin->wxDownImg($media_id,?sys_get_temp_dir()."$fileName");
????????if?($path?!=?false)?{
????????????//將圖片的路徑插入數(shù)據(jù)庫去存儲
????????????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')));
????????}
????????
????}
從微信服務(wù)器下載圖片到本地存儲
//從微信服務(wù)器端下載圖片到本地服務(wù)器
????????public?function?wxDownImg($media_id,?$path)?{
????????????//調(diào)用?多媒體文件下載接口
????????????$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');
????????????//判斷響應(yīng)首部里的的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();
????????????//這里返回響應(yīng)報文時,只要body的內(nèi)容,其他的都不要
????????????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;
????????}
從微信服務(wù)器下載圖片到本地存儲接口
到這里,已經(jīng)完成了:
先調(diào)用“拍照或從手機相冊選擇圖片接口”—>選擇成功圖片后—>調(diào)用“上傳圖片接口”—>上傳成功后(也就是圖片上傳到了微信服務(wù)器上)—>調(diào)用“下載圖片接口”—>將圖片下載到自己的服務(wù)器存儲。
這一思路的實現(xiàn)。我們用到了微信的選擇圖片接口、上傳圖片接口和下載媒體資源接口。
下面我附上這一接口開發(fā)的全部代碼:
<?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()));
????}
????/*********************圖片下載到本地服務(wù)器****************************************/
????//從微信服務(wù)器讀取圖片,然后下載到本地服務(wù)器
????public?function?upload($media_id)?{
????????//圖片文件名
????????$fileName?=?md5($this->wxId."/$media_id");
????????//調(diào)用下載圖片接口,返回路徑
????????$path?=?$this->weixin->wxDownImg($media_id,?sys_get_temp_dir()."$fileName");
????????if?($path?!=?false)?{
????????????//將圖片的路徑插入數(shù)據(jù)庫去存儲
????????????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();
//審核通過的移動應(yīng)用所給的AppID和AppSecret
$this->appId?=?'wx0000000000000000';
????????????$this->appSecret?=?'00000000000000000000000000000';
????????????$this->token?=?'00000000';
????????}
????????/**
?????????*?獲取jssdk所需參數(shù)的所有值
?????????*?@return?array
?????????*/
????????public?function?signPackage()?{
????????????$protocol?=?(!empty($_SERVER['HTTPS']?&&?$_SERVER['HTTPS']?==?'off'?||?$_SERVER['port']?==?443))???'https://'?:?'http://';
????????????//當前網(wǎng)頁的URL
????????????$url?=?"$protocol$_SERVER['host']$_SERVER['REQUEST_URI']";
????????????//生成簽名的時間戳
????????????$timestamp?=?time();
????????????//生成簽名的隨機串
????????????$nonceStr?=?$this->createNonceStr();
????????????//獲取公眾號用于調(diào)用微信JS接口的臨時票據(jù)
????????????$jsApiTicket?=?$this->getJsApiTicket();
????????????//對所有待簽名參數(shù)按照字段名的ASCII?碼從小到大排序(字典序)后,
????????????//使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字符串$str。
????????????//這里需要注意的是所有參數(shù)名均為小寫字符
????????????$str?=?"jsapi_ticket=$jsApiTicket&noncestr=$nonceStr×tamp=$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;
????????}
????????/**
?????????*?創(chuàng)建簽名的隨機字符串
?????????*?@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;
}
/**
* 獲取公眾號用于調(diào)用微信JS接口的臨時票據(jù)
* @return string
*/
private function getJsApiTicket() {
//先查看redis里是否存了jsapi_ticket此值,假如有,就直接返回
$jsApiTicket = $this->library->redisCache->get('weixin:ticket');
????????????if?(!$jsApiTicket)?{
????????????????//先獲取access_token(公眾號的全局唯一票據(jù))
????????????????$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;
????????}
????????/**
?????????*?獲取眾號的全局唯一票據(jù)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;
????????}
????????//從微信服務(wù)器端下載圖片到本地服務(wù)器
????????public?function?wxDownImg($media_id,?$path)?{
????????????//調(diào)用?多媒體文件下載接口
????????????$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');
????????????//判斷響應(yīng)首部里的的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();
????????????//這里返回響應(yīng)報文時,只要body的內(nèi)容,其他的都不要
????????????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接口注入權(quán)限驗證配置
????wx.config({
????????debug:?false,???//開啟調(diào)試模式,調(diào)用的所有api的返回值會在客戶端alert出來
????????appId:?wxJsApi.signPackage.appId,???//公眾號的唯一標識
????????timestamp:?wxJsApi.signPackage.timestamp,???//生成簽名的時間戳
????????nonceStr:?wxJsApi.signPackage.nonceStr,?//生成簽名的隨機串
????????signature:?wxJsApi.signPackage.signature,???//簽名
????????jsApiList:?['chooseImage',?'uploadImage']???//需要使用的JS接口列表?這里我用了選擇圖片和上傳圖片接口
????});
????//通過ready接口處理成功驗證,config信息驗證后會執(zhí)行ready方法,所有接口調(diào)用都必須在config接口獲得結(jié)果之后
????wx.ready(function(){
????????//得到上傳圖片按鈕
????????document.querySelector('#uploadImage').onclick?=?function()?{
????????????var?images?=?{localId:[],serverId:[]};
????????????//調(diào)用?拍照或從手機相冊中選圖接口
????????????wx.chooseImage({
????????????????success:?function(res)?{
????????????????????if?(res.localIds.length?!=?1)?{
????????????????????????alert('只能上傳一張圖片');
????????????????????????return;
????????????????????}
????????????????????//返回選定照片的本地ID列表
????????????????????iamges.localId?=?res.localIds;
????????????????????images.serverId?=?[];
????????????????????//上傳圖片函數(shù)
????????????????????function?upload()?{
????????????????????????//調(diào)用上傳圖片接口
????????????????????????wx.uploadImage({
????????????????????????????localId:?images.localId[0],?//?需要上傳的圖片的本地ID,由chooseImage接口獲得
????????????????????????????isShowProcess:?1,???//?默認為1,顯示進度提示
????????????????????????????success:?function(res)?{
????????????????????????????????//返回圖片的服務(wù)器端ID?res.serverId,然后調(diào)用wxImgCallback函數(shù)進行下載圖片操作
????????????????????????????????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)?{
????????????//存儲到服務(wù)器成功后的處理
????????????//
????????}
????});
}
本次講解就到此,這篇博文是給對微信接口開發(fā)有興趣的朋友參考,如果你是高手,完全可以繞道。
?更多微信JS-SDK之圖像接口開發(fā)相關(guān)文章請關(guān)注PHP中文網(wǎng)!