关于如何在discuz! X2中生成验证码以及验证码的验证,我公司知码网为朋友们搜集了如下资料。
希望朋友们从中可以得到自己想要的关于如何生成验证码的方法以及代码
一、验证码的产生
1、如何在模板中添加一个验证码
在X2中验证码的模板部分独立为一个模板文件(template/default/common/seccheck.htm),供各个地方调用。
在模板中可以添加如下代码来调用验证码模板部分:
1. <!--{eval $seccodecheck = 1;}-->
2. <!--{eval $sectpl ='<tr><th><sec></th><td><sec><pclass="d"><sec></p></td>';}-->
3. <!--{subtemplatecommon/seccheck}-->
复制代码
解释下这三句话:
第一句的意思为,我要开启验证码,即 $seccodecheck
变量
必须为真,就表示当前页面要开启验证码。
第二句的意思为,给要显示出来的验证码设置一个显示的模板格式,$sectpl 这个变量对应的就是模板,设置 $sectpl 可以让验证码的显示与当前页面的格式更好的结合。从示例的模板代码中可以看出,只有 <sec> 不属于 HMTL 标准代码,而且出现了 3 次,这 3 次分别代表:“验证码”文字、验证码输入框、验证码图片,如下图所示:
这样就可以把验证码不同的部分合理的安放在您的页面中了。
第三句的意思为,将独立的验证码模板合并到当前页面中,与当前页面的模板一同输出。
在模板中添加上如上的代码后,刷新页面就可以看到验证码部分了。
2、验证码的生成流程
(以X2默认设置的“英文图片验证码”为例)
1)刚出现的验证码会默认执行一段 JS 代码
1. <scripttype="text/javascript"reload="1">updateseccode('SQq29j20');</script>
复制代码
执行的 JS 主要就是执行了 updateseccode 这个函数,直接点击验证码图片执行的也是这个函数。函数中的 'SQq29j20' 是当前页面验证码的唯一字符串 idhash,他是由是否为Ajax请求、session id、自增数字组成,此处不必深究其含义。
2)updateseccode 函数在static/js/common.js 中
1. function updateseccode(idhash, play) {
2. $F('_updateseccode', arguments);
3. }
复制代码
通过上面代码可以看到,updateseccode 又调用了 _updateseccode 私有函数,_updateseccode 函数在 static/js/common_extra.js 文件中
1. function _updateseccode(idhash, play) {
2. if(isUndefined(play)) {
3. if($('seccode_' + idhash)) {
4. $('seccodeverify_' + idhash).value = '';
5. if(secST['code_' + idhash]) {
6. clearTimeout(secST['code_' + idhash]);
7. }
8. $('checkseccodeverify_' + idhash).innerHTML = '<img src="'+IMGDIR + '/none.gif" width="16" height="16"class="vm" />';
9. ajaxget('misc.php?mod=seccode&action=update&idhash=' + idhash,'seccode_' + idhash, null, '', '', function() {
10. secST['code_' + idhash] = setTimeout(function() {$('seccode_'+ idhash).innerHTML = '<span class="xi2 cur1"οnclick="updateseccode(''+idhash+'')">刷新验证码</span>';}, 180000);
11. });
12. }
13. } else {
14. eval('window.document.seccodeplayer_' + idhash +'.SetVariable("isPlay", "1")');
15. }
16. }
复制代码
这段 JS 代码有两个含义:
一是通过 ajaxget 请求了 misc.php?mod=seccode&action=update&idhash=xxxx 这样一个地址
二是设定了一个
定时器
,从显示了验证码开始,3分钟后自动将验证码图片换为“刷新验证码”的文字,点击该文字就执行 updateseccode 这个函数,重新更新验证码。由此可以看出,此种方式可以很好的解决验证码过期的问题。
3)找到通过 ajaxget 请求的程序 source/module/misc/misc_seccode.php
通过 url 中的 action=update 可以看出,应该查看if($_G['gp_action'] == 'update') { …… } 中的一段
1. if($_G['gp_action'] == 'update') {
2. $message = '';
3. if($_G['setting']['seccodestatus']) {
4. $rand = random(5, 1);
5. $flashcode = '';
6. $idhash = isset($_G['gp_idhash']) ? $_G['gp_idhash']: '';
7. $ani =$_G['setting']['seccodedata']['animator'] ? '_ani' : '';
8. if($_G['setting']['seccodedata']['type'] == 2){
9. ……
10. }elseif($_G['setting']['seccodedata']['type'] == 3) {
11. …...
12. } else {
13. $message = lang('core','seccode_image'.$ani.'_tips').'<imgοnclick="updateseccode(''.$idhash.'')"width="'.$_G['setting']['seccodedata']['width'].'"height="'.$_G['setting']['seccodedata']['height'].'"src="misc.php?mod=seccode&update='.$rand.'&idhash='.$idhash.'"class="vm" alt="" />';
14. }
15. }
16. includetemplate('common/header_ajax');
17. echo lang('message', $message,array('flashcode' => $flashcode, 'idhash' => $idhash));
18. includetemplate('common/footer_ajax');
19. }
复制代码
默认设置的“英文图片验证码”的 $_G['setting']['seccodedata']['type'] 为 0,所以看 else 的部分。仔细看这里就是按照 ajax 的格式返回了一个验证码的图片,但是图片的 src 为 misc.php?mod=seccode&update=$rand&idhash=$idhash 这样一个动态链接,所以是通过这个链接动态生成的图片,此时又产生了一个新的请求。
4)找到通过图片链接请求的程序 source/module/misc/misc_seccode.php(和上面是同一个文件)
通过 url 可以看出,应该查看 if($_G['gp_action'] == 'update') { …… } else { …… } 中的一段
1. } else {
2.
3. $refererhost = parse_url($_SERVER['HTTP_REFERER']);
4. $refererhost['host'].= !empty($refererhost['port']) ? (':'.$refererhost['port']) : '';
5.
6. if($_G['setting']['seccodedata']['type'] < 2 &&($refererhost['host'] != $_SERVER['HTTP_HOST'] ||!$_G['setting']['seccodestatus']) || $_G['setting']['seccodedata']['type'] == 2&& !extension_loaded('ming') && $_POST['fromFlash'] != 1 ||$_G['setting']['seccodedata']['type'] == 3 && $_GET['fromFlash'] != 1){
7. exit('Access Denied');
8. }
9.
10. $seccode =make_seccode($_G['gp_idhash']);
11.
12. if(!$_G['setting']['nocacheheaders']) {
13. @header("Expires: -1");
14. @header("Cache-Control: no-store, private, post-check=0, pre-check=0,max-age=0", FALSE);
15. @header("Pragma: no-cache");
16. }
17.
18. require_oncelibfile('class/seccode');
19.
20. $code = new seccode();
21. $code->code = $seccode;
22. $code->type =$_G['setting']['seccodedata']['type'];
23. $code->width =$_G['setting']['seccodedata']['width'];
24. $code->height =$_G['setting']['seccodedata']['height'];
25. $code->background =$_G['setting']['seccodedata']['background'];
26. $code->adulterate =$_G['setting']['seccodedata']['adulterate'];
27. $code->ttf =$_G['setting']['seccodedata']['ttf'];
28. $code->angle =$_G['setting']['seccodedata']['angle'];
29. $code->warping =$_G['setting']['seccodedata']['warping'];
30. $code->scatter =$_G['setting']['seccodedata']['scatter'];
31. $code->color =$_G['setting']['seccodedata']['color'];
32. $code->size =$_G['setting']['seccodedata']['size'];
33. $code->shadow =$_G['setting']['seccodedata']['shadow'];
34. $code->animator =$_G['setting']['seccodedata']['animator'];
35. $code->fontpath =DISCUZ_ROOT.'./static/image/seccode/font/';
36. $code->datapath =DISCUZ_ROOT.'./static/image/seccode/';
37. $code->includepath =DISCUZ_ROOT.'./source/class/';
38.
39. $code->display();
40. }
复制代码
这部分开始是先做了一些安全性的验证,最后是根据给定的参数和由 make_seccode 生成的验证码字符串,生成验证码的图片,所以中间是重点。
make_seccode($_G['gp_idhash']) 这个函数传入了当前页面验证码的唯一字符串 idhash,生成了用于验证码的字符串。
5)make_seccode 函数在source/function/function_seccode.php 文件
1. function make_seccode($idhash){
2. global $_G;
3. $seccode = random(6, 1);
4. $seccodeunits = '';
5. if($_G['setting']['seccodedata']['type'] == 1) {
6. $lang = lang('seccode');
7. $len = strtoupper(CHARSET) == 'GBK' ? 2 : 3;
8. $code = array(substr($seccode, 0, 3),substr($seccode, 3, 3));
9. $seccode = '';
10. for($i =0; $i < 2; $i++) {
11. $seccode .= substr($lang['chn'], $code[$i] *$len, $len);
12. }
13. }elseif($_G['setting']['seccodedata']['type'] == 3) {
14. $s =sprintf('%04s', base_convert($seccode, 10, 20));
15. $seccodeunits = 'CEFHKLMNOPQRSTUVWXYZ';
16. } else {
17. $s =sprintf('%04s', base_convert($seccode, 10, 24));
18. $seccodeunits = 'BCEFGHJKMPQRTVWXY2346789';
19. }
20. if($seccodeunits) {
21. $seccode= '';
22. for($i =0; $i < 4; $i++) {
23. $unit = ord($s{$i});
24. $seccode .= ($unit >= 0x30 && $unit<= 0x39) ? $seccodeunits[$unit - 0x30] : $seccodeunits[$unit - 0x57];
25. }
26. }
27. dsetcookie('seccode'.$idhash,authcode(strtoupper($seccode)."t".(TIMESTAMP -180)."t".$idhash."t".FORMHASH, 'ENCODE',$_G['config']['security']['authkey']), 0, 1, true);
28. return $seccode;
29. }
复制代码
从函数中可以看到,验证码 $seccode 首先来自一个6位的随机数字 random(6, 1) (此函数如何工作,最后讲解)。
默认设置的“英文图片验证码”的 $_G['setting']['seccodedata']['type'] 为 0,所以看 else 的部分。将 $seccode 的数字通过 base_convert 函数由 10
进制
转为 24 进制,然后设定可以在验证码出现的字符串
'BCEFGHJKMPQRTVWXY2346789'。
最后将 24 进制的验证码在 $seccodeunits 中取得真正的 4 位验证码字符串 $seccode ,最后将 $seccode 通过 authcode 加密函数进行加密,写入 cookie 中,并返回,cookie 的名字是 seccode 连上 $idhash 的值(例如:seccodeSQq29j20)。加密时使用的是在 config/config_global.php 中设置的$_G['config']['security']['authkey'] 的值。
至此验证码及图片生成完毕,生成的验证码到目前为止只以加密的方式存在于 cookie 中。
整个的生产方式较为简单,如果内行朋友可以根据我们给大家的提醒一步步的操作即可;
Discuz! X2生产验证码的方式我们已经为大家介绍完了,之后我们还会有关于验证的一篇文章。
知码网,专业答题、验证码识别及实名制投票服务机构!