首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

ThinkPHP 自動驗證失效排查指南:常見原因與解決方案

     編輯:PHP 綜合知識

ThinkPHP 2.x/3.x 的自動驗證(_validate)是模型層資料完整性的第一道防線。但實務上常遇到「驗證不生效」、「getError() 回傳空值」、「Token 驗證衝突」等問題。本文系統整理失效常見原因、除錯步驟與修正方案。

一、典型失效場景與原因

現象常見原因快速驗證
create() 總回傳 true,未驗證1. 模型類別未繼承 Model
2. _validate 陣列語法錯誤
3. 欄位名稱與表單 name 不符
var_dump($model->_validate) 檢查定義
create() 回傳 false 但 getError() 為空1. 驗證規則未匹配(條件參數錯誤)
2. create() 參數 '' 導致重置資料
3. 自動完成 _auto 衝突
加 var_dump($model->getError()) 即時看
重新整理出現「令牌表單錯誤」1. 表單缺少 {:token()} 隱藏欄位
2. Session 未啟動或儲存失敗
3. 多標籤頁同時操作 Token 失效
檢查 HTML 原始碼是否有 <input name="__hash__">
驗證規則部分生效1. 規則順序:require 應在最前
2. 正則未加分隔符
3. 回調函數回傳非布林
逐條註解測試

二、標準自動驗證定義範本

<?php
namespace Home\Model;
use Think\Model;

class LoginModel extends Model {
    protected $tableName = 'admin'; // 實際資料表
    
    // 自動驗證規則
    protected $_validate = [
        // [欄位, 規則, 錯誤訊息, 條件, 類型, 時間]
        ['username', 'require', '帳號不得為空', self::MUST_VALIDATE, 'regex', self::MODEL_BOTH],
        ['username', '/^[a-zA-Z0-9_]{3,20}$/', '帳號格式錯誤', self::VALUE_VALIDATE, 'regex', self::MODEL_BOTH],
        ['password', 'require', '密碼不得為空', self::MUST_VALIDATE, 'regex', self::MODEL_BOTH],
        ['password', '/^.{6,32}$/', '密碼長度 6-32 字元', self::VALUE_VALIDATE, 'regex', self::MODEL_BOTH],
        // 回調函數驗證(需在模型內定義 public/protected 方法)
        ['email', 'checkEmail', 'Email 格式錯誤', self::VALUE_VALIDATE, 'callback', self::MODEL_BOTH],
    ];
    
    // 自動完成(選用)
    protected $_auto = [
        ['status', 1, self::MODEL_INSERT],
        ['create_time', 'time', self::MODEL_INSERT, 'function'],
        ['update_time', 'time', self::MODEL_BOTH, 'function'],
    ];
    
    // 回調驗證方法
    protected function checkEmail($value) {
        return filter_var($value, FILTER_VALIDATE_EMAIL) !== false;
    }
}

規則陣列六個參數詳解

  1. 欄位名:對應 $_POST['field'] 鍵名。
  2. 驗證規則:require、email、url、currency、number、zip、ip、regex(正則)、function(回調)、confirm(比對另一欄位)。
  3. 錯誤訊息:驗證失敗回傳字串。
  4. 條件:
    • self::MUST_VALIDATE (1):必須驗證(欄位存在即驗證,含空值)。
    • self::VALUE_VALIDATE (2):值不為空時驗證(預設)。
    • self::EXISTS_VALIDATE (0):欄位存在於資料陣列即驗證。
  5. 類型:regex、function、callback、confirm、unique(唯一值)。
  6. 時間:self::MODEL_INSERT (1)、self::MODEL_UPDATE (2)、self::MODEL_BOTH (3)。

三、控制器正確呼叫模式

