验证数据

不受信任的数据来自许多来源(用户、第三方站点,甚至您自己的数据库!),所有这些都需要在使用前进行检查。

请记住:即使是管理员也是用户,用户会故意或无意地输入不正确的数据。保护他们不受伤害是你的工作。

_验证_输入是根据预定义模式(或模式)测试数据并得出明确结果的过程:有效或无效。与清理相比,验证是一种更具体的方法,但两者都有其作用。

简单验证示例:

  • 检查必填字段是否未留空
  • 检查输入的电话号码是否仅包含数字和标点符号
  • 检查请求的字符串是否是五个有效选项之一
  • 检查数量字段是否大于 0

**应尽早进行数据验证。**这意味着在执行任何操作之前验证数据。

验证哲学

关于如何进行验证有几种不同的理念。每一种都适用于不同的场景。

安全列表

仅接受来自已知和可信值的有限列表的数据。

将不受信任的数据与安全列表进行比较时,确保使用严格的类型检查很重要。否则,攻击者可能会以一种能够通过安全列表但仍然具有恶意效果的方式制作输入。

比较运算符

$untrusted_input = '1 malicious string';  // will evaluate to integer 1 during loose comparisons

if ( 1 === $untrusted_input ) {  // == would have evaluated to true, but === evaluates to false
    echo '<p>Valid data';
} else {
    wp_die( 'Invalid data' );
}

in_array()

$untrusted_input = '1 malicious string';  // will evaluate to integer 1 during loose comparisons
$safe_values     = array( 1, 5, 7 );

if ( in_array( $untrusted_input, $safe_values, true ) ) {  // `true` enables strict type checking
    echo '<p>Valid data';
} else {
    wp_die( 'Invalid data' );
}

switch()

$untrusted_input = '1 malicious string';  // will evaluate to integer 1 during loose comparisons

switch ( true ) {
    case 1 === $untrusted_input:  // do your own strict comparison instead of relying on switch()'s loose comparison
        echo '<p>Valid data';
        break;

    default:
        wp_die( 'Invalid data' );
}

黑名单

拒绝来自已知不受信任值的有限列表的数据。这很少是个好主意。

格式检测

测试数据格式是否正确。如果是的话,只接受它。

if ( ! ctype_alnum( $data ) ) {
  wp_die( "Invalid format" );
}

if ( preg_match( "/[^0-9.-]/", $data ) ) {
  wp_die( "Invalid format" );
}

格式校正

接受几乎所有数据,但删除或更改危险部分。

$trusted_integer = (int) $untrusted_integer;
$trusted_alpha = preg_replace( '/[^a-z]/i', "", $untrusted_alpha );
$trusted_slug = sanitize_title( $untrusted_slug );

例一

假设我们有一个旨在接受美国邮政编码的输入字段:

<input type="text" id="wporg_zip_code" name="my-zipcode" maxlength="10" />

在这里,我们已经告诉浏览器最多只允许输入十个字符……但是对于它们可以输入_的_字符没有限制。他们可以输入11221eval()

这就是验证的用武之地。在处理表单时,我们编写代码来检查每个字段的正确数据类型,如果不正确则将其丢弃。

例如:要检查my-zipcode字段,我们可能会这样做:

/**
 * Validate a US zip code.
 *
 * @param string $zip_code   RAW zip code to check.
 *
 * @return bool              true if valid, false otherwise.
 */
function wporg_is_valid_us_zip_code( string $zip_code ):bool {
    // Scenario 1: empty.
    if ( empty( $zip_code ) ) {
        return false;
    }

    // Scenario 2: more than 10 characters.
    // The `maxlength` attribute is only enforced by 
    // the browser, so we still need to validate the
    // length of the input on the server to protect
    // against a manual submission.
    if ( 10 < strlen( trim( $zip_code ) ) ) {
        return false;
    }

    // Scenario 3: incorrect format.
    if ( ! preg_match( '/^d{5}(-?d{4})?$/', $zip_code ) ) {
        return false;
    }

    // Passed successfully.
    return true;
}

然后,在处理表单时,您的代码应该检查字段wporg_zip_code并根据结果执行操作:

if ( isset( $_POST['wporg_zip_code'] ) && wporg_is_valid_us_zip_code( $_POST['wporg_zip_code'] ) ) {
    // $_POST['wporg_zip_code'] is valid; carry on
}

请注意,此特定示例正在检查提供的数据格式是否正确;它不检查提供的和格式正确的数据是否是有效的邮政编码。为此,您需要第二个函数来与有效邮政编码列表进行比较。

例二

假设您的代码将查询数据库中的帖子,并且您希望允许用户对查询结果进行排序。

$allowed_keys = array( 'author', 'post_author', 'date', 'post_date' );
$orderby      = sanitize_key( $_POST['orderby'] );
if ( in_array( $orderby, $allowed_keys, true ) ) {
    // $orderby is valid; carry on
}

orderby 此示例代码通过将传入的排序键与一组允许的排序键进行比较来检查传入排序键(存储在输入参数中)的有效性。这可以防止用户传入任意和潜在的恶意数据。

在根据数组检查传入的排序键之前,键被传递到内置的 WordPress 函数中 sanitize_key()。此函数确保(除其他外)键是小写的,这是我们想要的,因为in_array()执行区分大小写的搜索。

传递true到 的第三个参数 in_array()启用严格的类型检查,它告诉函数不仅要比较值,还要比较值类型。这允许代码确定传入的排序键是字符串而不是其他某种数据类型。

验证函数

大多数验证是作为自定义代码的一部分完成的,但也有一些辅助函数。这些是除“消毒”页面上列出的之外的内容。

  • balanceTags( $html )force_balance_tags( $html )– 尝试确保 HTML 标签是平衡的,以便输出有效的 XML。
  • count()用于检查数组中有多少项
  • in_array()用于检查数组中是否存在某些内容
  • is_email()将验证电子邮件地址是否有效。
  • in_array()用于检查数组中是否存在某些内容
  • mb_strlen()strlen()用于检查字符串是否具有预期的字符数
  • preg_match(),strpos()用于检查某些字符串在其他字符串中的出现
  • sanitize_html_class( $class, $fallback )– 清理 html 类名以确保它只包含有效字符。将字符串剥离为 AZ,az,0-9,'-',如果这导致空字符串,则它将返回提供的替代值。
  • tag_escape( $html_tag_name )– 清理 HTML 标签名称(不转义任何内容,尽管有函数名称)。
  • term_exists()检查标签、类别或其他分类术语是否存在。
  • username_exists()检查用户名是否存在。
  • validate_file()将验证输入的文件路径是否为真实路径(但不验证文件是否存在)。

查看WordPress 代码参考以了解更多此类功能。搜索具有如下名称的函数:*_exists()*_validate()和 is_*()。并非所有这些都是验证函数,但很多都是有用的。