PHP实现验证码

验证码是什么

验证码为全自动区分人和计算机的图灵测试的缩写,是一种区分用户是计算机或人的公共全自动程序。

验证码应用场景

  1. 登录、注册确定提交之前,做人/及其校验
  2. 发布、回复信息之前,做人/及其校验
  3. 疑似机器请求时,做人/及其校验

验证码实现步骤

  1. 生成底图
  2. 生成验证内容
  3. 生成验证码图片
  4. 校验验证内容

所用到的PHP函数

imagecreatetruecolor ( int $width, int $height ) 
//创建一个宽$width高$height的画布
imagecolorallocate ( resource $image, int $red, int $green, int $blue ) 
//为画布分配颜色,red,green 和 blue分别是所需要的颜色的RGB值
imagefill ( resource $image, int $x, int $y, int $color ) 
//将分配好的颜色填充到画布
imagepng(resource $image [, string filename])
//输出一张png格式的图片
imagestring ( resource $image, int $fontsize, int $x, int $y, string $content, int $color ) 
//在画布上面水平写上文字
imagesetpixel ( resource $image, int $x, int $y, int $color ) 
//画一个点或者一个单一像素
imageline ( resource $image, int $x1, int $y1, int $x2, int $y2, int $color ) 
//画一条线段
substr ( string $string, int $start, int $length )
//详情请查看手册
imagedestroy ( $image )
//销毁图像资源,释放与 image 关联的内存

目标1

通过PHP代码,生成一张100*30px大小的图片

TIPS

  1. 依赖GD扩展
  2. 输出图片前必须提前输出图片header信息
  3. 该方法默认输出为黑色背景
<?php
$width = 100;
$height = 30;
$image = imagecreatetruecolor($width,$height);
$pale = imagecolorallocate($image,204,204,204);
imagefill($image,0,0, $pale);
header('content-type:image/png');
imagepng($image);
imagedestroy($image);
?>

目标2

在底图上显示随机数字

TIPS

注意好字体大小和分布,避免字体重叠或显示不全

<?php
$width = 100;
$height = 30;
$image = imagecreatetruecolor($width,$height);
$pale = imagecolorallocate($image,204,204,204);
imagefill($image,0,0, $pale);

$length = 4;
for ($i=1;$i<=$length;$i++){
    $fontsize = 6;
    $fontcontent = mt_rand(0,9);
    $x = $i*100/5;
    $y = mt_rand(5,10);
    $fontcolor = imagecolorallocate($image,mt_rand(0,120),mt_rand(0,120),mt_rand(0,120));
    imagestring($image,$fontsize,$x,$y,$fontcontent,$fontcolor);
}

header('content-type:image/png');
imagepng($image);
imagedestroy($image);
?>

目标3

为验证码增加干扰元素,干扰的点或线

TIPS

干扰信息一定要控制好颜色,避免喧宾夺主

<?php
$width = 100;
$height = 30;
$image = imagecreatetruecolor($width, $height);
$bgcolor = imagecolorallocate($image,204,204,204);
imagefill($image,0,0,$bgcolor);

$length = 4;
for ($i=1;$i<=$length;$i++){
    $fontsize = 6;
    $x = $i*100/5;
    $y = mt_rand(5,10);
    $fontcontent = mt_rand(0,9);
    $fontcolor = imagecolorallocate($image,mt_rand(0,120),mt_rand(0,120),mt_rand(0,120));
    imagestring($image,$fontsize,$x,$y,$fontcontent,$fontcolor);
}

$pointnum = 200;
for ($i=1;$i<=200;$i++){
    $x = mt_rand(1,99);
    $y = mt_rand(1,29);
    $pointcolor = imagecolorallocate($image,mt_rand(50,200),mt_rand(50,200),mt_rand(50,200));
    imagesetpixel($image,$x,$y,$pointcolor);
}

$linenum = 3;
for ($i=1;$i<=$linenum;$i++){
    $linecolor = imagecolorallocate($image,mt_rand(80,220),mt_rand(80,220),mt_rand(80,220));
    imageline($image,mt_rand(1,99),mt_rand(1,29),mt_rand(1,99),mt_rand(1,29),$linecolor);
}

header('content-type:image/png');
imagepng($image);
imagedestroy($iamge);

目标4

让图片上的验证码内容显示为字母或数字、字母的混合体

TIPS

N/A

<?php
$width = 100;
$height = 30;
$image = imagecreatetruecolor($width, $height);
$bgcolor = imagecolorallocate($image,204,204,204);
imagefill($image,0,0,$bgcolor);

$length = 4;
for ($i=1;$i<=$length;$i++){
    $fontsize = 6;
    $x = $i*100/5;
    $y = mt_rand(5,10);
    $data = 'ABCDEFGHIGKMNOPQRSTUVWXYabcdefghijkmnopqrstuvwxy34567890';
    $fontcontent = substr($data,mt_rand(0,strlen($data)),1);
    $fontcolor = imagecolorallocate($image,mt_rand(0,120),mt_rand(0,120),mt_rand(0,120));
    imagestring($image,$fontsize,$x,$y,$fontcontent,$fontcolor);
}

$pointnum = 200;
for ($i=1;$i<=200;$i++){
    $x = mt_rand(1,99);
    $y = mt_rand(1,29);
    $pointcolor = imagecolorallocate($image,mt_rand(50,200),mt_rand(50,200),mt_rand(50,200));
    imagesetpixel($image,$x,$y,$pointcolor);
}

