前几天由于公司要开发微信公众平台,打开公众号开发平台官网,咋一看官方文档,竟然没得一个demo,弄了半天才明白是咋个回事,看起来容易但又感觉不好下手;网上这方面的代码案例比较少,而且都是凌乱的几个方法,新手很难接受,
现在把我们公众平台开发的完整代码贴出来给大家参考一下,让新手少走点弯路,文章最后有我对整个代码总结的中心思想;
<?php header("Content-type: text/html; charset=utf-8"); define ( "TOKEN", "aidaijia" ); $wechatObj = new WeiXin(); class WeiXin{ private static $ACCESS_TOKEN = 0; //当前access_token的值 private static $ACCESS_TIME = 0; //access_token最后一次更新的时间 private static $XMLDATA; //接收请求的xml数据 private static $ARRELE = array(); //存放请求的xml节点 用来判断是属于那种请求 public function __construct() { // $this->valid();die; //服务器验证 // $this->createMenu();die; //自定义菜单 $path = dirname(__FILE__); $acpath = $path."/weixin.c"; //存放最近一次access_token更新的时间 $access = $path."/access_token.c"; //最近一次更新的access_token $xml = $path."/xmldata.c"; //存放最近一次接收的xml数据 //检查access_token是否过期 if(!file_exists($acpath)){ $this->getAssessToken(); file_put_contents($acpath, self::$ACCESS_TIME); file_put_contents($access, self::$ACCESS_TOKEN); }else { $acint = file_get_contents($acpath)+0; if((time()-$acint)>=7000) { $this->getAssessToken(); file_put_contents($acpath, self::$ACCESS_TIME); file_put_contents($access, self::$ACCESS_TOKEN); }else { self::$ACCESS_TOKEN = file_get_contents($access); } } //校验信息真实性(防止微信以外的第三方灌水机器人) $this->checkSignature(); //将请求的xml数据存为全局 self::$XMLDATA = $GLOBALS["HTTP_RAW_POST_DATA"]; //添加xml数据日志 file_put_contents($xml, self::$XMLDATA); $this->begin(); } private function begin() { $postObj = simplexml_load_string(self::$XMLDATA, 'SimpleXMLElement', LIBXML_NOCDATA); foreach ($postObj as $key => $value) { array_push(self::$ARRELE,$key); } //事件消息 if(in_array("Event", self::$ARRELE)) { //新用户关注 if($postObj->Event=="subscribe") { $textTpl = " <xml> <ToUserName><![CDATA[".$postObj->FromUserName."]]></ToUserName> <FromUserName><![CDATA[".$postObj->ToUserName."]]></FromUserName> <CreateTime>".time()."</CreateTime> <MsgType><![CDATA[news]]></MsgType> <ArticleCount>2</ArticleCount> <Articles> <item> <Title><![CDATA[爱代驾送福利:百万代驾券、iPhone6大奖等你来拿!]]></Title> <Description><![CDATA[爱代驾送福利]]></Description> <PicUrl><![CDATA[http://aidaijia.com/Public/Index/image/tu1.jpg]]></PicUrl> <Url><![CDATA[http://aidaijia.com/home]]></Url> </item> <item> <Title><![CDATA[酒后有车咋个走,爱代驾只需29]]></Title> <Description><![CDATA[爱代驾最低29元起]]></Description> <PicUrl><![CDATA[http://aidaijia.com/Public/Index/image/syx4.jpg]]></PicUrl> <Url><![CDATA[http://aidaijia.com/Index/Index/price]]></Url> </item> </Articles> </xml>"; echo $textTpl; return ; } //取消关注 if($postObj->Event=="unsubscribe") { $sql = "delete from dj_weixin where wuser='$postObj->FromUserName'"; $mysqli = new mysqli("localhost", "username", "666666", "driver"); $mysqli->query($sql); $mysqli->close(); return ; } //更新用户的坐标 if($postObj->Event=='LOCATION') { //上报地理位置事件 if(in_array("Latitude",self::$ARRELE) ) { $time = time(); $obj = simplexml_load_string(self::$XMLDATA, 'SimpleXMLElement', LIBXML_NOCDATA); $sql = "insert into `dj_weixin` (`wuser`, `wlon`, `wlat`, `wtime`,`wto`) values ('$obj->FromUserName', $obj->Longitude, $obj->Latitude, $time,'$obj->ToUserName') ON DUPLICATE KEY UPDATE `wlon` = $obj->Longitude, `wlat` = $obj->Latitude, `wtime` =$time, `wto` ='$obj->ToUserName' ;"; // $access = dirname(__FILE__)."/access_token.c"; // file_put_contents($access, $sql); $mysqli = new mysqli("localhost", "username", "666666", "driver"); $mysqli->query($sql); $mysqli->close(); return; } } } //用户主动发送了位置信息 if(in_array("Location_X",self::$ARRELE)) { self::fdriver(); return; } //自定义菜单事件 if(in_array("EventKey",self::$ARRELE)) { if(substr($postObj->EventKey,0,3)=='WD_') { self::menuevent(); return ; } } //普通消息 if($postObj->MsgType=='text') { self::responseMsg(); return; } } private function checkSignature(){ $signature = $_GET["signature"]; $timestamp = $_GET["timestamp"]; $nonce = $_GET["nonce"]; $token = TOKEN; $tmpArr = array($token, $timestamp, $nonce); sort($tmpArr, SORT_STRING); $tmpStr = implode( $tmpArr ); $tmpStr = sha1( $tmpStr ); if( $tmpStr == $signature ){ return true; }else{ return false; } } //获取access_token public function getAssessToken(){ $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=wxfa50fcdbae10f8c8&secret=e845e613792e369034a91b9bd2db513a "; $curl = curl_init($url); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); //以文件流的形式返回 $data = curl_exec($curl); $arr = json_decode($data, true); //把返回的json字符串转化为数组 self::$ACCESS_TOKEN = $arr['access_token']; //更新access_token self::$ACCESS_TIME = time(); //最后一次获取access_token的时间 curl_close($curl); // echo self::$ACCESS_TOKEN."<br>"; // echo self::$ACCESS_TIME."<br>"; } //回复文本消息 public function responseMsg() { $postObj = simplexml_load_string(self::$XMLDATA, 'SimpleXMLElement', LIBXML_NOCDATA); $fromUsername = $postObj->FromUserName; $toUsername = $postObj->ToUserName; $content = $postObj->Content; $contentStr = ""; if(substr($content,0,1)=='@') { $pos = substr($content,1); if(strlen($pos)!=11) { $contentStr = "温馨提示:请填写正确的手机号"; }else { $path = dirname(__FILE__); $xmlele = $path."/xmlele.c"; $sql = "select * from dj_order_info where from_phonenum='$pos' order by orderid desc limit 4"; $mysqli = new mysqli("localhost", "username", "666666", "driver"); $result = $mysqli->query($sql); $mysqli->close(); while($obj = $result->fetch_object()){ $contentStr.="单号".$obj->order_num."\n------->时间".substr($obj->call_time,5,5)."\n"; } if($contentStr=='') $contentStr = "你好,没有查询到相关订单"; } } $time = time(); $textTpl = "<xml> <ToUserName><![CDATA[%s]]></ToUserName> <FromUserName><![CDATA[%s]]></FromUserName> <CreateTime>%s</CreateTime> <MsgType><![CDATA[%s]]></MsgType> <Content><![CDATA[%s]]></Content> <FuncFlag>0</FuncFlag> </xml>"; $msgType = "text"; if($contentStr=='') $contentStr = "你好,我是爱代驾,你可以在这里快速找代驾,近期订单查询,进入微官网还有更多惊喜,24小时客服热线:4000700029 爱代驾是一家历史悠久的代驾公司,公司本着以人为本,诚信经营的宗旨,在全国享有很高的声誉 "; $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr); echo $resultStr; } // 自定义菜单事件消息 public static function menuevent() { $obj = simplexml_load_string(self::$XMLDATA, 'SimpleXMLElement', LIBXML_NOCDATA); $eventKey = $obj->EventKey; $fromUsername = $obj->FromUserName; $toUsername = $postObj->ToUserName; $time = time(); $msgType = "text"; $content = $eventKey; switch($eventKey) { case "WD_JIAGE": $content = "7:00-21:00=>29元起\n21:00-24:00=>49元起\n0:00-7:00=>69元起\n"; break; case "WD_ZHAODAIJIA": self::finddriver($fromUsername);break; // $content = "请发送你的位置以便寻找附近司机:\n1、点击左下方 '小键盘' \n2、点击右下方 '+号键' \n3、点击 '位置' 图标\n4、完成定位后点击 '发送'"; break; case "WD_DINGDAN": $content = "请发送@+手机号查询"; break; case "WD_FUWUREXIAN": $content = "24小时服务热线:4000-7000-29"; break; default: // $content = "无法识别"; } $textTpl = "<xml> <ToUserName><![CDATA[%s]]></ToUserName> <FromUserName><![CDATA[%s]]></FromUserName> <CreateTime>%s</CreateTime> <MsgType><![CDATA[%s]]></MsgType> <Content><![CDATA[%s]]></Content> <FuncFlag>0</FuncFlag> </xml>"; $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $content); echo $resultStr; } //寻找附近司机,针对于开启了位置服务的用户,我方公众号需要在公众平台开启高级权限接口并启用位置服务 public static function finddriver($username) { // $access = dirname(__FILE__)."/access_token.c"; $sql = "select * from dj_weixin where wuser = '$username'"; $mysqli = new mysqli("localhost", "username", "666666", "driver"); $res = $mysqli->query($sql); $mysqli->close(); $count = 0; if($res->num_rows!=0) { $obj = $res->fetch_object(); $lon = $obj->wlon; $lat = $obj->wlat; $fromUsername = $obj->wuser; $toUsername = $obj->wto; $time = $obj->wtime; $nowtime = time(); if(($nowtime-$time)>120) { $count=-1; goto flag; } }else { $obj = simplexml_load_string(self::$XMLDATA, 'SimpleXMLElement', LIBXML_NOCDATA); $fromUsername = $obj->FromUserName; $toUsername = $obj->ToUserName; $count = -1; goto flag; } $sql = "call queryDriverByClient($lat,$lon)"; $mysqli = new mysqli("localhost", "username", "66666666", "driver"); $result = $mysqli->query($sql); $mysqli->close(); $count = $result->num_rows; //如果没有获取到用户的地理信息 直接跳到这里 flag : $textTpl = "<xml> <ToUserName><![CDATA[%s]]></ToUserName> <FromUserName><![CDATA[%s]]></FromUserName> <CreateTime>%s</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[%s]]></Content> <FuncFlag>0</FuncFlag> </xml>"; if($count>0) { $content = "你附近有".$count."个空闲司机。\n马上去选司机: http://aidaijia.com/find?lat=".$lat."&lon=".$lon; } else { if($count==-1) $content = "无法获取你的地理位置,请点击爱代驾头像,在资料页面把[提供位置信息]开启\n你也可以手动发送地理位置信息:\n1、点击左下方 '小键盘' \n2、点击右下方 '+号键' \n3、点击 '位置' 图标\n4、完成定位后点击 '发送'"; else $content = "抱歉!你附近暂没有空闲司机。你可以等会儿在操作或拨打客服咨询4000-7000-29\n"; } $time = time(); $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $content); echo $resultStr; } //寻找附近的司机 针对没有开启位置服务的用户 (需要用户手动发送位置信息) public static function fdriver() { $obj = simplexml_load_string(self::$XMLDATA, 'SimpleXMLElement', LIBXML_NOCDATA); $lon = $obj->Location_Y ; //经度 $lat = $obj->Location_X ; //纬度 $fromUsername = $obj->FromUserName; $toUsername = $obj->ToUserName; $sql = "call queryDriverByClient($lat,$lon)"; $mysqli = new mysqli("localhost", "username", "666666", "driver"); $result = $mysqli->query($sql); $mysqli->close(); $count = $result->num_rows; $textTpl = "<xml> <ToUserName><![CDATA[%s]]></ToUserName> <FromUserName><![CDATA[%s]]></FromUserName> <CreateTime>%s</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[%s]]></Content> <FuncFlag>0</FuncFlag> </xml>"; if($count>0) { $content = "你附近有".$count."个空闲司机。\n马上去选司机: http://aidaijia.com/find?lat=".$lat."&lon=".$lon; } else { $content = "抱歉!你附近暂没有空闲司机。你可以等会儿在操作或拨打客服咨询4000-7000-29\n"; } $time = time(); $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $content); echo $resultStr; } //设置菜单 public function createMenu(){ $url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=DWJG0l5MhgkJBDfjg032jnOfjwZX3Fatk1PccFNgJuRYr0b8I3w-jd77P2_p95pJd4xtFB_DdZRi5k-WHaSNGA"; $btnjson = '{ "button":[{ "type":"click", "name":"找代驾", "key":"WD_ZHAODAIJIA" }, { "name":"微助手", "sub_button":[ { "type":"view", "name":"微官网", "url":"http://aidaijia.com/home" }, { "type":"view", "name":"路况信息", "url":"http://map.baidu.com/mobile/webapp/index/index/foo=bar/vt=map&traffic=on&viewmode=no_ad/?third_party=ucsearchbox#index/index/foo=bar/vt=map&traffic=on&viewmode=no_ad" }, { "type":"click", "name":"最近订单", "key":"WD_DINGDAN" } ] }, { "name":"更多服务", "sub_button":[ { "type":"click", "name":"服务热线", "key":"WD_FUWUREXIAN" }, { "type":"click", "name":"价格列表", "key":"WD_JIAGE" }, { "type":"view", "name":"下载客户端", "url":"http://aidaijia.com/d" } ] }] }'; $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_POST, 1); curl_setopt($curl, CURLOPT_POSTFIELDS, $btnjson); $data = curl_exec($curl); curl_close($curl); echo $data; } //验证服务器 public function valid() { $echoStr = $_GET["echostr"]; //valid signature , option if($this->checkSignature()){ echo $echoStr; exit; } } //收尾工作 public function __destruct() { // .. } } ?>
总结:
在微信公众平台开启开发者模式(其实有两个模式,一个是给普通人使用的,一个是给开发者使用的,默认是普通模式),开启开发者模式后,以后关注你的用户发送任何信息或者触发任何事件给你 ,都会走开发者路线,这些所有的信息都会以xml的形式发送到你制定的网址(比如:www.hello.com/doweixin.php),所有的数据都由这个doweixin.php来处理,里面的代码就类似我上面的代码,所以我们要做的事情就是解析用户发送过来的xml数据,通过这里面的数据 我们就可以知道用户想要什么 触发了我们定义的某个按钮
,那么我们根据业务返回用户所需要的数据 我们返回的数据也是xml形式 ,我上面的代码都是被动触发,也就是用户主动来给你发送消息或者触发了某个事件,对于一些营销的任务微信也提供了给你的关注用户主动推送消息的接口 但是有使用次数限制 一般就几次 ,其实这篇文章已经写好了很久了 只是感觉还有要写的 但又没时间 所以一直放在草稿箱 今天打开偶然看到了 感觉也没什么要添加的 就这样草草的发了 如果有朋友对代码有疑问就直接在下面留言吧