微信开发接口封装调用
我们知道微信公众号开发主要就是调用微信官方开放给我们的一些接口。这里就不再一个一个接口的示例了,我直接把自己封装好的一个微信接口类展示一下,可以直接套用。后续会不断完善。
1.首先我写了一个入口文件index.php。这个文件主要是微信公众号后台配置时候的验证以及分离请求方向。
<?php
/*
入口文件,使用之前需要先引入调用的类文件
*/
require_once('weixin_api.php');
define("TOKEN","weixin");//定义TOKEN值,此值在微信公众号后台自定义。
$echoStr = $_GET["echostr"];
$weixin = new WeixinApi();//实例化WeixinApi类
if (!isset($echoStr)) {
$weixin->responseMsg();//调用responseMsg()函数
}else{
$weixin->valid();//调用valid()函数
}
2.这个文件就是封装好的一些常用接口:weixin_api.php,代码中都有详细的注释,可以关联查看
<?php
/*
封装成类:WeixinApi
signature,timestamp,nonce:由微信服务器通过GET方法发送过来
TOKEN:开发者在公众号中自定义
*/
class WeixinApi
{
//验证消息
public function valid()
{
if($this->checkSignature()){
echo $_GET["echostr"];
}else{
echo "ERROR";
}
}
//检验微信加密签名,私有化
private function checkSignature()
{
$signature = $_GET["signature"];//1.signature:微信加密签名,由开发者填写的 TOKEN值,请求中的时间戳timesstamp,随机数nonce 组合而成
$timestamp = $_GET["timestamp"];//2.timestamp:时间戳
$nonce = $_GET["nonce"];//3.nonce:随机数
$token = TOKEN;//4.TOKEN值
$tmpArr = array($token, $timestamp, $nonce);//以上2,3,4三个参数使用 sort() 函数进行字典排序
sort($tmpArr,SORT_STRING);
$tmpStr = implode( $tmpArr );
$tmpStr = sha1( $tmpStr );//数组再转化为字符串,然后进行哈希sha1加密
if( $tmpStr == $signature ){
return true;
}else{
return false;
}
}
//响应消息responseMsg
public function responseMsg()
{
//1.接收XML数据包
$postData = $GLOBALS["HTTP_RAW_POST_DATA"];//$HTTP_RAW_POST_DATA;
//2将日志写入xml文件
$this->logger("R \r\n".$postData);
//3处理XML数据包
$xmlObj = simplexml_load_string($postData,"simpleXMLElement",LIBXML_NOCDATA);//将XML字符串载入对象中,失败返回false
$toUserName = $xmlObj->ToUserName;//获取开发者微信号
$fromUserName = $xmlObj->FromUserName;//获取用户的openID
//收到的消息类型
$msgType = $xmlObj->MsgType;//发送的消息类型(text)
switch ($msgType)
{ case 'event': //事件
echo $this->receiveEvent($xmlObj);
break;
case 'text': //文本
echo $this->receiveText($xmlObj);
break;
case 'image': //图片
echo $this->receiveImage($xmlObj);
break;
case 'voice': //语音
echo $this->receiveVoice($xmlObj);
break;
default:
# code...
break;
}
}
//接收推送事件消息receiveEvent
public function receiveEvent($obj)
{
$openid = $obj->FromUserName;
$event = $obj->Event;
switch ($event) {
//关注事件
case 'subscribe':
require_once('wxjssdk.php');
$jssdk = new JSSDK();
$userinfo = $jssdk->get_user_info($openid);
$municipalities = array("北京", "上海", "天津", "重庆", "香港", "澳门"); //四市二区 市名为区地区,这里用省名代替市名
if (in_array($userinfo['province'], $municipalities)){
$userinfo['city'] = $userinfo['province'];
}
$content = "您好:欢迎".$userinfo['nickname'];
if ($userinfo['country'] == '中国') {
require_once('weather.php');
$weatherInfo = getWeatherInfo($userinfo['city']);
$content .= "您来自".$userinfo['city']." \n欢迎关注:谷文杰微信公众测试号 \n QQ:1140243510 \n 微信:q18737198019 \n 回复'资讯' 获取最新资讯!\n 当前天气如下\r\n".$weatherInfo[1]["Title"];
}
return $this->replyText($obj,$content);
break;
//取消关注事件
case 'unsubscribe':
$content = "取消关注";
return $this->replyText($obj,$content);
break;
case 'CLICK':
switch ($obj->EventKey) {//自定义菜单中的key值
case 'getnew':
$content = array(
array(
'Title'=>'爽歪歪',
'Description'=>'爽歪歪,酷爽一夏!',
'PicUrl'=>'http://wxtest.freephp.top/wxSDK/img/5147dc2160c34.jpg',
'Url'=>'https://www.baidu.com/home/news/data/newspage?nid=17137570521980907234&n_type=0&p_from=1&dtype=-1'
)
);
return $this->replyNews($obj,$content);
break;
default:
# code...
break;
}
break;
default:
# code...
break;
}
}
//接收文本消息receiveText
public function receiveText($obj)
{
$content = trim($obj->Content);//获取文本内容
//进行关键字回复
switch ($content)
{
case '你好':
return $this->replyText($obj,"姓名:谷文杰 \n QQ:1140243510 \n 微信:q18737198019");
break;
case '资讯':
$newsArr = array(
array(
'Title'=>'爽歪歪',
'Description'=>'爽歪歪,酷爽一夏!',
'PicUrl'=>'http://wxtest.freephp.top/wxSDK/img/5147dc2160c34.jpg',
'Url'=>'https://www.baidu.com/home/news/data/newspage?nid=17137570521980907234&n_type=0&p_from=1&dtype=-1'
),
array(
'Title'=>'歪歪爽',
'Description'=>'酷爽一夏,爽歪歪!',
'PicUrl'=>'http://wxtest.freephp.top/wxSDK/img/5147dc20619b2.jpg',
'Url'=>'https://www.baidu.com/home/news/data/newspage?nid=3396686089578539736&n_type=0&p_from=1&dtype=-1'
)
);
return $this->replyNews($obj,$newsArr);
break;
default:
return $this->replyText($obj,$content);
break;
}
}
//接收图片消息
public function receiveImage($obj)
{
$array = array('mediaId'=>$obj->MediaId);
return $this->replyImage($obj,$array);
}
//接收语音消息
public function receiveVoice($obj)
{
if (isset($obj->Recognition) && !empty($obj->Recognition)){
$content = "你刚才说的是:".$obj->Recognition;
return $this->replyText($obj,$content);
}else{
$content = array("mediaId"=>$obj->MediaId);
return $this->replyVoice($obj,$content);
}
}
//回复文本消息replyText
public function replyText($obj,$content)
{
$replyTextMsg = '<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>';
return sprintf($replyTextMsg,$obj->FromUserName,$obj->ToUserName,time(),$content);
}
//回复图片消息replyImage
public function replyImage($obj,$array)
{
$replyImgMsg = '<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[image]]></MsgType>
<Image>
<MediaId><![CDATA[%s]]></MediaId>
</Image>
</xml>';
return sprintf($replyImgMsg,$obj->FromUserName,$obj->ToUserName,time(),$array['mediaId']);
}
//回复图文消息replyNews
public function replyNews($obj,$newsArr)
{
if (is_array($newsArr)) {
$item = "";
foreach($newsArr as $val){
$itemTpl = "<item>
<Title><![CDATA[%s]]></Title>
<Description><![CDATA[%s]]></Description>
<PicUrl><![CDATA[%s]]></PicUrl>
<Url><![CDATA[%s]]></Url>
</item>";
$item .= sprintf($itemTpl,$val['Title'],$val['Description'],$val['PicUrl'],$val['Url']);
}
$replyNewsMsg = '<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[news]]></MsgType>
<ArticleCount>%u</ArticleCount>
<Articles>'.$item.'</Articles>
</xml>';
return sprintf($replyNewsMsg,$obj->FromUserName,$obj->ToUserName,time(),count($newsArr));
}
}
//回复语音消息
public function replyVoice($obj,$content)
{
$voiceTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[voice]]></MsgType>
<Voice>
<MediaId><![CDATA[%s]]></MediaId>
</Voice>
</xml>";
return sprintf($voiceTpl,$obj->FromUserName, $obj->ToUserName,time(),$content['mediaId']);
}
//日志记录
private function logger($log_content)
{
if(isset($_SERVER['HTTP_APPNAME'])){ //SAE
sae_set_display_errors(false);
}else if($_SERVER['REMOTE_ADDR'] != "127.0.0.1"){ //LOCAL
$max_size = 1000000;
$log_filename = "log.xml";
if(file_exists($log_filename) and (abs(filesize($log_filename)) > $max_size)){unlink($log_filename);}
file_put_contents($log_filename, date('Y-m-d H:i:s')." ".$log_content."\r\n", FILE_APPEND);
}
}
}
3.其中在接受关注事件的时候,实例化了一个jSSDK类,这个类主要处理获取用户信息以及获取卡券信息
<?php
/*
微信JSSDK类
1.jsapi_ticket:是公众号用于调用微信JS接口的临时票据,jsapi_ticket的有效期为7200秒,通过access_token来获取
2.JS SDK签名:参与签名的字段包括noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳), url(当前网页的URL,不包含#及其后面部分)。对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1。这里需要注意的是所有参数名均为小写字符。对string1作sha1加密,字段名和字段值都采用原始值,不进行URL 转义
3.在TP中引入使用vendor方法注意:如果你的类库没有使用命名空间定义的话,实例化的时候需要加上根命名空间。
*/
class JSSDK
{
var $appid = 'wx*************49';
var $appsecret = '3a6*****************************15c';
//构造函数,获取Access Token
public function __construct($appid = NULL, $appsecret = NULL)
{
if($appid && $appsecret){
$this->appid = $appid;
$this->appsecret = $appsecret;
}
$res = file_get_contents('access_token.json');
$result = json_decode($res, true);
$this->expires_time = $result["expires_time"];
$this->access_token = $result["access_token"];
if (time() > ($this->expires_time + 3600)){
$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$this->appid."&secret=".$this->appsecret;
$res = $this->http_request($url);
$result = json_decode($res, true);
$this->access_token = $result["access_token"];
$this->expires_time = time();
file_put_contents('access_token.json', '{"access_token": "'.$this->access_token.'", "expires_time": '.$this->expires_time.'}');
}
}
//生成长度16的随机字符串
public function createNonceStr($length = 16) {
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
$str = "";
for ($i = 0; $i < $length; $i++) {
$str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
}
return $str;
}
//获得微信卡券api_ticket
public function getCardApiTicket()
{
$res = file_get_contents('cardapi_ticket.json');
$result = json_decode($res, true);
$this->cardapi_ticket = $result["cardapi_ticket"];
$this->cardapi_expire = $result["cardapi_expire"];
if (time() > ($this->cardapi_expire + 3600)){
$url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card&access_token=".$this->access_token;
$res = $this->http_request($url);
$result = json_decode($res, true);
$this->cardapi_ticket = $result["ticket"];
$this->cardapi_expire = time();
file_put_contents('cardapi_ticket.json', '{"cardapi_ticket": "'.$this->cardapi_ticket.'", "cardapi_expire": '.$this->cardapi_expire.'}');
}
return $this->cardapi_ticket;
}
//cardSign卡券签名
public function get_cardsign($bizObj)
{
//字典序排序
asort($bizObj);
//URL键值对拼成字符串
$buff = "";
foreach ($bizObj as $k => $v){
$buff .= $v;
}
//sha1签名
return sha1($buff);
}
//获得JS API的ticket
private function getJsApiTicket()
{
$res = file_get_contents('jsapi_ticket.json');
$result = json_decode($res, true);
$this->jsapi_ticket = $result["jsapi_ticket"];
$this->jsapi_expire = $result["jsapi_expire"];
if (time() > ($this->jsapi_expire + 3600)){
$url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=".$this->access_token;
$res = $this->http_request($url);
$result = json_decode($res, true);
$this->jsapi_ticket = $result["ticket"];
$this->jsapi_expire = time();
file_put_contents('jsapi_ticket.json', '{"jsapi_ticket": "'.$this->jsapi_ticket.'", "jsapi_expire": '.$this->jsapi_expire.'}');
}
return $this->jsapi_ticket;
}
//获得签名包
public function getSignPackage() {
$jsapiTicket = $this->getJsApiTicket();
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
$url = "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
$timestamp = time();
$nonceStr = $this->createNonceStr();
$string = "jsapi_ticket=$jsapiTicket&noncestr=$nonceStr×tamp=$timestamp&url=$url";
$signature = sha1($string);
$signPackage = array(
"appId" => $this->appid,
"nonceStr" => $nonceStr,
"timestamp" => $timestamp,
"url" => $url,
"signature" => $signature,
"rawString" => $string
);
return $signPackage;
}
//获取用户列表
public function get_user_list($next_openid = NULL)
{
$url = "https://api.weixin.qq.com/cgi-bin/user/get?access_token=".$this->access_token."&next_openid=".$next_openid;
$res = $this->http_request($url);
$list = json_decode($res, true);
if ($list["count"] == 10000){
$new = $this->get_user_list($next_openid = $list["next_openid"]);
$list["data"]["openid"] = array_merge_recursive($list["data"]["openid"], $new["data"]["openid"]); //合并OpenID列表
}
return $list;
}
//获取用户基本信息
public function get_user_info($openid)
{
$url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=".$this->access_token."&openid=".$openid."&lang=zh_CN";
$res = $this->http_request($url);
return json_decode($res, true);
}
//HTTP请求(支持HTTP/HTTPS,支持GET/POST)
protected function http_request($url, $data = null)
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
if (!empty($data)){
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
$output = curl_exec($curl);
curl_close($curl);
return $output;
}
}
4.在回复关注事件那里,会发现还引入了一个获取天气信息的文件weather.php(这个文件由方倍工作室提供)ak,sk不定期停用(方倍提供)
<?php
function getWeatherInfo($cityName)
{
$ak = 'WT7idirGGBgA6BNdGM36f3kZ';
$sk = 'uqBuEvbvnLKC8QbNVB26dQYpMmGcSEHM';
$url = 'http://api.map.baidu.com/telematics/v3/weather?ak=%s&location=%s&output=%s&sn=%s';
$uri = '/telematics/v3/weather';
$location = $cityName;
$output = 'json';
$querystring_arrays = array(
'ak' => $ak,
'location' => $location,
'output' => $output
);
$querystring = http_build_query($querystring_arrays);
$sn = md5(urlencode($uri.'?'.$querystring.$sk));
$targetUrl = sprintf($url, $ak, urlencode($location), $output, $sn);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $targetUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($ch);
curl_close($ch);
$result = json_decode($result, true);
if ($result["error"] != 0){
return $result["status"];
}
$curHour = (int)date('H',time());
$weather = $result["results"][0];
$weatherArray[] = array("Title" =>$weather['currentCity']."天气预报", "Description" =>"", "PicUrl" =>"", "Url" =>"");
for ($i = 0; $i < count($weather["weather_data"]); $i++) {
$weatherArray[] = array("Title"=>
$weather["weather_data"][$i]["date"]."\n".
$weather["weather_data"][$i]["weather"]." ".
$weather["weather_data"][$i]["wind"]." ".
$weather["weather_data"][$i]["temperature"],
"Description"=>"",
"PicUrl"=>(($curHour >= 6) && ($curHour < 18))?$weather["weather_data"][$i]["dayPictureUrl"]:$weather["weather_data"][$i]["nightPictureUrl"], "Url"=>"");
}
return $weatherArray;
}
?>
还没有评论,来说两句吧...