Home » Code » PHP简单验证码类

PHP简单验证码类

验证码是实际开发中经常需要用到的。各个框架也都有自己的验证码类。抱着学习的态度,另一方面也不知道该写点什么了,就偷一下懒自己也写一个吧。验证码这个类可以说基本就是一次性的单个类,不存在什么继承,也没什么可以给其他类重用的地方,业务逻辑也不依赖于对象,瞅着全部是私有的静态方法即可。好吧,对于什么时候用静态什么时候非静态,这个至今不能很好的掌握。

我这个验证码类可以传入的参数有:

  • length:字符个数,默认4个
  • type:验证码类型,1纯数字,2纯字母,3数字+字母,4计算。默认3
  • width:宽度,默认120(px)
  • height:高度,默认40(px)
  • points:干扰点数量,默认400
  • lines:干扰线数量,默认10
  • size:字符大小,默认20(px)
  • font:渲染所用的字体,默认微软雅黑。字体跟类文件须放在同一目录

看着基本够用,可能就类型少了点。中文验证码没有,这个 一般用得不多,需要用到时再整吧,主要是随机生成中文不会搞。

使用方法:引入Captcha类,传入数组参数进行new出一个对象:

$captcha = new Captcha(array(
		'length' => 5,
		'width' => 250,
		'type' => 4,
		'size' => 25,
		'height' => 80,
));

获得的对象只有一个公开方法:build(),$capthca->build()就会输出验证码图像并返回验证码的答案。不会自动存入SESSION,手动存一下即可。输出了图像是是无法再输出任何字符串了的,所以要看一下答案是什么,得注释掉调用build的代码,再查看SESSION里面的值,就知道对不对了。如果发现验证码字符显示不全等,调整参数即可,可能是宽度不够,或者字号设置得太大个数太多等,需要各参数组合起来合理才行。以上参数输出的效果如下:

captcha
可能有这么一个问题,验证码颜色太鲜艳了,干扰线干扰点根本没啥用。这个有需要再改改代码里面的颜色值吧,暂时不改了。代码如下,贴上方便用到时直接复制:

class Captcha
{
	const TYPE_NUM = 1;

	const TYPE_LETTER = 2;

	const TYPE_NUM_LETTER = 3;

	const TYPE_CALC = 4;

	private static $length = 4;//字符个数

	private static $type = self::TYPE_NUM_LETTER;//类型,1数字,2数字+字母,3字母,4算术

	private static $width = 120;//宽度

	private static $height = 40;//高度

	private static $points = 400;//干扰点

	private static $lines = 10;//干扰线

	private static $size = 20;//字体大小

	private static $font = 't1.ttf';//字体

	private static $img = NULL;//画布资源句柄

	public function __construct(array $options = array())
	{
		foreach ($options as $key => $value)
		{
			if ($key === 'type')
			{
				if ($value == self::TYPE_CALC || $value == self::TYPE_LETTER || $value == self::TYPE_NUM || $value == self::TYPE_NUM_LETTER)
				{
					self::$type = $value;
				}
				continue;
			}
			if (isset(self::$$key) && $key !== 'img')
			{
				self::$$key = intval($value);
			}
		}
	}

	public function build()
	{
		self::createBackground();
		if (self::$points > 0)
		{
			self::createPoints();
		}
		if (self::$lines > 0)
		{
			self::createLines();
		}
		$code = self::createCode();
		if ($code === FALSE)
		{
			return FALSE;
		}
		header('Content-Type:image/png');
		imagepng(self::$img);
		imagedestroy(self::$img);
		return $code;
	}

	private static function createBackground()
	{
		self::$img = imagecreatetruecolor(self::$width, self::$height);
		$bgColor = imagecolorallocate(self::$img, 125, 125, 125);//这应该是一个比较浅的颜色
		imagefill(self::$img, 0, 0, $bgColor);
	}

	private static function createPoints()
	{
		if (self::$points > 0)
		{
			$len = self::$points;
			$img = self::$img;
			$w = self::$width;
			$h = self::$height;
			for ($i = 0; $i < $len; $i++)
			{
				//一个比背景深点的随机颜色
				$color = imagecolorallocate($img, mt_rand(50, 120), mt_rand(50, 120), mt_rand(50, 120));
				imagesetpixel($img, mt_rand(1, $w), mt_rand(1, $h), $color);//随机设置干扰点
			}
		}
	}

