您的位置:首页 > 移动开发 > 微信开发

如何使用开发者服务器运维微信公众号

2018-03-04 18:58 204 查看
很多人都有自己的服务器,特别是对于大学生而言,很多服务器公司都对学生有优惠,例如腾讯云只要1元每月:http://blog.csdn.net/tiandixuanwuliang/article/details/56494528 ,那么我们作为一名程序员,总想把一切掌控在自己手中,<哈哈>,那么如何使用我们开发者服务器去管理微信公众号呢?这就是本文介绍的内容。

本文介绍以下内容:

(1)如何把微信公众号授权给开发者服务器

(2)如何使用代码把开发者服务器与微信服务器进行关联

(3)实现接受和发送消息

(4)自定义菜单

1 如何把微信公众号授权给开发者服务器

(1)进入微信公众号平台,https://mp.weixin.qq.com/,首先请取消其他第三方服务器的授权,方法如下:







注:这里也可以不取消第三方服务器的授权,不取消的话,公众号粉丝发送的数据会同时1发送到第三方服务器和开发者服务器,本人已经验证了,有兴趣可以自行研究

(2)回到微信公众号管理平台首页,页面往下拉,选择“基本配置”,如图:



(3)添加ip白名单



(4)选择修改配置



(5)下图中的url,指向你自己的服务器中正在运行的php地址,这是本文代码开发的重点,具体内容请看下一章。token可以随便写,但是需要与上述php文件中配置的一样,具体内容请看下一章



2 如何使用代码把开发者服务器与微信服务器进行关联

(0)这一章讲解代码的开发。第一章第5小节中的url指向自己的服务器中正在运行的php文件,本章将介绍这一个文件的内容。关于如何运行这个php文件,请看php教程http://blog.csdn.net/tiandixuanwuliang/article/category/7344088

(1)该php文件内容如下,下面的代码实现了连接开发者服务器、关键字回复、图灵机器人功能,注:请把下面的token填写为第一章第5小节中截图中设置的token

<?php
/**
* 微信公众号开发-入门
*
* api
*/
define("TOKEN",'we--xxxx');   //这里和你微信公众号开放平台上的tonken填写一样的即可
$weixinApi=new WeixinApi();
if(isset($_GET["echostr"])){
$weixinApi->valid();
}else{
$weixinApi->responseMsg();
}

class WeixinApi{
//验证接口
public function valid(){
$echoStr = $_GET["echostr"];//从微信用户端获取一个随机字符赋予变量echostr
if($this->checkSignature()){
echo $echoStr;
exit;
}
}
//检查签名
private function checkSignature(){
//1 接受微信服务器get请求发送过来的4个参数
$signature = $_GET["signature"];//从用户端获取签名赋予变量signature
$timestamp = $_GET["timestamp"];//从用户端获取时间戳赋予变量timestamp
$nonce = $_GET["nonce"];    //从用户端获取随机数赋予变量nonce
//2 加密和校验请求
//2.1 将token、timestamp、nonce三个参数进行字典序排序
$tmpArr = array(TOKEN, $timestamp, $nonce);//简历数组变量tmpArr
sort($tmpArr, SORT_STRING);//新建排序
//2.2 将三个参数字符串拼接成一个字符串进行sha1加密
$tmpStr = implode($tmpArr);//数组转字符串
$tmpStr = sha1($tmpStr);//shal加密
//2.3 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
if ($tmpStr == $signature) {
return true;
} else {
return false;
}
}
//回复消息
public function responseMsg(){
//3 以下代码接受消息
//3.1 接受微信服务器发送过来的原生的POST的数据包
//        $postData = $GLOBALS["HTTP_RAW_POST_DATA"];
$postData = isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] :file_get_contents("php://input");

//3.2 处理数据包
$xmlObj = simplexml_load_string($postData, "SimpleXMLElement", LIBXML_NOCDATA);
$msgType = $xmlObj->MsgType;
//4 根据消息类型进行业务处理
switch ($msgType) {
//接受事件消息
case 'event':
$this->disposeEvent($xmlObj);
break;
//接受文本消息
case 'text':
$this->disposeText($xmlObj);
break;
//接受图片消息
case 'image':
$this->disposeImage($xmlObj);
break;
}
}
//处理接收的事件消息
private function disposeEvent($xmlObj){
switch ($xmlObj->Event){
case 'subscribe'://订阅事件
$this->sendText('欢迎您的订阅');
break;
case 'unsubscribe'://取消订阅事件
$this->sendText('good-bye');//该消息用户其实是看不到的,取消订阅事件一般用来清除数据库记录
break;
}
}
//处理接收的文本消息
private function disposeText($xmlObj){
$text=trim($xmlObj->Content);
//包含关键字都不做处理
if (!(
strstr($text,'违规')    //这里对违规的关键字做排除,不予理睬
)){
switch ($text){
case '你好':
$this->sendText($xmlObj,'Hi 我是开发者服务器');
break;
case 'new':
$newsArr=array(
array(
"title"=>"看到这条消息,你可以买彩票了",
"description"=>"本公众号有许多小彩蛋,欢迎您的探索。",
"picUrl"=>"http://img.mp.itc.cn/upload/20170610/03d69e8df0524b8cb59fd16dc2fec989.jpg",
"url"=>"http://www.baidu.com"
)
);
$this->sendNews($xmlObj,$newsArr);
break;
default:
$this->tuling123($xmlObj,trim($xmlObj->Content));   //图灵机器人
}
}
}
//处理接收的图片消息
private function disposeImage($xmlObj){    //一般情况下,不会去处理用户发送的图片
$this->sendImage($xmlObj,$xmlObj->PicUrl,$xmlObj->MediaId);
}

