验证

CodeIgniter 提供了一个全面的数据验证类,有助于最大限度地减少您编写的代码量。

概述

在解释 CodeIgniter 的数据验证方法之前,让我们描述一下理想情况

  1. 显示一个表单。

  2. 您填写并提交它。

  3. 如果您提交了无效内容,或者可能遗漏了必填项,则会重新显示包含您的数据的表单,以及描述问题的错误消息。

  4. 此过程会持续进行,直到您提交有效表单。

在接收端,脚本必须

  1. 检查必填数据。

  2. 验证数据是否为正确的类型,并满足正确的条件。例如,如果提交了用户名,则必须验证它是否只包含允许的字符。它必须具有最小长度,并且不能超过最大长度。用户名不能是其他人的现有用户名,甚至可能是保留字。等等。

  3. 为了安全起见,对数据进行清理。

  4. 如果需要,对数据进行预格式化。

  5. 准备数据以插入数据库。

虽然上述过程并不复杂,但通常需要大量的代码,并且为了显示错误消息,通常将各种控制结构放置在表单 HTML 中。表单验证虽然创建起来很简单,但通常实现起来非常混乱和乏味。

表单验证教程

以下是有关实现 CodeIgniter 的表单验证的“动手”教程。

为了实现表单验证,您需要三样东西

  1. 包含表单的 视图 文件。

  2. 包含“成功”消息的视图文件,该消息将在成功提交后显示。

  3. 一个 控制器 方法来接收和处理提交的数据。

让我们使用会员注册表单作为示例来创建这三样东西。

表单

使用文本编辑器创建一个名为 signup.php 的表单。在其中放置此代码并将其保存到您的 app/Views/ 文件夹中

<html>
<head>
    <title>My Form</title>
</head>
<body>

    <?= validation_list_errors() ?>

    <?= form_open('form') ?>

        <h5>Username</h5>
        <input type="text" name="username" value="<?= set_value('username') ?>" size="50">

        <h5>Password</h5>
        <input type="text" name="password" value="<?= set_value('password') ?>" size="50">

        <h5>Password Confirm</h5>
        <input type="text" name="passconf" value="<?= set_value('passconf') ?>" size="50">

        <h5>Email Address</h5>
        <input type="text" name="email" value="<?= set_value('email') ?>" size="50">

        <div><input type="submit" value="Submit"></div>

    <?= form_close() ?>

</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;

class Form extends BaseController
{
    protected $helpers = ['form'];

    public function index()
    {
        if (! $this->request->is('post')) {
            return view('signup');
        }

        $rules = [
            // @TODO
        ];

        $data = $this->request->getPost(array_keys($rules));

        if (! $this->validateData($data, $rules)) {
            return view('signup');
        }

        // If you want to get the validated data.
        $validData = $this->validator->getValidated();

        return view('success');
    }
}

注意

$this->request->is() 方法可从 v4.3.0 版本开始使用。在以前的版本中,您需要使用 if (strtolower($this->request->getMethod()) !== 'post')

注意

$this->validator->getValidated() 方法可从 v4.4.0 版本开始使用。

路由

然后在 app/Config/Routes.php 中添加控制器的路由

// ...

$routes->get('form', 'Form::index');
$routes->post('form', 'Form::index');

// ...

试试看!

要尝试您的表单,请使用类似于此的 URL 访问您的网站

example.com/index.php/form/

如果您提交表单,您应该只会看到表单重新加载。这是因为您尚未在 $this->validateData() 中设置任何验证规则。

validateData() 方法是控制器中的一个方法。它使用内部的 验证类。请参阅 $this->validateData()

注意

由于您尚未告诉 validateData() 方法验证任何内容,因此它 默认返回 false(布尔值 false)。只有在成功应用您的规则并且没有规则失败的情况下,validateData() 方法才会返回 true。

解释

您会注意到上面页面的一些内容。

signup.php

该表单 (**signup.php**) 是一个标准的 Web 表单,但有一些例外。

  1. 它使用 表单助手 来创建表单的开始和结束。从技术上讲,这不是必需的。您可以使用标准的 HTML 创建表单。但是,使用助手的优点是它会根据配置文件中的 URL 为您生成操作 URL。这使得您的应用程序在 URL 发生更改时更具可移植性。

  2. 在表单的顶部,您会注意到以下函数调用。

    <?= validation_list_errors() ?>
    

    此函数将返回验证器发回的任何错误消息。如果没有消息,它将返回一个空字符串。

Form.php

控制器 (**Form.php**) 具有一个属性:$helpers。它加载视图文件使用的表单助手。

控制器有一个方法:index()。当非 POST 请求到来时,此方法返回 **signup** 视图以显示表单。否则,它使用控制器提供的 $this->validateData() 方法。它还会运行验证例程。根据验证是否成功,它要么显示表单,要么显示成功页面。

