Day26-從基礎學習 ThinkPHP-驗證碼

前言

這一篇將會來介紹 ThinkPHP 中的驗證碼功能,本身 ThinkPHP 就有提供驗證碼功能,如果沒有特別的需求的話,使用 ThinkPHP 本身內建驗證碼功能是滿足夠使用的。

起手式

由於 ThinkPHP 驗證碼這區塊是屬於擴展包,所以如果要在 ThinkPHP 中使用驗證碼功能,必須先透過 Composer 安裝 think-captcha,那麼我們打開 cmd 後移動到專案目錄輸入以下指令:

1
composer require topthink/think-captcha=2.0.*

安裝擴展包

使用方式

使用驗證碼的方式非常簡單,有兩種寫法可以使用,只需要在 HTML 模板裡面寫入就可以顯示驗證碼。

第一種寫法,透過 ThinkPHP 生成:

1
2
3
4
<div>
<div>{:captcha_img()}</div>
<input type="text" name="captcha" id="captcha" class="form-control" placeholder="captcha">
</div>

另一種則是使用 img 標籤的寫法,我個人推薦使用這個做法,因為這會攸關後面所講的東西:

1
2
3
4
<div>
<div><img src="{:captcha_src()}" alt="captcha" /></div>
<input type="text" name="captcha" id="captcha" class="form-control" placeholder="captcha">
</div>

這樣子我們就可以在前端畫面上看到驗證碼囉 ↓

驗證碼

另外接下來還有一個動作要做,當使用者若沒有填入驗證碼或是驗證碼輸入錯誤時,我們必須要提示錯誤訊息給使用者,所以這邊就要搭配表單驗證的功能,我們打開表單驗證的 validate/User.php,加入 captcha 驗證 & 錯誤提示訊息:

1
2
3
4
5
6
7
8
protected $rule = [
'captcha'=>'require|captcha'
];

protected $message = [
'captcha.require'=>'驗證碼必填',
'captcha.captcha'=>'驗證碼輸入錯誤',
];

這樣子就可以達到驗證碼錯誤訊息提示的效果了,當然這邊就讓我們實際測試送看看,首先是空白的驗證碼會發生何事 ↓

驗證碼必填

那如果我故意輸入的驗證碼呢?將會導致什麼錯誤訊息? ↓

驗證碼輸入錯誤

另外你也可以自定義驗證碼,例如驗證碼變成中文驗證、驗證碼大小、模糊度等等,但是這邊我就不多作介紹,詳細可以看官方手冊 → 連結

點擊驗證碼刷新

由於 ThinkPHP 提供的驗證碼並沒有點擊驗證碼刷新的功能,所以我這邊就提供一下我的作法,由於我有測試過使用 {:captcha_img()} 來製作點擊驗證碼刷新,但是有可能會發生沒有反應的問題,所以我個人推薦使用 img 標籤的作法:

1
2
3
4
5
<div>
<div><img src="{:captcha_src()}" alt="captcha" id="captchaImg" style="cursor: pointer;" title="刷新驗證碼"/></div>
<input type="text" name="captcha" id="captcha" class="form-control" placeholder="captcha">
<span class="text-danger">{$Request.session.error.captcha}</span>
</div>

這樣使用者在滑鼠移過去點擊驗證碼圖片時就會顯示 刷新驗證碼 的字樣 ↓

刷新驗證碼

接下來就是寫 JavaScript 來刷新驗證碼圖片,主要只需要重新賦予 captcha 驗證碼圖片路徑:

1
2
3
4
5
const captchaImg = document.getElementById('captchaImg');
captchaImg.addEventListener('click',(e) => {
e.preventDefault();
captchaImg.src = "/captcha";
})

這樣子就可以達到點擊驗證碼刷新囉~

最後提供一個超級簡化點擊驗證碼刷新縮寫版,只需要在 img 標籤再加入 onclick="this.src='{:captcha_src()}'" 即可搞定:

1
2
3
4
5
<div>
<div><img src="{:captcha_src()}" alt="captcha" id="captchaImg" style="cursor: pointer;" onclick="this.src='{:captcha_src()}'" title="刷新驗證碼"/></div>
<input type="text" name="captcha" id="captcha" class="form-control" placeholder="captcha">
<span class="text-danger">{$Request.session.error.captcha}</span>
</div>

定時刷新驗證碼

如果希望可以每 60 秒就會自動刷新驗證碼,只需要使用 setInterval() 就可以達到這個需求,這邊也提供給各位參考:

1
2
3
4
5
6
7
8
const captchaImg = document.getElementById('captchaImg');
captchaImg.addEventListener('click',(e) => {
e.preventDefault();
captchaImg.src = "/captcha";
})
window.setInterval(() => {
captchaImg.src = "/captcha";
},60000)

結尾

我在製作驗證碼的時候,其實是使用 <div>{:captcha_img()}</div> 的做法,但是後來為了要能夠點擊驗證碼刷新驗證碼時,就發現怎麼不能動?後來改寫 <div><img src="{:captcha_src()}" alt="captcha" id="captchaImg" style="cursor: pointer;"/></div> 就可以搞定這個問題,我想應該是因為 JavaScript 被載入時 {:captcha_img()} 驗證碼還沒被渲染完畢,導致 JavaScript 抓不到進而無法控制驗證碼。