刚刚接触Typecho,发现Joe主题不错,摸索了两天之后,发现Joe本身不支持评论验证码,就查阅资料,修改部分Joe主题文件,增加评论验证码功能。
当前版本
- Typecho:1.2.0
- Joe主题:7.3.6
目标
- 非插件方式,简单实现原生支持验证码,过滤机器人灌水。
涉及文件
/Joe/core/function.php (必须)
- 目的: 增加需要用到的函数
- 增加如下3个函数
#生成验证码
function comment_protection_code(){
$num1=rand(1,9);
$num2=rand(1,9);
$rand=rand(1,100)%3;
switch($rand){
case 0:
$ret=$num1 + $num2;
$symbol='+';
break;
case 1:
$ret=$num1 - $num2;
$symbol='-';
break;
case 2:
$ret=$num1 * $num2;
$symbol='×';
break;
}
@session_start();
$_SESSION['verify']=$ret;
$_SESSION['verify_md5']=md5($num1.$num2);
@session_write_close();
echo "<input type=\"text\" autocomplete=\"off\" name=\"sum\" placeholder=\"$num1 $symbol $num2 = ?\" />";
echo "<input type=\"hidden\" name=\"num1\" value=\"$num1\">\n";
echo "<input type=\"hidden\" name=\"num2\" value=\"$num2\">";
}
#验证
function comment_protection_do(){
/* 已登录,不检测验证码 */
Typecho_Widget::widget('Widget_User')->to($current_user);
if($current_user->hasLogin()){
return 0;
}
@session_start();
$case1=md5($_SESSION['verify']) != md5($_POST['sum']);
$case2=$_SESSION['verify_md5'] != md5($_POST['num1'].$_POST['num2']);
$debug=$_SESSION['verify'].$_SESSION['verify_md5'].$case1. $case2;
@session_write_close();
if($case1 || $case2){
throw new Typecho_Widget_Exception(_t('验证码错误,建议先复制评论,然后刷新重试!','评论失败'), 200);
}
return 0;
}
#判断路由用到
function endsWith($haystack, $needle){
return $needle === '' || substr_compare($haystack, $needle, -strlen($needle)) === 0;
}
/Joe/core/core.php (必须)
- 目的: 挂载验证函数
- 搜索函数
themeInit
,将如下代码粘贴到函数内
#仅在提交评论时生效
if(endsWith($self->request->getPathInfo(), '/comment')){
$comment = comment_protection_do();
}
/Joe/public/comment.php (必须)
- 目的: 增加验证码输入框
- 搜索
输入网址
,在它的下方增加一个兄弟节点,用来输入验证码
...
<div class="list">
<input type="text" autocomplete="off" name="url" placeholder="请输入网址(非必填)..." />
</div>
#上方为原始代码
#下方为新增
<!-- @苏苏修改 增加验证码输入框-->
<div class="list">
<?php comment_protection_code();?>
</div>
/Joe/assets/js/joe.global.js (必须)
- 目的: 在提交评论时,增加验证码校验参数
- 打开未压缩版js文件,搜索
激活评论提交
,用下方代码替换,然后压缩后替换同文件夹的joe.global.min.js
/* 激活评论提交 已修改 */
{
if ($('.joe_comment').length) {
let isSubmit = false;
$('.joe_comment__respond-form').on('submit', function (e) {
e.preventDefault();
const action = $('.joe_comment__respond-form').attr('action') + '?time=' + +new Date();
const type = $('.joe_comment__respond-form').attr('data-type');
const parent = $('.joe_comment__respond-form').attr('data-coid');
const author = $(".joe_comment__respond-form .head input[name='author']").val();
const _ = $(".joe_comment__respond-form input[name='_']").val();
const mail = $(".joe_comment__respond-form .head input[name='mail']").val();
const url = $(".joe_comment__respond-form .head input[name='url']").val();
const sum = $(".joe_comment__respond-form .head input[name='sum']").val();
const num1 = $(".joe_comment__respond-form .head input[name='num1']").val();
const num2 = $(".joe_comment__respond-form .head input[name='num2']").val();
let text = $(".joe_comment__respond-form .body textarea[name='text']").val();
if (sum === '') return Qmsg.info('请输入验证信息!');
if (author.trim() === '') return Qmsg.info('请输入昵称!');
if (!/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(mail)) return Qmsg.info('请输入正确的邮箱!');
if (type === 'text' && text.trim() === '') return Qmsg.info('请输入评论内容!');
if (type === 'draw') {
const txt = $('#joe_comment_draw')[0].toDataURL('image/webp', 0.1);
text = '{!{' + txt + '}!} ';
}
if (isSubmit) return;
isSubmit = true;
$('.joe_comment__respond-form .foot .submit button').html('发送中...');
$.ajax({
url: action,
type: 'POST',
data: { author, mail, text, parent, url, num1, num2, sum, _ },
dataType: 'text',
success(res) {
let arr = [],
str = '';
arr = $(res).contents();
Array.from(arr).forEach(_ => {
if (_.parentNode.className === 'container') str = _;
});
if (!/Joe/.test(res)) {
Qmsg.warning(str.textContent.trim() || '');
isSubmit = false;
$('.joe_comment__respond-form .foot .submit button').html('发表评论');
} else {
window.location.reload();
}
},
error(res) {
isSubmit = false;
$('.joe_comment__respond-form .foot .submit button').html('发表评论');
Qmsg.warning('发送失败!请刷新重试!');
}
});
});
}
}
自定义css(可选)
- 目的: 在输入框左侧增加竖形分割线,统一外观
- 添加方式:Joe主题设置->全局设置->自定义CSS,粘贴下面的代码
/*验证码处css*/
@media (min-width: 768px){.joe_comment__respond-form .head .list:nth-child(4){position:relative}.joe_comment__respond-form .head .list:nth-child(4)::before{content:'';position:absolute;top:50%;transform:translateY(-50%);width:1px;height:15px;background:var(--classA)}.joe_comment__respond-form .head .list:nth-child(4)::before{left:0}}
最终效果
{/tabs-pane}
{tabs-pane label="未输入验证码提示"}
]
{/tabs-pane}
{tabs-pane label="验证码错误提示"}
{/tabs-pane}
原来是我在function中发错位置了,已经按照文章的指引,顺利添加成功,感谢!
另外,就是这段CSS放在后台,我的主题评论会显示空白,我就放进了joe.normalize.min.css中,就正常了。
这计算还有负值啊,建议这个修复一下。
$rand=rand(1,100)%3改成%2,case 1代码段删掉,case 2改成case 1即可
这个策略是删除了减法吗?有没有办法来个判断,num1>num2 则可以使用减法?
乱提了,可能比较麻烦
那不就脱了裤子放屁了
你好,按照你上面的代码,我的老是报错,我也是joe主题,comment文件的代码是这个:
https://pic.fuuuy.cn/i/2022/09/18/63267cc7ab784.jpg
应该怎么改呢
报错提示什么?
遇到问题了 我上午测试评论时是登陆状态 评论没问题
下午我测试了访客评论 即便输入正确验证码也会提示验证码错误 关键是控制台也没看到报错
我写一篇转载可以吗
可以转载,注明来源即可
OK
问题解决了 是我自己笨蛋了 哈哈 多谢教程
不客气,解决就好
多谢你写的教程
请问你用什么压缩的 我这压缩完报错 提示 Invalid or unexpected token
已发送邮件,我用的VS Codse 的JS & CSS Minifier (Minify)插件
7.3.7 版本验证码没生效
不显示输入框,还是验证码无论是否输入正确都提示验证码错误,或者验证码输入错误仍然可以正常发表评论?