# Image-validation **Repository Path**: changrui_com/image-validation ## Basic Information - **Project Name**: Image-validation - **Description**: 发送验证码之前,让用户把一张被旋转过的图片扶正。这个包是 Composer SDK:出图、校验角度、签发一次性通行证。HTTP 接口和短信发送写在业务项目里。 - **Primary Language**: Unknown - **License**: GPL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-23 - **Last Updated**: 2026-09-24 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 旋转扶正验证 发送验证码之前,让用户把一张被旋转过的图片扶正。这个包是 Composer SDK:出图、校验角度、签发一次性通行证。HTTP 接口和短信发送写在业务项目里。 图片字段是完整的 data URI,可以直接作为 `img` / `image` 的 `src`: ```text data:image/png;base64,iVBORw0KGgo... ``` ## 安装 ```bash composer require image-validation/rotate-captcha ``` 需要 PHP 8.1+、`ext-gd`、`ext-json`。Redis 使用本机已安装的 `phpredis` 或 `predis`,在配置里用 `redis.client` 选择。 默认原图目录是包内 `captcha/in/image`,里面只放 jpg、png、webp,并且保持正放。 ## 配置 Hyperf: ```bash php bin/hyperf.php vendor:publish image-validation/rotate-captcha ``` 生成 `config/autoload/rotate_captcha.php`。 Webman: ```bash mkdir -p config/plugin/image-validation/rotate-captcha cp vendor/image-validation/rotate-captcha/publish/rotate_captcha.php config/plugin/image-validation/rotate-captcha/rotate_captcha.php ``` PHP-FPM: ```bash mkdir -p config cp vendor/image-validation/rotate-captcha/publish/rotate_captcha.php config/rotate_captcha.php ``` FPM 使用的 `php.ini` 要启用 `gd`。`redis.client` 为 `phpredis` 时还要启用 `redis` 扩展。可以用 FPM 对应的 `php -m` 确认,它和命令行 PHP 不一定是同一份配置。 业务侧要改的主要是这三项: ```php 'redis' => [ 'client' => 'phpredis', // phpredis 或 predis 'host' => '127.0.0.1', 'port' => 6379, 'username' => '', 'password' => '', 'database' => 0, 'timeout' => 2.0, 'prefix' => 'rotate_captcha:', ], // 出图时顺时针旋转的度数,每次在闭区间内随机取一个角度 'rotate_min' => 30, 'rotate_max' => 330, // 扶正后与正确角度相差在这个度数以内算通过 'verify_degrees' => 10, ``` `rotate_min` 与 `rotate_max` 写成同一个数时,每次都转这个固定度数。`image_dir` 为 `null` 时使用包内 `captcha/in/image`。 ## 调用 ```php use ImageValidation\RotateCaptcha\Exception\PassException; use ImageValidation\RotateCaptcha\Exception\VerifyException; $result = $captcha->create('sms', $phone); // $result['token'] // $result['image'] try { $passed = $captcha->verify($token, (float) $angle); // $passed['pass_token'] // $passed['expires_in'] } catch (VerifyException $e) { // 未通过。$e->remaining() 为剩余次数,0 表示需要重新 create } try { $captcha->assertPass($passToken, 'sms', $phone); // 通过后再发送验证码 } catch (PassException $e) { // 通行证无效、已使用,或与场景、手机号不一致 } ``` 用户提交的 `angle` 是为了扶正而顺时针转过的角度。同一张图默认最多校验 3 次。失败结果里只有剩余次数,没有角度差。通行证默认 60 秒,使用一次后失效,并且绑定 `scene` 和手机号或邮箱。 ### Hyperf 发布配置后,容器里可以直接注入 `ImageValidation\RotateCaptcha\RotateCaptcha`。 ### Webman ```php use ImageValidation\RotateCaptcha\Webman\RotateCaptchaProvider; $captcha = RotateCaptchaProvider::make(); ``` `make()` 读取 `config/plugin/image-validation/rotate-captcha/rotate_captcha.php`。也可以传入配置数组。 ### PHP-FPM 在站点入口引入 Composer 自动加载,用配置文件创建实例。每个请求新建一次即可,不需要常驻进程。 ```php create((string) $payload['scene'], (string) $payload['target'])); return; } if ($action === 'verify') { try { echo json_encode($captcha->verify((string) $payload['token'], (float) $payload['angle'])); } catch (VerifyException $e) { http_response_code(422); echo json_encode(['message' => $e->getMessage(), 'remaining' => $e->remaining()]); } return; } if ($action === 'send') { try { $captcha->assertPass((string) $payload['pass_token'], 'sms', (string) $payload['phone']); // 通过后再调用原来的短信发送 echo json_encode(['ok' => true]); } catch (PassException $e) { http_response_code(422); echo json_encode(['message' => $e->getMessage()]); } } ``` Nginx 把该文件交给 `php-fpm` 即可,例如 `/captcha.php?action=create`。路由仍由业务自己定,SDK 不注册接口。 ## 前端示例 滑块松手再提交角度。拖动过程中只用 CSS 旋转预览。 配合前端 [front-image-validation/rotate-captcha](https://gitee.com/changrui_com/front-image-validation) 使用的前端组件。弹窗里拖动左侧滑块,把圆形图片转正。松手后才提交角度。手机和 PC 都能拖。 组件不发请求地址,由业务传入 `create` 和 `verify`。验证通过后抛出 `passToken`,页面再去发验证码。 ## 安装 ```bash npm install front-image-validation ``` Vue 3 项目需要已安装 `vue@3`。 ## Vue 3 ```vue ``` `create` 返回 `{ token, image }`,`image` 是后端给出的 `data:image/png;base64,...`。`verify` 成功返回 `{ pass_token, expires_in }`。失败时抛出带 `remaining` 的错误。剩余次数为 `0`,或消息里包含「失效」时,组件会自动重新拉图。 ## uni-app 使用 Vue 3。页面里: ```vue ``` 小程序里用手指拖滑块。H5 上鼠标和触摸都可以。意见反馈用同名插槽 `feedback`,不传就不显示。 ## 属性 | 属性 | 说明 | | --- | --- | | `open` / `v-model:open` | 是否显示弹窗 | | `scene` | 场景,例如 `sms` | | `target` | 手机号或邮箱 | | `create` | `(scene, target) => Promise<{ token, image }>` | | `verify` | `(token, angle) => Promise<{ pass_token, expires_in }>` | | `title` | 默认「安全验证」 | | `subtitle` | 默认「请完成下方验证后继续操作」 | | `hint` | 默认「拖动左侧滑块使图片为正」 | 滑块最左是 0°,最右是 360°,提交的是顺时针角度。点遮罩不会关闭,点右上角关闭。