一,通過composer安裝think-captcha擴展包
1,命令:
~~~
liuhongdi@lhdpc:/data/php/admapi$ composer require topthink/think-captcha
~~~
說明:我們不直接使用這個擴展,只是用它帶來的字體文件
2,在項目中查看:

## 二,編寫php代碼
1,lib/util/captcode.php
[](javascript:void(0); "復制代碼")
~~~
<?php
namespace app\lib\util;
use think\Config;
use think\facade\Cache;
use think\Session;
class captcode {
/**
* @var Config|null
*/
private $config = null;
/**
* @var Session|null
*/
private $session = null;
// 驗證碼字符集合
protected $codeSet = '2345678abcdefhijkmnpqrstuvwxyzABCDEFGHJKLMNPQRTUVWXY';
// 驗證碼過期時間(s)
protected $expire = 1800;
// 使用中文驗證碼
protected $useZh = false;
// 中文驗證碼字符串
protected $zhSet = '們以我到他會作時要動國產的一是工就年階義發成部民可出能方進在了不和有大這主中人上為來分生對于學下級地個用同行面說種過命度革而多子后自社加小機也經力線本電高量長黨得實家定深法表著水理化爭現所二起政三好十戰無農使性前等反體合斗路圖把結第里正新開論之物從當兩些還天資事隊批點育重其思與間內去因件日利相由壓員氣業代全組數果期導平各基或月毛然如應形想制心樣干都向變關問比展那它最及外沒看治提五解系林者米群頭意只明四道馬認次文通但條較克又公孔領軍流入接席位情運器并飛原油放立題質指建區驗活眾很教決特此常石強極土少已根共直團統式轉別造切九你取西持總料連任志觀調七么山程百報更見必真保熱委手改管處己將修支識病象幾先老光專什六型具示復安帶每東增則完風回南廣勞輪科北打積車計給節做務被整聯步類集號列溫裝即毫知軸研單色堅據速防史拉世設達爾場織歷花受求傳口斷況采精金界品判參層止邊清至萬確究書術狀廠須離再目海交權且兒青才證低越際八試規斯近注辦布門鐵需走議縣兵固除般引齒千勝細影濟白格效置推空配刀葉率述今選養德話查差半敵始片施響收華覺備名紅續均藥標記難存測士身緊液派準斤角降維板許破述技消底床田勢端感往神便賀村構照容非搞亞磨族火段算適講按值美態黃易彪服早班麥削信排臺聲該擊素張密害侯草何樹肥繼右屬市嚴徑螺檢左頁抗蘇顯苦英快稱壞移約巴材省黑武培著河帝僅針怎植京助升王眼她抓含苗副雜普談圍食射源例致酸舊卻充足短劃劑宣環落首尺波承粉踐府魚隨考刻靠夠滿夫失包住促枝局菌桿周護巖師舉曲春元超負砂封換太模貧減陽揚江析畝木言球朝醫校古呢稻宋聽唯輸滑站另衛字鼓剛寫劉微略范供阿塊某功套友限項余倒卷創律雨讓骨遠幫初皮播優占死毒圈偉季訓控激找叫云互跟裂糧粒母練塞鋼頂策雙留誤礎吸阻故寸盾晚絲女散焊功株親院冷徹彈錯散商視藝滅版烈零室輕血倍缺厘泵察絕富城沖噴壤簡否柱李望盤磁雄似困鞏益洲脫投送奴側潤蓋揮距觸星松送獲興獨官混紀依未突架寬冬章濕偏紋吃執閥礦寨責熟穩奪硬價努翻奇甲預職評讀背協損棉侵灰雖矛厚羅泥辟告卵箱掌氧恩愛停曾溶營終綱孟錢待盡俄縮沙退陳討奮械載胞幼哪剝迫旋征槽倒握擔仍呀鮮吧卡粗介鉆逐弱腳怕鹽末陰豐霧冠丙街萊貝輻腸付吉滲瑞驚頓擠秒懸姆爛森糖圣凹陶詞遲蠶億矩康遵牧遭幅園腔訂香肉弟屋敏恢忘編印蜂急拿擴傷飛露核緣游振操央伍域甚迅輝異序免紙夜鄉久隸缸夾念蘭映溝乙嗎儒殺汽磷艱晶插埃燃歡鐵補咱芽永瓦傾陣碳演威附牙芽永瓦斜灌歐獻順豬洋腐請透司危括脈宜笑若尾束壯暴企菜穗楚漢愈綠拖牛份染既秋遍鍛玉夏療尖殖井費州訪吹榮銅沿替滾客召旱悟刺腦措貫藏敢令隙爐殼硫煤迎鑄粘探臨薄旬善福縱擇禮愿伏殘雷延煙句純漸耕跑澤慢栽魯赤繁境潮橫掉錐希池敗船假亮謂托伙哲懷割擺貢呈勁財儀沉煉麻罪祖息車穿貨銷齊鼠抽畫飼龍庫守筑房歌寒喜哥洗蝕廢納腹乎錄鏡婦惡脂莊擦險贊鐘搖典柄辯竹谷賣亂虛橋奧伯趕垂途額壁網截野遺靜謀弄掛課鎮妄盛耐援扎慮鍵歸符慶聚繞摩忙舞遇索顧膠羊湖釘仁音跡碎伸燈避泛亡答勇頻皇柳哈揭甘諾概憲濃島襲誰洪謝炮澆斑訊懂靈蛋閉孩釋乳巨徒私銀伊景坦累勻霉杜樂勒隔彎績招紹胡呼痛峰零柴簧午跳居尚丁秦稍追梁折耗堿殊崗挖氏刃劇堆赫荷胸衡勤膜篇登駐案刊秧緩凸役剪川雪鏈漁啦臉戶洛孢勃盟買楊宗焦賽旗濾硅炭股坐蒸凝竟陷槍黎救冒暗洞犯筒您宋弧爆謬涂味津臂障褐陸啊健尊豆拔莫抵桑坡縫警挑污冰柬嘴啥飯塑寄趙喊墊丹渡耳刨虎筆稀昆浪薩茶滴淺擁穴覆倫娘噸浸袖珠雌媽紫戲塔錘震歲貌潔剖牢鋒疑霸閃埔猛訴刷狠忽災鬧喬唐漏聞沈熔氯荒莖男凡搶像漿旁玻亦忠唱蒙予紛捕鎖尤乘烏智淡允叛畜俘摸銹掃畢璃寶芯爺鑒秘凈蔣鈣肩騰枯拋軌堂拌爸循誘祝勵肯酒繩窮塘燥泡袋朗喂鋁軟渠顆慣貿糞綜墻趨彼屆墨礙啟逆卸航衣孫齡嶺騙休借';
// 驗證碼位數
protected $length = 4;
//算術驗證碼
protected $math = false;
/**
* 創建驗證碼
* @return array
* @throws Exception
*/
public function generate(): array
{
$bag = '';
if ($this->math) {
$this->useZh = false;
$this->length = 5;
$x = random_int(10, 30);
$y = random_int(1, 9);
$bag = "{$x} + {$y} = ";
$key = $x + $y;
$key .= '';
} else {
if ($this->useZh) {
$characters = preg_split('/(?<!^)(?!$)/u', $this->zhSet);
} else {
$characters = str_split($this->codeSet);
}
for ($i = 0; $i < $this->length; $i++) {
$bag .= $characters[rand(0, count($characters) - 1)];
}
$key = mb_strtolower($bag, 'UTF-8');
}
$key = uniqid().mt_rand(1000,9999);
return [
'value' => $bag,
'key' => $key,
];
}
/**
* 驗證驗證碼是否正確
* @access public
* @param string $code 用戶驗證碼
* @return bool 用戶驗證碼是否正確
*/
public function check(string $code,string $key)
{
$cacheCode = Cache::get($key);
if(!$cacheCode){
return ['code'=>400,"msg"=>'驗證碼失效了'];
}
if(mb_strtolower($cacheCode) == mb_strtolower($code)){
Cache::delete($key);
return ['code'=>200,'msg'=>'驗證成功'];
}
return ['code'=>400,'msg'=>'驗證碼錯誤'];
}
}
~~~
2,lib/util/captcha.php
~~~
<?php
namespace app\lib\util;
use app\result\Result;
use think\facade\Cache;
use think\Response;
class captcha {
private $im = null; // 驗證碼圖片實例
private $color = null; // 驗證碼字體顏色
// 使用背景圖片
protected $useImgBg = false;
// 驗證碼字體大小(px)
protected $fontSize = 25;
// 是否畫混淆曲線
protected $useCurve = true;
// 是否添加雜點
protected $useNoise = true;
// 驗證碼圖片高度
protected $imageH = 0;
// 驗證碼圖片寬度
protected $imageW = 0;
// 驗證碼字體,不設置隨機獲取
protected $fontttf = '';
// 背景顏色
protected $bg = [243, 251, 254];
// 使用中文驗證碼
protected $useZh = false;
// 驗證碼位數
protected $length = 4;
//算術驗證碼
protected $math = false;
/**
* 輸出驗證碼
* @access public
* @param null|string $config
* @param bool $api
* @return Response
*/
public function create($generator)
{
$config = [
// 驗證碼字體大小
'fontSize' => 80,
// 驗證碼位數
'length' => 4,
// 關閉驗證碼雜點
'useNoise' => true,
];
$key = $generator['key'];
// 圖片寬(px)
$this->imageW || $this->imageW = $this->length * $this->fontSize * 1.5 + $this->length * $this->fontSize / 2;
// 圖片高(px)
$this->imageH || $this->imageH = $this->fontSize * 2.5;
// 建立一幅 $this->imageW x $this->imageH 的圖像
$this->im = imagecreate(intval($this->imageW), intval($this->imageH));
// 設置背景
imagecolorallocate($this->im, $this->bg[0], $this->bg[1], $this->bg[2]);
// 驗證碼字體隨機顏色
$this->color = imagecolorallocate($this->im, mt_rand(1, 150), mt_rand(1, 150), mt_rand(1, 150));
// 驗證碼使用隨機字體
$ttfPath = root_path().'/vendor/topthink/think-captcha/assets/' . ($this->useZh ? 'zhttfs' : 'ttfs') . '/';
if (empty($this->fontttf)) {
$dir = dir($ttfPath);
$ttfs = [];
while (false !== ($file = $dir->read())) {
if ('.' != $file[0] && substr($file, -4) == '.ttf') {
$ttfs[] = $file;
}
}
$dir->close();
$this->fontttf = $ttfs[array_rand($ttfs)];
}
$fontttf = $ttfPath . $this->fontttf;
if ($this->useImgBg) {
$this->background();
}
if ($this->useNoise) {
// 繪雜點
$this->writeNoise();
}
if ($this->useCurve) {
// 繪干擾線
$this->writeCurve();
}
// 繪驗證碼
$text = $this->useZh ? preg_split('/(?<!^)(?!$)/u', $generator['value']) : str_split($generator['value']); // 驗證碼
foreach ($text as $index => $char) {
//mt_rand(1.2, 1.6) *
$x = $this->fontSize * ($index + 1) * ($this->math ? 1 : 1.5);
$y = $this->fontSize + mt_rand(10, 20);
$angle = $this->math ? 0 : mt_rand(-40, 40);
imagettftext($this->im, $this->fontSize, $angle, intval($x), intval($y), intval($this->color), $fontttf, $char);
}
ob_start();
// 輸出圖像
imagepng($this->im);
$content = ob_get_clean();
imagedestroy($this->im);
$base64 = chunk_split(base64_encode($content));
$data = [
"key"=>$key,
"image"=>"data:image/jpg/png/gif;base64,".$base64,
//"code"=>$generator['value'],
];
return $data;
}
/**
* 畫一條由兩條連在一起構成的隨機正弦函數曲線作干擾線(你可以改成更帥的曲線函數)
*
* 高中的數學公式咋都忘了涅,寫出來
* 正弦型函數解析式:y=Asin(ωx+φ)+b
* 各常數值對函數圖像的影響:
* A:決定峰值(即縱向拉伸壓縮的倍數)
* b:表示波形在Y軸的位置關系或縱向移動距離(上加下減)
* φ:決定波形與X軸位置關系或橫向移動距離(左加右減)
* ω:決定周期(最小正周期T=2π/∣ω∣)
*
*/
protected function writeCurve(): void
{
$px = $py = 0;
// 曲線前部分
$A = mt_rand(1, intval($this->imageH / 2)); // 振幅
$b = mt_rand(intval(-$this->imageH / 4), intval($this->imageH / 4)); // Y軸方向偏移量
$f = mt_rand(intval(-$this->imageH / 4), intval($this->imageH / 4)); // X軸方向偏移量
$T = mt_rand(intval($this->imageH), intval($this->imageW * 2)); // 周期
$w = (2 * M_PI) / $T;
$px1 = 0; // 曲線橫坐標起始位置
$px2 = mt_rand(intval($this->imageW / 2), intval($this->imageW * 0.8)); // 曲線橫坐標結束位置
for ($px = $px1; $px <= $px2; $px = $px + 1) {
if (0 != $w) {
$py = $A * sin($w * $px + $f) + $b + $this->imageH / 2; // y = Asin(ωx+φ) + b
$i = (int) ($this->fontSize / 5);
while ($i > 0) {
imagesetpixel($this->im, intval($px + $i), intval($py + $i), intval($this->color));
$i--;
}
}
}
// 曲線后部分
$A = mt_rand(1, intval($this->imageH / 2)); // 振幅
$f = mt_rand(intval(-$this->imageH / 4), intval($this->imageH / 4)); // X軸方向偏移量
$T = mt_rand(intval($this->imageH), intval($this->imageW * 2)); // 周期
$w = (2 * M_PI) / $T;
$b = $py - $A * sin($w * $px + $f) - $this->imageH / 2;
$px1 = $px2;
$px2 = $this->imageW;
for ($px = $px1; $px <= $px2; $px = $px + 1) {
if (0 != $w) {
$py = $A * sin($w * $px + $f) + $b + $this->imageH / 2; // y = Asin(ωx+φ) + b
$i = (int) ($this->fontSize / 5);
while ($i > 0) {
imagesetpixel($this->im, intval($px + $i), intval($py + $i), intval($this->color));
$i--;
}
}
}
}
/**
* 畫雜點
* 往圖片上寫不同顏色的字母或數字
*/
protected function writeNoise(): void
{
$codeSet = '2345678abcdefhijkmnpqrstuvwxyz';
for ($i = 0; $i < 10; $i++) {
//雜點顏色
$noiseColor = imagecolorallocate($this->im, mt_rand(150, 225), mt_rand(150, 225), mt_rand(150, 225));
for ($j = 0; $j < 5; $j++) {
// 繪雜點
imagestring($this->im, 5, mt_rand(-10, intval($this->imageW)), mt_rand(-10, intval($this->imageH)), $codeSet[mt_rand(0, 29)], $noiseColor);
}
}
}
/**
* 繪制背景圖片
* 注:如果驗證碼輸出圖片比較大,將占用比較多的系統資源
*/
protected function background(): void
{
$path = __DIR__ . '/../assets/bgs/';
$dir = dir($path);
$bgs = [];
while (false !== ($file = $dir->read())) {
if ('.' != $file[0] && substr($file, -4) == '.jpg') {
$bgs[] = $path . $file;
}
}
$dir->close();
$gb = $bgs[array_rand($bgs)];
list($width, $height) = @getimagesize($gb);
// Resample
$bgImage = @imagecreatefromjpeg($gb);
@imagecopyresampled($this->im, $bgImage, 0, 0, 0, 0, $this->imageW, $this->imageH, $width, $height);
@imagedestroy($bgImage);
}
}
~~~
3,controller/Article.php
~~~
<?php
declare (strict_types = 1);
namespace app\controller;
use app\BaseController;
use app\lib\util\captcha;
use app\result\Result;
use think\Request;
use think\facade\Cache;
use app\model\Article as ArticleModel;
use Exception;
use think\Config;
use think\Response;
use think\Session;
//use think\facade\Cache;
use app\lib\util\captcode;
class Article extends BaseController
{
/**
* 生成驗證碼
*
* @return \think\Response
*/
public function captcha() {
$code = new captcode();
$generator = $code->generate();
//var_dump($generator);
$capt = new captcha();
$image = $capt->create($generator);
Cache::set($generator['key'],$generator['value'],300);
//var_dump($image);
return Result::Success($image);
}
/**
* 檢查驗證碼是否正確
*
* @return \think\Response
*/
public function captcheck() {
//得到參數
$code = $this->request->param("captcha");
$key = $this->request->param("key");
//比較
$ccode = new captcode();
$resCheck = $ccode->check($code,$key);
if ($resCheck['code'] == 200) {
return Result::Success("驗證成功");
} else {
return Result::Error($resCheck['code'],$resCheck['msg']);
}
}
}
~~~
## 三,編寫vue代碼
1,Captcha.vue
~~~
<template>
<div style="text-align: center;">
<img ref="imgRef" @click="getCaptcha" :src="captData.image" /><br/>
<input id="captInput" v-model="captValue" type="text" placeholder="請輸入驗證碼" style="width:392px;margin-top:10px;font-size:16px;" /><br/>
<!--v-loading.fullscreen.lock="isLoading"-->
<div @click="authcapt" style="margin:0px auto;margin-top:10px;width: 400px;height:40px;line-height:40px;background: #ff0000;border-radius: 10px;">
登錄
</div>
</div>
</template>
<script>
import { ref} from "vue";
import {ElMessage} from "element-plus";
import {apiCaptcha, apiCaptCheck} from "../api/api";
export default {
name: "Captcha",
setup() {
const imgRef = ref(null);
const captData = ref([]);
const captValue = ref("");
const getCaptcha = () => {
apiCaptcha().then(res => {
//成功
if (res.code == 0) {
console.log(res.data);
captData.value = res.data;
} else {
ElMessage.error("獲取驗證碼失敗:"+res.msg);
}
}).catch((error) => {
console.log(error)
})
}
getCaptcha();
const authcapt=()=> {
//alert("當前輸入的驗證碼是:"+captValue.value);
if (captValue.value.length < 4) {
alert("驗證碼長度不可小于4");
document.getElementById('captInput').focus();
return;
}
var data = new FormData();
data.append("key",captData.value.key);
data.append("captcha",captValue.value);
apiCaptCheck(data).then(res => {
//成功
if (res.code == 0) {
//保存jwt token到本地
//localStorage.setItem('token', res.data.token);
//提示
ElMessage.success("驗證成功!");
} else {
ElMessage.error("驗證失敗:"+res.msg);
}
}).catch((error) => {
console.log(error)
})
}
return {
imgRef,
captData,
captValue,
authcapt,
//reloadCapt,
}
}
}
</script>
<style scoped>
</style>
~~~
2,api.js
~~~
//get,
import { get, postForm} from './axios'
//user
export const apiCaptcha = pCaptcha => get('/api/article/captcha', pCaptcha)
export const apiCaptCheck = pCaptCheck => postForm('/api/article/captcheck', pCaptCheck)
~~~
## 四,測試效果

