---
# System prepended metadata

title: Laravel 密碼檢查通用Rule
tags: [PHP, Laravel 5.8]

---

# Laravel 密碼檢查通用Rule

###### tags: `PHP` `Laravel 5.8`

---
* **目的**
因應各種不同專案時，每個客戶往往對於密碼設置有不同的要求，但是實際分析，密碼規則也往往通常是那幾種條件，故有調整成可設定性的方向開發，希望以後有遇到時，能直接重複使用ＸＤ。（當然，依照需求的不同，可以視情況新增修改規則）

* **程式碼**
以下就先廢話不多說，直接上CODE(使用Laravel Validation Rule的方式)

```php 
<?php


namespace App\Rules;


use Illuminate\Contracts\Validation\Rule;

/**
 * 密碼檢查使用
 * (schema 可視情況調整)
 *
 * Class PasswordValidation
 * @package App\Rules
 */
class PasswordValidation implements Rule
{
    /**
     * @var int 最少的密碼長度
     */
    protected $lengthLimit = 8;

    /**
     * @var bool 是否檢查與帳號不能相同
     */
    protected $checkNotSameAsAccount = true;
    /**
     * @var string 如果 $checkNotSameAsAccount = true 時 為必填
     */
    protected $accountValue = '';

    /**
     * @var bool 是否檢查至少要一個 大寫英文
     */
    protected $checkRequiredUppercase = true;

    /**
     * @var bool 是否檢查至少要一個 小寫英文
     */
    protected $checkRequiredLowercase = true;

    /**
     * @var bool 是否檢查至少要一個 數字
     */
    protected $checkRequiredNumber = true;

    /**
     * @var bool 是否檢查至少要一個 特殊符號
     */
    protected $checkRequiredSpecialSymbol = true;

    protected $errorMsg = '';

    public function __construct(array $setting = [])
    {
        // 可以客製化調整
        if ($setting) {
            foreach ($setting as $key => $value) {
                if (property_exists(self::class, $key)) {
                    $this->$key = $value;
                }
            }
        }
    }

    public function passes($attribute, $value)
    {
        if (is_integer($this->lengthLimit) && $this->lengthLimit > 0) {
            if (!preg_match('/^.{' . $this->lengthLimit . ',}$/', $value)) {
                $this->errorMsg = '密碼需要至少' . $this->lengthLimit . '個字元';
                return false;
            }
        }

        if ($this->checkNotSameAsAccount === true) {
            if (!$this->accountValue || !is_string($this->accountValue)) {
                throw new \Exception('檢查帳號與密碼不能相同時，需要帳號資訊');
            }

            if ($this->accountValue === $value) {
                $this->errorMsg = '密碼不能與帳號相同';
                return false;
            }
        }

        if ($this->checkRequiredUppercase === true) {
            if (!preg_match('/[A-Z]{1}/', $value)) {
                $this->errorMsg = '密碼需要至少1個大寫英文字母';
                return false;
            }
        }

        if ($this->checkRequiredLowercase === true) {
            if (!preg_match('/[a-z]{1}/', $value)) {
                $this->errorMsg = '密碼需要至少1個小寫英文字母';
                return false;
            }
        }

        if ($this->checkRequiredNumber === true) {
            if (!preg_match('/[0-9]{1}/', $value)) {
                $this->errorMsg = '密碼需要至少1個數字';
                return false;
            }
        }

        if ($this->checkRequiredSpecialSymbol === true) {
            if (!preg_match('/[@$!%*?&]{1}/', $value)) {
                $this->errorMsg = '密碼需要至少1個特殊字元';
                return false;
            }
        }

        return true;
    }

    public function message()
    {
        $msg = '密碼格式不正確' . ($this->errorMsg ? '：' . $this->errorMsg : '');
        return $msg;
    }
}

```

* **目前檢查規則**
1. 密碼長度
2. 密碼設定可否與帳號相同
3. 密碼是否需要至少一個「大寫英文」
4. 密碼是否需要至少一個「小寫英文」
5. 密碼是否需要至少一個「數字」
6. 密碼是否需要至少一個「特殊符號」（目前允許特殊符號：@$!%*?&）

* **使用方式**
1. Validation，寫在Request時
![](https://i.imgur.com/bWLUzPx.png)
2. 直接用Validation檢查(e.g. 可以使用在Observer，Model saving的event中)
![](https://i.imgur.com/Ha1TMGK.png)
3. 客製化調整，可於創建式時，設置檢查開關（預設值為全部都開啟）(e.g. 不檢查第二點帳號和第五點數字，如下圖)
![](https://i.imgur.com/FAsDU1K.png)


* **注意事項**
1. 「密碼設定可否與帳號相同」需要帶入帳號（accountValue）的參數，可於創建式時帶入
2. 「密碼長度」，目前只有最小字元數（最大字元數需視TABLE SCHEMA調整）
3. 預設值檢查為全部都開啟


---
* **小結**
希望能夠看是否能幫助到人ＸＤ，以及自己未來能夠使用，也希望如果有什麼想法能夠也回饋給筆者，像是有什麼更良好的架構使用方式...等，或者是調整方向（包裝成package之類）ＸＤ。
乾蝦乾蝦:)。