添加验证规则

然后在控制器 (**Form.php**) 中添加验证规则。

// ...

$rules = [
    'username' => 'required|max_length[30]',
    'password' => 'required|max_length[255]|min_length[10]',
    'passconf' => 'required|max_length[255]|matches[password]',
    'email'    => 'required|max_length[254]|valid_email',
];

// ...

如果您提交表单,您应该看到成功页面或带有错误消息的表单。

验证配置

传统规则和严格规则

CodeIgniter 4 有两种验证规则类。传统的规则类 (**传统规则**) 具有命名空间 CodeIgniter\Validation,而新的类 (**严格规则**) 具有 CodeIgniter\Validation\StrictRules,它提供严格的验证。

注意

从 v4.3.0 版本开始,默认情况下使用 **严格规则** 以提高安全性。

传统规则

重要

传统规则仅为了向后兼容而存在。不要在新项目中使用它们。即使您已经在使用它们,我们也建议您切换到严格规则。

警告

在验证包含非字符串值(例如 JSON 数据)的数据时,建议使用 **严格规则**。

**传统规则** 隐式地假设字符串值被验证,并且输入值可能会被隐式转换为字符串值。它适用于大多数基本情况,例如验证 POST 数据。

但是,例如,如果您使用 JSON 输入数据,它可能是一种布尔/空/数组类型。当您使用传统规则类验证布尔值 true 时,它会被转换为字符串 '1'。如果您使用 integer 规则验证它,'1' 将通过验证。

严格规则

4.2.0 版本新增。

**严格规则** 不使用隐式类型转换。

使用传统规则

如果您想使用传统规则,您需要更改 **app/Config/Validation.php** 中的规则类。

<?php

namespace Config;

// ...

class Validation extends BaseConfig
{
    // ...

    public array $ruleSets = [
        \CodeIgniter\Validation\CreditCardRules::class,
        \CodeIgniter\Validation\FileRules::class,
        \CodeIgniter\Validation\FormatRules::class,
        \CodeIgniter\Validation\Rules::class,
    ];

    // ...
}

加载库

该库被加载为名为 **validation** 的服务。

$validation = \Config\Services::validation();

这会自动加载 Config\Validation 文件,该文件包含用于包含多个规则集和易于重复使用的规则集合的设置。

注意

您可能永远不需要使用这种方法,因为 控制器模型 都提供方法来使验证更容易。

设置验证规则

CodeIgniter 允许您为给定字段设置任意数量的验证规则,并按顺序级联它们。要设置验证规则,您将使用 setRule()setRules()withRequest() 方法。

设置单个规则

setRule()

此方法设置单个规则。它具有以下方法签名

setRule(string $field, ?string $label, array|string $rules[, array $errors = []])

$rules 接受用管道分隔的规则列表或规则的数组集合

$validation->setRule('username', 'Username', 'required|max_length[30]|min_length[3]');
$validation->setRule('password', 'Password', ['required', 'max_length[255]', 'min_length[8]', 'alpha_numeric_punct']);

传递给 $field 的值必须与发送的任何数据数组的键匹配。如果数据直接从 $_POST 获取,则它必须与表单输入名称完全匹配。

警告

在 v4.2.0 之前,此方法的第三个参数 $rules 被类型提示为接受 string。在 v4.2.0 及之后,类型提示被移除以允许数组。为了避免在扩展类覆盖此方法时破坏 LSP,子类的该方法也应该被修改以移除类型提示。

设置多个规则

setRules()

setRule() 相似,但接受字段名称及其规则的数组

$validation->setRules([
    'username' => 'required|max_length[30]',
    'password' => 'required|max_length[255]|min_length[10]',
]);
// or
$validation->setRules([
    'username' => ['required', 'max_length[30]'],
    'password' => ['required', 'max_length[255]', 'min_length[10]'],
]);

要提供带标签的错误消息,您可以设置如下

$validation->setRules([
    'username' => ['label' => 'Username', 'rules' => 'required|max_length[30]'],
    'password' => ['label' => 'Password', 'rules' => 'required|max_length[255]|min_length[10]'],
]);
// or
$validation->setRules([
    'username' => ['label' => 'Username', 'rules' => 'required|max_length[30]'],
    'password' => ['label' => 'Password', 'rules' => ['required', 'max_length[255]', 'min_length[10]']],
]);

注意

setRules() 将覆盖之前设置的任何规则。要向现有规则集添加多个规则,请多次使用 setRule()

为数组数据设置规则

如果您的数据位于嵌套的关联数组中,您可以使用“点数组语法”轻松验证您的数据