public function login() {
    if (IS_POST) {
        $model = D('Login'); // 實例化模型
        
        // 1. create() 自動驗證 + 資料物件建立
        // 參數為空字串表示使用 $_POST,也可傳入陣列
        if (!$model->create()) {
            // 驗證失敗
            $this->error($model->getError());
            return;
        }
        
        // 2. 業務邏輯(密碼加密、查詢比對)
        $map = [
            'username' => $model->username,
            'password' => md5($model->password . C('PWD_SALT')), // 加鹽
        ];
        $user = $model->where($map)->find();
        
        if ($user) {
            session('user_id', $user['id']);
            session('username', $user['username']);
            $this->success('登入成功', U('Index/index'));
        } else {
            $this->error('帳號或密碼錯誤');
        }
    } else {
        $this->display(); // 輸出登入模板
    }
}

四、表單 Token 整合(防 CSRF)

<!-- 模板登入表單 -->
<form action="__URL__" method="post">
    <input type="text" name="username" placeholder="帳號" required>
    <input type="password" name="password" placeholder="密碼" required>
    <input type="email" name="email" placeholder="Email">
    
    <!-- 必須:Token 隱藏欄位 -->
    <input type="hidden" name="__hash__" value="{:token()}">
    
    <button type="submit">登入</button>
</form>
  • 控制器需啟用 C('TOKEN_ON', true)(預設開啟)。
  • Token 驗證失敗時 create() 回傳 false,getError() 回傳 令牌表單錯誤。
  • AJAX 提交需在 Header 傳送 X-CSRF-Token: {:token()}。

五、除錯技巧

<?php
// 1. 檢查驗證規則是否正確載入
$model = D('Login');
var_dump($model->_validate); // 應輸出陣列定義

// 2. 檢查 create() 內部資料
$model->create();
var_dump($model->getError()); // 立即查看錯誤
var_dump($model->getDbFields()); // 模型對應欄位

// 3. 開啟 SQL 日誌
C('DB_SQL_LOG', true);
// 執行後查看 Runtime/Logs/.../sql.log

// 4. 手動觸發驗證(繞過 create)
$validate = $model->getValidate();
$result = $model->_validate($data, $validate); // 內部方法,慎用

六、常見坑點對照表

錯誤程式碼/設定問題修正
protected $_validate = array('username', 'require', '...');二維陣列缺少外層 array()每條規則用 array(...) 包裹
'password', '/^\d+$/', '...', 1, 'regex'正則未加分隔符 /.../補上 /^\\d+$/
'repass', 'confirm', '...', 1, 'confirm', 3, 'password'confirm 第 6 參數應為比對欄位名'repass', 'confirm', '...', 1, 'confirm', 3, 'password'(正確)
模型類別名 LoginModel,控制器 D('Login')命名對應:D('Login') 對應 LoginModel確認命名空間與檔案位置
表單 name="user",驗證欄位 username欄位名不匹配統一命名

七、升級建議:ThinkPHP 5/6/8 驗證器

ThinkPHP 5.0+ 棄用模型內建 _validate,改用獨立 驗證器類別:

// app/validate/User.php
namespace app\validate;
use think\Validate;

class User extends Validate {
    protected $rule = [
        'username' => 'require|alphaNum|length:3,20',
        'password' => 'require|length:6,32',
        'email'    => 'email',
    ];
    protected $message = [
        'username.require' => '帳號不得為空',
        'username.alphaNum' => '帳號僅限英數底線',
    ];
}

// 控制器
$validate = new \app\validate\User();
if (!$validate->check($data)) {
    $this->error($validate->getError());
}
  • 優點:規則複用、單元測試友善、支援場景驗證(scene('login'))、獨立於模型。
  • 遷移策略:新功能用驗證器,舊模型漸進式重構。

總結:ThinkPHP 自動驗證失效 90% 來自「規則定義語法錯誤」、「欄位名不匹配」、「Token 缺失」。遵循標準定義範本、善用除錯輸出、正確整合 Token,即可穩定運作。長期規劃應遷移至獨立驗證器架構。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved