微信开发接口封装调用

川长思鸟来 2022-06-10 09:47 322阅读 0赞

我们知道微信公众号开发主要就是调用微信官方开放给我们的一些接口。这里就不再一个一个接口的示例了,我直接把自己封装好的一个微信接口类展示一下,可以直接套用。后续会不断完善。

1.首先我写了一个入口文件index.php。这个文件主要是微信公众号后台配置时候的验证以及分离请求方向。

  1. <?php
  2. /*
  3. 入口文件,使用之前需要先引入调用的类文件
  4. */
  5. require_once('weixin_api.php');
  6. define("TOKEN","weixin");//定义TOKEN值,此值在微信公众号后台自定义。
  7. $echoStr = $_GET["echostr"];
  8. $weixin = new WeixinApi();//实例化WeixinApi类
  9. if (!isset($echoStr)) {
  10. $weixin->responseMsg();//调用responseMsg()函数
  11. }else{
  12. $weixin->valid();//调用valid()函数
  13. }

2.这个文件就是封装好的一些常用接口:weixin_api.php,代码中都有详细的注释,可以关联查看

  1. <?php
  2. /*
  3. 封装成类:WeixinApi
  4. signature,timestamp,nonce:由微信服务器通过GET方法发送过来
  5. TOKEN:开发者在公众号中自定义
  6. */
  7. class WeixinApi
  8. {
  9. //验证消息
  10. public function valid()
  11. {
  12. if($this->checkSignature()){
  13. echo $_GET["echostr"];
  14. }else{
  15. echo "ERROR";
  16. }
  17. }
  18. //检验微信加密签名,私有化
  19. private function checkSignature()
  20. {
  21. $signature = $_GET["signature"];//1.signature:微信加密签名,由开发者填写的 TOKEN值,请求中的时间戳timesstamp,随机数nonce 组合而成
  22. $timestamp = $_GET["timestamp"];//2.timestamp:时间戳
  23. $nonce = $_GET["nonce"];//3.nonce:随机数
  24. $token = TOKEN;//4.TOKEN值
  25. $tmpArr = array($token, $timestamp, $nonce);//以上2,3,4三个参数使用 sort() 函数进行字典排序
  26. sort($tmpArr,SORT_STRING);
  27. $tmpStr = implode( $tmpArr );
  28. $tmpStr = sha1( $tmpStr );//数组再转化为字符串,然后进行哈希sha1加密
  29. if( $tmpStr == $signature ){
  30. return true;
  31. }else{
  32. return false;
  33. }
  34. }
  35. //响应消息responseMsg
  36. public function responseMsg()
  37. {
  38. //1.接收XML数据包
  39. $postData = $GLOBALS["HTTP_RAW_POST_DATA"];//$HTTP_RAW_POST_DATA;
  40. //2将日志写入xml文件
  41. $this->logger("R \r\n".$postData);
  42. //3处理XML数据包
  43. $xmlObj = simplexml_load_string($postData,"simpleXMLElement",LIBXML_NOCDATA);//将XML字符串载入对象中,失败返回false
  44. $toUserName = $xmlObj->ToUserName;//获取开发者微信号
  45. $fromUserName = $xmlObj->FromUserName;//获取用户的openID
  46. //收到的消息类型
  47. $msgType = $xmlObj->MsgType;//发送的消息类型(text)
  48. switch ($msgType)
  49. { case 'event': //事件
  50. echo $this->receiveEvent($xmlObj);
  51. break;
  52. case 'text': //文本
  53. echo $this->receiveText($xmlObj);
  54. break;
  55. case 'image': //图片
  56. echo $this->receiveImage($xmlObj);
  57. break;
  58. case 'voice': //语音
  59. echo $this->receiveVoice($xmlObj);
  60. break;
  61. default:
  62. # code...
  63. break;
  64. }
  65. }
  66. //接收推送事件消息receiveEvent
  67. public function receiveEvent($obj)
  68. {
  69. $openid = $obj->FromUserName;
  70. $event = $obj->Event;
  71. switch ($event) {
  72. //关注事件
  73. case 'subscribe':
  74. require_once('wxjssdk.php');
  75. $jssdk = new JSSDK();
  76. $userinfo = $jssdk->get_user_info($openid);
  77. $municipalities = array("北京", "上海", "天津", "重庆", "香港", "澳门"); //四市二区 市名为区地区,这里用省名代替市名
  78. if (in_array($userinfo['province'], $municipalities)){
  79. $userinfo['city'] = $userinfo['province'];
  80. }
  81. $content = "您好:欢迎".$userinfo['nickname'];
  82. if ($userinfo['country'] == '中国') {
  83. require_once('weather.php');
  84. $weatherInfo = getWeatherInfo($userinfo['city']);
  85. $content .= "您来自".$userinfo['city']." \n欢迎关注:谷文杰微信公众测试号 \n QQ:1140243510 \n 微信:q18737198019 \n 回复'资讯' 获取最新资讯!\n 当前天气如下\r\n".$weatherInfo[1]["Title"];
  86. }
  87. return $this->replyText($obj,$content);
  88. break;
  89. //取消关注事件
  90. case 'unsubscribe':
  91. $content = "取消关注";
  92. return $this->replyText($obj,$content);
  93. break;
  94. case 'CLICK':
  95. switch ($obj->EventKey) {//自定义菜单中的key值
  96. case 'getnew':
  97. $content = array(
  98. array(
  99. 'Title'=>'爽歪歪',
  100. 'Description'=>'爽歪歪,酷爽一夏!',
  101. 'PicUrl'=>'http://wxtest.freephp.top/wxSDK/img/5147dc2160c34.jpg',
  102. 'Url'=>'https://www.baidu.com/home/news/data/newspage?nid=17137570521980907234&n_type=0&p_from=1&dtype=-1'
  103. )
  104. );
  105. return $this->replyNews($obj,$content);
  106. break;
  107. default:
  108. # code...
  109. break;
  110. }
  111. break;
  112. default:
  113. # code...
  114. break;
  115. }
  116. }
  117. //接收文本消息receiveText
  118. public function receiveText($obj)
  119. {
  120. $content = trim($obj->Content);//获取文本内容
  121. //进行关键字回复
  122. switch ($content)
  123. {
  124. case '你好':
  125. return $this->replyText($obj,"姓名:谷文杰 \n QQ:1140243510 \n 微信:q18737198019");
  126. break;
  127. case '资讯':
  128. $newsArr = array(
  129. array(
  130. 'Title'=>'爽歪歪',
  131. 'Description'=>'爽歪歪,酷爽一夏!',
  132. 'PicUrl'=>'http://wxtest.freephp.top/wxSDK/img/5147dc2160c34.jpg',
  133. 'Url'=>'https://www.baidu.com/home/news/data/newspage?nid=17137570521980907234&n_type=0&p_from=1&dtype=-1'
  134. ),
  135. array(
  136. 'Title'=>'歪歪爽',
  137. 'Description'=>'酷爽一夏,爽歪歪!',
  138. 'PicUrl'=>'http://wxtest.freephp.top/wxSDK/img/5147dc20619b2.jpg',
  139. 'Url'=>'https://www.baidu.com/home/news/data/newspage?nid=3396686089578539736&n_type=0&p_from=1&dtype=-1'
  140. )
  141. );
  142. return $this->replyNews($obj,$newsArr);
  143. break;
  144. default:
  145. return $this->replyText($obj,$content);
  146. break;
  147. }
  148. }
  149. //接收图片消息
  150. public function receiveImage($obj)
  151. {
  152. $array = array('mediaId'=>$obj->MediaId);
  153. return $this->replyImage($obj,$array);
  154. }
  155. //接收语音消息
  156. public function receiveVoice($obj)
  157. {
  158. if (isset($obj->Recognition) && !empty($obj->Recognition)){
  159. $content = "你刚才说的是:".$obj->Recognition;
  160. return $this->replyText($obj,$content);
  161. }else{
  162. $content = array("mediaId"=>$obj->MediaId);
  163. return $this->replyVoice($obj,$content);
  164. }
  165. }
  166. //回复文本消息replyText
  167. public function replyText($obj,$content)
  168. {
  169. $replyTextMsg = '<xml>
  170. <ToUserName><![CDATA[%s]]></ToUserName>
  171. <FromUserName><![CDATA[%s]]></FromUserName>
  172. <CreateTime>%s</CreateTime>
  173. <MsgType><![CDATA[text]]></MsgType>
  174. <Content><![CDATA[%s]]></Content>
  175. </xml>';
  176. return sprintf($replyTextMsg,$obj->FromUserName,$obj->ToUserName,time(),$content);
  177. }
  178. //回复图片消息replyImage
  179. public function replyImage($obj,$array)
  180. {
  181. $replyImgMsg = '<xml>
  182. <ToUserName><![CDATA[%s]]></ToUserName>
  183. <FromUserName><![CDATA[%s]]></FromUserName>
  184. <CreateTime>%s</CreateTime>
  185. <MsgType><![CDATA[image]]></MsgType>
  186. <Image>
  187. <MediaId><![CDATA[%s]]></MediaId>
  188. </Image>
  189. </xml>';
  190. return sprintf($replyImgMsg,$obj->FromUserName,$obj->ToUserName,time(),$array['mediaId']);
  191. }
  192. //回复图文消息replyNews
  193. public function replyNews($obj,$newsArr)
  194. {
  195. if (is_array($newsArr)) {
  196. $item = "";
  197. foreach($newsArr as $val){
  198. $itemTpl = "<item>
  199. <Title><![CDATA[%s]]></Title>
  200. <Description><![CDATA[%s]]></Description>
  201. <PicUrl><![CDATA[%s]]></PicUrl>
  202. <Url><![CDATA[%s]]></Url>
  203. </item>";
  204. $item .= sprintf($itemTpl,$val['Title'],$val['Description'],$val['PicUrl'],$val['Url']);
  205. }
  206. $replyNewsMsg = '<xml>
  207. <ToUserName><![CDATA[%s]]></ToUserName>
  208. <FromUserName><![CDATA[%s]]></FromUserName>
  209. <CreateTime>%s</CreateTime>
  210. <MsgType><![CDATA[news]]></MsgType>
  211. <ArticleCount>%u</ArticleCount>
  212. <Articles>'.$item.'</Articles>
  213. </xml>';
  214. return sprintf($replyNewsMsg,$obj->FromUserName,$obj->ToUserName,time(),count($newsArr));
  215. }
  216. }
  217. //回复语音消息
  218. public function replyVoice($obj,$content)
  219. {
  220. $voiceTpl = "<xml>
  221. <ToUserName><![CDATA[%s]]></ToUserName>
  222. <FromUserName><![CDATA[%s]]></FromUserName>
  223. <CreateTime>%s</CreateTime>
  224. <MsgType><![CDATA[voice]]></MsgType>
  225. <Voice>
  226. <MediaId><![CDATA[%s]]></MediaId>
  227. </Voice>
  228. </xml>";
  229. return sprintf($voiceTpl,$obj->FromUserName, $obj->ToUserName,time(),$content['mediaId']);
  230. }
  231. //日志记录
  232. private function logger($log_content)
  233. {
  234. if(isset($_SERVER['HTTP_APPNAME'])){ //SAE
  235. sae_set_display_errors(false);
  236. }else if($_SERVER['REMOTE_ADDR'] != "127.0.0.1"){ //LOCAL
  237. $max_size = 1000000;
  238. $log_filename = "log.xml";
  239. if(file_exists($log_filename) and (abs(filesize($log_filename)) > $max_size)){unlink($log_filename);}
  240. file_put_contents($log_filename, date('Y-m-d H:i:s')." ".$log_content."\r\n", FILE_APPEND);
  241. }
  242. }
  243. }

