实现思路:PHP从图片库中随机取出一张,使用gd库裁剪并随机旋转0-360°【A】,记下旋转度数。把图片输出给前端。用户将图片旋转至正确的位置(只能朝着一侧旋转,且最大旋转值为360°),前端记下用户旋转的角度【B】传给后端。
验证思路:A = 360 - B 即正常(可以加左右模糊值)。否则验证失败。
代码如下:
<?php
namespace controllers\auth;
use Gd\Imagine;
use File;
use Image;
class ImageVerify extends ApiController {
const ALLOW_ERROR_RANGE = 15; // 允许的角度误差范围
const EXPIRED_TIME = 60; //操作过期时间
const IMG_SIZE = 300; //图片大小
/**
* 获取验证图片
*
* @return string
*/
public function actionGetVerifyImage() {
$phone = $app->request->post('phone');
if (!$phone){
return '参数错误';
}
//从图片库取图片
//随机取图(略)
$imgUrl = $image->url;
//生成验证码图片
$srcImg = imagecreatefromstring(file_get_contents($imgUrl));
$imageSize = getimagesize($imgUrl);
$w = $imageSize[0];
$h = $imageSize[1];
$cw = min($w, $h);
$ch = $cw;
$circleImg = imagecreatetruecolor($cw, $ch);
imagealphablending($circleImg,false );
imagesavealpha($circleImg, true);
$bg = imagecolorallocatealpha($circleImg, 255, 255, 255, 127);
imagefill($circleImg, 0, 0, $bg);
$r = $cw / 2;
for ($x = 0; $x < $w; $x++) {
for ($y = 0; $y < $h; $y++) {
$rgbColor = imagecolorat($srcImg, $x, $y);
if (((($x - $r) * ($x - $r) + ($y - $r) * ($y - $r)) < ($r * $r))) {
imagesetpixel($circleImg, $x, $y, $rgbColor);
}
}
}
$ip = str_replace('.', '', $app->request->getUserIP());
$key = $ip . $phone . date('Ymd');
ob_start();
imagepng($circleImg);
$imgContent = ob_get_contents();
ob_end_clean();
imagedestroy($circleImg);
//旋转验证码图片
$randAngle = rand(60, 300);
$imagineGd = new Imagine();
$imageInterface = $imagineGd->load($imgContent);
$imgResource = Image::resize($imageInterface, self::IMG_SIZE, self::IMG_SIZE, true, true)->rotate($randAngle);
$size = $imgResource->getSize()->getWidth();
$r_new = self::IMG_SIZE / 2;
$imgStr = Image::crop($imgResource, self::IMG_SIZE, self::IMG_SIZE, [$size / 2 - $r_new, $size / 2 - $r_new])->get('png');
$base64ImgString = 'data:image/png;base64,' . chunk_split(base64_encode($imgStr));
$app->cache->set($key, $randAngle, self::EXPIRED_TIME); //redis记录下旋转角度
// header('Content-type: image/png');
// header('Content-Transfer-Encoding: binary');
echo $base64ImgString;
exit();
}
/**
* 验证旋转角度
*
* @return array|string
* @throws \Exception
*/
public function verifyAngle() {
$data = $app->request->post();
if (!$data['phone']){
return [1, '参数错误'];
}
$ip = str_replace('.', '', $app->request->getUserIP());
$key = $ip . $data['phone'] . date('Ymd');
$angle= $app->cache->get($key); //获取redis中存下来的角度
if (!$angle){
return [1, '操作超时'];
}
$app->cache->delete($key); //删除redis记录
$rightAngle = 360 - $data['angle'];
if (($angle >= ($rightAngle - self::ALLOW_ERROR_RANGE)) && ($angle <= ($rightAngle + self::ALLOW_ERROR_RANGE))){
//验证通过........................
return true;
}
return [1, '验证失败'];
}
}
|