//发送文本的方法
private function sendText($xmlObj,$content){
$replyTextMsg="<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>";
echo sprintf($replyTextMsg,$xmlObj->FromUserName,$xmlObj->ToUserName,time(),$content);
}
//发送图片的方法
private function sendImage($xmlObj,$mediaId){
$replyImageMsg="<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[image]]></MsgType>
<Image>
<MediaId><![CDATA[%s]]></MediaId>
</Image>
</xml>";
echo sprintf($replyImageMsg,$xmlObj->FromUserName,$xmlObj->ToUserName,time(),$mediaId);
}
//发送图文的方法
private function sendNews($xmlObj,$newsArr){
$newsTplHead = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[news]]></MsgType>
<ArticleCount>%s</ArticleCount>
<Articles>";
$newsTplBody = "<item>
<Title><![CDATA[%s]]></Title>
<Description><![CDATA[%s]]></Description>
<PicUrl><![CDATA[%s]]></PicUrl>
<Url><![CDATA[%s]]></Url>
</item>";
$newsTplFoot = "</Articles>
<FuncFlag>%s</FuncFlag>
</xml>";
$replyNewsMsg = sprintf($newsTplHead, $xmlObj->FromUserName, $xmlObj->ToUserName, time(),count($newsArr));
foreach($newsArr as $key => $value){
$replyNewsMsg .= sprintf($newsTplBody, $value['title'], $value['description'], $value['picUrl'], $value['url']);
}
$replyNewsMsg  .= sprintf($newsTplFoot, 0);
echo $replyNewsMsg;
}

public function tuling123($xmlObj,$message){//这是是使用图灵机器人
$tuTonken='2d8aaa17141c443----xxx---fsa';   //请去图灵网http://www.tuling123.com/自己申请一个tonken
$tuUrl='http://www.tuling123.com/openapi/api?key='.$tuTonken.'&info='.$message.'&userid='.$xmlObj->FromUserName;
$tuData='{
"key": "'.$tuTonken.'",
"info": "'.$message.'",
"userid": "'.$xmlObj->FromUserName.'"
}';
$results = $this->htts_request($tuUrl,$tuData);
//        print_r($results);
if ($results['code']==100000){
$text=$results['text'];
$this->sendText($xmlObj,$text);
}else{
$this->sendText($xmlObj,'有问题,请输入“帮助”');
}
}

//https请求(get和post)
private function htts_request($url,$data=array()){
//1 初始化curl
$ch=curl_init();
//2 设置传输选项
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);//把页面以文件流的形式返回
if (!empty($data)) {
curl_setopt($ch, CURLOPT_POST, true); //设置为 POST 请求
curl_setopt($ch, CURLOPT_POSTFIELDS, $data); //设置POST的请求数据
}
//3 执行curl请求
$outopt=curl_exec($ch);
$outoptArr=json_decode($outopt,true);
//4 关闭curl
curl_close($ch);
return $outoptArr;
}
}
?>


(2)上面代码可以用下面的结构图进行分析:



(3)下面是自定义菜单的代码(不建议使用,原因请看下面的第5小节)

