一 準備工作。
一 受限於wx 上傳圖片時,要getToken ,而調access_token 時,需要加ip 白名單。不然報 invalid signature
出現如下情況,優先考慮ip 白名單問題,當然還有可能 ngix 反向代理引發的問題,我暫時沒碰到。
其次就是 js 安全域名設置
進入後按微信平臺要求設好對應的域名。
二 代碼實現
//控制器層
$data = MyWxServ::getParams();
$this->render("index" , $data);
//視圖層
<script src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
<script src="http://apps.bdimg.com/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<!--圖片類型驗證方法1-->
<input type="button" value="選擇上傳文件" class = 'chooseImg' />
<input type="button" value="上傳" class = 'uploadImg' />
<h4>選擇文件如下:</h4>
<img id="img1" src = '/1.jpg' style="width: 250px;"/>
</div>
<script>
function wxConfig(appId,timestamp,nonceStr,signature) {
wx.config({
debug: true, // 開啓調試模式,調用的所有api的返回值會在客戶端alert出來,若要查看傳入的參數,可以在pc端打開,參數信息會通過log打出,僅在pc端時纔會打印。
appId: appId, // 必填,公衆號的唯一標識
timestamp:timestamp , // 必填,生成簽名的時間戳
nonceStr: nonceStr, // 必填,生成簽名的隨機串
signature: signature,// 必填,簽名
jsApiList: ['chooseImage', 'previewImage','uploadImage','downloadImage','getLocalImgData'] // 必填,需要使用的JS接口列表
});
wx.ready(function(){ });
wx.error(function(res){ });
}
wxConfig('<?php echo $appid;?>' , <?php echo $time;?> , '<?php echo $noncestr;?>', '<?php echo $sign; ?>' )
wx.ready(function(){
// config信息驗證後會執行ready方法,所有接口調用都必須在config接口獲得結果之後,config是一個客戶端的異步操作,所以如果需要在頁面加載時就調用相關接口,則須把相關接口放在ready函數中調用來確保正確執行。對於用戶觸發時才調用的接口,則可以直接調用,不需要放在ready函數中。
});
wx.error(function(res){
// config信息驗證失敗會執行error函數,如簽名過期導致驗證失敗,具體錯誤信息可以打開config的debug模式查看,也可以在返回的res參數中查看,對於SPA可以在這裏更新簽名。
});
var images = {
localId: [],
serverId: []
};
$(".uploadImg").click(function(){
wx.uploadImage({
localId: images.localId[0],
success: function (res) {
var serverId = res.serverId; // 返回圖片的服務器端ID
$.get("/wxpic/upload", {media_id:serverId},function(r){
alert(r);
})
},
fail: function (res) {
alert(JSON.stringify(res));
}
});
});
$(".chooseImg").click(function() {
wx.chooseImage({
count:1,
success: function (res) {
images.localId = res.localIds;
// alert('已選擇 ' + res.localIds.length + ' 張圖片');
$("#img1").attr("src" ,res.localIds[0] );
if (images.localId.length == 0) {
alert('請先使用 chooseImage 接口選擇圖片');
return;
}
}
});
});
</script>
class MyWxServ
{
static function getParams(){
$appid = "xxxx";
$sercet = "yyyy";
$ticket = self::getJsapiTicket($appid, $sercet, 0);
$data["appid"] = $appid;
$data["sercet"] = $sercet;
$data["ticket"] = $ticket;
$noncestr = "1234567";
$data["noncestr"] = $noncestr;
$time = time();
$url = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
$sign = sha1("jsapi_ticket=$ticket&noncestr=$noncestr×tamp=$time&url=$url");
$data["sign"] = $sign;
$data["is_wx"] = true;
$data["time"] = $time;
return $data;
}
static function getToken($time, $appid, $secret)
{
$url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' . $appid . '&secret=' . $secret;
$obj = self::accessapi($url, 0, "GET");
if (!isset($obj->expires_in)) {
return false;
}
$obj->expires_in = $time + $obj->expires_in - 30;
return $obj;
}
public static function getAccessToken($update = 0, $appid = '', $secret = '')
{
$time = time();
$token_file = COMMON_FOLDER . '/logs/' . $appid . '.token';
if (is_file($token_file)) {
$token = file_get_contents($token_file);
$obj = json_decode($token);
if ($obj->expires_in < $time || $update == 1) {
$obj = self::getToken($time, $appid, $secret);
if (!$obj) {
return false;
}
file_put_contents($token_file, json_encode($obj));
}
} else {
$obj = self::getToken($time, $appid, $secret);
if (!$obj) {
return false;
}
file_put_contents($token_file, json_encode($obj), 777);
}
return $obj->access_token;
}
static function accessapi($url, $method = 'POST', $jsonData = '', $repeat = 1, $appid = '', $secret = '')
{
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonData);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$tmpInfo = curl_exec($ch);
if (curl_errno($ch)) {
echo 'Errno:' . curl_error($ch);
exit;
}
curl_close($ch);
$obj = json_decode($tmpInfo);
Yii::log($tmpInfo, 'error', '$obj');
if (!is_object($obj)) {
Yii::log( "accessapi異常:".print_r($obj , 1), CLogger::LEVEL_ERROR ,'log_error');
return $tmpInfo;
}
if (isset($obj->errcode)) {
if ($obj->errcode == 40001 && $repeat == 1) {
$arr = parse_url($url);
$arr1 = explode('&', $arr['query']);
$query = '';
if (count($arr1) > 0 && $arr['query']) {
$i = 0;
foreach ($arr1 as $arr2) {
$arr3 = explode("=", $arr2);
if ($arr3[0] == 'access_token') {
$token = self::getAccessToken(1, $appid, $secret);
$arr2 = $arr3[0] . '=' . $token;
}
if ($i > 0) {
$query .= '&' . $arr2;
} else {
$query .= $arr2;
}
$i++;
}
}
$url = $arr['scheme'] . '://' . $arr['host'] . $arr['path'] . '?' . $query;
return self::accessapi($url, $method, $jsonData, 0);
}
}
return $obj;
}
static function getJsapiTicket($appid, $sercet, $update = 0)
{
$time = time();
$token_file = COMMON_FOLDER . '/logs/' . $appid . '.ticket';
if (!$update && is_file($token_file)) {
$token = file_get_contents($token_file);
$obj = json_decode($token);
if (!isset($obj->expires_in) || $obj->expires_in < $time || $update == 1) {
self::getJsapiTicket($appid, $sercet, 1);
}
} else {
$token = self::getAccessToken(0, $appid, $sercet);
$url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" . $token . "&type=jsapi";
$obj = WxServ::accessapi($url, 'get');
if (!$obj || $obj->errcode) {
return false;
}
$obj->expires_in = $time + $obj->expires_in - 30;
file_put_contents($token_file, json_encode($obj));
}
return $obj->ticket;
}
public static function getMaterialImage($media_id, $appid = '', $sercet = '')
{
$token = self::getAccessToken(0, $appid, $sercet);
Yii::log($token, 'error', '$token');
$url = "https://api.weixin.qq.com/cgi-bin/media/get?access_token=" . $token . "&media_id=" . $media_id;
$json = self::accessapi($url, 'POST', '', 1, $appid, $sercet);
$filename = $media_id . '.jpg';
file_put_contents($_SERVER["DOCUMENT_ROOT"]."/" . $filename, $json);
return $filename;
}
}
三 其它
如果需要把從微信下載到服務器上。
var serverId = res.serverId; // 返回圖片的服務器端ID
//將服務器端的serverId 做爲參數傳參。
$.get("/wxpic/upload", {media_id:serverId},function(r){
alert(r);
})
//服務器端保存下即可。
$media_id = $_GET["media_id"];
$appid = "xxx";
$sercet = "yyy";
$name = MyWxServ::getMaterialImage($media_id, $appid , $sercet);
echo $name;
public static function getMaterialImage($media_id, $appid = '', $sercet = '')
{
$token = self::getAccessToken(0, $appid, $sercet);
//調用微信得到media 數據的接口。
$url = "https://api.weixin.qq.com/cgi-bin/media/get?access_token=" . $token . "&media_id=" . $media_id;
$json = self::accessapi($url, 'POST', '', 1, $appid, $sercet);
$filename = $media_id . '.jpg';
file_put_contents($_SERVER["DOCUMENT_ROOT"]."/" . $filename, $json);
return $filename;
}
總結: 難點在於微信授權這塊的折騰。
//所以 MyWxServ 的 getJsapiTicket 方法
$obj = WxServ::accessapi($url, 'get');
if (!$obj || $obj->errcode) {
return false;
}
//返回爲異常時,多多調試。