/*
 * The data to test:
 * [
 *     'contacts' => [
 *         'name' => 'Joe Smith',
 *         'friends' => [
 *             [
 *                 'name' => 'Fred Flinstone',
 *             ],
 *             [
 *                 'name' => 'Wilma',
 *             ],
 *         ]
 *     ]
 * ]
 */

// Joe Smith
$validation->setRules([
    'contacts.name' => 'required|max_length[60]',
]);

您可以使用 * 通配符来匹配数组的任何一个级别

// Fred Flintsone & Wilma
$validation->setRules([
    'contacts.friends.*.name' => 'required|max_length[60]',
]);

注意

在 v4.4.4 之前,由于一个 bug,通配符 * 在错误的维度验证数据。详情请参见 升级

“点数组语法”在处理单维数组数据时也很有用。例如,多选下拉菜单返回的数据。

/*
 * The data to test:
 * [
 *     'user_ids' => [
 *         1,
 *         2,
 *         3,
 *     ]
 * ]
 */

// Rule
$validation->setRules([
    'user_ids.*' => 'required|max_length[19]',
]);

withRequest()

重要

此方法仅出于向后兼容性而存在。在新项目中不要使用它。即使您已经在使用它,我们建议您使用其他更合适的方法。

警告

如果您只想验证 POST 数据,请不要使用 withRequest()。此方法使用 $request->getVar(),它按顺序返回 $_GET$_POST$_COOKIE 数据(取决于 php.ini request-order)。较新的值会覆盖较旧的值。如果 cookie 与 POST 值具有相同的名称,则 POST 值可能会被 cookie 覆盖。

使用验证库最常见的情况之一是验证来自 HTTP 请求的输入数据。如果需要,您可以传递当前请求对象的实例,它将获取所有输入数据并将其设置为要验证的数据。

$validation = \Config\Services::validation();
$request    = \Config\Services::request();

if ($validation->withRequest($request)->run()) {
    // If you use the input data, you should get it from the getValidated() method.
    // Otherwise you may create a vulnerability.
    $validData = $validation->getValidated();

    // ...
}

警告

使用此方法时,您应该使用 getValidated() 方法获取验证后的数据。因为此方法从 $request->getJSON() 获取 JSON 数据(当请求为 JSON 请求时,Content-Type: application/json),或从 $request->getRawInput() 获取原始数据(当请求为 PUT、PATCH、DELETE 请求且不是 HTML 表单提交时,Content-Type: multipart/form-data),或从 $request->getVar() 获取数据,攻击者可能会更改验证的数据。

注意

自 v4.4.0 版本起,可以使用 getValidated() 方法。

使用验证

运行验证

run() 方法运行验证。它具有以下方法签名

run(?array $data = null, ?string $group = null, ?string $dbGroup = null): bool

$data 是要验证的数据数组。可选的第二个参数 $group 是要应用的 预定义规则组。可选的第三个参数 $dbGroup 是要使用的数据库组。

如果验证成功,此方法将返回 true。

if (! $validation->run($data)) {
    // handle validation errors
}
// or
if (! $validation->run($data, 'signup')) {
    // handle validation errors
}

运行多个验证

注意

run() 方法不会重置错误状态。如果之前的运行失败,run() 将始终返回 false,并且 getErrors() 将返回所有之前的错误,直到显式重置。

如果您打算运行多个验证,例如在不同的数据集上或使用不同的规则,您可能需要在每次运行之前调用 $validation->reset() 来清除之前的运行错误。请注意,reset() 将使您之前设置的任何数据、规则或自定义错误失效,因此需要重复 setRules()setRuleGroup() 等。

foreach ($userAccounts as $user) {
    $validation->reset();
    $validation->setRules($userAccountRules);

    if (! $validation->run($user)) {
        // handle validation errors
    }
}

验证 1 个值

check() 方法根据规则验证一个值。第一个参数 $value 是要验证的值。第二个参数 $rule 是验证规则。可选的第三个参数 $errors 是自定义错误消息。

if ($validation->check($value, 'required')) {
    // $value is valid.
}

注意

在 v4.4.0 之前,此方法的第二个参数 $rule 被类型提示为接受 string。在 v4.4.0 及之后,类型提示被移除以允许数组。

注意

此方法调用 setRule() 方法在内部设置规则。

获取验证后的数据

版本 4.4.0 中新增。

可以使用 getValidated() 方法检索实际的验证数据。此方法返回一个仅包含已通过验证规则验证的元素的数组。

$validation = \Config\Services::validation();
$validation->setRules([
    'username' => 'required',
    'password' => 'required|min_length[10]',
]);

$data = [
    'username'   => 'john',
    'password'   => 'BPi-$Swu7U5lm$dX',
    'csrf_token' => '8b9218a55906f9dcc1dc263dce7f005a',
];

