Сменить изображение с определённым углом поворота для проверки подлинности, используя PHP для генерации проверочных изображений (gd или imagick) для поворота проверочного изображения. Может использоваться в различных фреймворках.
Фронтенд уже поддерживает нативные JS, jquery, vue2, uniapp версии и продолжает обновляться. Можно смело использовать.
Версия для react пока не реализована, но вы можете попробовать реализовать её самостоятельно, опираясь на существующую версию.
Известно, что uniapp упаковывает приложение WeChat (iOS имеет проблемы с зависанием, надеемся, что кто-то сможет это исправить, у меня нет устройства, чтобы воспроизвести проблему).
Если вы обнаружите ошибку или у вас есть лучшие предложения, пожалуйста, сообщите об этом через issue.
2021-09-10 Новое
2021-09-16 Новое
2021-09-17 Новое
2021-09-19 Обновление
2021-09-20 Обновление
2021-09-22 Обновление
2021-09-23 Обновление
2021-09-24 Обновление
2021-09-25 Обновление
2021-09-26 Обновление
2021-10-07 Обновление
2021-10-20 Обновление
2022-01-05 Обновление
2022-09-12 Обновление
Используется для тестирования, эта часть может самостоятельно загружать весь материал из библиотеки в базу данных или кэш, в общем, очень гибко.
$list = [
'1.png',
'2.png',
'1.jpg',
'2.jpg',
'3.jpg',
'4.jpg',
'5.jpg',
'6.jpg',
'7.jpg',
'8.jpg',
'9.jpg',
];
// upload_path нужно написать самому
// Случайно взять одно изображение
$key = array_rand($list, 1);
if (isset($list[$key])) {
// Взять изображение из каталога хранения материалов
$image = upload_path('captcha_mtl') . $list[$key];
}
Примечание: метод upload_path
— это пользовательский метод, который зависит от используемого вами фреймворка и позволяет получить корневой каталог, где хранятся ваши материалы. Например, в фреймворке TP6 можно написать так:
function upload_path(string $path = ''): string
{
return public_path(DIRECTORY_SEPARATOR .'uploads' . DIRECTORY_SEPARATOR . ($path ? ltrim($path, DIRECTORY_SEPARATOR) : $path));
}
Новое: из указанного каталога случайным образом считывает файл. Неизвестна эффективность этого метода, он основан на классе FilesystemIterator.
$image = File::make(upload_path('captcha_mtl'))->rand();
Создаёт изображение для проверки.
// Устанавливает язык
$rotateCaptcha = RotateCaptcha::setLang('zh-cn');
$rotateCaptcha->create(...);
$data = RotateCaptcha::create(
$image,
upload_path('captcha') // Используется для хранения сгенерированного изображения
)->get(260); // 260 — конечный размер сгенерированного изображения.
if (!$data) {
$this->result(1, 'error');
}
// $data['str'] — путь к изображению с шифрованием, используется для обмена изображениями проверки на стороне клиента
// Здесь клиент не участвует в получении угла, всё отправляется на сервер для проверки
// Можно использовать заголовок для передачи токена X-Captchatoken
$this->result(0, 'success', ['str' => $data['str']], ['X-Captchatoken' => $data['token']]);
Проверка
public function verify(Request $request)
{
$angle = $request->get('angle');
// Предпочитает получать токен из заголовка
$token = $request->header('X-Captchatoken') ?: $request->get('token');
if (empty($token) || empty($angle)) {
$this->result(1, 'error');
}
try {
if (RotateCaptcha::check($token, $angle) === true) {
$this->result(0, 'success');
}
} catch (CaptchaException $e) {
$this->result(1, $e->getMessage());
}
$this->result(1, 'error');
}
Отображение изображения через клиент
public function img(Request $request)
{
$str = $request->get('id');
[$mime, $image] = RotateCaptcha::output($str, upload_path('captcha'));
if (empty($image)) {
return '';
}
return response($image, 200, [
'Cache-Control' => 'private, no-cache, no-store, must-revalidate',
'Content-Type' => $mime,
'Content-Length' => strlen($image)
]);
}
Возврат JSON
public function result(int|string $code = 0, string $msg = 'success', array|string $data, array $header = [])
{
$result = [
'code' => $code,
'data' => $data,
'msg' => lang($msg) ?: ($code > 0 ? 'error' : 'success'),
];
$response = Response::create($result, 'json')->code(200);
if (!empty($header)) {
$response = $response->header($header);
}
throw new \think\exception\HttpResponseException($response);
}
``` 10.jpg,
11.jpg,
12.jpg,
13.jpg;
$key = array_rand($list, 1);
if (isset($list[$key])) {
$image = $list[$key];
}
$image = path('upload') . 'captcha_mtl' . DIRECTORY_SEPARATOR . $image;
// 新增: 从指定目录随机读取文件,这个方法不知道效率如何,基于FilesystemIterator类实现
$image = File::make(path('upload') . 'captcha_mtl' . DIRECTORY_SEPARATOR)->rand();
$data = Captcha::configDrive(\CaptchaConfig::class)->create($image, path('upload') . 'captcha' . DIRECTORY_SEPARATOR)->get(260);
header('Content-Type:application/json; charset=utf-8');
if ($data) {
// 可以使用header传递token
header('X-CaptchaToken: '. $data['token']);
echo json_encode([
'code' => 0,
'msg' => 'success',
'data' => [/*'token' => $data['token'], */'str' => $data['str']],
]);
}
echo json_encode([
'code' => 1,
'msg' => 'error',
'data' => null,
]);
非thinkphp6框架,验证
use isszz\captcha\rotate\support\request\Request;
use isszz\captcha\rotate\CaptchaException;
use isszz\captcha\rotate\facade\Captcha;
class CaptchaConfig extends \isszz\captcha\rotate\Config
{
public function get(string $name, string $defaultValue = null): mixed
{
return \Config::get($name, $defaultValue);
}
public function put(string $name, array|string $data): bool
{
return \Config::put($name, $data);
}
public function forget(string $name): bool
{
return \Config::forget($name);
}
}
$angle = $_GET['angle'] ?? '';
// 优先从header获取token
$token = Request::header('X-Captchatoken') ?: $_GET['token'] ?? '';
if(empty($token) || empty($angle)) {
exit(json_encode(['code' => 1, 'msg' => 'error']));
}
try {
if(Captcha::configDrive(\CaptchaConfig::class)->setLang('zh-cn')->check($token, $angle) === true) {
exit(json_encode(['code' => 0, 'msg' => 'success']));
}
} catch(CaptchaException $e) {
exit(json_encode(['code' => 1, 'msg' => $e->getMessage()]));
}
exit(json_encode(['code' => 1, 'msg' => 'error']));
非thinkphp6框架,输出图片
<?php
use isszz\captcha\rotate\facade\Captcha;
$id = $_GET['id'] ?? null;
if(empty($id)) {
exit('');
}
[$mime, $image] = Captcha::output($id, upload_path('captcha'));
if(empty($image)) {
exit('');
}
header('Cache-Control: private, no-cache, no-store, must-revalidate');
// header('Content-Disposition: inline; filename=captcha_' . $id . '.' . str_replace('image/', '.', $mime));
header('Content-type: '. $mime);
header('Content-Length: '. strlen($image));
echo $image;
use isszz\captcha\rotate\Store;
use isszz\captcha\rotate\Config;
class CaptchaConfig extends Config
{
public function get(string $name, string $defaultValue = null): mixed
{
// 获取配置
return Config::get($name, $defaultValue);
}
public function put(string $name, array|string $data): bool
{
// 存储配置 - 暂时无用
return Config::put($name, $data);
}
public function forget(string $name): bool
{
// 删除配置 - 暂时无用
return Config::forget($name);
}
}
class CaptchaSessionStore extends Store
{
public function get(string $token): array
{
if(!Session::has($token)) {
return [];
}
$payload = Session::get($token);
if(empty($payload)) {
return [];
}
$payload = $this->encrypter->decrypt($payload);
if(empty($payload)) {
return [];
}
Session::forget($token);
return json_decode($payload, true);
}
public function put(?int $degrees): string
{
[$token, $payload] = $this->buildPayload($degrees);
// 存储token, 并设置token过期时间ttl
``` **Сессия::put($token, $payload, $this->ttl);**
**return $token;**
}
Это язык PHP.
Передняя конфигурация:
options = {
theme: '#07f', // Основной цвет проверки
title: 'Безопасная проверка',
desc: 'Перетащите ползунок, чтобы угол изображения был правильным',
width: 305, // Ширина окна проверки
successClose: 1500, // Время закрытия страницы после успешной проверки
timerProgressBar: !0, // Отображать ли индикатор выполнения после успешной проверки
timerProgressBarColor: '#07f', // Цвет индикатора выполнения
url: {
info: '/captcha', // Получить информацию о проверке
check: '/captcha/check', // Проверить
img: '/captcha/img', // Заменить изображение
},
init: function (captcha) {}, // Инициализация
success: function () {}, // Проверка успешна
fail: function () {}, // Проверка не удалась
complete: function (state) {}, // Вызвать проверку, независимо от успеха или неудачи
close: function (state) {} // Закрыть окно проверки и вернуть состояние проверки state
};
Использование на передней части:
// .J__captcha__ — это контейнер для вывода проверки
// Способ 1
let myCaptcha = document.querySelectorAll('.J__captcha__').item(0).captcha({
// Что показывать при успешной проверке
timerProgressBar: !0, // Использовать ли индикатор выполнения
timerProgressBarColor: '#07f', // Цвет индикатора выполнения
url: {
create: '/common/captcha/rotate', // Получить информацию о проверке
check: '/common/captcha/verify', // Проверить
img: '/common/captcha/img' // Заменить изображение
},
// Обратный вызов инициализации
init: function (captcha) {
// console.log(captcha);
},
// Успешный обратный вызов
success: function() {
console.log('Состояние проверки Captcha: успешно');
},
// Неудачный обратный вызов
fail: function() {
console.log('Состояние проверки Captcha: неудачно');
},
// Вызов проверки обратного вызова, независимо от успеха или неудачи
complete: function(state) {
console.log('Проверка Captcha завершена, состояние: ', state);
},
// Триггер проверки закрытия (необходимо закрыть после успешной проверки)
close: function(state) {
modal.close(); // Закрыть ваш modal
console.log('Закрыть проверку Captcha, состояние: ', state);
}
});
// Способ 2
let myCaptcha = new Captcha(document.querySelectorAll('.J__captcha__').item(0), {
// options аналогично...
});
// .J__captcha__ - это контейнер для вывода проверки
modal.element.find('.J__captcha__').captcha({
// options аналогично...
});
// Получить экземпляр Captcha
// var captcha = modal.element.find('.J__captcha__').data('captcha');
// console.log(captcha.state());
<template>
<div id="app">
<div @click="openCaptcha">
<img alt="Vue logo" src="./assets/logo.png">
<div>Открыть проверку</div>
</div>
<RoutateCaptcha :options="captchaOptions" v-if="captchaShow" @close="captchaShow = false" @init="captchaInit" @complete="captchaComplete" @success="captchaSuccess" @fail="captchaFail"></RoutateCaptcha>
</div>
</template>
<script>
// Путь к компоненту, здесь импортировать. Расположение компонента: js/vue/RoutateCaptcha
import RoutateCaptcha from './components/RoutateCaptcha/index.vue'
export default {
name: 'captchaDemo',
components: {
RoutateCaptcha
},
data() {
return {
captchaShow: false,
captchaOptions: {
theme: '#07f',
title: 'Безопасный чек',
desc: 'Перетащить ползунок, чтобы сделать угол изображения правильным',
successClose: 1500, // время закрытия страницы после успешного чека
timerProgressBar: true, // отображать ли индикатор прогресса после успешного чека
timerProgressBarColor: 'rgba(0, 0, 0, 0.2)',
request: {
// получить информацию о чеке
info: (callback) => {
this.getJSON('http://vmd.co/common/captcha/rotate', null, function(res, xhr) {
if(xhr.status != 200) {
alert('Система ошибка: '+ res.statusCode +', пожалуйста, закройте и попробуйте снова!');
return false
}
// Второй параметр передает токен из заголовка, если вам неудобно, вы можете вернуть токен в res
callback(res, xhr.getResponseHeader('X-CaptchaToken'))
})
},
// проверка, угол пользовательского вращения
check: (angle, token, callback) => {
// Установите токен хорошо, данные проверки передаются на серверную часть
// Конечно, этот запрос данных только для справки, фактическое использование должно соответствовать вашему собственному запросу данных
this.token = token
this.getJSON('http://vmd.co/common/captcha/verify', {angle: angle}, function(res, xhr) {
if(xhr.status != 200) {
alert('Системная ошибка: '+
``` Данный фрагмент представляет собой код на языке Vue.js, который описывает компонент для отображения и проверки капчи в приложении на платформе uniapp.
В коде описывается компонент с именем «rotate-captcha», который отображает вращающуюся капчу и предоставляет методы для взаимодействия с ней. Компонент принимает несколько параметров:
* «options» — объект с настройками капча (например, тема, заголовок, описание, время ожидания после успешной проверки и т. д.);
* «init» — функция, которая вызывается при инициализации капча;
* «close» — функция, вызываемая при закрытии капча;
* «complete» — функция, вызываемая после завершения проверки капча;
* «success» — функция, вызываемая в случае успешной проверки капча;
* «fail» — функция, вызываемая в случае неудачной проверки капча.
Компонент также содержит методы «captchaInit», «captchaSuccess», «captchaFail», которые вызываются при соответствующих событиях.
Код не содержит информации о том, как именно работает капча, но описывает её внешний вид и поведение.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )