我经营一个 PTC 网站,为人们宣传网站。而且我需要一个易于降低或完全阻止机器人使用的方法。
广告计数器完成倒计时后,我想加载验证码。
但我不想要你必须输入任何东西的验证码。只需单击鼠标。
如果验证码可以在 javascript 中完成,那就太好了。
我正在寻找类似这样的东西:
计数器:0 选择匹配数:7 [1] [0] [7] [2]
用户必须单击与该数字匹配的框中的数字。
数字将在 1-9 之间。
我制作了一个验证码脚本。它的大小、字符数和可供选择的字符都是可定制的。
这里是captcha.php
:
<?php
function generateCaptcha($num_digits, $challenge_num, $size, $chars, $incode = false) {
if(session_id() == '') session_start();
if(isset($_SESSION['captcha'])) unset($_SESSION['captcha']);
// You *must* type your own random salt here, *DO NOT* use this one.
$salt = 'H#(*h3^rh@(*E%h$W*WK#vMIv)%(D*(A&*W@A^D6@r4*I%u8tgsc#yejdi$d8dee';
$message = '';
if(isset($_POST['hash']) && isset($_POST['code'])) {
if(!empty($_POST['hash']) && !empty($_POST['code']) && !empty($_POST['correct_index'])) {
if(md5($_POST['hash'] . $_POST['code'] . $salt) == $_POST['correct_index']) {
$message = '<p>Correct!</p>';
} else {
$message = 'Incorrect code. Please try again.';
}
}
}
$code = '';
if($incode == false) {
for($i = 0; $i < $num_digits; $i++) {
$digit = substr($chars, floor(mt_rand(0, strlen($chars) - 1)), 1);
while(strpos($code, "$digit") !== false) {
$digit = substr($chars, floor(mt_rand(0, strlen($chars) - 1)), 1);
}
$code .= $digit;
}
} else {
for($i = 0; $i < $num_digits; $i++) {
$digit = substr($incode, floor(mt_rand(0, strlen($incode) - 1)), 1);
while(strpos($code, "$digit") !== false) {
$digit = substr($incode, floor(mt_rand(0, strlen($incode) - 1)), 1);
}
$code .= $digit;
}
}
$parts = str_split($code);
$width = $num_digits * $size;
$height = $size * 2;
$image = imagecreatetruecolor($width, $height);
$background = imagecolorallocate($image, floor(mt_rand(96, 255)), floor(mt_rand(96, 255)), floor(mt_rand(96, 255)));
imagefilledrectangle($image, 0, 0, $width, $height, $background);
$num_spots = floor(mt_rand($size * 2, $size * 15));
for($i = 0; $i < $num_spots; $i++) {
$color = imagecolorallocate($image, floor(mt_rand(30, 255)), floor(mt_rand(30, 255)), floor(mt_rand(30, 255)));
$x = floor(mt_rand(0, $width));
$y = floor(mt_rand(0, $height));
$ellipse_width = floor(mt_rand(0, $size / 2));
$ellipse_height = floor(mt_rand(0, $size / 2));
imagefilledellipse($image, $x, $y, $ellipse_width, $ellipse_height, $color);
$x1 = floor(mt_rand(0, $width));
$y1 = floor(mt_rand(0, $height));
$x2 = floor(mt_rand(0, $width));
$y2 = floor(mt_rand(0, $height));
imageline($image, $x1, $y1, $x2, $y2, $color);
}
$num_dots = floor(mt_rand($size * 50, $size * 80));
for($i = 0; $i < $num_dots; $i++) {
$color = imagecolorallocate($image, floor(mt_rand(30, 255)), floor(mt_rand(30, 255)), floor(mt_rand(30, 255)));
$x = floor(mt_rand(0, $width));
$y = floor(mt_rand(0, $height));
imagesetpixel($image, $x, $y, $color);
}
for($i = 0; $i < count($parts); $i++) {
$color = imagecolorallocate($image, floor(mt_rand(0, 150)), floor(mt_rand(0, 150)), floor(mt_rand(0, 150)));
$x = floor(mt_rand($size * 0.9, $size * 1.1));
$y = floor(mt_rand($size, $size * 2));
imagettftext($image, $size, floor(mt_rand(-10, 10)), $i * $x, $y, $color, 'Justus-Bold.ttf', $parts[$i]);
imagettftext($image, $size, floor(mt_rand(-10, 10)), $i * $x + floor(mt_rand(1, 7)), $y, $color, 'Justus-Bold.ttf', $parts[$i]);
imagettftext($image, $size, floor(mt_rand(-10, 10)), $i * $x + floor(mt_rand(1, 7)), $y, $color, 'Justus-Bold.ttf', $parts[$i]);
imagettftext($image, $size, floor(mt_rand(-10, 10)), $i * $x + floor(mt_rand(1, 7)), $y, $color, 'Justus-Bold.ttf', $parts[$i]);
}
$white = imagecolorallocate($image, 255, 255, 255);
$filename = md5(time() . $_SERVER['REMOTE_ADDR'] . mt_rand(0, 1000)) . '.png';
imagepng($image, $filename);
imagedestroy($image);
$file = file_get_contents($filename);
$imgsize = getimagesize($filename);
unlink($filename);
$captcha = 'data:' . $imgsize['mime'] . ';base64,' . base64_encode($file);
$challenge = array('captcha' => '', 'code' => null, 'size' => 0, 'digits' => 0);
if($incode == false) {
$challenge = generateCaptcha($challenge_num, 0, $size, $chars, $code);
}
$hash = md5($challenge['code'] . $salt);
$correct_index = array();
for($i = 0; $i < strlen($challenge['code']); $i++) {
$correct_index[] = strpos($code, substr($challenge['code'], $i, 1));
}
$result = array(
'captcha' => $captcha,
'challenge' => array($challenge['captcha'], $challenge['size'], $challenge['digits']),
'size' => array($imgsize[0], $imgsize[1]),
'hash' => $hash,
'code' => $code,
'message' => $message,
'width' => $size,
'digits' => $num_digits,
'correct_index' => md5($hash . implode('', $correct_index) . $salt)
);
return $result;
}
?>
...这里是captcha.html
:
<!DOCTYPE HTML>
<!--
<?php
include 'captcha.php';
$captcha = generateCaptcha(4, 2, 100, '0123456789');
?>
-->
<html lang="en-US">
<head>
<meta charset="UTF-8" />
<title>Click-captcha test</title>
<style type="text/css">
#challenge, #captcha-img {
margin: 10px
}
#captcha-img {
overflow: hidden
}
.captcha-digit {
display: block;
float: left;
width: <?php echo $captcha['width']; ?>px;
height: 100%;
cursor: pointer
}
.captcha-digit-selected {
background: #ccc;
opacity: .75;
filter: progid:DXImageTransform.Microsoft.Gradient(StartColorStr='#f2cccccc', EndColorStr='#f2cccccc')
}
</style>
<script type="text/javascript">
var captchaLinks = [];
var digits = [];
var num_digits = <?php echo $captcha['challenge'][2]; ?> - 1;
addEvent(window, 'load', init);
function init() {
captchaLinks = ['<?php
$digits = array();
for($i = 'digit0'; $i < 'digit' . $captcha['digits']; $i++) {
$digits[] = $i;
}
echo implode("', '", $digits);
?>'];
for(var i = 0; i < captchaLinks.length; i++) {
//for(var link in captchaLinks) {
addEvent(document.getElementById(captchaLinks[i]), 'click', newCaptchaDigit);
}
}
function newCaptchaDigit(e) {
if(e.target.className == 'captcha-digit captcha-digit-selected') {
digits.splice(digits.indexOf(e.target.id.substr(-1, 1)), 1);
e.target.className = 'captcha-digit';
} else if(digits.length <= num_digits) {
digits.splice(num_digits, digits.length - num_digits, e.target.id.substr(-1, 1));
e.target.className = 'captcha-digit captcha-digit-selected';
}
document.getElementById('code').value = digits.join('');
}
function addEvent(elem, event, handler) {
if(elem !== null & typeof elem !== 'undefined') {
if(elem.addEventListener) {
elem.addEventListener(event, handler, false);
} else if(elem.attachEvent) {
elem.attachEvent('on' + event, handler);
} else if(elem['on' + event]) {
elem['on' + event] = handler;
}
}
}
</script>
</head>
<body>
<div>
<form action="<?php echo $_SERVER['REQUEST_URI']; ?>" method="post">
<div id="captcha">
<div><?php echo $captcha['message']; ?></div>
<div>Click the following number sequence:
<div id="challenge" style="width: <?php echo $captcha['challenge'][1][0]; ?>px; height: <?php echo $captcha['challenge'][1][1]; ?>px; background-image: url('<?php echo $captcha['challenge'][0]; ?>')"></div>
</div>
<div id="captcha-img" style="width: <?php echo $captcha['size'][0]; ?>px; height: <?php echo $captcha['size'][1]; ?>px; background-image: url('<?php echo $captcha['captcha']; ?>')">
<?php for($i = 'digit0'; $i < 'digit' . $captcha['digits']; $i++) { ?>
<a class="captcha-digit" id="<?php echo $i; ?>"></a>
<?php } ?>
</div>
</div>
<input type="hidden" name="hash" value="<?php echo $captcha['hash']; ?>" />
<input type="hidden" name="correct_index" value="<?php echo $captcha['correct_index']; ?>" />
<input type="hidden" name="code" id="code" value="" />
<input type="submit" value="Submit" />
</form>
</div>
</body>
</html>
希望你能看到发生了什么,但我会在这里解释。:-)
该函数被调用generateCaptcha
,它接受参数$num_digits, $challenge_num, $size, $chars, $incode = false
。
$num_digits
: 输入验证码的字符数$challenge_num
: 加入挑战的字符数$size
:验证码的大小$chars
:要包含哪些字符(例如数字'0123456789'
:)$incode
:这只是为了让脚本可以判断它是否被自己调用来生成挑战。不要设置它。因此,要创建一个包含 4 个字符、一个 1 个字符的挑战(如您的问题)、大小为 30 且仅包含数字的验证码图像,请使用以下代码:
<?php
include 'captcha.php';
$captcha = generateCaptcha(4, 1, 30, '0123456789');
?>
然后变量$captcha
最终会是这样的:
array(9) {
["captcha"]=>
string(118058) "data:image/png;base64,iVBORw0KG...kSuQmCC"
["challenge"]=>
array(3) {
[0]=>
string(76266) "data:image/png;base64,iVBORw0KG...kJggg=="
[1]=>
array(2) {
[0]=>
int(200)
[1]=>
int(200)
}
[2]=>
int(2)
}
["size"]=>
array(2) {
[0]=>
int(400)
[1]=>
int(200)
}
["hash"]=>
string(32) "81bc501400b8da366e70b26007cb2323"
["code"]=>
string(4) "4817"
["message"]=>
string(0) ""
["width"]=>
int(100)
["digits"]=>
int(4)
["correct_index"]=>
string(32) "17ae615be69c757505dc7f69fce2afb1"
}
如果您需要更多信息,请在评论中提问。
如果没有完整的验证码,您将无法阻止一个坚定的机器人。
一些想法。
在 10 分钟内允许 10 - 15 个请求,如果超过,要求验证码或完全阻止。确保这是基于 IP 的,因为 cookie/会话不起作用
在表单中添加一些javascript,这样没有它就无法发布。大多数电子邮件收集垃圾邮件机器人不会运行 javascript 并放弃。生成一个随机字符串,存储在页面请求的 $_SESSION 中。使用 javascript 添加到表单帖子。如果该字符串不存在表单帖子上的匹配项,则显示验证码。
或者使用 javascript 来构造表单本身。
一个坚定的刮刀可以解决大多数问题,但您只是想增加这样做的成本。