Files
BESCMS/dayrui/App/Weixin/Controllers/Home.php
T

653 lines
31 KiB
PHP

<?php namespace Phpcmf\Controllers;
class Home extends \Phpcmf\Common {
private $token;
private $data;
private $access_token;
public function index() {
if (!isset($this->weixin['account']['appid']) || !$this->weixin['account']['appid']) {
exit('插件AppId未配置(如果后台已经配置,请更新缓存后,才会生效)');
} elseif (!isset($this->weixin['account']['token']) || !$this->weixin['account']['token']) {
exit('插件Token未配置(如果后台已经配置,请更新缓存后,才会生效)');
} elseif ($this->checkSignature()) {
// 判读是不是只是验证
$echostr = \Phpcmf\Service::L('Input')->get('echostr', true);
if ($echostr) {
echo $echostr;exit;
} else {
// 实际处理用户消息
$content = file_get_contents('php://input');
if (isset($this->weixin['account']['log']) && $this->weixin['account']['log']) {
file_put_contents(WRITEPATH.'app/weixin.log', dr_date(SYS_TIME, 'Y-m-d H:i:s').' - '.$content.PHP_EOL.'==================================='.PHP_EOL, FILE_APPEND);
}
//file_put_contents(APPPATH."wx.txt", var_export($content, true));
if ($content) {
// 解析微信传过来的 XML 内容 转化为数组
$this->data = dr_object2array(simplexml_load_string($content, 'SimpleXMLElement', LIBXML_NOCDATA));
if (!$this->data['EventKey']) {
$this->data['EventKey'] = '';
}
$this->token = $this->data['ToUserName'];
$rt = weixin_get_access_token();
$rt['code'] && $this->access_token = $rt['msg'];
// 微信消息钩子
\Phpcmf\Hooks::trigger('weixin_msg', $this);
// 存储和分析请求
switch ($this->data['MsgType']) {
case 'text':
# 文本消息
// 初始化用户 将其加入到粉丝组里面
$this->_init_user();
\Phpcmf\Service::M('Weixin', 'Weixin')->save_message($this->data);
//
// 搜索自定义回复
$kws = $this->get_cache('weixin-kws'.(WEIXIN_MORE_ID > 1 ? '_more_'.WEIXIN_MORE_ID : ''));
if ($kws) {
foreach ($kws as $kw => $id) {
if (strpos($this->data['Content'], (string)$kw) !== false) {
$data = \Phpcmf\Service::M()->table(weixin_wxtable('reply'))->get($id);
if ($data) {
// 记录
\Phpcmf\Service::M()->table(weixin_wxtable('reply'))->update($data['id'], [
'counts' => $data['counts'] + 1,
'updatetime' => SYS_TIME,
]);
if ($data['tid']) {
// 回复素材
return $this->_to_weixin_content($data['content']);
} else {
// 回复文本
return $this->_to_weixin_text($data['content']);
}
break;
}
}
}
}
// 用于自定义开发回复
if (is_file(APPPATH.'Plugins/AutoReply/Run.php')) {
require APPPATH.'Plugins/AutoReply/Run.php';
}
// 搜索模块内容回复
if ($this->weixin['config']['ss']) {
// 搜索模块内容回复
if ($this->weixin['config']['ss_dir']) {
// 搜索模块内容
foreach ($this->weixin['config']['ss_dir'] as $dirname) {
foreach ($this->site as $siteid) {
$table = dr_module_table_prefix($dirname, $siteid);
// 判断是否存在表
if (!\Phpcmf\Service::M()->is_table_exists($table)) {
continue;
}
// 查询 关键 词
$kw = dr_safe_replace($this->data['Content']);
$data = \Phpcmf\Service::M()->db->table($table)->where('`title` LIKE "%'.$kw.'%"')->orderBy('id desc')->limit(1)->get()->getResultArray();
#log_message('error', ''.\Phpcmf\Service::M()->get_sql_query());
if ($data) {
// 查询成功,回复他们
$cdata = [
'tid' => 'index',
'content' => [],
];
foreach ($data as $ii => $t) {
$i = 10 + $ii;
$cdata['content'][$i] = [
'title_'.$i => $t['title'],
'author_'.$i => $t['author'],
'thumb_'.$i => $t['thumb'] ? dr_get_file($t['thumb']) : SITE_LOGO,
'description_'.$i => $t['description'],
'url_'.$i => dr_url_prefix($t['url']),
];
if ($t['thumb'] && !isset($cdata['content'][1])) {
$cdata['content'][1] = [
'title_1' => $t['title'],
'author_1' => $t['author'],
'thumb_1' => dr_get_file($t['thumb']),
'description_1' => $t['description'],
'url_1' => dr_url_prefix($t['url']),
];
unset($cdata['content'][$i]);
}
}
ksort($cdata['content']);
// 回复内容
return $this->_to_weixin_content_data($cdata);
}
}
}
}
// 没有找到回复内容
if ($this->weixin['config']['ss_type']) {
// 回复素材
return $this->_to_weixin_content($this->weixin['config']['ss_value_1']);
} else {
// 回复文本
return $this->_to_weixin_text($this->weixin['config']['ss_value_0']);
}
}
break;
case 'image':
# 图片消息
case 'voice':
# 语音消息
case 'video':
# 视频消息
case 'shortvideo':
# 小视频消息
case 'link':
# 链接消息
// 初始化用户 将其加入到粉丝组里面
$this->_init_user();
\Phpcmf\Service::M('Weixin', 'Weixin')->save_message($this->data);
break;
case 'location':
# 地理位置消息
break;
case 'event':
# 事件推送
switch ($this->data['Event']) {
case 'PUBLISHJOBFINISH':
// 发布内容推送
\Phpcmf\Service::M()->table(weixin_wxtable('content'))
->where('publish_id', $this->data['PublishEventInfo']['publish_id'])->update(0, [
'status' => $this->data['PublishEventInfo']['publish_status'],
'article_id' => $this->data['PublishEventInfo']['article_id'],
]);
break;
case 'subscribe':
// 关注时
// 统计数据
/*
$fans = \Phpcmf\Service::M()->table(weixin_wxtable('count_fans'))->where('date', date('Ymd'))->getRow();
if (!$fans) {
// 今日新关注
$usercount = \Phpcmf\Service::M()->table(weixin_wxtable('user'))->counts();
$rt = \Phpcmf\Service::M()->table(weixin_wxtable('count_fans'))->insert([
'new' => 1,
'cancel' => 0,
'cumulate' => $usercount,
'date' => date('Ymd'),
]);
} else {
$rt = \Phpcmf\Service::M()->table(weixin_wxtable('count_fans'))->update($fans['id'], [
'new' => $fans['new'] + 1,
'cumulate' => $fans['cumulate'] + 1,
]);
}*/
if (strpos($this->data['EventKey'], 'qrscene_bang-') === 0) {
// 表示通过扫描二维码关注微信公众号
$this->_gz_bang_user();
} else {
// 初始化用户 将其加入到粉丝组里面
$user = $this->_init_user();
$this->_gz_login_user();
// 回复关注信息
if ($this->weixin['config']['gz']) {
if ($this->weixin['config']['gz_type']) {
// 回复素材
if ($this->weixin['config']['gz_value_1']) {
$this->_to_weixin_content($this->weixin['config']['gz_value_1']);
}
} else {
// 回复文本
if ($this->weixin['config']['gz_value_0']) {
$this->_to_weixin_text($this->_gz_msg($this->weixin['config']['gz_value_0'], $user));
}
}
}
}
break;
case 'unsubscribe':
// 取消关注时
/*
$fans = \Phpcmf\Service::M()->table(weixin_wxtable('count_fans'))->where('date', date('Ymd'))->getRow();
if (!$fans) {
// 今日新取消关注
$usercount = \Phpcmf\Service::M()->table(weixin_wxtable('user'))->counts();
$rt = \Phpcmf\Service::M()->table(weixin_wxtable('count_fans'))->insert([
'new' => 0,
'cancel' => 1,
'cumulate' => $usercount,
'date' => date('Ymd'),
]);
} else {
$rt = \Phpcmf\Service::M()->table(weixin_wxtable('count_fans'))->update($fans['id'], [
'cancel' => $fans['new'] + 1,
'cumulate' => max(0, $fans['cumulate'] - 1),
]);
}*/
// 删除各种记录
\Phpcmf\Service::M()->db->table(weixin_wxtable('user'))->where('openid', $this->data['FromUserName'])->delete();
\Phpcmf\Service::M()->db->table(weixin_wxtable('follow'))->where('openid', $this->data['FromUserName'])->delete();
\Phpcmf\Service::M()->db->table(weixin_wxtable('message'))->where('openid', $this->data['FromUserName'])->delete();
\Phpcmf\Service::M()->db->table('member_oauth')->where('oauth', 'wechat')->where('oid', $this->data['FromUserName'])->delete();
break;
default:
if (strpos($this->data['EventKey'], 'App::') === 0) {
// 表示执行插件控制器
$file = APPPATH.'Plugins/'.ucfirst(substr($this->data['EventKey'], 5)).'/Run.php';
if (!is_file($file)) {
log_message('error', '微信小插件运行程序不存在:'.$file);
} else {
require $file;
}
// 初始化用户 将其加入到粉丝组里面
$this->_init_user();
} elseif (strpos($this->data['EventKey'], 'bang-') === 0 || strpos($this->data['EventKey'], 'qrscene_bang-') === 0) {
// 表示通过扫描二维码关注微信公众号
$this->_gz_bang_user();
} elseif (strpos($this->data['EventKey'], 'login-') === 0 || strpos($this->data['EventKey'], 'qrscene_login-') === 0) {
// 表示通过扫描二维码关注微信公众号
$this->_gz_login_user();
}
break;
}
break;
default:
# code...
// 初始化用户 将其加入到粉丝组里面
$this->_init_user();
break;
}
}
}
}
exit;
}
// 表示通过扫描二维码关注微信公众号
private function _gz_bang_user() {
list($s, $uid) = explode('-', $this->data['EventKey']);
$member = $uid ? dr_member_info($uid) : [];
if ($member) {
// 绑定账号
$rt = wx_get_https_json_data('https://api.weixin.qq.com/cgi-bin/user/info?access_token='.$this->access_token.'&openid='.$this->data['FromUserName']);
if (!$rt['code']) {
return;
} elseif (!$rt['data']['openid']) {
return;
}
\Phpcmf\Service::M('member')->insert_oauth($uid, 'login', [
'oid' => $rt['data']['openid'],
'oauth' => 'wechat',
'avatar' => (string)$rt['data']['headimgurl'],
'unionid' => (string)$rt['data']['unionid'],
'nickname' => dr_emoji2html($rt['data']['nickname']?$rt['data']['nickname']:'微信用户'),
'expire_at' => SYS_TIME,
'access_token' => 0,
'refresh_token' => 0,
], '');
\Phpcmf\Service::M()->db->table(weixin_wxtable('user'))->where('openid', $this->data['FromUserName'])->update([
'uid' => (int)$member['uid'],
'username' => (string)$member['username'],
]);
if ( $this->weixin['config']['gz']) {
if ($this->weixin['config']['gz_type']) {
// 回复素材
$this->_to_weixin_content($this->weixin['config']['gz_value_1']);
} else {
// 回复文本
$this->_to_weixin_text($this->_gz_msg($this->weixin['config']['gz_value_0'], $member));
}
}
}
}
// 表示通过扫描二维码关注微信公众号
private function _gz_login_user() {
list($s, $ep) = explode('-', $this->data['EventKey']);
if ($ep) {
// 登录或注册账号
$rt = wx_get_https_json_data('https://api.weixin.qq.com/cgi-bin/user/info?access_token='.$this->access_token.'&openid='.$this->data['FromUserName']);
if (!$rt['code']) {
return;
}
$user = \Phpcmf\Service::M()->table('member_oauth')->where('oid', $rt['data']['openid'])->where('oauth', 'wechat')->getRow();
if (!$user && isset($rt['data']['unionid']) && $rt['data']['unionid']) {
$user = \Phpcmf\Service::M()->table('member_oauth')->where('unionid', $rt['data']['unionid'])->getRow();
}
if ($user['uid']) {
// 已经关注,就登录
\Phpcmf\Service::M()->table('member_oauth')->update($user['id'], [
'refresh_token' => 'login-'.$ep,
]);
if ($this->weixin['config']['gz_login']) {
$user = dr_member_info($user['uid']);
$this->_to_weixin_text(str_replace(['{user}', '{time}', '{name}'], [$user['username'], dr_date(SYS_TIME), $user['name']], $this->weixin['config']['gz_login']));
} else {
$this->_to_weixin_text('通过扫描二维码在PC登录成功');
}
return;
}
if ($this->member_cache['oauth']['login']) {
// 直接注册
$oauth = [
'oid' => $rt['data']['openid'],
'oauth' => 'wechat',
'avatar' => $rt['data']['headimgurl'],
'unionid' => (string)$rt['data']['unionid'],
'nickname' => dr_emoji2html($rt['data']['nickname']?$rt['data']['nickname']:'微信用户'),
'expire_at' => SYS_TIME,
'access_token' => 0,
'refresh_token' => 'login-'.$ep,
];
$rt2 = \Phpcmf\Service::M('member')->insert_oauth(0, 'register', $oauth, '');
if (!$rt2['code']) {
$this->_to_weixin_text($rt2['msg']);
}
$oauth['id'] = $rt2['code'];
$groupid = (int)$this->member_cache['register']['groupid'];
if (!$groupid) {
$this->_to_weixin_text('系统没有设置默认注册的用户组');
}
$rt = \Phpcmf\Service::M('member')->register_oauth($groupid, $oauth);
if ($rt['code']) {
// 登录成功
if ($this->weixin['config']['gz_reg']) {
$user = $rt['data']['member'];
$this->_to_weixin_text(str_replace(['{user}', '{time}', '{name}'], [$user['username'], dr_date(SYS_TIME), $user['name']], $this->weixin['config']['gz_reg']));
} else {
$this->_to_weixin_text('通过扫描二维码在PC注册成功,随机账号为:'.$rt['data']['member']['username']);
}
} else {
$this->_to_weixin_text($rt['msg']);
}
} else {
// 绑定账号
$url = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid='.$this->weixin['account']['appid'].'&redirect_uri='.urlencode(SITE_URL.'index.php?s=weixin&c=member&ep=login-'.$ep).'&response_type=code&scope=snsapi_base&state=member#wechat_redirect';
$txt = $this->weixin['config']['bang_text'] ? $this->weixin['config']['bang_text'] : '您还没有绑定本站账号,点我立即绑定账号';
$this->_to_weixin_text('<a href="'.$url.'">'.$txt.'</a>');
}
}
}
// 替换返回值
private function _gz_msg($tpl, $user) {
if (!isset($user['username']) || !$user['username']) {
$user['username'] = $user['nickname'];
}
return str_replace('{username}', $user['username'], (string)$tpl);
}
// 初始化用户情况
private function _init_user() {
$rt = wx_get_https_json_data('https://api.weixin.qq.com/cgi-bin/user/info?access_token='.$this->access_token.'&openid='.$this->data['FromUserName']);
if (!$rt['code']) {
return;
}
$user = \Phpcmf\Service::M()->table(weixin_wxtable('user'))->where('openid', $this->data['FromUserName'])->getRow();
if (!$user) {
// 入库粉丝表
$user = \Phpcmf\Service::M('User', APP_DIR)->insert_user($rt['data']);
} else {
// 更新
$user = \Phpcmf\Service::M('User', APP_DIR)->update_user($user, $rt['data']);;
}
// 判断当用户没有绑定会员的情况时
if (!$user['uid']) {
// 判断是否绑定过公众号
$bang = \Phpcmf\Service::M()->table('member_oauth')->where('oauth', 'wechat')->where('oid', $this->data['FromUserName'])->getRow();
if (!$bang && isset($user['unionid']) && $user['unionid']) {
$bang = \Phpcmf\Service::M()->table('member_oauth')->where('unionid', $user['unionid'])->getRow();
}
if ($bang && $bang['uid']) {
$member = dr_member_info($bang['uid']);
\Phpcmf\Service::M()->table(weixin_wxtable('user'))->update($user['id'], [
'uid' => (int)$bang['uid'],
'username' => (string)$member['username'],
]);
} else {
if ($this->weixin['config']['bang']) {
// 提醒用户绑定会员
$url = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid='.$this->weixin['account']['appid'].'&redirect_uri='.urlencode(SITE_URL.'index.php?s=weixin&c=member').'&response_type=code&scope=snsapi_base&state=member#wechat_redirect';
$txt = $this->weixin['config']['bang_text'] ? $this->weixin['config']['bang_text'] : '您还没有绑定本站账号,点我立即绑定账号';
$this->_to_weixin_text('<a href="'.$url.'">'.$txt.'</a>');
}
return $user;
}
}
// 存储cookie
$this->uid = $user['uid'];
$this->member = \Phpcmf\Service::M('member')->get_member($this->uid);
\Phpcmf\Service::M('member')->save_cookie($this->member);
return $this->member;
}
// 验证微信请求
private function checkSignature() {
$nonce = (string)$_GET["nonce"];
$signature = (string)$_GET["signature"];
$timestamp = (string)$_GET["timestamp"];
$token = $this->weixin['account']['token'];
$tmpArr = [$token, $timestamp, $nonce];
sort($tmpArr, SORT_STRING);
$tmpStr = implode( $tmpArr );
$tmpStr = sha1( $tmpStr );
if ($tmpStr == $signature){
return true;
} else{
return false;
}
}
// ================================================
// 回复文本
public function _to_weixin_text($text) {
if (!$text) {
return;
}
echo '<xml>
<ToUserName><![CDATA['.$this->data['FromUserName'].']]></ToUserName>
<FromUserName><![CDATA['.$this->data['ToUserName'].']]></FromUserName>
<CreateTime>'.(SYS_TIME+2).'</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA['.$text.']]></Content>
</xml>';exit;
}
// 回复素材
public function _to_weixin_content($id) {
$id = (int)substr($id, 5);
if (!$id) {
return;
}
// 查询内容
$data = \Phpcmf\Service::M()->table(weixin_wxtable('content'))->get($id);
if (!$data) {
return;
}
$value = dr_string2array($data['content']);
$data['content'] = [];
if ($value) {
for ($i = 1; $i<=9; $i++) {
if (!$value['thumb_'.$i] || !$value['title_'.$i]) {
break;
}
$data['content'][$i] = [
"title_".$i => $value['title_'.$i],
"thumb_".$i => dr_get_file($value['thumb_'.$i]),
"description_".$i => $value['description_'.$i],
"url_".$i => html_entity_decode(dr_url_prefix($value['url_'.$i]))
];
}
}
#file_put_contents(WRITEPATH."weixin/wx.txt", var_export($data, true));
return $this->_to_weixin_content_data($data);
}
// 开始回复
public function _to_weixin_content_data($cdata) {
if (!$cdata['tid']) {
$cdata['tid'] = 'index';
}
switch ($cdata['tid']) {
case 'index':
// 回复图文
$count = 0;
$text = '';
foreach ($cdata['content'] as $i => $t) {
if ($t['title_'.$i]) {
$count ++;
$text.= '<item>
<Title><![CDATA['.$t['title_'.$i].']]></Title>
<Description><![CDATA['.$t['description_'.$i].']]></Description>
<PicUrl><![CDATA['.$t['thumb_'.$i].']]></PicUrl>
<Url><![CDATA['.$t['url_'.$i].']]></Url>
</item>';
}
}
if (!$count) {
$this->_to_weixin_text('没有找到相关内容');
return;
}
exit('
<xml>
<ToUserName><![CDATA['.$this->data['FromUserName'].']]></ToUserName>
<FromUserName><![CDATA['.$this->data['ToUserName'].']]></FromUserName>
<CreateTime>'.(SYS_TIME+2).'</CreateTime>
<MsgType><![CDATA[news]]></MsgType>
<ArticleCount>'.$count.'</ArticleCount>
<Articles>
'.$text.'
</Articles>
</xml>
');
break;
case 'image':
if (!$cdata['media_id']) {
$this->_to_weixin_text('没有找到相关内容');
return;
}
exit('<xml>
<ToUserName><![CDATA['.$this->data['FromUserName'].']]></ToUserName>
<FromUserName><![CDATA['.$this->data['ToUserName'].']]></FromUserName>
<CreateTime>'.(SYS_TIME+2).'</CreateTime>
<MsgType><![CDATA[image]]></MsgType>
<Image>
<MediaId><![CDATA['.$cdata['media_id'].']]></MediaId>
</Image>
</xml>');
break;
case 'voice':
if (!$cdata['media_id']) {
$this->_to_weixin_text('没有找到相关内容');
return;
}
exit('<xml>
<ToUserName><![CDATA['.$this->data['FromUserName'].']]></ToUserName>
<FromUserName><![CDATA['.$this->data['ToUserName'].']]></FromUserName>
<CreateTime>'.(SYS_TIME+2).'</CreateTime>
<MsgType><![CDATA[voice]]></MsgType>
<Image>
<MediaId><![CDATA['.$cdata['media_id'].']]></MediaId>
</Image>
</xml>');
break;
case 'video':
if (!$cdata['media_id']) {
$this->_to_weixin_text('没有找到相关内容');
return;
}
exit('<xml>
<ToUserName><![CDATA['.$this->data['FromUserName'].']]></ToUserName>
<FromUserName><![CDATA['.$this->data['ToUserName'].']]></FromUserName>
<CreateTime>'.(SYS_TIME+2).'</CreateTime>
<MsgType><![CDATA[video]]></MsgType>
<Image>
<MediaId><![CDATA['.$cdata['media_id'].']]></MediaId>
</Image>
</xml>');
break;
case 'link':
exit('<xml>
<ToUserName><![CDATA['.$this->data['FromUserName'].']]></ToUserName>
<FromUserName><![CDATA['.$this->data['ToUserName'].']]></FromUserName>
<CreateTime>'.(SYS_TIME+2).'</CreateTime>
<MsgType><![CDATA[link]]></MsgType>
<Title><![CDATA['.$cdata['title'].']]></Title>
<Description><![CDATA['.$cdata['description'].']]></Description>
<Url><![CDATA['.$cdata['url'].']]></Url>
</xml>');
break;
}
$this->_to_weixin_text('没有找到相关内容');
}
/* 组装xml数据 */
private function _data2xml($xml, $data, $item = 'item') {
foreach ( $data as $key => $value ) {
is_numeric ( $key ) && ($key = $item);
if (is_array ( $value ) || is_object ( $value )) {
$child = $xml->addChild ( $key );
$this->_data2xml ( $child, $value, $item );
} else {
if (is_numeric ( $value )) {
$child = $xml->addChild ( $key, $value );
} else {
$child = $xml->addChild ( $key );
$node = dom_import_simplexml ( $child );
$node->appendChild ( $node->ownerDocument->createCDATASection ( $value ) );
}
}
}
}
}