├── .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 | <?php echo WEB_TITLE; ?> 8 | 9 | 15 | 16 | 17 | 18 |
19 |
20 | 大会介绍 21 | 22 |

23 |

更多大会相关资讯, 敬请关注官方后续消息推送。

24 |
25 |
26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /conf/config.php: -------------------------------------------------------------------------------- 1 | 39 | -------------------------------------------------------------------------------- /my.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | <?php echo WEB_TITLE; ?> 14 | 15 | 21 | 22 | 23 | 24 | 27 |
28 |
29 | 我的入场券
30 | 31 |

32 |

33 | 注意事项:
34 | 1.入场券是大会入场的唯一凭证,请妥善保管,切勿转发!
35 | 2.为了保证您顺利签到入场,建议提前下载保存入场券(长按图片,在弹出的对话框选择保存)! 36 |

37 |
38 |
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 | <?php echo WEB_TITLE; ?> 14 | 20 | 21 | 22 | 23 | 24 | window.location="'.$url.'"'; 31 | } 32 | ?> 33 |
34 | 现场签到 35 | 40 |

41 |

42 | 确认签到 43 | 继续扫码 44 |

45 |
46 | 53 | 54 | 104 | 105 | 106 | --------------------------------------------------------------------------------