if ($validation->run($data)) {
    $validatedData = $validation->getValidated();
    // $validatedData = [
    //     'username' => 'john',
    //     'password' => 'BPi-$Swu7U5lm$dX',
    // ];
}
// In Controller.

if (! $this->validate([
    'username' => 'required',
    'password' => 'required|min_length[10]',
])) {
    // The validation failed.
    return view('login', [
        'errors' => $this->validator->getErrors(),
    ]);
}

// The validation was successful.

// Get the validated data.
$validData = $this->validator->getValidated();

将验证规则集保存到配置文件

Validation 类的另一个优点是它允许您将整个应用程序的所有验证规则存储在配置文件中。您可以将规则组织成“组”。每次运行验证时,您可以指定不同的组。

如何保存规则

要存储验证规则,只需在 Config\Validation 类中创建一个新的公共属性,并使用您的组的名称。此元素将保存一个包含验证规则的数组。如前所述,验证数组将具有以下原型

<?php

namespace Config;

// ...

class Validation extends BaseConfig
{
    // ...

    public array $signup = [
        'username'     => 'required|max_length[30]',
        'password'     => 'required|max_length[255]',
        'pass_confirm' => 'required|max_length[255]|matches[password]',
        'email'        => 'required|max_length[254]|valid_email',
    ];

    // ...
}

如何指定规则组

您可以在调用 run() 方法时指定要使用的组

$validation->run($data, 'signup');

如何保存错误消息

您还可以将自定义错误消息存储在此配置文件中,方法是将属性命名为与组相同的名称,并在后面附加 _errors。当使用此组时,这些消息将自动用于任何错误

<?php

namespace Config;

// ...

class Validation extends BaseConfig
{
    // ...

    public array $signup = [
        'username'     => 'required|max_length[30]',
        'password'     => 'required|max_length[255]',
        'pass_confirm' => 'required|max_length[255]|matches[password]',
        'email'        => 'required|max_length[254]|valid_email',
    ];

    public array $signup_errors = [
        'username' => [
            'required' => 'You must choose a username.',
        ],
        'email' => [
            'valid_email' => 'Please check the Email field. It does not appear to be valid.',
        ],
    ];

    // ...
}

或者将所有设置传递到一个数组中

<?php

namespace Config;

// ...

class Validation extends BaseConfig
{
    // ...

    public array $signup = [
        'username' => [
            'rules'  => 'required|max_length[30]',
            'errors' => [
                'required' => 'You must choose a Username.',
            ],
        ],
        'email' => [
            'rules'  => 'required|max_length[254]|valid_email',
            'errors' => [
                'valid_email' => 'Please check the Email field. It does not appear to be valid.',
            ],
        ],
    ];

    // ...
}

有关数组格式的详细信息,请参阅 设置自定义错误消息

获取和设置规则组

获取规则组

此方法从验证配置中获取规则组

$validation->getRuleGroup('signup');
设置规则组

此方法将验证配置中的规则组设置为验证服务。

$validation->setRuleGroup('signup');

验证占位符

Validation 类提供了一种简单的方法,可以根据传递给它的数据替换规则中的部分内容。这听起来可能很模糊,但对于 is_unique 验证规则来说特别有用。占位符只是作为 $data 传入的字段(或数组键)的名称,用花括号括起来。它将被匹配的传入字段的 **值** 替换。一个例子应该可以澄清这一点

$validation->setRules([
    'id'    => 'max_length[19]|is_natural_no_zero',
    'email' => 'required|max_length[254]|valid_email|is_unique[users.email,id,{id}]',
]);

注意

从 v4.3.5 版本开始,您必须为占位符字段(上面示例代码中的 id 字段)设置验证规则,以确保安全。

在这组规则中,它指出电子邮件地址在数据库中应该是唯一的,除了与占位符值匹配的行的 id。假设表单 POST 数据如下

$_POST = [
    'id'    => 4,
    'email' => '[email protected]',
];

那么 {id} 占位符将被数字 **4** 替换,从而得到以下修改后的规则

$validation->setRules([
    'id'    => 'max_length[19]|is_natural_no_zero',
    'email' => 'required|max_length[254]|valid_email|is_unique[users.email,id,4]',
]);

因此,在验证电子邮件是否唯一时,它将忽略数据库中具有 id=4 的行。

注意

从 v4.3.5 版本开始,如果占位符 (id) 值未通过验证,则不会替换占位符。

这也可以用来在运行时创建更动态的规则,只要您注意任何传入的动态键不会与您的表单数据冲突。

处理错误

Validation 库提供了一些方法来帮助您设置错误消息,提供自定义错误消息,以及检索一个或多个错误以显示。

