图片验证码

本实例主要是为了解决部分用户输出验证码的时候,未能正确的把验证码响应至HTTP响应的问题。

  1. namespace App\Utility\VerifyCode;
  2. class Verify
  3. {
  4. public static function create($codeStr){
  5. $codeSet = '12346789ABCDEFGHJKLMNPQRTUVWXY';//字符容器
  6. $fontSize = 25; // 验证码字体大小(px)
  7. $useCurve = true; // 是否画混淆曲线
  8. $useNoise = true; // 是否添加杂点
  9. $imageH = 0; // 验证码图片宽
  10. $imageL = 0; // 验证码图片长
  11. $length = 4; // 验证码位数
  12. $bg = array(243, 251, 254); // 背景
  13. $_image = null; // 验证码图片实例
  14. $_color = null; // 验证码字体颜色
  15. $imageL = $length * $fontSize * 1.5 + $fontSize*1.5;
  16. $imageH = $fontSize * 2;
  17. // 建立一幅图像
  18. $_image = imagecreate($imageL,$imageH);
  19. // 设置背景
  20. imagecolorallocate($_image,$bg[0], $bg[1], $bg[2]);
  21. // 验证码字体随机颜色
  22. $_color = imagecolorallocate($_image, mt_rand(1,120), mt_rand(1,120), mt_rand(1,120));
  23. // 验证码使用随机字体 暂时不做
  24. $ttf = __DIR__.'/'."font.ttf";
  25. /**
  26. * 画杂点
  27. * 往图片上写不同颜色的字母或数字
  28. */
  29. for($i = 0; $i < 10; $i++){
  30. //杂点颜色
  31. $noiseColor = imagecolorallocate(
  32. $_image,
  33. mt_rand(150,225),
  34. mt_rand(150,225),
  35. mt_rand(150,225)
  36. );
  37. for($j = 0; $j < 5; $j++){
  38. // 绘杂点
  39. imagestring(
  40. $_image,
  41. 5,
  42. mt_rand(-10, $imageL),
  43. mt_rand(-10, $imageH),
  44. $codeSet[mt_rand(0, 27)], // 杂点文本为随机的字母或数字
  45. $noiseColor
  46. );
  47. }
  48. }
  49. //画出横穿干扰线
  50. $A = mt_rand(1, $imageH/2); // 振幅
  51. $b = mt_rand(-$imageH/4,$imageH/4); // Y轴方向偏移量
  52. $f = mt_rand(-$imageH/4,$imageH/4); // X轴方向偏移量
  53. $T = mt_rand($imageH*1.5, $imageL*2); // 周期
  54. $w = (2* M_PI)/$T;
  55. $px1 = 0; // 曲线横坐标起始位置
  56. $px2 = mt_rand($imageL/2,$imageL * 0.667); // 曲线横坐标结束位置
  57. for ($px=$px1; $px<=$px2; $px=$px+ 0.9) {
  58. if ($w!=0) {
  59. $py = $A * sin($w*$px + $f)+ $b + $imageH/2; // y = Asin(ωx+φ) + b
  60. $i = (int) (($fontSize - 6)/4);
  61. while ($i > 0) {
  62. imagesetpixel($_image, $px + $i, $py + $i, $_color); // 这里画像素点比imagettftext和imagestring性能要好很多
  63. $i--;
  64. }
  65. }
  66. }
  67. $A = mt_rand(1,$imageH/2); // 振幅
  68. $f = mt_rand(-$imageH/4, $imageH/4); // X轴方向偏移量
  69. $T = mt_rand($imageH*1.5, $imageL*2); // 周期
  70. $w = (2* M_PI)/$T;
  71. $b = $py - $A * sin($w*$px + $f) - $imageH/2;
  72. $px1 = $px2;
  73. $px2 = $imageL;
  74. for ($px=$px1; $px<=$px2; $px=$px+ 0.9) {
  75. if ($w!=0) {
  76. $py = $A * sin($w*$px + $f)+ $b + $imageH/2; // y = Asin(ωx+φ) + b
  77. $i = (int) (($fontSize - 8)/4);
  78. while ($i > 0) {
  79. imagesetpixel($_image, $px + $i, $py + $i, $_color); // 这里(while)循环画像素点比imagettftext和imagestring用字体大小一次画出(不用这while循环)性能要好很多
  80. $i--;
  81. }
  82. }
  83. }
  84. //将验证码写入
  85. // 绘验证码
  86. if(!empty($codeStr)){
  87. $codeNX = 0; // 验证码第N个字符的左边距
  88. for ($i = 0; $i<$length; $i++) {
  89. $codeNX += mt_rand($fontSize*1.2,$fontSize*1.6);
  90. // 写一个验证码字符
  91. imagettftext($_image,$fontSize, mt_rand(-40, 70), $codeNX, $fontSize*1.5, $_color, $ttf, $codeStr[$i]);
  92. }
  93. }
  94. ob_start();
  95. imagepng($_image);
  96. $image = ob_get_contents();
  97. ob_end_clean();
  98. imagedestroy($_image);
  99. return new Result($codeStr,$image);
  100. }
  101. }

关键点在于ob_start与ob_end_clean,原因在于imagepng 其实是等于 echo $var;这样无法把图片信息响应到response中。

  1. namespace App\Utility\VerifyCode;
  2. class Result
  3. {
  4. protected $codeStr;
  5. protected $imageSting;
  6. protected $imageMineType = 'image/png';
  7. function __construct($string,$image)
  8. {
  9. $this->codeStr = $string;
  10. $this->imageSting = $image;
  11. }
  12. /**
  13. * @return mixed
  14. */
  15. public function getCodeStr()
  16. {
  17. return $this->codeStr;
  18. }
  19. /**
  20. * @return mixed
  21. */
  22. public function getImageSting()
  23. {
  24. return $this->imageSting;
  25. }
  26. /**
  27. * @return string
  28. */
  29. public function getImageMineType()
  30. {
  31. return $this->imageMineType;
  32. }
  33. }

注意,生成验证码的时候,需要字体文件。本代码对应的字体文件是verify_code_font.ttf