├── .gitignore
├── images
└── intro.png
├── signAfter.php
├── signPre.php
├── README.md
├── intro.php
├── conf
└── config.php
├── my.php
├── css
└── global.css
├── js
└── global.js
└── sign.php
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | demo.zip
3 |
4 | my_bak.php
5 |
--------------------------------------------------------------------------------
/images/intro.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bihe0832/QrcodeSign/HEAD/images/intro.png
--------------------------------------------------------------------------------
/signAfter.php:
--------------------------------------------------------------------------------
1 | window.location="'.$url.'"';
11 | ?>
12 |
--------------------------------------------------------------------------------
/signPre.php:
--------------------------------------------------------------------------------
1 | window.location="'.$url.'"';
13 | }else{
14 | setcookie("wechat", "", time()-3600);
15 | $url = REDICT_URL;
16 | //echo $url;
17 | echo '';
18 | }
19 | ?>
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | qrcodeSign
2 | ==========
3 |
4 | 基于微信公共账号的二维码签到工具
5 |
6 | ### 原理:
7 |
8 | 签到页面先去检测本地的cookie,如果本地cookie和通过授权页面设置的不一致,视为未授权设备,直接跳转到指定的页面;如果一致,拉取用户的报名信息。
9 |
10 | ### 关键点:
11 |
12 | 1. 微信内置的webview支持cookie和页面之间的JS跳转
13 | 2. 微信扫一扫支持直接跳转到扫描结果
14 |
15 | ### 风险点:
16 |
17 | 1. 生成二维码的接口都是调用第三方,不是自己控制,可能会挂掉
18 | 2. 生成的二维码一般第三方都会有图片保存,不够安全
19 |
20 | ### 缺点:
21 |
22 | 1. 使用微信扫一扫要先登陆微信,如果设备较多,需要足够的微信账号
23 |
24 | ### 后续优化:
25 |
26 | 1. 目前接口直接用了openID,没有做进一步验证,可以增加一个签名,例如openID和appid字典序MD5增加在入场券的二维码中,获取签到信息的时候后台验证一下
27 | 2. 出现签到失败可以给后台发送一条告警,及时发现和定位异常
28 | 3. 自己写一个js二维码
29 |
30 | ### demo 使用:[点击查看]( https://blog.bihe0832.com/wechar_sign_with_qrcode.html)
31 |
32 | ### 代码结构:
33 |
34 | — conf:二维码签到demo中所有的核心配置,更改配置以后即可为你所用。
35 | — css:页面css
36 | — images:资源图片
37 | — js:页面js
38 | — intro.php:会议介绍页面,未授权设备扫码后跳转页面
39 | — my_bak.php: 使用公司内部生成二维码接口生成二维码入场券页面
40 | — my.php: 使用外部第三方生成二维码接口生成二维码入场券页面
41 | — sign.php: 授权后设备扫描入场券以后跳转页面
42 | — signPre.php: 设备授权
43 | — signAfter.php: 设备取消授权
44 |
--------------------------------------------------------------------------------
/intro.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
15 |
16 |
17 |
18 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/conf/config.php:
--------------------------------------------------------------------------------
1 |
39 |
--------------------------------------------------------------------------------
/my.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
12 |
13 |
14 |
15 |
21 |
22 |
23 |
24 |
27 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/css/global.css:
--------------------------------------------------------------------------------
1 | /*全局样式*/
2 | body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,p,blockquote,th,td{margin:0;padding:0;list-style:none;}
3 | fieldset,img{border:0;}
4 | address,caption,cite,code,dfn,em,th,var{font-style:normal;font-weight:normal;}
5 | body {
6 | font-family: "Microsoft Yahei";
7 | font-size: 16px;
8 | margin: 10px;
9 | background:#070F1D;
10 | background-repeat: no-repeat;
11 | background-position:center;
12 | background-attachment:fixed;
13 | }
14 | .vote{
15 | margin:0 auto;
16 | width:280px;
17 | font-size: 16px;
18 | line-height: 50px;
19 | color: #fff;
20 | padding:20px;
21 | text-align:center;
22 | }
23 | #title{
24 | text-align:center;
25 | font-weight: bold;
26 | }
27 | .vote p{
28 | margin-top:20px;
29 | margin-bottom:20px;
30 | text-align:center;
31 | font-weight: bold;
32 | }
33 | #tips{
34 | margin-top:10px;
35 | margin-bottom:20px;
36 | text-align:left;
37 | line-height: 20px;
38 | font-size: 12px;
39 | font-weight:normal;
40 |
41 | }
42 | #info_up{
43 | margin-top:-30px;
44 | margin-bottom:20px;
45 | text-align:left;
46 | line-height: 25px;
47 | font-size: 14px;
48 | font-weight:normal;
49 | }
50 | #info_down{
51 | margin-top:10px;
52 | text-align:left;
53 | line-height: 25px;
54 | font-size: 14px;
55 | font-weight:normal;
56 | }
57 | .vote_list{
58 | text-align:left;
59 | width:170px;
60 | height:25px;
61 | font-family: "Microsoft Yahei";
62 | font-weight: bold;
63 | }
64 | li{
65 | padding-left: 3px;
66 | border-top: solid 2px #fff;
67 | font-weight: bold;
68 | text-align:left;
69 | }
70 | li.last{
71 | border-bottom: solid 2px #fff;
72 | }
73 |
74 |
75 | .show{
76 | position:absolute;
77 | background-color: #fff;
78 | border-color: #888;
79 | border: 1px solid transparent;
80 | border-radius: 4px 4px 4px 4px;
81 | width:250px;
82 | height:140px;
83 | }
84 |
85 | .tipsTitle{
86 | font-size: 12px;
87 | color: #333;
88 | line-height: 1.42857;
89 | margin-top: 10px;
90 | margin-left: 7px;
91 | text-align: center;
92 | }
93 | .tipsHr{
94 | height:1px;
95 | border:0;
96 | border-bottom:2px solid #eee;
97 | noshade:noshade;
98 | }
99 | .tipsContent{
100 | font-family: "Microsoft Yahei";
101 | font-size: 14px;
102 | color: #333;
103 | line-height: 1.5;
104 | padding: 5px;
105 | margin-top: 5px;
106 | margin-left: 15px;
107 | margin-right: 15px;
108 | text-align: left;
109 | font-weight: bold;
110 | }
111 |
112 | .tipsBtn{
113 | font-size: 12px;
114 | color: #333;
115 | text-align: center;
116 | line-height: 1.7;
117 | }
118 |
119 |
120 | .butt{
121 | background-color: #ddd;
122 | border-color: #888;
123 | color: #333;
124 | -moz-user-select: none;
125 | border: 1px solid transparent;
126 | border-radius: 4px 4px 4px 4px;
127 | cursor: pointer;
128 | display: inline-block;
129 | font-size: 16px;
130 | font-weight: normal;
131 | line-height: 1.42857;
132 | margin-bottom: 0;
133 | padding: 6px 12px;
134 | text-align: center;
135 | vertical-align: middle;
136 | white-space: nowrap;
137 | text-decoration: none;
138 | }
139 | /*全局样式结束*/
--------------------------------------------------------------------------------
/js/global.js:
--------------------------------------------------------------------------------
1 | var Meeting = {
2 | //参加会议的用户的ID
3 | attenderID:"",
4 | //参加会议的用户类型
5 | attenderTypeList:{"0":"参会人员","1":"参会嘉宾","2":"参会媒体","3":"参会类型3"},
6 | };
7 |
8 | function signInit(result){
9 | //初始化用户信息
10 | if(result.ecode == -1){
11 | //尚未报名
12 | document.getElementById( "name" ).innerHTML="" ;
13 | document.getElementById( "status" ).innerHTML="尚未报名" ;
14 | document.getElementById( "userSign" ).innerHTML="尚未报名" ;
15 | document.getElementById( "userSign" ).onclick= function(){
16 | showTips( "没有报名" );
17 | };
18 | }else if (result.ecode > -1){
19 | document.getElementById( "name" ).innerHTML=result.msg.name;
20 | if (result.msg.status == 3){
21 | document.getElementById( "status" ).innerHTML="已签到" ;
22 | document.getElementById( "is_special" ).innerHTML = Meeting.attenderTypeList[result.msg.is_special];
23 | document.getElementById( "userSign" ).innerHTML="已经签到" ;
24 | document.getElementById( "userSign" ).onclick= function(){
25 | showTips( "已经签到" );
26 | };
27 | }else if(result.msg.status == 2){
28 | document.getElementById( "status" ).innerHTML="尚未签到" ;
29 | document.getElementById( "is_special").innerHTML = Meeting.attenderTypeList[result.msg.is_special];
30 | document.getElementById( "userSign" ).onclick= function(){
31 | /************************************效果展示代码开始****************************************/
32 | eval('var result = {"ecode":1,"msg":"success"}');
33 | signFinished(result);
34 | return;
35 | /************************************效果展示代码结束****************************************/
36 | var JSONP=document.createElement( "script");
37 | JSONP.type= "text/javascript" ;
38 | JSONP.src= "http://wekf.qq.com/wechat2/app/roadshow/cgi/roadshow.cgi.php?cmd=101003&id="+Meeting.attenderID+"&callback=signFinished" ;
39 | document.getElementsByTagName( "head" )[0].appendChild(JSONP);
40 | };
41 | }else{
42 | document.getElementById( "status" ).innerHTML="资料审核不通过";
43 | document.getElementById( "userSign" ).innerHTML="审核不通过" ;
44 | document.getElementById( "userSign" ).onclick= function(){
45 | showTips( "资料审核不通过" );
46 | };
47 | }
48 | } else {
49 | showInfo(result.ecode);
50 | }
51 | }
52 | function signFinished(result){
53 | if(result.ecode ==1){
54 | showTips("签到成功");
55 | document.getElementById("status").innerHTML="已签到";
56 | document.getElementById( "userSign" ).innerHTML="已经签到" ;
57 | document.getElementById( "userSign" ).onclick= function(){
58 | showTips( "已经签到" );
59 | };
60 | }else{
61 | showTips("签到失败,请重试");
62 | WeixinJSBridge.invoke("scanQRCode");
63 | }
64 | }
65 |
66 | function showInfo(id) {
67 | var info = {
68 | '-10000':'服务器错误,请重试!'
69 | };
70 | if(info[id]){
71 | showTips(info[id]);
72 | }else{
73 | showTips(info[-10000] + id);
74 | }
75 | }
76 |
77 | function hideTips (){
78 | document.getElementById("show").style.display="none";
79 | }
80 |
81 | function showTips (tips){
82 | document.getElementById("tipsContent").innerHTML=tips;
83 | var x = (document.body.clientWidth - 250) /2 ;
84 | document.getElementById("show").style.left = x+"px";
85 | var a = tips.length;
86 | if(a > 15){
87 | document.getElementById("show").style.height = "145px";
88 | var y = (document.body.clientHeight - 140) / 2;
89 | }else{
90 | document.getElementById("show").style.height = "125px";
91 | var y = (document.body.clientHeight - 120) / 2;
92 | }
93 | document.getElementById("show").style.top = y+"px";
94 | document.getElementById("show").style.display="";
95 | }
96 |
--------------------------------------------------------------------------------
/sign.php:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
20 |
21 |
22 |
23 |
24 | window.location="'.$url.'"';
31 | }
32 | ?>
33 |
34 |
现场签到
35 |
36 | - 来宾姓名:
37 | - 报名状态:
38 | - 参会类别:
39 |
40 |
41 |
42 | 确认签到
43 | 继续扫码
44 |
45 |
46 |
47 |
腾讯游戏投资公司沙龙
48 |
49 |
您已经签到成功!
50 |
51 |
确定
52 |
53 |
54 |
104 |
105 |
106 |
--------------------------------------------------------------------------------