默认情况下,错误消息来自 **system/Language/en/Validation.php** 中的语言字符串,其中每个规则都有一个条目。如果您想更改消息默认值,请创建一个文件 **app/Language/en/Validation.php**(以及/或者您使用的语言环境的对应文件夹,以代替/除了 en),并在其中放置您想要更改默认值的那些错误消息的键值对。

设置自定义错误消息

setRule()setRules() 方法都可以在最后一个参数中接受一个自定义消息数组,这些消息将用作每个字段的特定错误。这为用户提供了非常愉快的体验,因为错误是针对每个实例定制的。如果没有提供自定义错误消息,将使用默认值。

以下是两种提供自定义错误消息的方法。

作为最后一个参数

$validation->setRules(
    [
        'username' => 'required|max_length[30]|is_unique[users.username]',
        'password' => 'required|max_length[254]|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|max_length[30]|is_unique[users.username]',
        'errors' => [
            'required' => 'All accounts must have {field} provided',
        ],
    ],
    'password' => [
        'label'  => 'Password',
        'rules'  => 'required|max_length[255]|min_length[10]',
        'errors' => [
            'min_length' => 'Your {field} is too short. You want to get hacked?',
        ],
    ],
]);

如果你想包含字段的“人类”名称,或者某些规则允许的可选参数(例如 max_length),或者被验证的值,你可以分别在你的消息中添加 {field}{param}{value} 标记

'min_length' => 'Supplied value ({value}) for {field} must have at least {param} characters.'

在一个名为“用户名”的字段上,规则为 min_length[6],值为“Pizza”,错误将显示为:“用户名提供的值(Pizza)必须至少包含 6 个字符。”

警告

如果你使用 getErrors()getError() 获取错误消息,则消息不会进行 HTML 转义。如果你使用用户输入数据,例如 ({value}) 来创建错误消息,它可能包含 HTML 标记。如果你在显示消息之前没有对其进行转义,则可能发生 XSS 攻击。

注意

当使用标签样式错误消息时,如果你将第二个参数传递给 setRules(),它将被第一个参数的值覆盖。

消息和验证标签的翻译

要使用语言文件中的翻译字符串,我们可以简单地使用点语法。假设我们有一个包含翻译的文件,位于这里:app/Languages/en/Rules.php。我们可以简单地使用在这个文件中定义的语言行,如下所示

$validation->setRules([
    'username' => [
        'label'  => 'Rules.username',
        'rules'  => 'required|max_length[30]|is_unique[users.username]',
        'errors' => [
            'required' => 'Rules.username.required',
        ],
    ],
    'password' => [
        'label'  => 'Rules.password',
        'rules'  => 'required|max_length[255]|min_length[10]',
        'errors' => [
            'min_length' => 'Rules.password.min_length',
        ],
    ],
]);

获取所有错误

如果您需要检索所有失败字段的错误消息,可以使用 getErrors() 方法

$errors = $validation->getErrors();
/*
 * Produces:
 * [
 *     'field1' => 'error message',
 *     'field2' => 'error message',
 * ]
 */

如果不存在错误,将返回一个空数组。

使用通配符 (*) 时,错误将指向特定字段,用相应的键/键替换星号

// for data
'contacts' => [
    'friends' => [
        [
            'name' => 'Fred Flinstone',
        ],
        [
            'name' => '',
        ],
    ]
]

// rule
'contacts.friends.*.name' => 'required'

// error will be
'contacts.friends.1.name' => 'The contacts.friends.*.name field is required.'

获取单个错误

您可以使用 getError() 方法检索单个字段的错误。唯一的参数是字段名称

$error = $validation->getError('username');

如果不存在错误,将返回一个空字符串。

注意

使用通配符时,所有匹配掩码的找到的错误将合并到一行中,并用 EOL 字符分隔。

检查错误是否存在

您可以使用 hasError() 方法检查错误是否存在。唯一的参数是字段名称

if ($validation->hasError('username')) {
    echo $validation->getError('username');
}

指定带有通配符的字段时,将检查所有匹配掩码的错误

/*
 * For errors:
 * [
 *     'foo.0.bar'   => 'Error',
 *     'foo.baz.bar' => 'Error',
 * ]
 */

// returns true
$validation->hasError('foo.*.bar');

重定向和验证错误

PHP 在请求之间不共享任何内容。因此,当您在验证失败时重定向时,重定向的请求中将不会有验证错误,因为验证已在之前的请求中运行。

在这种情况下,您需要使用 Form 助手函数 validation_errors()validation_list_errors()validation_show_error()。这些函数检查存储在会话中的验证错误。

要将验证错误存储在会话中,您需要使用 withInput()redirect()

