驗證類?
CodeIgniter 提供了全面的數據驗證類,最大程度減少你需要編寫的代碼量。
概述?
在解釋 CodeIgniter 的數據驗證之前,我們先介紹理想的狀況:
- 顯示一個表單。
- 你填寫并提交。
- 如果你提交的表單數據無效,或者丟失了必填項,將重新顯示包含了你的數據和錯誤消息的表單。
- 這個過長將一直持續到你提交的表單數據有效為止。
在接收端,腳本必須:
- 檢查需要的數據。
- 驗證數據的類型是否正確,并且符合要求的標準。例如,如果提交了用戶名,則必須僅包含允許的字符。 它必須大于最小長度,小于最大長度。用戶名不能是系統中已經存在的用戶名,甚至是保留的關鍵詞。 等等。
- 處理數據以保證安全。
- 如果有必要,對數據進行格式化 (是否需要裁剪數據 ? HTML 編碼? 等等。)
- 準備要插入數據庫的數據。
盡管上述過程沒有什么非常復雜的,但是通常需要編寫大量的代碼,并且顯示各種錯誤消息,在 HTML 表單中 放置各種控制結構。表單驗證雖然容易創建,但是通常十分混亂,實現起來很繁瑣。
表單驗證教程?
以下是實現 CodeIgniter 表單驗證的“動手”教程。
為了實現表單驗證,你需要做三件事:
- 一個包含表單的 View 文件。
- 一個提交成功后顯示 “success” 的 View 文件。
- 一個 controller 方法用來接收和處理提交的數據。
讓我們以會員注冊表單為例來做這三件事。
表單?
使用編輯器創建一個名為 Signup.php 的視圖文件,將代碼復制到文件中,并保存到 app/Views/ 文件夾:
<html>
<head>
<title>My Form</title>
</head>
<body>
<?= $validation->listErrors() ?>
<?= form_open('form') ?>
<h5>Username</h5>
<input type="text" name="username" value="" size="50" />
<h5>Password</h5>
<input type="text" name="password" value="" size="50" />
<h5>Password Confirm</h5>
<input type="text" name="passconf" value="" size="50" />
<h5>Email Address</h5>
<input type="text" name="email" value="" size="50" />
<div><input type="submit" value="Submit" /></div>
</form>
</body>
</html>
成功頁?
使用編輯器創建一個名為 Success.php 的視圖文件,將代碼復制到文件中,并保存到 app/Views/ 文件夾:
<html>
<head>
<title>My Form</title>
</head>
<body>
<h3>Your form was successfully submitted!</h3>
<p><?= anchor('form', 'Try it again!') ?></p>
</body>
</html>
控制器?
使用編輯器創建一個名為 Form.php 的控制器文件,將代碼復制到文件中,并保存到 app/Controllers/ 文件夾:
<?php namespace App\Controllers;
use CodeIgniter\Controller;
class Form extends Controller
{
public function index()
{
helper(['form', 'url']);
if (! $this->validate([]))
{
echo view('Signup', [
'validation' => $this->validator
]);
}
else
{
echo view('Success');
}
}
}
試一試!?
要嘗試使用表單,請使用與此網址相似的網址訪問你的網站
example.com/index.php/form/
如果你提交表單,則應該只看到表單重新加載。那是因為你沒有設置任何驗證規則。
注解
由于你沒有告訴 Validation 類 進行任何驗證, 它在 默認情況 下 返回 false (boolean false)。 validate()
方法僅在驗證你設置的 所有規則 并且沒有 任何失敗 的情況下返回 true 。
說明?
你會注意到上述頁面的幾件事情:
表單 (Signup.php) 是一個標準的 web 表單,但有一些例外:
它使用表單輔助類來創建表單。從技術上講這沒必要,你可以使用標準的 HTML 代碼來創建表單。 但是,使用表單輔助類可以根據配置文件中的 URL 來生成表單的 action URL。當你的網址發生 更改時,則你的程序更容易進行移植。
在表單的頂部,你會注意到調用了以下函數:
<?= $validation->listErrors() ?>
該函數將返回 validator 發送的所有錯誤消息。如果沒有消息,則返回一個空字符串。
控制器 (Form.php) 擁有一個方法: index()
。這個方法使用控制器提供的 validate 方法,
并加載表單輔助類和 URL 輔助類。它還運行驗證程序,根據驗證程序是否驗證成功,它將顯示表單或成功頁。
加載 validation 庫?
該庫通過名叫 validation 的服務進行加載:
$validation = \Config\Services::validation();
這將自動加載 Config\Validation
文件,文件中包含了多個規則類,以及便于重用的規則集合。
注解
你可用永遠都不會使用該方法,因為 Controller 和 Model 中都提供了更簡便的驗證方法。
設置驗證規則?
CodeIgniter 允許你為給定字段設置多個驗證規則,并按順序執行它們。要設置驗證規則,你將使用
setRule()
,setRules()
方法。
setRule()?
該方法設置單個規則,它使用 字段名稱 作為第一個參數,第二個參數是一個可選的標簽,第三個參數是以豎線 分隔的規則列表的字符串:
$validation->setRule('username', 'Username', 'required');
字段名稱 必須與需要驗證的任何數據數組的鍵匹配。如果直接從 $_POST 獲取數組,則它必須與表單的 input name 完全匹配。
setRules()?
與 setRule()
類似,但其接受字段名稱與其規則所組成的數組:
$validation->setRules([
'username' => 'required',
'password' => 'required|min_length[10]'
]);
想設置帶標簽的錯誤消息,你可以像這樣設置:
$validation->setRules([
'username' => ['label' => 'Username', 'rules' => 'required'],
'password' => ['label' => 'Password', 'rules' => 'required|min_length[10]']
]);
withRequest()?
使用驗證庫最常見的場景之一是驗證從 HTTP 請求輸入的數據。如果需要,你可以傳遞當前的 Request 對象的實例, 它將接收所有輸入數據,并將其設置為待驗證的數據:
$validation->withRequest($this->request)
->run();
處理 Validation?
驗證數組的鍵?
如果需要驗證的數據在嵌套的關聯數組中,則可以使用 “點數組語法” 輕松驗證數據:
// The data to test:
'contacts' => [
'name' => 'Joe Smith',
'friends' => [
[
'name' => 'Fred Flinstone'
],
[
'name' => 'Wilma'
]
]
]
// Joe Smith
$validation->setRules([
'contacts.name' => 'required'
]);
// Fred Flintsone & Wilma
$validation->setRules([
'contacts.friends.name' => 'required'
]);
你可以使用通配符 “*” 來匹配數組的任何一個層級:
// Fred Flintsone & Wilma
$validation->setRules([
'contacts.*.name' => 'required'
]);
“點數組語法” 也通常用于一維數組。例如,多選下拉列表返回的數據:
// The data to test:
'user_ids' => [
1,
2,
3
]
// Rule
$validation->setRules([
'user_ids.*' => 'required'
]);
將驗證規則集合保存到配置文件?
Validation 類一個好的功能是,它允許你將整個程序的驗證規則存儲在配置文件中。將規則組合成一個 “group” ,可以在運行驗證時指定不同的組。
如何保存你的規則?
要存儲你的驗證規則,只需在 Config\Validation
類中使用 group 名創建一個新的公共屬性,
該元素將包含你的驗證規則數組。驗證規則數組的原型如下所示:
class Validation
{
public $signup = [
'username' => 'required',
'password' => 'required',
'pass_confirm' => 'required|matches[password]',
'email' => 'required|valid_email'
];
}
你可以在調用 run()
方法時指定要使用的組:
$validation->run($data, 'signup');
你也可以將自定義錯誤消息存儲在配置文件中,屬性名稱與組名相同并添加 _errors
。
當使用該組時,默認的錯誤消息將被替換:
class Validation
{
public $signup = [
'username' => 'required',
'password' => 'required',
'pass_confirm' => 'required|matches[password]',
'email' => 'required|valid_email'
];
public $signup_errors = [
'username' => [
'required' => 'You must choose a username.',
],
'email' => [
'valid_email' => 'Please check the Email field. It does not appear to be valid.'
]
];
}
或者在組中傳遞所有的設置:
class Validation
{
public $signup = [
'username' => [
'rules' => 'required',
'errors' => [
'required' => 'You must choose a Username.'
]
],
'email' => [
'rules' => 'required|valid_email',
'errors' => [
'valid_email' => 'Please check the Email field. It does not appear to be valid.'
]
],
];
}
有關數組格式的詳細信息請查看下文。
獲取與設置規則組?
獲取規則組
該方法從驗證配置中獲取規則組:
$validation->getRuleGroup('signup');
設置規則組
該方法設置將規則組從驗證配置設置到驗證服務:
$validation->setRuleGroup('signup');
運行多個 Validation?
注解
run()
方法不會重置錯誤狀態。如果上次運行失敗,run()
方法將始終返回 false ,
getErrors()
方法將始終返回上次的所有錯誤,直至狀態被顯式重置。
如果需要運行多個驗證,例如在不同的數據集上運行或者一個接一個的運行不同的規則,你應該在每次運行前
調用 $validation->reset()
清除上次運行產生的錯誤。需要注意的是 reset()
將重置之前的所有數據、規則
或是自定義錯誤消息。所以需要重復 setRules()
,setRuleGroup()
等方法:
for ($userAccounts as $user) {
$validation->reset();
$validation->setRules($userAccountRules);
if (!$validation->run($user)) {
// handle validation errors
}
}
Validation 占位符?
Validation 類提供了一個簡單的方法,可以根據傳入的數據替換部分規則。這聽起來十分晦澀,但在使用 is_unique
進行驗證時
十分方便。 占位符是字段的名稱(或數組的鍵),該字段名稱(或數組的鍵)將用花括號包起來作為 $data 傳入。它將被替換為匹配的
傳入字段的 值。 以下例子可以解釋這些:
$validation->setRules([
'email' => 'required|valid_email|is_unique[users.email,id,{id}]'
]);
在這組規則中,它聲明 email 在數據庫中是唯一的,除了具有與占位符匹配的 id 信息, 假設表單 POST 數據中有以下內容:
$_POST = [
'id' => 4,
'email' => 'foo@example.com'
];
那么占位符 {id}
將被修改為數字 4,以下是修改后的規則:
$validation->setRules([
'email' => 'required|valid_email|is_unique[users.email,id,4]'
]);
因此,在驗證 email 唯一時,將忽略數據庫中 id=4
的行。
這也可以用于在運行時動態創建更多的規則,只要你確保傳入的任何動態鍵都不會與表單 數據產生沖突。
處理錯誤?
Validation 庫提供了幾種方法幫助你設置錯誤消息,提供自定義錯誤消息,以及顯示一個 或多個錯誤消息。
默認情況下,錯誤消息來自 system/Language/en/Validation.php
中的語言字符串,
其中每個規則都有一個條目。
設置自定義錯誤消息?
setRule()
和 setRules()
允許自定義錯誤消息數據作為最后一個參數傳入。每一個錯誤的
錯誤消息都是定制的,這將帶來愉快的用戶體驗。如果沒有設置自定義錯誤消息,則提供默認值。
這是兩種設置錯誤消息的方式。
作為最后一個參數:
$validation->setRules([
'username' => 'required|is_unique[users.username]',
'password' => 'required|min_length[10]'
],
[ // Errors
'username' => [
'required' => 'All accounts must have usernames provided',
],
'password' => [
'min_length' => 'Your password is too short. You want to get hacked?'
]
]
);
或者作為標簽樣式:
$validation->setRules([
'username' => [
'label' => 'Username',
'rules' => 'required|is_unique[users.username]',
'errors' => [
'required' => 'All accounts must have {field} provided'
]
],
'password' => [
'label' => 'Password',
'rules' => 'required|min_length[10]',
'errors' => [
'min_length' => 'Your {field} is too short. You want to get hacked?'
]
]
]
);
如果你希望包含字段的“human”名稱,或者某些規則允許的可選參數 (比如 max_length),或當前參與驗證的值,
則可以分別將 {field}
,{param}
,{value}
標記添加到你的消息中:
'min_length' => 'Supplied value ({value}) for {field} must have at least {param} characters.'
在一個用戶名字段為 Username ,驗證規則為 min_length[6] ,字段值為 “Pizza” 的驗證中,將顯示錯誤消息 “Supplied value (Pizza) for Username must have at least 6 characters”
注解
如果你傳遞最后一個參數,則標簽樣式的錯誤信息將被忽略。
消息和驗證標簽的翻譯?
要使用語言文件中的翻譯字符串,可以簡單的使用點語法。假設我們有一個包含翻譯的文件位
于 app/Languages/en/Rules.php
。我們可以簡單的使用定義在文件中的語言行,如下:
$validation->setRules([
'username' => [
'label' => 'Rules.username',
'rules' => 'required|is_unique[users.username]',
'errors' => [
'required' => 'Rules.username.required'
]
],
'password' => [
'label' => 'Rules.password',
'rules' => 'required|min_length[10]',
'errors' => [
'min_length' => 'Rules.password.min_length'
]
]
]
);
獲取所有錯誤?
如果你需要檢索所有驗證失敗字段的錯誤消息,你可以使用 getErrors()
方法:
$errors = $validation->getErrors();
// Returns:
[
'field1' => 'error message',
'field2' => 'error message',
]
如果沒有錯誤,則返回空數組。
自定義錯誤顯示?
當你調用 $validation->listErrors()
或 $validation->showError()
,它將在后臺加載一個視圖文件,
該文件確定錯誤的顯示方法。默認情況下,它在經過包裝的 div 上顯示 errors
。你可以輕松的創建視圖并在整個程序
中使用它。
創建視圖?
第一步是創建視圖文件,它可以放在 view()
方法可以加載的任何地方。這意味著標準的 View 目錄,或者任何命名空間
下的 View 目錄都可以正常工作。例如,可以在 /app/Views/_errors_list.php 創建新的視圖文件:
<div class="alert alert-danger" role="alert">
<ul>
<?php foreach ($errors as $error) : ?>
<li><?= esc($error) ?></li>
<?php endforeach ?>
</ul>
</div>
$errors
數組可以在包含錯誤列表的視圖中使用,其中鍵是發生錯誤的字段名,值是錯誤消息,如下所示:
$errors = [
'username' => 'The username field must be unique.',
'email' => 'You must provide a valid email address.'
];
實際上可以創建兩種類型的視圖文件。第一種包含所有錯誤消息,這就是我們剛才看到的。另一種更簡單,只包含一個錯誤消息變量 $error
。
它與指定字段名的 showError()
方法一起使用。
<span class="help-block"><?= esc($error) ?></span>
創建自定義規則?
規則簡單的存儲在命名空間類中。只要自動加載器能找到它們,你可將他們存儲到任何位置。這些文件稱作規則集。要添加新的規則集,
請編輯 Config/Validation.php 并將新文件添加到 $ruleSets
數組:
public $ruleSets = [
\CodeIgniter\Validation\Rules::class,
\CodeIgniter\Validation\FileRules::class,
\CodeIgniter\Validation\CreditCardRules::class,
];
你可以將其添加為具有完全限定類的簡單字符串,或者使用 ::class
后綴進行添加。如上所示,這里的好處是,它在更高級的 IED
中提供了額外的一些導航功能。
在文件中,每一個方法都是一個規則,它必須接受字符串作為第一個字符串,并且必須返回布爾值 true 或 false 。如果通過測試則返回 true ,否則返回 false 。
class MyRules
{
public function even(string $str): bool
{
return (int)$str % 2 == 0;
}
}
默認情況下,系統將在 CodeIgniter\Language\en\Validation.php
中查找錯誤要使用語言字符串。在自定義規則中,你可以通過第二個參數 $error 的引用來
提供錯誤消息:
public function even(string $str, string &$error = null): bool
{
if ((int)$str % 2 != 0)
{
$error = lang('myerrors.evenError');
return false;
}
return true;
}
現在你可像其他規則一樣使用新的自定義規則:
$this->validate($request, [
'foo' => 'required|even'
]);
允許參數?
如果你的方法需要使用參數,則該函數至少需要三個參數:要驗證的字符串、參數字符串以及包含提交表單所有數據的數組。 $data 數組對于像 require_with 這樣需要檢查另一個提交字段的值作為其結果基礎的規則來說十分方便:
public function required_with($str, string $fields, array $data): bool
{
$fields = explode(',', $fields);
// If the field is present we can safely assume that
// the field is here, no matter whether the corresponding
// search field is present or not.
$present = $this->required($str ?? '');
if ($present)
{
return true;
}
// Still here? Then we fail this test if
// any of the fields are present in $data
// as $fields is the lis
$requiredFields = [];
foreach ($fields as $field)
{
if (array_key_exists($field, $data))
{
$requiredFields[] = $field;
}
}
// Remove any keys with empty values since, that means they
// weren't truly there, as far as this is concerned.
$requiredFields = array_filter($requiredFields, function ($item) use ($data) {
return ! empty($data[$item]);
});
return empty($requiredFields);
}
自定義錯誤可以通過第四個參數傳遞,如上所述。
可用規則?
以下是可供使用的所有本地規則的列表:
注解
規則是一個字符串;參數之間 不能有空格,尤其是 is_unique
規則。
ignore_value
前后不能有空格。
// is_unique[table.field,ignore_field,ignore_value]
$validation->setRules([
'name' => "is_unique[supplier.name,uuid, $uuid]", // is not ok
'name' => "is_unique[supplier.name,uuid,$uuid ]", // is not ok
'name' => "is_unique[supplier.name,uuid,$uuid]", // is ok
'name' => "is_unique[supplier.name,uuid,{uuid}]", // is ok - see "Validation Placeholders"
]);
Rule | Parameter | Description | Example |
---|---|---|---|
alpha | No | Fails if field has anything other than alphabetic characters. | |
alpha_space | No | Fails if field contains anything other than alphabetic characters or spaces. | |
alpha_dash | No | Fails if field contains anything other than alphanumeric characters, underscores or dashes. | |
alpha_numeric | No | Fails if field contains anything other than alphanumeric characters. | |
alpha_numeric_space | No | Fails if field contains anything other than alphanumeric or space characters. | |
alpha_numeric_punct | No | Fails if field contains anything other than alphanumeric, space, or this limited set of punctuation characters: ~ (tilde), ! (exclamation), # (number), $ (dollar), % (percent), & (ampersand), * (asterisk), - (dash), _ (underscore), + (plus), = (equals), | (vertical bar), : (colon), . (period). | |
decimal | No | Fails if field contains anything other than a decimal number. Also accepts a + or - sign for the number. | |
differs | Yes | Fails if field does not differ from the one in the parameter. | differs[field_name] |
exact_length | Yes | Fails if field is not exactly the parameter value. One or more comma-separated values. | exact_length[5] or exact_length[5,8,12] |
greater_than | Yes | Fails if field is less than or equal to the parameter value or not numeric. | greater_than[8] |
greater_than_equal_to | Yes | Fails if field is less than the parameter value, or not numeric. | greater_than_equal_to[5] |
hex | No | Fails if field contains anything other than hexadecimal characters. | |
if_exist | No | If this rule is present, validation will only return possible errors if the field key exists, regardless of its value. | |
in_list | Yes | Fails if field is not within a predetermined list. | in_list[red,blue,green] |
integer | No | Fails if field contains anything other than an integer. | |
is_natural | No | Fails if field contains anything other than a natural number: 0, 1, 2, 3, etc. | |
is_natural_no_zero | No | Fails if field contains anything other than a natural number, except zero: 1, 2, 3, etc. | |
is_not_unique | Yes | Checks the database to see if the given value exist. Can ignore records by field/value to filter (currently accept only one filter). | is_not_unique[table.field,where_field,where_value] |
is_unique | Yes | Checks if this field value exists in the database. Optionally set a column and value to ignore, useful when updating records to ignore itself. | is_unique[table.field,ignore_field,ignore_value] |
less_than | Yes | Fails if field is greater than or equal to the parameter value or not numeric. | less_than[8] |
less_than_equal_to | Yes | Fails if field is greater than the parameter value or not numeric. | less_than_equal_to[8] |
matches | Yes | The value must match the value of the field in the parameter. | matches[field] |
max_length | Yes | Fails if field is longer than the parameter value. | max_length[8] |
min_length | Yes | Fails if field is shorter than the parameter value. | min_length[3] |
numeric | No | Fails if field contains anything other than numeric characters. | |
regex_match | Yes | Fails if field does not match the regular expression. | regex_match[/regex/] |
permit_empty | No | Allows the field to receive an empty array, empty string, null or false. | |
required | No | Fails if the field is an empty array, empty string, null or false. | |
required_with | Yes | The field is required when any of the other required fields are present in the data. | required_with[field1,field2] |
required_without | Yes | The field is required when all of the other fields are present in the data but not required. | required_without[field1,field2] |
string | No | A generic alternative to the alpha* rules that confirms the element is a string | |
timezone | No | Fails if field does match a timezone per timezone_identifiers_list |
|
valid_base64 | No | Fails if field contains anything other than valid Base64 characters. | |
valid_json | No | Fails if field does not contain a valid JSON string. | |
valid_email | No | Fails if field does not contain a valid email address. | |
valid_emails | No | Fails if any value provided in a comma separated list is not a valid email. | |
valid_ip | No | Fails if the supplied IP is not valid. Accepts an optional parameter of ‘ipv4’ or ‘ipv6’ to specify an IP format. | valid_ip[ipv6] |
valid_url | No | Fails if field does not contain a valid URL. | |
valid_date | No | Fails if field does not contain a valid date. Accepts an optional parameter to matches a date format. | valid_date[d/m/Y] |
valid_cc_number | Yes | Verifies that the credit card number matches the format used by the specified provider. Current supported providers are: American Express (amex), China Unionpay (unionpay), Diners Club CarteBlance (carteblanche), Diners Club (dinersclub), Discover Card (discover), Interpayment (interpayment), JCB (jcb), Maestro (maestro), Dankort (dankort), NSPK MIR (mir), Troy (troy), MasterCard (mastercard), Visa (visa), UATP (uatp), Verve (verve), CIBC Convenience Card (cibc), Royal Bank of Canada Client Card (rbc), TD Canada Trust Access Card (tdtrust), Scotiabank Scotia Card (scotia), BMO ABM Card (bmoabm), HSBC Canada Card (hsbc) | valid_cc_number[amex] |
文件上傳規則?
這些驗證規則可以讓你進行基本的檢查,驗證上傳的文件是否滿足你的業務需求。 由于文件上傳字段在 HTML 字段中不存在,并且存儲在 $_FILES 全局變量中, 因此字段名需要輸入兩次,第一個用于指定驗證的字段,像其他規則一樣,第二次 作為所有文件上傳規則的第一個參數:
// In the HTML
<input type="file" name="avatar">
// In the controller
$this->validate([
'avatar' => 'uploaded[avatar]|max_size[avatar,1024]'
]);
Rule | Parameter | Description | Example |
---|---|---|---|
uploaded | Yes | Fails if the name of the parameter does not match the name of any uploaded files. | uploaded[field_name] |
max_size | Yes | Fails if the uploaded file named in the parameter is larger than the second parameter in kilobytes (kb). | max_size[field_name,2048] |
max_dims | Yes | Fails if the maximum width and height of an uploaded image exceed values. The first parameter is the field name. The second is the width, and the third is the height. Will also fail if the file cannot be determined to be an image. | max_dims[field_name,300,150] |
mime_in | Yes | Fails if the file’s mime type is not one listed in the parameters. | mime_in[field_name,image/png,image/jpg] |
ext_in | Yes | Fails if the file’s extension is not one listed in the parameters. | ext_in[field_name,png,jpg,gif] |
is_image | Yes | Fails if the file cannot be determined to be an image based on the mime type. | is_image[field_name] |
文件驗證規則適用于單個和多個文件上傳。
注解
你也可以使用任何最多允許兩個參數的本地 PHP 函數, 其中至少需要一個參數(傳遞字段數據)。