微信订阅通知开发 (小白教程)微擎

微擎复制可用 

微擎访问绕过登陆校验请查看 https://blog.csdn.net/fuchto/article/details/118190252

文中 微擎 WeAccount::create($id); 等函数绕过绕过登陆校验直接使用是无法使用的会报错

需要溯源到对应的方法中 传参调用 

如果让用户在同一个页点击两次 同意授权可能会发生 发送两条消息的情况 可以试试 location.reload(); 刷新一下试试

第一步 公众号配置  选择对应的模版 

开发此功能必须是 服务号

官方文档 https://developers.weixin.qq.com/doc/offiaccount/Subscription_Messages/intro.html

设置公众号的 相关配置  业务域名 js域名 授权域名 

 第二步 创建数据库



SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for ims_template_log
-- ----------------------------
DROP TABLE IF EXISTS `ims_template_log`;
CREATE TABLE `ims_template_log`  (
  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `openid` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户openid',
  `template_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '模版id',
  `uniacid` int(11) NULL DEFAULT NULL COMMENT '公众号id',
  `status` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '订阅状态',
  `number` int(11) NULL DEFAULT 1 COMMENT '同意次数',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 61 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

-- ----------------------------
-- Table structure for ims_template_msg
-- ----------------------------
DROP TABLE IF EXISTS `ims_template_msg`;
CREATE TABLE `ims_template_msg`  (
  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `uniacid` int(11) NULL DEFAULT NULL COMMENT '公众号id',
  `head_title` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '网页标题',
  `headimage` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '头像地址',
  `content` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '显示文案',
  `bg_image` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '背景图',
  `button_text` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '按钮内容',
  `herad_media_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '头像media_id',
  `bg_media_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '背景图media_id',
  `template` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '模版内容',
  `createtime` int(11) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

-- ----------------------------
-- Table structure for ims_template_sendLog
-- ----------------------------
DROP TABLE IF EXISTS `ims_template_sendLog`;
CREATE TABLE `ims_template_sendLog`  (
  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `msg_id` int(11) NULL DEFAULT NULL COMMENT '消息id templat_msg',
  `uniacid` int(11) NULL DEFAULT NULL,
  `sum` int(11) NULL DEFAULT NULL COMMENT '推送数',
  `success` int(11) NULL DEFAULT NULL COMMENT '推送成功数',
  `start_time` int(11) NULL DEFAULT NULL COMMENT '开始数据',
  `end_time` int(11) NULL DEFAULT NULL COMMENT '结束时间',
  `status` int(2) NULL DEFAULT NULL COMMENT '推送状态:0=推送中,1=推送完成',
  `title` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '推送模版标题',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 18 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

SET FOREIGN_KEY_CHECKS = 1;

template_msg 中的 template 格式为

[
    {
        "name":"模版名称",
        "type":"跳转类型",
        "appid":"小程序appid",
        "pages":"小程序路径",
        "jump_url":"跳转链接",
        "template_id":"模版id",
        "模版id":{
            "模版参数key":"模版参数value",
            "模版参数key":"模版参数value",
            "模版参数key":"模版参数value"
        }
    },
    {
        
        "name":"模版名称",
        "type":"跳转类型",
        "appid":"小程序appid",
        "pages":"小程序路径",
        "jump_url":"跳转链接",
        "template_id":"模版id",
        "模版id":{
            "模版参数key":"模版参数value",
            "模版参数key":"模版参数value",
            "模版参数key":"模版参数value"
        }
    }
]

生成对应的 授权页链接

https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

若提示“该链接无法访问”,请检查参数是否填写错误,是否拥有scope参数对应的授权作用域权限。

参数是否必须说明
appid公众号的唯一标识
redirect_uri授权后重定向的回调链接地址, 请使用 urlEncode 对链接进行处理
response_type返回类型,请填写code
scope应用授权作用域,snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且, 即使在未关注的情况下,只要用户授权,也能获取其信息 )
state重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节
#wechat_redirect无论直接打开还是做页面302重定向时候,必须带此参数

官方网页 

https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html 

第二步:通过code换取网页授权access_token

首先请注意,这里通过code换取的是一个特殊的网页授权access_token,与基础支持中的access_token(该access_token用于调用其他接口)不同。公众号可通过下述接口来获取网页授权access_token。如果网页授权的作用域为snsapi_base,则本步骤中获取到网页授权access_token的同时,也获取到了openid,snsapi_base式的网页授权流程即到此为止。

尤其注意:由于公众号的secret和获取到的access_token安全级别都非常高,必须只保存在服务器,不允许传给客户端。后续刷新access_token、通过access_token获取用户信息等步骤,也必须从服务器发起。

获取code后,请求以下链接获取access_token: https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

参数说明

参数是否必须说明
appid公众号的唯一标识
secret公众号的appsecret
code填写第一步获取的code参数
grant_type填写为authorization_code

微擎代码

$id = $_GPC['uniacid'];
    $code = $_GPC['code'];
    $account_api = WeAccount::create($id);
    // 获取到用户 openid
    $OauthInfo = $account_api->getOauthInfo($code);

    $wechats_info = pdo_get("account_wechats",['uniacid'=>$id]);
    $appid = $wechats_info['key'];


    $openid = $OauthInfo['openid'];
    // 微信 jsapi_ticket
    $Ticket = $account_api->getJsApiTicket();
    // 生成时间戳
    $time = TIMESTAMP;
    // 随机字符串
    $noncestr = mt_rand(10000,99999);
    // 获取当前网页
    $thisUrl = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].'?'.$_SERVER['QUERY_STRING'];
    // 拼接签名
    $str = "jsapi_ticket={$Ticket}&noncestr={$noncestr}&timestamp={$time}&url={$thisUrl}";
    //  生成签名
    $signature=sha1($str);

    $info = pdo_get('template_msg',['uniacid'=>$id,'id'=>$_GPC['id']]);
   

    $template_info = json_decode($info['template'],true);
    // 获取所有已设置的模版
    // $templateList = getTemplateList($id);
    $templateId = '';

    foreach ($template_info as $key => $value){
        $templateId .=trim($value['template_id']).',';
    }

    // foreach ($templateList['data'] as $key => $value){
    //     $templateId .=$value['priTmplId'].',';
    // }

    $templateId = substr($templateId,0,strlen($templateId)-1);

    template('platform/template_home');




//获取私有模板列表
function getTemplateList($uniacid){
    $account_api = WeAccount::create($uniacid);
    $token = $account_api->getAccessToken();
    $url  = "https://api.weixin.qq.com/wxaapi/newtmpl/gettemplate?access_token={$token}";
    $response = ihttp_get($url);
    $data = json_decode($response['content'],true);
    return $data;
}

html 文件中 使用 开放标签 拉起授权页

第一步 引入js文件

在需要调用JS接口的页面引入如下JS文件:http://res.wx.qq.com/open/js/jweixin-1.6.0.js (支持https)

如需进一步提升服务稳定性,当上述资源不可访问时,可改访问:http://res2.wx.qq.com/open/js/jweixin-1.6.0.js (支持https)

备注:支持使用 AMD/CMD 标准模块加载方法加载


<script src="http://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>

第二步 配置对应参数

$(document).ready(function() {
		wx.config({
			debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
			appId: 'appid', // 必填,公众号的唯一标识
			timestamp: '{$time}', // 必填,生成签名的时间戳
			nonceStr: '{$noncestr}', // 必填,生成签名的随机串
			signature: '{$signature}',// 必填,签名
			jsApiList: ['addEventListener'], // 必填,需要使用的JS接口列表
			openTagList :['wx-open-subscribe'] // 必填 使用的 开放标签
		});
	})
	wx.ready(function () {
		// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中
		console.log('验证成功');

	});
	wx.error(function (res) {
		// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名
		console.log('验证失败');
	});

第三步 使用开放标签

{$templateId}  为获取到的 模版id  多个模版id用,隔开   开发标签中的按钮 只有在 手机端才显示 pc端不显示按钮

<wx-open-subscribe template="{$templateId}" id="subscribe-btn">
					<script type="text/wxtag-template" slot="style">
						<style>
							.subscribe-btn {
								border: none;
								padding: 10px;
								border-radius: 5px;
								color: #ff605e;
								background-color: #fff;
								font-size: 16px;
							}
						</style>
					</script>
					<script type="text/wxtag-template">
						<button class="subscribe-btn">
							这是按钮显示文字
						</button>
					</script>
				</wx-open-subscribe>

第四步 提交数据给后端接收

var btn = document.getElementById('subscribe-btn');
	//  加载成功
	btn.addEventListener('success', function (e) {
		console.log('success', e.detail);
		if(e.detail.errMsg == "subscribe:ok"){
			console.log('同意');
			console.log(e.detail.subscribeDetails);
			$.ajax({
				type : 'post',
				url : "url",
				async:false,
				data : {
					uniacid : "{$id}",
					openid : "{$openid}",
					template : e.detail.subscribeDetails,
				},
				dataType : 'json',
				success:function(datas){
					console.log(datas);
					if(datas.code == 1){
						alert(datas.msg);
						//   WeixinJSBridge.call('closeWindow');
					}else{
						alert(datas.msg);
					}

				}
			})
		}else{
			console.log('不同意');
		}
	});
	// 加载失败
	btn.addEventListener('error',function (e) {
		alert("加载失败");
		console.log('fail', e.detail);
	});

注意在 授权也中 用户订阅几次则可以发送几次消息

和一次性订阅消息不一样 无论用户 同意几次 永远只能发送一次 

  如果用户在已发送的消息中 拒绝接收此消息则当前用户 无论发送几次给当前用户都不会 发送成功

 如果用户在已发送的消息中 点击接收此消息 则用户在授权页点击一次授权按钮 无论取消还是允许 次数都会加一 在授权页面中 在外面允许的 模版消息不会在出现到 授权列表里

发送消息 

        

 $uniacid = $_GPC['uniacid'];
    if(empty($uniacid)){
        echo("uniacid 公众号id 不能为空");
        die;
    }
    if(empty($_GPC['id'])){
        echo("消息id 不能为空");
        die;
    }
    if(empty($_GPC['template_id'])){
        echo("模版id 不能为空");
        die;
    }
    $user = pdo_getall("template_log",['uniacid'=>$uniacid,'template_id'=>$_GPC['template_id'],'status'=>'accept','number >'=> 0]);
    $template_info = pdo_get("template_msg",['uniacid'=>$uniacid,'id'=>$_GPC['id']]);
    if($user){
        // 总人数
        $count = count($user);
        $i = 0;
        $send_data = [
            'sum' => $count,
            'msg_id' => $template_info['id'],
            'uniacid' => $uniacid,
            'start_time' => TIMESTAMP,
            'status' => 0
        ];
        $template = json_decode($template_info['template'],true);
        foreach ($template as $k => $v){
            if($_GPC['template_id'] == $v['template_id']){
                $send_data['title'] = $v['name'];
            }
        }
        pdo_insert('template_sendLog',$send_data);
        $sendedid = pdo_insertid();
        foreach ($user as $key => $value){

            $status = send_template_msg($uniacid,$template,$value);
            if($status === true){
                $i = $i + 1;
                pdo_update("template_log",['number' => $value['number'] - 1],['id'=>$value['id']]);
            }
        }
        $sended = [
            'status' => 1,
            'success' => $i,
            'end_time' => TIMESTAMP,
        ];
        pdo_update('template_sendLog',$sended,['id'=> $sendedid]);
        echo '发送完成';
    }else{
        echo "暂无符合条件用户";
    }


function send_template_msg($uniacid,$template,$user){
    $account_api = WeAccount::create($uniacid);
    $token = $account_api->getAccessToken();
    $url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/bizsend?access_token={$token}";

    $data['touser'] = $user['openid'];
    $data['template_id'] = $user['template_id'];
    foreach ($template as $key => $value){
        if($value['template_id'] == $user['template_id']){
            if($value['type'] == 1){
                $data['page'] = ($value['jump_url']);
            }elseif($value['type'] == 2){
                $data['miniprogram']['appid'] = $value['appid'];
                $data['miniprogram']['pagepath'] = $value['pages'];
            }
            foreach ($value[$value['template_id']] as $k => $v){
                $data['data'][$k]['value'] = $v;
            }
        }

    }

    $response = ihttp_post($url,json_encode($data));
    $result = json_decode($response['content'],true);


//    有一种情况是 已发送消息给 用户 用户在模版中 选择拒绝接收此类消息时 下次发送消息时 报错43101 因此设置此条消息可发送次数为0
//  当用户在已接收的模版中选择 接收此模版消息时则是永久接收 选择访问时则没有选择这个模版的选项 因此在add_log 方法中提交过来的数据 永久接收的消息数据为同意则当前模版可发送次数+1
    if($result['errcode'] == 43101){
        pdo_update('ims_template_log',['number' => 0],['id'=>$user['id']]);
    }
    if($result['errcode'] == 0){
        return true;
    }else{
        var_dump($result);
        return false;
    }


}

有问题请联系我

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fuchto

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值