配置 token
配置 access_token
配置 appId
微信签名,如,示例中的 check_signature
方法。只在配置公众号时调用,平时请不要调用它了
验证微信公众号的地址,如,http://wechat.hlzblog.top/
Route::get('/', 'WechatController@check_signature'); // 验证前,路由指向这个方法
Route::any('/', 'WechatController@index'); // 验证后,用于回复用户
控制器示例
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Business\WechatMsgBusiness;
use App\Business\WechatLogicBusiness;
use App\Helpers\CurlRequest;
class WechatController extends Controller{
// 微信签名,签名才用。平时请不要调用它了
public function check_signature(){
$token = env('wechat_token');
// 微信服务器,发来三个字符串,用于生成签名
$signature = $_GET['signature']; // 微信服务器 用同样算法 生成的签名
$timestamp = $_GET['timestamp'];
$nonce = $_GET['nonce'];
// 签名算法 => 这一块,是用来让自己知道,微信发来的请求是不是你当前正在调试的公众号的请求
// 比如:你现在有 A、B两个公众号,你正在调试A,但是你地址填的B,微信公众号就以为B就是你了,所以就出错了。
$tmpArr = array($token, $timestamp, $nonce);
// use SORT_STRING rule
sort($tmpArr, SORT_STRING);
$tmpStr = implode( $tmpArr );
$tmpStr = sha1( $tmpStr ); // 这个是就是你生成的签名
// 对比 签名是否相同
if( $tmpStr == $signature ){
// 微信服务器,发来的第四个字符串,用于告诉微信服务器,你验证成功
$echostr = $_GET['echostr']; // 反正必须输出这个字符串
return $echostr;
}else{
return '测试失败';
}
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++
// 正式开发,使用的部分
//+++++++++++++++++++++++++++++++++++++++++++++++++++
protected $fromUsername ; // 发送方帐号
protected $toUsername ; // 开发者微信号
protected $CreateTime ; // 消息创建时间
protected $MsgType ; // 消息类型
protected $Event; // 事件的具体名称 ,选填
protected $EventKey; // 事件类型
protected $Content ; // 消息内容 ,选填
// 统一微信请求入口
public function index(){
// ~~~~~~~~~~~~~~~~~~~~~~~微信请求我们服务器时,的必要操作~~~~~~~~~~~~~~~~~~~~~~~
//get post data, May be due to the different environments
$wecaht_request_xml = file_get_contents('php://input'); // 允许读取 POST 的原始数据
//extract post data
if (!empty($wecaht_request_xml)){
/* libxml_disable_entity_loader is to prevent XML eXternal Entity Injection,
the best way is to check the validity of xml by yourself */
libxml_disable_entity_loader(true);
loader(true);
$postObj = simplexml_load_string($wecaht_request_xml, 'SimpleXMLElement', LIBXML_NOCDATA);
$this->fromUsername = $postObj->FromUserName[0];
$this->toUsername = $postObj->ToUserName[0]; // 公众号
$this->CreateTime = $postObj->CreateTime[0]; // 发送过来的消息
$this->MsgType = $postObj->MsgType[0]; // 消息类型
if( isset($postObj->Content[0]) ){
$this->Content = $postObj->Content[0];
}
if( isset($postObj->Event[0]) ){
$this->Event = $postObj->Event[0];
if( isset($postObj->EventKey[0]) ){
$this->EventKey = $postObj->EventKey[0];
}
}
$this->handle_requset();
}
}
/**
* 微信事件处理
* @return XML
*/
private function handle_requset(){
$result = array(); // 用于接收处理后的数据的
switch($this->MsgType){
// 接收普通消息
case 'text': // 文本消息
$result = WechatMsgBusiness::text( trim($this->Content) );
break;
case 'image': // 图片消息
break;
case 'voice': // 语音消息
break;
case 'video': // 视频消息
break;
case 'shortvideo': // 小视频消息
break;
case 'location': // 地理位置消息
break;
case 'link': // 链接消息
break;
// 接收事件推送
case 'event': // 接收事件推送
if( $this->Event =='CLICK' ){
// 关于我们
if( $this->EventKey=='About_button' ){
$result = WechatMsgBusiness::text('About_button');
}
}
break;
default: // 默认回复
$result = WechatMsgBusiness::text('');
break;
}
return $this->handle_response($result['event'], $result['arr']);
}
/**
* 选择回复用户的事件
* @param String event 回复的事件类型
* @param Array vars 回复的数组信息
* @return XML 用于传输微信服务器的的 XML 数据
*/
private function handle_response($event, $vars){
$vars['ToUserName'] = $this->fromUsername;
$vars['FromUserName'] = $this->toUsername;
$vars['CreateTime'] = $this->CreateTime;
// 回复事件
switch ($event) {
case 'text':
$xml = view('wechat.tpl_reply_text', $vars);
break;
case 'news':
$vars['ArticleCount'] = count( $vars['news'] ); // 计算图文数目
$xml = view('wechat.tpl_pic_content', $vars);
break;
default:
# code...
break;
}
echo $xml;
exit();
}
// 微信登陆入口
public function to_oauth(){
$url = 'https://open.weixin.qq.com/connect/oauth2/authorize?';
$get['appid'] = env('wechat_appid');
$get['redirect_uri'] = env('wechat_redirect_uri');
$get['response_type'] = 'code';
$get['scope'] = 'snsapi_userinfo';
$url .= http_build_query($get).'#wechat_redirect'; // 文档里说,这里必须加上这个hash值
header("Location:".$url);
exit();
}
// 获取用户授权信息
public function get_user_info(){
// 获取临时 access_token
$url = 'https://api.weixin.qq.com/sns/oauth2/access_token?';
$get['appid'] = env('wechat_appid');
$get['secret'] = env('wechat_appkey');
$get['code'] = $_GET['code']; // 由回调页面传来
$get['grant_type'] = 'authorization_code';
$url .= http_build_query($get);
$res = json_decode( CurlRequest::run($url) );
// 这个判断主要用于调试
if( isset($res->errcode) ){
return $res->errmsg;
}
// 拉取授权信息
$url = 'https://api.weixin.qq.com/sns/userinfo?';
$get = [];
$get['access_token'] = $res->access_token;
$get['openid'] = $res->openid;
$get['lang'] = 'zh_CN ';
$url .= http_build_query($get);
$user_info = json_decode( CurlRequest::run($url) );
// 微信登录逻辑
$wechat = new WechatLogicBusiness();
$wechat->login($user_info);
$redirect_url = '/user';
echo '<script>window.location.href="'.$redirect_url.'"</script>';
exit();
}
}
回复逻辑示例
<?php
// 微信回复相关
namespace App\Business;
class WechatMsgBusiness{
public function __construct(){}
/**
* 文本消息
* @return Array
*/
public static function text($text){
$arr = array(); // 初始化数据
switch ($text) {
case '活动':
// 返回类型
$event = 'news';
// 第一条
$info = array();
$info['Title'] = '云天河博客活动';
$info['Description'] = '留言随机送配对女友';
$info['PicUrl'] = '图文的图片链接';
$info['Url'] = '点击图文信息,跳转到的对应url链接'
$arr['news'][] = $info;
// 第 n 条 [最多5条]
$info['Title'] = '同上';
$info['Description'] = '同上';
$info['PicUrl'] = '同上';
$info['Url'] = '同上'
$arr['news'][] = $info;
break;
default:
// 返回类型
$event = 'text';
$str = "您好,欢迎关注云天河Blog!\n\n'";
$str .= "输入1,查看进行中的活动";
$arr['Content'] = $str;
break;
}
return [
'event' => $event,
'arr' => $arr
];
}
}
一些微信内部处理的逻辑,比如,这里的登陆逻辑
<?php
// 微信一些业务的逻辑
namespace App\Business;
use App\User;
class WechatLogicBusiness{
public function __construct(){}
/**
* 微信登录逻辑
* @param Object 用户信息
* @return String 随机md5值[redis中的变量名],
*/
public function login($user_info){
$vars['openid'] = $user_info->openid; // openid 以公众号为单位,如,公众号A 申请了公众号支付功能,则可以其对应的openid来填写订单信息
$vars['nickname'] = $user_info->nickname; // 昵称
$vars['headpic'] = $user_info->headimgurl; // 头像
// $vars['wxid'] = $user_info->unionid; // unionid 以公司为单位,如,一个企业可以有很多种微信号,如,订阅号、公众号1、公众号2..,为方便管理,我们需要一个公共身份,企业内的业务人员都能识别这个用户
// 已经有相关信息了?
$user = new User;
$res_1 = $user->where('wxid', $vars['wxid'])
->get();
// true 如果有用户
if( count($res_1) ){
$uid = $res_1[0]->id;
$vars = []; // 清空
$vars['uid'] = $uid;
$_SESSION['uid'] = $uid;
}else{
$_SESSION['wx_user'] = $vars;
}
}
}
<?php
namespace App\Helpers;
class CurlRequest {
/**
* POST或GET请求,并返回数据
* @param String url 访问地址
* @param Array|JSON data 用于POST的数据
* @param Array header HTTP头请求
* @return String 返回数据
*/
public static function run($url, $data = null, $header = null ){
//请求 URL,返回该 URL 的内容
$ch = curl_init(); // 初始化curl
curl_setopt($ch, CURLOPT_URL, $url); // 设置访问的 URL
curl_setopt($ch, CURLOPT_HEADER, 0); // 放弃 URL 的头信息
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 返回字符串,而不直接输出
// Add Headers?
if( $header ){
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
}
// Https ?
if( preg_match('/^https/', $url) ){
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 不做服务器的验证
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); // 做服务器的证书验证
}
// POST method?
if( $data ){
curl_setopt($ch, CURLOPT_POST, true); // 设置为 POST 请求
curl_setopt($ch, CURLOPT_POSTFIELDS, $data); // 设置POST的请求数据
}
$content = curl_exec($ch); // 开始访问指定URL
curl_close($ch); // 关闭 cURL 释放资源
return $content;
}
}
回复图文消息
<xml>
<ToUserName><![CDATA[{{$ToUserName}}]]></ToUserName>
<FromUserName><![CDATA[{{$FromUserName}}]]></FromUserName>
<CreateTime>{{$CreateTime}}</CreateTime>
<MsgType><![CDATA[news]]></MsgType>
<ArticleCount>{{$ArticleCount}}</ArticleCount>
<Articles>
@foreach ($news as $k => $v)
<item>
<Title><![CDATA[{{$v['Title']}}]]></Title>
<Description><![CDATA[{{$v['Description']}}]]></Description>
<PicUrl><![CDATA[{{$v['PicUrl']}}]]></PicUrl>
<Url><![CDATA[{{$v['Url']}}]]></Url>
</item>
@endforeach
</Articles>
</xml>
回复文本消息
<xml>
<ToUserName><![CDATA[{{$ToUserName}}]]></ToUserName>
<FromUserName><![CDATA[{{$FromUserName}}]]></FromUserName>
<CreateTime>{{$CreateTime}}</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[{!! $Content !!}]]></Content>
</xml>
如果用户发了地理位置给公众号
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>1351776360</CreateTime>
<MsgType><![CDATA[location]]></MsgType>
<Location_X>23.134521</Location_X>
<Location_Y>113.358803</Location_Y>
<Scale>20</Scale>
<Label><![CDATA[位置信息]]></Label>
<MsgId>1234567890123456</MsgId>
</xml>
找对应接口:web端 URI API
找到如下地址
http://api.map.baidu.com/place/search?query=海底捞&location=31.204055632862,121.41117785465&radius=1000®ion=上海&output=html&src=yourCompanyName|yourAppName
实际上,使用以下链接中的参数即可
http://api.map.baidu.com/place/search?query=海底捞&location=31.204055632862,121.41117785465&radius=1000&output=html
链接:http://pan.baidu.com/s/1qYmyD7u 密码:v0x9
评论列表点此评论