/*
*公司需要,学了一下微信公众号开发,写这篇博客的时候已经开发结束半个月了
*回来记录一下,采用php语言(现学的)进行开发,不足之处还望提出来共同探讨
*/
(原创不易,转载请注明出处!)
提示:目前微信公众号包含订阅号和服务号两种。详细区别官网有介绍,这里要说的是订阅号如果自己配置服务器url的话,是没有自定义菜单栏功能的,因此配置服务器url后只能接受用户的手动输入内容。而服务号需要企业认证,个人无法申请。
一、微信开发环境搭建
1.申请和配置微信公众平台
微信公众平台已经提供了一个很便捷的开发配置方式,这里不在赘述,展示一下配置完的画面,
切记,图中画红色圈的地方一定要点击启用,否则微信客户端的请求无法发送到我们配置的服务器地址。我在这里浪费了一早上的时间,醉了。。。。
2.微信请求的传递流程
稍微解释一下,微信的服务器只是起到转发的作用,将手机客户端的请求转发到我们配置的服务器地址,就是上图看到URL地址。
3.服务器地址文件的编写
这个才是开发的重点啊,下面先贴上本人编写的源码模板,可以直接使用的。
首先是微信界面菜单栏设计的请求,将下面这个php文件放进随便一个php环境运行一下就可以了,目的是让它发出请求就好了。(订阅号配置url后没有权限,会返回失败)
array(
array('name'=>'菜单一','sub_button'=>array(
array('type'=>'click', 'name'=>'二级菜单', 'key'=>'13'),
array('type'=>'view','name'=>'百度','url'=>'www.baidu.com'),
)
),
array('name'=>'菜单二','sub_button'=>array(
array('type'=>'view','name'=>'卡种查询','url'=>'www.baidu.com'),
array('type'=>'click', 'name'=>'百度', 'key'=>'21'),
)
),
array('name'=>'菜单三','sub_button'=>array(
array('type'=>'view', 'name'=>'百度', 'url'=>'www.baidu.com'),
)
),
)
);
/* 发起更新菜单用的curl请求 */
function https_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, 1);
$output = curl_exec($curl);
curl_close($curl);
return $output;
}
/* 去除php版本的影响 */
function json_encode_ex($value)
{
if (version_compare(PHP_VERSION,'5.4.0','<'))
{
$str = json_encode($value);
$str = preg_replace_callback(
"#\\\u([0-9a-f]{4})#i",
function($matchs)
{
return iconv('UCS-2BE', 'UTF-8', pack('H4', $matchs[1]));
},
$str
);
return $str;
}
else
{
return json_encode($value, JSON_UNESCAPED_UNICODE);
}
}
/* 发起请求 */
$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$appid}&secret={$appsecret}";
$result = https_request($url);
$jsoninfo = json_decode($result, true);
$access_token = $jsoninfo["access_token"];
$url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=".$access_token;
$jsonmenu = json_encode_ex($menu);
$result = https_request($url, $jsonmenu);
var_dump($result);
?>
接下来是前面配置的服务器url地址文件,就是那个index.php:(token要改成自己的)
valid(); //验证消息来自微信服务器第一次使用就行
$wechatObj->responseMsg(); //处理消息
class wechatCallbackapiTest
{
/**
* 接受处理微信服务器发送过来的消息
*/
public function responseMsg()
{
/*获取post数据(XML类型)*/
$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
if(!empty($postStr)){//判断获取到的XML数据是否为空
/* 解析XML数据 */
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
/* 获取发信方的用户名 */
$fromUsername = $postObj->FromUserName;
/* 获取消息类型(event 事件 | text 文本)*/
$RX_TYPE = trim($postObj->MsgType);
/* 根据 消息类型 进行跳转 */
switch ($RX_TYPE)
{
//点击事件
case "event":
$resultStr = $this->receiveEvent($postObj, $user);
break;
//文本输入事件
case "text":
$resultStr = $this->receiveText($postObj, $user);
break;
//其他
default:
$resultStr = "unknow msg type: ".$RX_TYPE;
break;
}
}else{
//XML数据为空,do nothing...
}
}
/**
* 点击事件接口
*/
protected function receiveEvent($postObj, $user){
/* 获取收发方 */
$fromUsername = $postObj->FromUserName; //得到发送方名称
$toUsername = $postObj->ToUserName; //得到接收方的名称
/*event事件的类型(subscribe 新用户订阅事件 | CLICK 点击回复请求 | VIEW 界面请求)*/
$event_type = trim($postObj->Event);
/* 生成一个menu对象,定义在menu.calss.php文件 */
$menu=new menu();
/*事件处理*/
if($event_type == "subscribe"){//新用户订阅事件处理
$sendData = array(
"act" => "asyn_send_adduser" ,
"bind_openid" => $fromUsername ,
"bind_key" => '147258' ,
);
$menu->Welcome_Words($fromUsername,$toUsername);//新用户欢迎词(我封装好的接口,后面会附上)
}
else if($event_type == "CLICK")
{
switch (trim($postObj->EventKey))//对用户请求的key进行筛选
{
case "13":
$data="Hi,你好~";
$result=$menu->Output_Text_Message($data,$fromUsername,$toUsername);
echo $result;
break;
case "21":
$data="Hi,你好~";
$result=$menu->Output_Text_Message($data,$fromUsername,$toUsername);
echo $result;
break;
default :
$data = "没有该菜单";
$result=$menu->Output_Text_Message($data,$fromUsername,$toUsername);
echo $result;
break;
}
exit(1);
}
}
/**
* 文本消息事件接口
*/
protected function receiveText($postObj, $user){
/* 获取收发方 */
$fromUsername = $postObj->FromUserName; //得到发送方名称
$toUsername = $postObj->ToUserName; //得到接收方的名称
/*获取当前时间*/
$time = time();
/* 生成一个menu对象,定义在menu.calss.php文件 */
$menu=new menu();
/*消息内容处理*/
if(is_numeric($keyword))//用户输入了纯数字
{
$data="Hi,你输入了数字!";
$result=$menu->Output_Text_Message($data,$fromUsername,$toUsername);
echo $result;
}
else {//其他情况
$data="Hi,你输入了其他内容!";
$result=$menu->Output_Text_Message($data,$fromUsername,$toUsername);
echo $result;
}
}
/**
* 验证消息是否来自微信服务器(入口)
*/
protected function valid()
{
$echoStr = $_GET["echostr"]; //收集get数据(随机字符串)
if($this->checkSignature()){ //判断checkSignature()自定义函数结果(验证微信服务器)
echo $echoStr; //为真则输出结果(随机字符串)
}
}
/**
* 验证消息是否来自微信服务器
*/
private function checkSignature()
{
$signature = $_GET["signature"]; //微信加密签名
$timestamp = $_GET["timestamp"]; //时间戳
$nonce = $_GET["nonce"]; //随机数
$token = TOKEN; //token与上面对应
$tmpArr = array($token, $timestamp, $nonce); //组装创建数组
sort($tmpArr, SORT_STRING); //把$tmpArr做字符串处理并排序(升序)
$tmpStr = implode( $tmpArr ); //将数组变成字符串
$tmpStr = sha1( $tmpStr ); //计算字符串散列
if( $tmpStr == $signature ){ //判断是否一致
return true; //符合返回真
}else{
return false; //否则返回假
}
}
}
?>
接下来是我封装好的menu类:
%s
0
";
$resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $data);
return $resultStr;
}
/* 新用户关注欢迎词 */
function Welcome_Words($fromUsername,$toUsername)
{
$data = "欢迎关注福建通联支付,点击菜单进入更多功能哦~".$this->bytes_to_emoji(0x1F604);
$resultStr=$this->Output_Text_Message($data,$fromUsername,$toUsername);
echo $resultStr;
}
/* 错误信息提示 */
function Input_Error($fromUsername,$toUsername)
{
$data="输入内容有误,请检查格式,重新输入哈~~~";
$show=$this->Output_Text_Message($data,$fromUsername,$toUsername);
return $show;
}
/* 字节转Emoji表情 */
function bytes_to_emoji($cp)
{
if ($cp > 0x10000){ # 4 bytes
return chr(0xF0 | (($cp & 0x1C0000) >> 18)).chr(0x80 | (($cp & 0x3F000) >> 12)).chr(0x80 | (($cp & 0xFC0) >> 6)).chr(0x80 | ($cp & 0x3F));
}else if ($cp > 0x800){ # 3 bytes
return chr(0xE0 | (($cp & 0xF000) >> 12)).chr(0x80 | (($cp & 0xFC0) >> 6)).chr(0x80 | ($cp & 0x3F));
}else if ($cp > 0x80){ # 2 bytes
return chr(0xC0 | (($cp & 0x7C0) >> 6)).chr(0x80 | ($cp & 0x3F));
}else{ # 1 byte
return chr($cp);
}
}
}
?>
到此,一个完整的微信公众平台就搭建完成啦~
这个只是一个基本的框架,微信公众号还有很多的功能,这里就不一一描述啦,详细的可以看官方的文档,上链接:
微信公众号开发官方文档
有什么错误的还希望大伙儿提出来探讨一下哈~~~
(原创不易,转载请注明出处!)