1

我经营一个 PTC 网站,为人们宣传网站。而且我需要一个易于降低或完全阻止机器人使用的方法。

广告计数器完成倒计时后,我想加载验证码。
但我不想要你必须输入任何东西的验证码。只需单击鼠标。

如果验证码可以在 javascript 中完成,那就太好了。

我正在寻找类似这样的东西:

计数器:0 选择匹配数:7 [1] [0] [7] [2]

用户必须单击与该数字匹配的框中的数字。

数字将在 1-9 之间。

4

2 回答 2

0

我制作了一个验证码脚本。它的大小、字符数和可供选择的字符都是可定制的。

这里是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"
}

如果您需要更多信息,请在评论中提问。

于 2012-08-09T10:11:55.073 回答
0

如果没有完整的验证码,您将无法阻止一个坚定的机器人。

一些想法。

在 10 分钟内允许 10 - 15 个请求,如果超过,要求验证码或完全阻止。确保这是基于 IP 的,因为 cookie/会话不起作用

在表单中添加一些javascript,这样没有它就无法发布。大多数电子邮件收集垃圾邮件机器人不会运行 javascript 并放弃。生成一个随机字符串,存储在页面请求的 $_SESSION 中。使用 javascript 添加到表单帖子。如果该字符串不存在表单帖子上的匹配项,则显示验证码。

或者使用 javascript 来构造表单本身。

一个坚定的刮刀可以解决大多数问题,但您只是想增加这样做的成本。

于 2012-08-06T22:50:41.037 回答