// In Controller.
if (! $this->validateData($data, $rules)) {
    return redirect()->back()->withInput();
}

自定义错误显示

当您调用 $validation->listErrors()$validation->showError() 时,它会在后台加载一个视图文件,该文件决定如何显示错误。默认情况下,它们在包装 div 上显示一个 errors 类。您可以轻松创建新的视图并在整个应用程序中使用它们。

创建视图

第一步是创建自定义视图。这些可以放置在 view() 方法可以找到它们的任何位置,这意味着标准 View 目录或任何命名空间 View 文件夹都可以。例如,您可以在 app/Views/_errors_list.php 创建一个新视图。

<?php if (! empty($errors)): ?>
    <div class="alert alert-danger" role="alert">
        <ul>
        <?php foreach ($errors as $error): ?>
            <li><?= esc($error) ?></li>
        <?php endforeach ?>
        </ul>
    </div>
<?php endif ?>

视图中有一个名为 $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>

配置

创建完视图后,您需要让 Validation 库了解它们。打开 app/Config/Validation.php。在里面,您会找到 $templates 属性,您可以在其中列出任意数量的自定义视图,并提供一个简短的别名,可以通过它来引用它们。如果我们要添加上面示例文件,它将看起来像这样

<?php

namespace Config;

// ...

class Validation extends BaseConfig
{
    // ...

    public array $templates = [
        'list'    => 'CodeIgniter\Validation\Views\list',
        'single'  => 'CodeIgniter\Validation\Views\single',
        'my_list' => '_errors_list',
    ];

    // ...
}

指定模板

您可以通过在 listErrors() 中传递模板别名作为第一个参数来指定要使用的模板。

<?= $validation->listErrors('my_list') ?>

在显示特定于字段的错误时,您可以将别名作为第二个参数传递给 showError() 方法,紧接在错误所属字段的名称之后。

<?= $validation->showError('username', 'my_single') ?>

创建自定义规则

使用规则类

规则存储在简单的命名空间类中。它们可以存储在您喜欢的任何位置,只要自动加载器可以找到它。这些文件称为 RuleSets。

添加 RuleSet

要添加新的 RuleSet,请编辑 **app/Config/Validation.php** 并将新文件添加到 $ruleSets 数组中。

<?php

namespace Config;

use CodeIgniter\Config\BaseConfig;
use CodeIgniter\Validation\CreditCardRules;
use CodeIgniter\Validation\FileRules;
use CodeIgniter\Validation\FormatRules;
use CodeIgniter\Validation\Rules;

class Validation extends BaseConfig
{
    // ...

    public array $ruleSets = [
        Rules::class,
        FormatRules::class,
        FileRules::class,
        CreditCardRules::class,
    ];

    // ...
}

您可以将其添加为带有完全限定类名的简单字符串,或者使用如上所示的 ::class 后缀。这里的主要好处是它在更高级的 IDE 中提供了一些额外的导航功能。

创建规则类

在文件本身中,每个方法都是一个规则,必须接受要验证的值作为第一个参数,并且必须返回一个布尔值 true 或 false,表示如果通过测试则为 true,如果未通过测试则为 false。

<?php

class MyRules
{
    public function even($value): bool
    {
        return (int) $value % 2 === 0;
    }
}

默认情况下,系统将在 **system/Language/en/Validation.php** 中查找错误中使用的语言字符串。要为您的自定义规则提供默认错误消息,您可以将它们放在 **app/Language/en/Validation.php**(以及/或您使用的语言环境的相应文件夹,以替换 en)。此外,如果您想使用其他语言字符串文件来代替默认的 **Validation.php**,您可以在第二个(或者,如果您的规则需要使用参数,如下所述 - 第四个)参数中接受一个 &$error 变量作为引用来提供错误消息。

<?php

class MyRules
{
    public function even($value, ?string &$error = null): bool
    {
        if ((int) $value % 2 !== 0) {
            $error = lang('myerrors.evenError');

            return false;
        }

        return true;
    }
}

使用自定义规则

您新的自定义规则现在可以像其他任何规则一样使用。

$validation->setRules([
    'foo' => 'required|max_length[19]|even',
]);

允许参数

如果您的方法需要使用参数,则函数至少需要三个参数

  1. 要验证的值 ($value)

  2. 参数字符串 ($params)

  3. 包含所有提交表单数据的数组 ($data)

  4. (可选) 自定义错误字符串 (&$error),如上所述。

警告

中的字段值$data未经验证(或可能无效)。使用未经验证的输入数据是漏洞的来源。您必须在使用数据之前在自定义规则中执行必要的验证$data

$data数组对于像required_with需要检查另一个提交字段的值来确定其结果的规则特别有用

<?php

class MyRules
{
    public function required_with($value, string $params, array $data): bool
    {
        $params = explode(',', $params);

        // 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($value ?? '');

        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 ($params 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, static fn ($item) => ! empty($data[$item]));

        return empty($requiredFields);
    }
}

使用闭包规则

版本 4.3.0 中的新增功能。

如果您在整个应用程序中只需要自定义规则的功能一次,可以使用闭包而不是规则类。

您需要使用数组来进行验证规则

$validation->setRules(
    [
        'foo' => [
            'required',
            static fn ($value) => (int) $value % 2 === 0,
        ],
    ],
    [
        // Errors
        'foo' => [
            // Specify the array key for the closure rule.
            1 => 'The value is not even.',
        ],
    ],
);

if (! $validation->run($data)) {
    // handle validation errors
}

您必须为闭包规则设置错误消息。当您指定错误消息时,请设置闭包规则的数组键。在上面的代码中,required规则具有键0,闭包具有1

或者您可以使用以下参数

$validation->setRules([
    'foo' => [
        'required',
        static function ($value, $data, &$error, $field) {
            if ((int) $value % 2 === 0) {
                return true;
            }

            $error = 'The value is not even.';

            return false;
        },
    ],
]);

可用规则

注意

规则是一个字符串;参数之间不能有空格,尤其是is_unique规则。在ignore_value之前和之后不能有空格。

// is_unique[table.field,ignore_field,ignore_value]

$validation->setRules([
    'name' => "max_length[36]|is_unique[supplier.name,uuid, {$uuid}]", // is not ok
    'name' => "max_length[36]|is_unique[supplier.name,uuid,{$uuid} ]", // is not ok
    'name' => "max_length[36]|is_unique[supplier.name,uuid,{$uuid}]",  // is ok
    'name' => 'max_length[36]|is_unique[supplier.name,uuid,{uuid}]',   // is ok - see "Validation Placeholders"
]);
// Warning: If `$uuid` is a user input, be sure to validate the format of the value before using it.
// Otherwise, it is vulnerable.

通用规则

以下是所有可用的原生规则列表

规则

参数

描述

示例

alpha

如果字段包含除 ASCII 字母以外的任何字符,则失败。

alpha_space

如果字段包含除 ASCII 字母或空格以外的任何字符,则失败。

alpha_dash

如果字段包含除 ASCII 字母数字字符、下划线或破折号以外的任何字符,则失败。

alpha_numeric

如果字段包含除 ASCII 字母数字字符以外的任何字符,则失败。

alpha_numeric_space

如果字段包含除 ASCII 字母数字字符或空格以外的任何字符,则失败。

alpha_numeric_punct

如果字段包含除字母数字字符、空格或以下有限的标点符号集以外的任何字符,则失败:~ (波浪号), ! (感叹号), # (数字), $ (美元), % (百分号), & (和号), * (星号), - (破折号), _ (下划线), + (加号), = (等于), | (竖线), : (冒号), . (句号).

decimal

如果字段包含除十进制数字以外的任何字符,则失败。也接受 +- 作为数字的符号。

differs

如果字段与参数中的字段不一致,则失败。

differs[field_name]

exact_length

如果字段不完全等于参数值,则失败。一个或多个用逗号分隔的值。

exact_length[5]exact_length[5,8,12]

greater_than

如果字段小于或等于参数值或不是数字,则失败。

greater_than[8]

greater_than_equal_to

如果字段小于参数值或不是数字,则失败。

greater_than_equal_to[5]

hex

如果字段包含十六进制字符以外的任何内容,则失败。

if_exist

如果存在此规则,则验证将仅在要验证的数据中存在字段键时检查字段。

in_list

如果字段不在预定的列表中,则失败。

in_list[red,blue,green]

integer

如果字段包含任何非整数内容,则失败。

is_natural

如果字段包含任何非自然数内容,则失败:0、1、2、3 等。

is_natural_no_zero

如果字段包含任何非自然数内容,则失败,除了零:1、2、3 等。

is_not_unique

检查数据库以查看给定值是否存在。可以通过字段/值忽略记录以进行过滤(目前仅接受一个过滤器)。

is_not_unique[table.field,where_field,where_value]

is_unique

检查此字段值是否存在于数据库中。可以选择设置要忽略的列和值,在更新记录时忽略自身很有用。

is_unique[table.field,ignore_field,ignore_value]

less_than

如果字段大于或等于参数值或不是数字,则失败。

less_than[8]

less_than_equal_to

如果字段大于参数值或不是数字,则失败。

less_than_equal_to[8]

matches

该值必须与参数中字段的值匹配。

matches[field]

max_length

如果字段长度超过参数值,则失败。

max_length[8]

min_length

如果字段长度小于参数值,则失败。

min_length[3]

not_in_list

如果字段在预定的列表中,则失败。

not_in_list[red,blue,green]

numeric

如果字段包含任何非数字字符,则失败。

regex_match

如果字段与正则表达式不匹配,则失败。

regex_match[/regex/]

permit_empty

允许字段接收空数组、空字符串、null 或 false。

required

如果字段为空数组、空字符串、null 或 false,则失败。

required_with

当数据中任何其他字段不为 empty() 时,该字段是必需的。

required_with[field1,field2]

required_without

当数据中任何其他字段为 empty() 时,此字段为必填字段。

required_without[field1,field2]

string

确认元素为字符串的通用替代方法,替代 alpha* 规则。

timezone

如果字段不匹配 timezone_identifiers_list() 中的时区,则失败。

valid_base64

如果字段包含任何非有效 Base64 字符,则失败。

valid_json

如果字段不包含有效的 JSON 字符串,则失败。

valid_email

如果字段不包含有效的电子邮件地址,则失败。

valid_emails

如果逗号分隔列表中提供的任何值不是有效的电子邮件,则失败。

valid_ip

如果提供的 IP 无效,则失败。接受可选参数 ipv4ipv6 来指定 IP 格式。

valid_ip[ipv6]

valid_url

如果字段不包含(宽松地)URL,则失败。包括可能作为主机名的简单字符串,例如“codeigniter”。通常,valid_url_strict 应该使用。

valid_url_strict

如果字段不包含有效的 URL,则失败。您可以选择指定有效模式列表。如果未指定,则 http,https 为有效模式。此规则使用 PHP 的 FILTER_VALIDATE_URL

valid_url_strict[https]

valid_date

如果字段不包含有效的日期,则失败。任何 strtotime() 接受的字符串如果未指定可选参数以匹配日期格式,则为有效字符串。因此通常需要指定参数。

valid_date[d/m/Y]

valid_cc_number

验证信用卡号码是否与指定提供商使用的格式匹配。当前支持的提供商包括:美国运通 (amex)、中国银联 (unionpay)、大来卡 (carteblanche)、大来卡 (dinersclub)、Discover 卡 (discover)、Interpayment (interpayment)、JCB (jcb)、万事达卡 (maestro)、Dankort (dankort)、NSPK MIR (mir)、Troy (troy)、万事达卡 (mastercard)、Visa (visa)、UATP (uatp)、Verve (verve)、CIBC 便利卡 (cibc)、加拿大皇家银行客户卡 (rbc)、TD 加拿大信托存取卡 (tdtrust)、丰业银行丰业卡 (scotia)、BMO ABM 卡 (bmoabm)、汇丰加拿大卡 (hsbc)

valid_cc_number[amex]

注意

您也可以使用任何返回布尔值并允许至少一个参数(要验证的字段数据)的原生 PHP 函数。验证库**永远不会更改**要验证的数据。

文件上传规则

验证上传的文件时,必须使用专门为文件验证创建的规则。

重要

只有下表中列出的规则才能用于验证文件。因此,在文件验证规则数组或字符串中添加任何通用规则,例如 permit_empty,文件验证将无法正常工作。

由于文件上传 HTML 字段的值不存在,而是存储在 $_FILES 全局变量中,因此需要使用输入字段的名称两次。一次用于指定字段名称,就像您对任何其他规则一样,但再次作为所有文件上传相关规则的第一个参数。

// In the HTML
<input type="file" name="avatar">

// In the controller
$this->validate([
    'avatar' => 'uploaded[avatar]|max_size[avatar,1024]',
]);

规则

参数

描述

示例

uploaded

如果参数的名称与任何上传文件的名称不匹配,则会失败。如果您希望文件上传是可选的(不是必需的),请不要定义此规则。

上传[field_name]

最大尺寸

如果上传的文件(参数中指定的名称)大于第二个参数(以 KB 为单位),则验证失败。或者,如果文件大小超过 php.ini 配置文件中声明的允许最大大小 - upload_max_filesize 指令。

max_size[field_name,2048]

最大尺寸

如果上传图像的最大宽度和高度超过指定值,则验证失败。第一个参数是字段名称,第二个参数是宽度,第三个参数是高度。如果无法确定文件是否为图像,也会失败。

max_dims[field_name,300,150]

MIME 类型包含

如果文件的 MIME 类型不在参数列表中,则验证失败。

mime_in[field_name,image/png,image/jpeg]

扩展名包含

如果文件的扩展名不在参数列表中,则验证失败。

ext_in[field_name,png,jpg,gif]

是否为图像

如果根据 MIME 类型无法确定文件是否为图像,则验证失败。

is_image[field_name]

文件验证规则适用于单文件上传和多文件上传。