- thinkphp6執行流程(一)
- php中use關鍵字用法詳解
- Thinkphp6使用騰訊云發送短信步驟
- 路由配置
- Thinkphp6,static靜態資源訪問路徑問題
- ThinkPHP6.0+ 使用Redis 原始用法
- smarty在thinkphp6.0中的最佳實踐
- Thinkphp6.0 搜索器使用方法
- 從已有安裝包(vendor)恢復 composer.json
- tp6with的用法,表間關聯查詢
- thinkphp6.x多對多如何添加中間表限制條件
- thinkphp6 安裝JWT
- 緩存類型
- 請求信息和HTTP頭信息
- 模型事件用法
- 助手函數匯總
- tp6集成Alipay 手機和電腦端支付的方法
- thinkphp6使用jwt
- 6.0session cookie cache
- tp6筆記
- TP6(thinkphp6)隊列與延時隊列
- thinkphp6 command(自定義指令)
- command(自定義指令)
- 本地文件上傳
- 緩存
- 響應
- 公共函數配置
- 七牛云+文件上傳
- thinkphp6:訪問多個redis數據源(thinkphp6.0.5 / php 7.4.9)
- 富文本編輯器wangEditor3
- IP黑名單
- 增刪改查 +文件上傳
- workerman 定時器操作控制器的方法
- 上傳文件到阿里云oss
- 短信或者郵箱驗證碼防刷代碼
- thinkphp6:訪問redis6(thinkphp 6.0.9/php 8.0.14)
- 實現關聯多個id以逗號分開查詢數據
- thinkphp6實現郵箱注冊功能的細節和代碼(點擊鏈接激活方式)
- 用mpdf生成pdf文件(php 8.1.1 / thinkphp v6.0.10LTS )
- 生成帶logo的二維碼(php 8.1.1 / thinkphp v6.0.10LTS )
- mysql數據庫使用事務(php 8.1.1 / thinkphp v6.0.10LTS)
- 一,創建過濾IP的中間件
- 源碼解析請求流程
- 驗證碼生成
- 權限管理
- 自定義異常類
- 事件監聽event-listene
- 安裝與使用think-addons
- 事件與多應用
- Workerman 基本使用
- 查詢用戶列表按拼音字母排序
- 擴展包合集
- 查詢用戶數據,但是可以通過輸入用戶昵稱來搜索用戶同時還要統計用戶的文章和粉絲數
- 根據圖片的minetype類型獲取文件真實拓展名思路
- 到處excel
- 用imagemagick庫生成縮略圖
- 生成zip壓縮包并下載
- API 多版本控制
- 用redis+lua做限流(php 8.1.1 / thinkphp v6.0.10LTS )
- 【thinkphp6源碼分析三】 APP類之父, 容器Container類
- thinkphp6表單重復提交解決辦法
- 小程序授權
- 最簡單的thinkphp6導出Excel
- 根據訪問設備不同訪問不同模塊
- 服務系統
- 前置/后置中間件
- 給接口api做簽名驗證(php 8.1.1 / thinkphp v6.0.10LTS )
- 6實現郵箱注冊功能的細節和代碼(點擊鏈接激活方式)
- 使用前后端分離的驗證碼(thinkphp 6.0.9/php 8.0.14/vue 3.2.26)
- 前后端分離:用jwt+middleware做用戶登錄驗證(php 8.1.1 / thinkphp v6.0.10LTS )
- vue前后端分離多圖上傳
- thinkphp 分組、頁面跳轉與ajax
- thinkphp6 常用方法文檔
- 手冊里沒有的一些用法
- Swagger 3 API 注釋
- PHP 秒級定時任務
- thinkphp6集成gatewayWorker(workerman)實現實時監聽
- thinkphp6按月新增數據表
- 使用redis 實現消息隊列
- api接口 統一結果返回處理類
- 使用swoole+thinkphp6.0+redis 結合開發的登錄模塊
- 給接口api做簽名驗證
- ThinkPHP6.0 + UniApp 實現小程序的 微信登錄
- ThinkPHP6.0 + Vue + ElementUI + axios 的環境安裝到實現 CURD 操作!
- 異常$e
- 參數請求驗證自定義和異常錯誤自定義