本文目录导读:

我来帮你写一个完整的PHP验证码类,包含多种验证码类型和安全特性:
完整的PHP验证码类
<?php
/**
* 验证码生成类
* 支持数字、字母、混合、算术运算等类型
*/
class Captcha {
// 配置参数
private $width = 100; // 宽度
private $height = 40; // 高度
private $length = 4; // 验证码长度
private $type = 'mixed'; // 类型:number, letter, mixed, chinese, math
private $fontFile = ''; // 字体文件路径
private $fontSize = 18; // 字体大小
private $bgColor = [255, 255, 255]; // 背景色RGB
private $textColor = [0, 0, 0]; // 文字颜色RGB
private $noiseLevel = 50; // 噪点数量
private $lineLevel = 3; // 干扰线数量
private $isDistortion = true; // 是否扭曲
private $isCurve = true; // 是否添加曲线
private $sessionName = 'captcha_code'; // Session名称
// 存储的验证码
private $code = '';
/**
* 构造函数
*/
public function __construct($config = []) {
if (!empty($config)) {
foreach ($config as $key => $value) {
if (property_exists($this, $key)) {
$this->$key = $value;
}
}
}
// 如果没有设置字体,使用系统默认字体
if (empty($this->fontFile)) {
$this->fontFile = $this->findFont();
}
// 启动Session
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
}
/**
* 生成验证码
*/
public function create() {
// 生成验证码内容
$this->code = $this->generateCode();
// 创建画布
$image = imagecreatetruecolor($this->width, $this->height);
// 设置背景色
$bgColor = imagecolorallocate($image, $this->bgColor[0], $this->bgColor[1], $this->bgColor[2]);
imagefilledrectangle($image, 0, 0, $this->width, $this->height, $bgColor);
// 添加干扰元素
$this->addNoise($image);
$this->addLines($image);
// 绘制文字
$this->drawText($image);
// 添加扭曲效果
if ($this->isDistortion) {
$image = $this->distortImage($image);
}
// 添加曲线
if ($this->isCurve) {
$this->drawCurve($image);
}
// 保存验证码到Session
$_SESSION[$this->sessionName] = $this->code;
// 输出图片
header('Content-Type: image/png');
imagepng($image);
imagedestroy($image);
}
/**
* 生成验证码内容
*/
private function generateCode() {
switch ($this->type) {
case 'number':
$characters = '0123456789';
break;
case 'letter':
$characters = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz';
break;
case 'chinese':
$characters = '的一是了我不人在他有这上们来到时大地为子中你说生国年着就那和要她出也得里后自以会家可下而过天去能对小多然于心学么之都好看起发当没成只如事把还用第样道想作种开美总从无情己面最女但现前些所同日手又行意动方期它头经长儿回位分爱老因很给名法间斯知世什两次使身者被高已亲其进此话常与活正感';
$this->length = 4; // 中文字符需要更多的空间
$code = '';
for ($i = 0; $i < $this->length; $i++) {
$code .= mb_substr($characters, mt_rand(0, mb_strlen($characters) - 1), 1);
}
return $code;
case 'math':
$num1 = mt_rand(10, 99);
$num2 = mt_rand(1, 9);
$operators = ['+', '-', '×'];
$operator = $operators[array_rand($operators)];
if ($operator == '-') {
if ($num1 < $num2) {
list($num1, $num2) = [$num2, $num1];
}
$code = "$num1 - $num2 = ?";
} elseif ($operator == '+') {
$code = "$num1 + $num2 = ?";
} else {
$code = "$num1 × $num2 = ?";
}
// 计算结果
$result = 0;
switch ($operator) {
case '+':
$result = $num1 + $num2;
break;
case '-':
$result = $num1 - $num2;
break;
case '×':
$result = $num1 * $num2;
break;
}
$_SESSION[$this->sessionName] = $result;
return $code;
default:
$characters = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789abcdefghjkmnpqrstuvwxyz';
}
$code = '';
$length = $this->length;
for ($i = 0; $i < $length; $i++) {
$code .= $characters[mt_rand(0, strlen($characters) - 1)];
}
return $code;
}
/**
* 绘制文字
*/
private function drawText($image) {
$textColor = imagecolorallocate($image, $this->textColor[0], $this->textColor[1], $this->textColor[2]);
if ($this->type == 'chinese') {
// 中文验证码
$x = 5;
$y = $this->height - 10;
for ($i = 0; $i < $this->length; $i++) {
$char = mb_substr($this->code, $i, 1);
$angle = mt_rand(-20, 20);
imagettftext($image, $this->fontSize, $angle, $x, $y, $textColor, $this->fontFile, $char);
$x += 25;
}
} elseif ($this->type == 'math') {
// 数学运算验证码
imagettftext($image, $this->fontSize, 0, 10, $this->height - 10, $textColor, $this->fontFile, $this->code);
} else {
// 普通验证码
$x = 5;
$y = $this->height - 10;
for ($i = 0; $i < strlen($this->code); $i++) {
$char = $this->code[$i];
$angle = mt_rand(-20, 20);
imagettftext($image, $this->fontSize, $angle, $x, $y, $textColor, $this->fontFile, $char);
$x += ceil($this->fontSize * 1.3);
}
}
}
/**
* 添加噪点
*/
private function addNoise($image) {
for ($i = 0; $i < $this->noiseLevel; $i++) {
$color = imagecolorallocate($image, mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255));
imagesetpixel($image, mt_rand(0, $this->width), mt_rand(0, $this->height), $color);
}
}
/**
* 添加干扰线
*/
private function addLines($image) {
for ($i = 0; $i < $this->lineLevel; $i++) {
$color = imagecolorallocate($image, mt_rand(100, 200), mt_rand(100, 200), mt_rand(100, 200));
imageline($image, mt_rand(0, $this->width), mt_rand(0, $this->height),
mt_rand(0, $this->width), mt_rand(0, $this->height), $color);
}
}
/**
* 添加曲线
*/
private function drawCurve($image) {
$steps = 50;
$count = 2;
for ($c = 0; $c < $count; $c++) {
$color = imagecolorallocate($image, mt_rand(100, 200), mt_rand(100, 200), mt_rand(100, 200));
$px = mt_rand(0, $this->width);
$py = mt_rand(0, $this->height);
$kx = mt_rand(1, 5) * 0.01;
$ky = mt_rand(1, 5) * 0.01;
for ($i = 0; $i < $steps; $i++) {
$t = $i / $steps;
$x = $px + ($t * 2 * 3.14159 * $kx * $this->width);
$y = $py + sin($t * 2 * 3.14159 * $ky * $this->height) * $this->height / 4;
if ($i > 0) {
imageline($image, $lastX, $lastY, $x, $y, $color);
}
$lastX = $x;
$lastY = $y;
}
}
}
/**
* 图像扭曲效果
*/
private function distortImage($image) {
$wave = mt_rand(1, 3);
$width = $this->width;
$height = $this->height;
$distorted = imagecreatetruecolor($width, $height);
$bgColor = imagecolorallocate($distorted, $this->bgColor[0], $this->bgColor[1], $this->bgColor[2]);
imagefilledrectangle($distorted, 0, 0, $width, $height, $bgColor);
for ($x = 0; $x < $width; $x++) {
for ($y = 0; $y < $height; $y++) {
$newX = $x + sin($y / 10 + $wave) * 3;
$newY = $y + cos($x / 10 + $wave) * 3;
if ($newX >= 0 && $newX < $width && $newY >= 0 && $newY < $height) {
$color = imagecolorat($image, $newX, $newY);
imagesetpixel($distorted, $x, $y, $color);
}
}
}
imagedestroy($image);
return $distorted;
}
/**
* 查找可用字体
*/
private function findFont() {
$fonts = [
'/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf',
'/usr/share/fonts/truetype/freefont/FreeSans.ttf',
'C:/Windows/Fonts/arial.ttf',
'C:/Windows/Fonts/msyh.ttf',
'D:/Windows/Fonts/arial.ttf',
'D:/Windows/Fonts/msyh.ttf'
];
foreach ($fonts as $font) {
if (file_exists($font)) {
return $font;
}
}
// 兜底方案:使用GD内置字体
return '';
}
/**
* 验证验证码
*/
public function verify($code) {
if (empty($code) || empty($_SESSION[$this->sessionName])) {
return false;
}
if ($this->type == 'math') {
$result = (int)$_SESSION[$this->sessionName];
return (int)$code === $result;
}
return strtolower($code) === strtolower($_SESSION[$this->sessionName]);
}
/**
* 清除验证码
*/
public function clear() {
unset($_SESSION[$this->sessionName]);
}
}
使用示例
生成验证码(captcha.php)
<?php
// 引入类文件
require_once 'Captcha.class.php';
// 创建验证码实例(带配置)
$captcha = new Captcha([
'width' => 120,
'height' => 40,
'length' => 4,
'type' => 'mixed', // number, letter, mixed, chinese, math
'noiseLevel' => 50,
'lineLevel' => 3,
'isDistortion' => true,
'isCurve' => true,
'sessionName' => 'my_captcha'
]);
// 输出验证码图片
$captcha->create();
显示验证码(HTML)
<!-- 简单的显示 -->
<img src="captcha.php" id="captcha_img" onclick="refreshCaptcha()">
<script>
function refreshCaptcha() {
document.getElementById('captcha_img').src = 'captcha.php?t=' + new Date().getTime();
}
</script>
验证输入(verify.php)
<?php
require_once 'Captcha.class.php';
$captcha = new Captcha();
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$inputCode = $_POST['captcha'];
if ($captcha->verify($inputCode)) {
echo "验证成功!";
// 清除验证码,防止重复使用
$captcha->clear();
} else {
echo "验证码错误!";
}
}
?>
<!-- 表单 -->
<form method="POST">
<input type="text" name="captcha" placeholder="请输入验证码">
<img src="captcha.php" onclick="this.src='captcha.php?t='+new Date().getTime()" style="cursor:pointer">
<button type="submit">验证</button>
</form>
高级用法
数学验证码
$captcha = new Captcha([
'type' => 'math', // 数学运算
'width' => 150,
'fontSize' => 16
]);
中文验证码
$captcha = new Captcha([
'type' => 'chinese', // 中文验证码
'width' => 160,
'length' => 4,
'fontSize' => 16
]);
完全自定义
$captcha = new Captcha([
'width' => 200,
'height' => 60,
'length' => 6,
'type' => 'mixed',
'fontSize' => 24,
'bgColor' => [240, 240, 240],
'textColor' => [50, 50, 50],
'noiseLevel' => 100,
'lineLevel' => 5,
'isDistortion' => true,
'isCurve' => true,
'sessionName' => 'custom_captcha'
]);
安全建议
- 使用HTTPS:确保验证码在HTTPS连接下传输
- 设置过期时间:验证码应在一定时间内有效(如5分钟)
- 限制尝试次数:防止暴力破解
- 定期更换:验证码使用一次后应销毁
- 避免透露信息:不要生成与用户信息相关的验证码
这个验证码类功能完整,支持多种验证码类型,可以根据实际需求灵活配置。