3.其中在接受关注事件的时候,实例化了一个jSSDK类,这个类主要处理获取用户信息以及获取卡券信息

  1. <?php
  2. /*
  3. 微信JSSDK类
  4. 1.jsapi_ticket:是公众号用于调用微信JS接口的临时票据,jsapi_ticket的有效期为7200秒,通过access_token来获取
  5. 2.JS SDK签名:参与签名的字段包括noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳), url(当前网页的URL,不包含#及其后面部分)。对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1。这里需要注意的是所有参数名均为小写字符。对string1作sha1加密,字段名和字段值都采用原始值,不进行URL 转义
  6. 3.在TP中引入使用vendor方法注意:如果你的类库没有使用命名空间定义的话,实例化的时候需要加上根命名空间。
  7. */
  8. class JSSDK
  9. {
  10. var $appid = 'wx*************49';
  11. var $appsecret = '3a6*****************************15c';
  12. //构造函数,获取Access Token
  13. public function __construct($appid = NULL, $appsecret = NULL)
  14. {
  15. if($appid && $appsecret){
  16. $this->appid = $appid;
  17. $this->appsecret = $appsecret;
  18. }
  19. $res = file_get_contents('access_token.json');
  20. $result = json_decode($res, true);
  21. $this->expires_time = $result["expires_time"];
  22. $this->access_token = $result["access_token"];
  23. if (time() > ($this->expires_time + 3600)){
  24. $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$this->appid."&secret=".$this->appsecret;
  25. $res = $this->http_request($url);
  26. $result = json_decode($res, true);
  27. $this->access_token = $result["access_token"];
  28. $this->expires_time = time();
  29. file_put_contents('access_token.json', '{"access_token": "'.$this->access_token.'", "expires_time": '.$this->expires_time.'}');
  30. }
  31. }
  32. //生成长度16的随机字符串
  33. public function createNonceStr($length = 16) {
  34. $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  35. $str = "";
  36. for ($i = 0; $i < $length; $i++) {
  37. $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
  38. }
  39. return $str;
  40. }
  41. //获得微信卡券api_ticket
  42. public function getCardApiTicket()
  43. {
  44. $res = file_get_contents('cardapi_ticket.json');
  45. $result = json_decode($res, true);
  46. $this->cardapi_ticket = $result["cardapi_ticket"];
  47. $this->cardapi_expire = $result["cardapi_expire"];
  48. if (time() > ($this->cardapi_expire + 3600)){
  49. $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card&access_token=".$this->access_token;
  50. $res = $this->http_request($url);
  51. $result = json_decode($res, true);
  52. $this->cardapi_ticket = $result["ticket"];
  53. $this->cardapi_expire = time();
  54. file_put_contents('cardapi_ticket.json', '{"cardapi_ticket": "'.$this->cardapi_ticket.'", "cardapi_expire": '.$this->cardapi_expire.'}');
  55. }
  56. return $this->cardapi_ticket;
  57. }
  58. //cardSign卡券签名
  59. public function get_cardsign($bizObj)
  60. {
  61. //字典序排序
  62. asort($bizObj);
  63. //URL键值对拼成字符串
  64. $buff = "";
  65. foreach ($bizObj as $k => $v){
  66. $buff .= $v;
  67. }
  68. //sha1签名
  69. return sha1($buff);
  70. }
  71. //获得JS API的ticket
  72. private function getJsApiTicket()
  73. {
  74. $res = file_get_contents('jsapi_ticket.json');
  75. $result = json_decode($res, true);
  76. $this->jsapi_ticket = $result["jsapi_ticket"];
  77. $this->jsapi_expire = $result["jsapi_expire"];
  78. if (time() > ($this->jsapi_expire + 3600)){
  79. $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=".$this->access_token;
  80. $res = $this->http_request($url);
  81. $result = json_decode($res, true);
  82. $this->jsapi_ticket = $result["ticket"];
  83. $this->jsapi_expire = time();
  84. file_put_contents('jsapi_ticket.json', '{"jsapi_ticket": "'.$this->jsapi_ticket.'", "jsapi_expire": '.$this->jsapi_expire.'}');
  85. }
  86. return $this->jsapi_ticket;
  87. }
  88. //获得签名包
  89. public function getSignPackage() {
  90. $jsapiTicket = $this->getJsApiTicket();
  91. $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
  92. $url = "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
  93. $timestamp = time();
  94. $nonceStr = $this->createNonceStr();
  95. $string = "jsapi_ticket=$jsapiTicket&noncestr=$nonceStr×tamp=$timestamp&url=$url";
  96. $signature = sha1($string);
  97. $signPackage = array(
  98. "appId" => $this->appid,
  99. "nonceStr" => $nonceStr,
  100. "timestamp" => $timestamp,
  101. "url" => $url,
  102. "signature" => $signature,
  103. "rawString" => $string
  104. );
  105. return $signPackage;
  106. }
  107. //获取用户列表
  108. public function get_user_list($next_openid = NULL)
  109. {
  110. $url = "https://api.weixin.qq.com/cgi-bin/user/get?access_token=".$this->access_token."&next_openid=".$next_openid;
  111. $res = $this->http_request($url);
  112. $list = json_decode($res, true);
  113. if ($list["count"] == 10000){
  114. $new = $this->get_user_list($next_openid = $list["next_openid"]);
  115. $list["data"]["openid"] = array_merge_recursive($list["data"]["openid"], $new["data"]["openid"]); //合并OpenID列表
  116. }
  117. return $list;
  118. }
  119. //获取用户基本信息
  120. public function get_user_info($openid)
  121. {
  122. $url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=".$this->access_token."&openid=".$openid."&lang=zh_CN";
  123. $res = $this->http_request($url);
  124. return json_decode($res, true);
  125. }
  126. //HTTP请求(支持HTTP/HTTPS,支持GET/POST)
  127. protected function http_request($url, $data = null)
  128. {
  129. $curl = curl_init();
  130. curl_setopt($curl, CURLOPT_URL, $url);
  131. curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
  132. curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
  133. if (!empty($data)){
  134. curl_setopt($curl, CURLOPT_POST, 1);
  135. curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
  136. }
  137. curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
  138. $output = curl_exec($curl);
  139. curl_close($curl);
  140. return $output;
  141. }
  142. }