$linenum = 3;
for ($i=1;$i<=$linenum;$i++){
    $linecolor = imagecolorallocate($image,mt_rand(80,220),mt_rand(80,220),mt_rand(80,220));
    imageline($image,mt_rand(1,99),mt_rand(1,29),mt_rand(1,99),mt_rand(1,29),$linecolor);
}
ob_clean();
header('content-type:image/png');
imagepng($image);
imagedestroy($image);

目标5

在服务器端记录验证码信息,便于用户输入后做校验

TIPS

  1. session_start()必须处于脚本最顶部
  2. 多服务器情况,需要考虑集中管理session信息
<?php
session_start();
$width = 100;
$height = 30;
$image = imagecreatetruecolor($width, $height);
$bgcolor = imagecolorallocate($image,204,204,204);
imagefill($image,0,0,$bgcolor);

$length = 4;
$vertify_code = '';
for ($i=1;$i<=$length;$i++){
    $fontsize = 6;
    $x = $i*100/5;
    $y = mt_rand(5,10);
    $data = 'ABCDEFGHIGKMNOPQRSTUVWXYabcdefghijkmnopqrstuvwxy34567890';
    $fontcontent = substr($data,mt_rand(0,strlen($data)),1);
    $vertify_code .= $fontcontent;
    $fontcolor = imagecolorallocate($image,mt_rand(0,120),mt_rand(0,120),mt_rand(0,120));
    imagestring($image,$fontsize,$x,$y,$fontcontent,$fontcolor);
}
$_SESSION['authcode'] = $vertify_code;

$pointnum = 200;
for ($i=1;$i<=200;$i++){
    $x = mt_rand(1,99);
    $y = mt_rand(1,29);
    $pointcolor = imagecolorallocate($image,mt_rand(50,200),mt_rand(50,200),mt_rand(50,200));
    imagesetpixel($image,$x,$y,$pointcolor);
}

$linenum = 3;
for ($i=1;$i<=$linenum;$i++){
    $linecolor = imagecolorallocate($image,mt_rand(80,220),mt_rand(80,220),mt_rand(80,220));
    imageline($image,mt_rand(1,99),mt_rand(1,29),mt_rand(1,99),mt_rand(1,29),$linecolor);
}
header('content-type:image/png');
imagepng($image);
imagedestroy($image);

目标6

将已生成的验证码提供给用户,并校验用户验证码的正确性

TIPS

创建两个PHP文件:vertify.php和form.php

vertify.php文件代码
<?php
session_start();
$width = 100;
$height = 30;
$image = imagecreatetruecolor($width, $height);
$bgcolor = imagecolorallocate($image,204,204,204);
imagefill($image,0,0,$bgcolor);

$length = 4;
$vertify_code = '';
for ($i=1;$i<=$length;$i++){
    $fontsize = 6;
    $x = $i*100/5;
    $y = mt_rand(5,10);
    $data = 'ABCDEFGHIGKMNOPQRSTUVWXY34567890';
    $fontcontent = substr($data,mt_rand(0,strlen($data)),1);
    $vertify_code .= $fontcontent;
    $fontcolor = imagecolorallocate($image,mt_rand(0,120),mt_rand(0,120),mt_rand(0,120));
    imagestring($image,$fontsize,$x,$y,$fontcontent,$fontcolor);
}
$_SESSION['authcode'] = $vertify_code;

$pointnum = 200;
for ($i=1;$i<=200;$i++){
    $x = mt_rand(1,99);
    $y = mt_rand(1,29);
    $pointcolor = imagecolorallocate($image,mt_rand(50,200),mt_rand(50,200),mt_rand(50,200));
    imagesetpixel($image,$x,$y,$pointcolor);
}

$linenum = 3;
for ($i=1;$i<=$linenum;$i++){
    $linecolor = imagecolorallocate($image,mt_rand(80,220),mt_rand(80,220),mt_rand(80,220));
    imageline($image,mt_rand(1,99),mt_rand(1,29),mt_rand(1,99),mt_rand(1,29),$linecolor);
}
header('content-type:image/png');
imagepng($image);
imagedestroy($image);
form.php文件代码
<?php
header('content-type:text/html;charset=utf-8');
if (isset($_REQUEST['authcode'])){
    session_start();
    if (strtoupper($_REQUEST['authcode']) == $_SESSION['authcode']){
        echo '输入正确';
    }else{
        echo '输入错误';
    }
}
?>

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>确认验证码</title>
    </head>
    <body>
    <form action="form.php" method="post">
        <p>验证码图片: <img src="test.php" alt=""></p>
        <p>请输入图片中的内容:<input type="text" name="authcode" value=""></p>
        <p><input type="submit" value="提交"></p>
    </form>
    </body>
</html>

目标7

验证码的动态校验及设计原理:“看不清、换一个”的实现原理

简单三步即可实现动态验证

  1. 增加可点击的“换一个”文案
  2. 用JS选取器选取验证码图片
  3. 用JS修改验证码图片地址(改src)
<?php
header('content-type:text/html;charset=utf-8');
if (isset($_REQUEST['authcode'])){
    session_start();
    if (strtoupper($_REQUEST['authcode']) == $_SESSION['authcode']){
        echo '输入正确';
    }else{
        echo '输入错误';
    }
}
?>

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>确认验证码</title>
    </head>
    <body>
    <form action="form.php" method="post">
        <p>验证码图片: <img id="vertify_img" src="vertify.php"></p>
        <a href="javascript:void(0)" onclick="document.getElementById('vertify_img').src='vertify.php'">换一个?</a>
        <p>请输入图片中的内容:<input type="text" name="authcode" value=""></p>
        <p><input type="submit" value="提交"></p>
    </form>
    </body>
</html>

目标8

复杂验证码的实现:图片、视频验证码

图片、视频验证码实现方案类似

  1. 准备一定量的验证码物料库
  2. 做好物料的对应关系