一 准备工作。
一 受限于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;
}
//返回为异常时,多多调试。