4.在回复关注事件那里,会发现还引入了一个获取天气信息的文件weather.php(这个文件由方倍工作室提供)ak,sk不定期停用(方倍提供)

  1. <?php
  2. function getWeatherInfo($cityName)
  3. {
  4. $ak = 'WT7idirGGBgA6BNdGM36f3kZ';
  5. $sk = 'uqBuEvbvnLKC8QbNVB26dQYpMmGcSEHM';
  6. $url = 'http://api.map.baidu.com/telematics/v3/weather?ak=%s&location=%s&output=%s&sn=%s';
  7. $uri = '/telematics/v3/weather';
  8. $location = $cityName;
  9. $output = 'json';
  10. $querystring_arrays = array(
  11. 'ak' => $ak,
  12. 'location' => $location,
  13. 'output' => $output
  14. );
  15. $querystring = http_build_query($querystring_arrays);
  16. $sn = md5(urlencode($uri.'?'.$querystring.$sk));
  17. $targetUrl = sprintf($url, $ak, urlencode($location), $output, $sn);
  18. $ch = curl_init();
  19. curl_setopt($ch, CURLOPT_URL, $targetUrl);
  20. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  21. $result = curl_exec($ch);
  22. curl_close($ch);
  23. $result = json_decode($result, true);
  24. if ($result["error"] != 0){
  25. return $result["status"];
  26. }
  27. $curHour = (int)date('H',time());
  28. $weather = $result["results"][0];
  29. $weatherArray[] = array("Title" =>$weather['currentCity']."天气预报", "Description" =>"", "PicUrl" =>"", "Url" =>"");
  30. for ($i = 0; $i < count($weather["weather_data"]); $i++) {
  31. $weatherArray[] = array("Title"=>
  32. $weather["weather_data"][$i]["date"]."\n".
  33. $weather["weather_data"][$i]["weather"]." ".
  34. $weather["weather_data"][$i]["wind"]." ".
  35. $weather["weather_data"][$i]["temperature"],
  36. "Description"=>"",
  37. "PicUrl"=>(($curHour >= 6) && ($curHour < 18))?$weather["weather_data"][$i]["dayPictureUrl"]:$weather["weather_data"][$i]["nightPictureUrl"], "Url"=>"");
  38. }
  39. return $weatherArray;
  40. }
  41. ?>

发表评论

表情:
评论列表 (有 0 条评论,322人围观)

还没有评论,来说两句吧...

相关阅读

    相关 开发接口封装调用

    我们知道微信公众号开发主要就是调用微信官方开放给我们的一些接口。这里就不再一个一个接口的示例了,我直接把自己封装好的一个微信接口类展示一下,可以直接套用。后续会不断完善。 1

    相关 开发调用扫一扫接口

    前言 这是自己第一次进行微信开发,自己之前一直以为很简单,但是自己真正来做的时候才发现会遇到很多问题。认识的一个小伙伴进行微信开发已经挺久了,如果需要可以直接问他或者将他

    相关 退款接口开发

    步骤: 发送退款请求到微信->同步告诉你请求成功还是失败->异步回调告诉你退款成功还是失败 说明:微信退款是需要证书的,先要下载证书.如何下载百度一下就可以,很简单 //

    相关 Android应用调用登录接口

    很多App都是需要用户登录的,例如电商类的APP,用户登录后可以查看自己的购物订单,浏览痕迹等,登陆的话又可以分为多种登录,例如QQ,微信,微博,支付宝等,那么接下来这篇文章讲