	private static function createLines()
	{
		if (self::$lines > 0)
		{
			$len = self::$lines;
			$img = self::$img;
			$w = self::$width;
			$h = self::$height;
			for ($i = 0; $i < $len; $i++)
			{
				//更深一点?浅一点
				$color = imagecolorallocate($img, mt_rand(20, 80), mt_rand(20, 80), mt_rand(20, 80));
				//随机设置干扰线,这是直线
				imageline($img, mt_rand(0, 5), mt_rand(1, $h), mt_rand($w - 5, $w), mt_rand(1, $h), $color);
			}
		}
	}

	private static function createCode()
	{
		switch (self::$type)
		{
			case self::TYPE_LETTER:
				$codeArr = self::getLetters();
				$code = implode('', $codeArr);
				break;
			case self::TYPE_NUM:
				$codeArr = self::getNumbers();
				$code = implode('', $codeArr);
				break;
			case self::TYPE_NUM_LETTER:
				$codeArr = self::getNumberAndLetter();
				$code = implode('', $codeArr);
				break;
			case self::TYPE_CALC:
				$result = self::getCalcString();
				$code = $result['code'];
				$codeArr = $result['codeArr'];
				break;
			default:
				return FALSE;
		}
		self::drawCode($codeArr);
		return $code;
	}

	private static function drawCode(array $codes)
	{
		$img = self::$img;
		$w = self::$width;
		$h = self::$height;
		$size = self::$size;
		$fontFile = __DIR__.DIRECTORY_SEPARATOR.trim(self::$font, './');//字体跟类目录一致
		$d = ($w - 10)/self::$length;//水平位移公差
		foreach ($codes as $k => $code)
		{
			//较深的一个颜色
			$color = imagecolorallocate($img, mt_rand(150, 220), mt_rand(150, 220), mt_rand(150, 220));
			imagettftext($img, $size, mt_rand(-30, 30), ($k*$d + $d/2 - $size/2), ($h/2 + $size/2), $color, $fontFile, $code);
		}
	}

	private static function getNumbers()
	{
		$numbers = array();
		$len = self::$length;
		for ($i = 0; $i < $len; $i++)
		{
			$numbers[] = mt_rand(0, 9);
		}
		return $numbers;
	}

	private static function getLetters()
	{
		$allLetter = 'abcdefghijkmnpqrstuvwxyzABCDEFGHIJKMNPQRSTUVWZYZ';//去掉l、L,o、O
		$count = strlen($allLetter);
		$len = self::$length;
		$letters = array();
		for ($i = 0; $i < $len; $i++)
		{
			$letters[] = $allLetter[mt_rand(0, $count)];
		}
		return $letters;
	}

	private static function getNumberAndLetter()
	{
		$lowercase = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y');
		$toUpperCase = array_map('strtoupper', $lowercase);
		$number = array('2', '3', '4', '5', '6', '7', '8', '9');
		$numberAndLetter = array_merge($lowercase, $toUpperCase, $number);
		shuffle($numberAndLetter);
		return array_slice($numberAndLetter, 0, self::$length);
	}

	private static function getCalcString()
	{
		$a = mt_rand(21, 99);
		$b = mt_rand(1, 20);
		$icon = mt_rand(1, 10);
		$codeArr = array();
		if ($icon > 5)
		{
			//加法
			$codeArr[] = strval($b);
			$codeArr[] = '+';
			$codeArr[] = '?';
			$codeArr[] = '=';
			$codeArr[] = strval($a);
			self::$length = count($codeArr);
			$code = strval($a - $b);
		}
		else 
		{
			$codeArr[] = strval($a);
			$codeArr[] = '—';
			$codeArr[] = strval($b);
			$codeArr[] = '=';
			$codeArr[] = '?';
			self::$length = count($codeArr);
			$code = strval($a - $b);
		}

		return array('code' => $code, 'codeArr' => $codeArr);
	}
}

Leave a Reply

Your email address will not be published. Required fields are marked *

*

Time limit is exhausted. Please reload CAPTCHA.