//获取access_token
private function getAccessToken(){
//获取微信接口凭证
$appid="wxb4----xxx";//请在第一章第5小节的图片中看
$appsecret="21d---xxx";//请在第一章第5小节的图片中看

$data=json_decode(file_get_contents('./access_token.json'));
if ($data->expires_time <time()){
$url="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$appid}&secret={$appsecret}";
$outoptArr=$this->htts_request($url,array(),false);
$access_token=$outoptArr['access_token'];
if (!empty($access_token)){
//把access_token写入文件
$data->access_token=$outoptArr['access_token'];
$data->expires_time=time()+7000;
$fp=fopen('access_token.json','w');
fwrite($fp,json_encode($data));
fclose($fp);
}else{
echo '请求access_token错误';
}
}else{
$access_token=$data->access_token;
}
//        echo $access_token;
return $access_token;
}
//实现自定义菜单
public function menu_create(){
$access_token=$this->getAccessToken();
$url="https://api.weixin.qq.com/cgi-bin/menu/create?access_token={$access_token}";
$data='{
"button": [
{
"type": "click",
"name": "java",
"key": "learn_java"
},
{
"name":"chengxu",
"sub_button":[
{
"type": "view",
"name": "CSDN",
"url": "http://blog.csdn.net/tiandixuanwuliang/"
},
{
"type": "view",
"name": "Github",
"url": "https://github.com/wllfengshu/"
},
{
"type": "view",
"name": "jianshu",
"url": "https://www.jianshu.com/users/4d12e03d0a5f/timeline/"
},
{
"type": "view",
"name": "kaifazhe",
"url": "https://toutiao.io/u/431066/"
},
{
"type": "view",
"name": "yuyan",
"url": "http://www.baidu.com"
}]
},
{
"name":"jiaoliu",
"sub_button":[
{
"type": "view",
"name": "shuji",
"url": "http://blog.csdn.net/tiandixuanwuliang/"
},
{
"type": "view",
"name": "ziyuan",
"url": "https://github.com/wllfengshu/"
},
{
"type": "view",
"name": "sucai",
"url": "https://www.jianshu.com/users/4d12e03d0a5f/timeline/"
},
{
"type": "view",
"name": "daxuesheng",
"url": "https://toutiao.io/u/431066/"
},
{
"type": "click",
"name": "zuozhe",
"key": "about_author"
}]
}
]
}';
echo $url." ///// ".$data;
$outoptArr=$this->htts_request($url,json_decode($data,true),true);
echo '***';
print_r($outoptArr);
}


(4)下面是网页授权,授权后我们才可以在代码中调用(不建议使用,原因请看下面的第5小节)

//网页授权-base型
public function snsapi_base($redirect_uri){
//以下是测试账号
$appid="wxb4----xxx";//请在第一章第5小节的图片中看
$appsecret="21da56-----xxx";//请在第一章第5小节的图片中看

//准备scope
$snsapi_base_url="https://open.weixin.qq.com/connect/oauth2/authorize?appid={$appid}&redirect_uri={$redirect_uri}&response_type=code&scope=SCOPE&state=123#wechat_redirect";
$code=$_GET['code'];
//获取code
if (!isset($code)){
header("Location:{$snsapi_base_url}");
}
//获取access_token
$url="https://api.weixin.qq.com/sns/oauth2/access_token?appid={$appid}&secret={$appsecret}&code={$code}&grant_type=authorization_code";
return $this->htts_request($url);
}


(5)但是由于个人注册的订阅号没有自定义菜单的开发权限,所以我建议大家自定义菜单的功能交给第三方服务处理,这也是一个窍门,就是微信公众号同时授权给第三方服务器和开发者服务器,这是一个bug,哈哈。请注意,一定要先授权给开发者服务器,再授权给第三方服务器,否则将不成功。原理图如下:



上图中的第三方服务器具有关键字功能,我建议一些常用的关键字都交给第三方服务器做。一些具有逻辑性的关键字、需要存放到数据库的关键字、或者私密性的关键字可以由开发者服务器做。但是由于微信公众号粉丝发送的数据会同时发送到两个服务器,而且开发者服务器还具有图灵机器人功能,可以采取屏蔽的方法,在任意一方屏蔽一次,这样就避免了一条消息,回复了两次的问题。

(6)请把上述php文件,放到AppServ软件安装的根目录下的www文件夹下,然后重启AppServ中的服务,最后再把 http://服务器ip地址/index.php 填写到第一章第5节的url中即可。可以开始玩了



本文地址:http://blog.csdn.net/tiandixuanwuliang/article/details/79438662

欢迎大家看我的另一篇文章,这篇文章从需求分析、系统设计、代码实现等方面进行讲解,欢迎大家批评指正,http://blog.csdn.net/tiandixuanwuliang/article/details/79438738

欢迎大家关注,里面有很多资源分享:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息