PHP 利用 GD 库生成验证码图片

近年来人工智能 AI 和网络爬虫机器人的日益发达,让人机验证渐渐成为一种刚需,但是如果想要接入某些大厂的人机验证API,就必须要达到某些申请条件,但普通人没办法达到怎么办,就只能用自己生成的验证码来进行人机验证了。这次通过PHP,我们生成了数字验证码图片,并且通过修改这个 PHP 的脚本,我们可以自由控制难度(验证码的长度)。

注意:这个脚本要先安装GD库才能运行哦!

>PHP 如何生成图片?

相信很多人都没有使用 PHP 生成图片的经验,但是其实通过 PHP 的 GD 库,我们可以进行图片的生成,编辑等操作,首先我们可以通过 imagecreate 来生成图片,我们以下生成一个宽 20 * 验证码长度 px ,高为 20 px 的图片:

$codelen = 6;
$im = imagecreate(20 * $codelen, 20);

之后我们可以通过 imagecolorallocate 函数来生成颜色,并由 imagefill 函数来填充我们的背景色,我们以下先生成 RGB 255, 255, 255 也就是白色,并且从 (0, 0) 位置填充到我们整张图片:

imagefill($im, 0, 0, imagecolorallocate($im, 255, 255, 255));

>PHP 如何在图片上画出数字?

我们可以通过 imagestring 函数来生成我们的数字,只不过这里我们要把握好我们的 x 轴与 y 轴的距离避免越界,我们以下会在 x 轴 验证码位数 * 20 + (0到5) ,y轴 (2到5)的位置,以随机的颜色来画出我们设定好的 $codelen 位的随机数字验证码:

for($i = 0; $i < $codelen; $i++) {
    imagestring($im, mt_rand(0, 5) + ($i * 20), mt_rand(2, 5), mt_rand(0, 9), ImageColorAllocate($im, mt_rand(0, 255), mt_rand(0, 100), mt_rand(0, 200)));
}

这里留了一个小巧思,为什么这里的随机颜色最大值不是 RGB (255, 255, 255) 呢?那是因为如果太接近白色的话,我们也是会看不清楚到底数字是什么哦!我们毕竟还是要让真实的人去通过验证的,如果为了拦住 AI 而流失掉真实用户就又掉太得不偿失了。

>PHP 如何在图片上画线条?

生成了数字之后,为了不被 AI 识别,我们必须加上一些线条来掩盖,以混乱 AI 的判断,我们可以通过 imageline 函数来生成一些线条,但是需要注意的是,如果图片大小过小而线条太多的话,可能会搞到连人都看不到数字是什么哦!我们以下来添加 5 条随机长度、方向、位置和颜色的线条:

for($i = 0; $i < 5; $i++) {
    imageline($im, mt_rand(0, 120), mt_rand(0, 20), mt_rand(0, 120), mt_rand(0, 20), ImageColorAllocate($im, mt_rand(0, 255), mt_rand(0, 100), mt_rand(0, 200)));
}

>PHP 生成图片之后如何输出图片?

很多人下意识的认为 PHP 只能返回 HTML 内容,但这个概念其实是错的,PHP 通过 header 函数也是能够返回图片内容的,我们可以通过下面这段代码实现:

@header("Content-Type: image/jpeg");

然后我们可以通过 imagejpeg 来返回一张 jpeg 的图片,并且用 imagedestroy 来销毁我们生成的图片来节省资源:

imagejpeg($im);

imagedestroy($im);

这样我们就完成输出了。

>完整代码

<?php

header("Content-Type: image/jpeg");

$codeLen = 6; # 验证码长度

$im = @imagecreate(20 * $codeLen, 20); # 图片大小 (宽度, 高度)
imagefill($im, 0, 0, ImageColorAllocate($im, 255, 255, 255)); # 背景颜色:白色

# 随机生成数字
for($i = 0; $i < $codeLen; $i++) {
    imagestring($im, 5, mt_rand(0, 5) + ($i * 20), mt_rand(2, 5), mt_rand(0, 9), ImageColorAllocate($im, mt_rand(0, 255), mt_rand(0, 100), mt_rand(0, 200)));
}

# 随机生成线条
for($i = 0; $i < 5; $i++) {
    imageline($im, mt_rand(0, 120), mt_rand(0, 20), mt_rand(0, 120), mt_rand(0, 20), ImageColorAllocate($im, mt_rand(0, 255), mt_rand(0, 100), mt_rand(0, 200)));
}

# 输出图片
imagejpeg($im);

# 销毁图片
imagedestroy($im);

?>