【问题标题】:Checking that a value contains only digits, regex or no?检查一个值是否只包含数字、正则表达式或不包含?
【发布时间】:2012-11-26 13:59:34
【问题描述】:

我有一个在我的代码中使用的函数。该函数期望传递的参数是一个正整数。由于 PHP 是松散类型的,因此数据类型并不重要。但它很重要,它只包含数字。目前,我正在使用正则表达式来检查值,然后再继续。

这是我的代码的简化版

function do_something($company_id) {
    if (preg_match('/\D/', $company_id)) exit('Invalid parameter');
    //do several things that expect $company_id to be an integer
}

我来自 Perl 背景,经常使用正则表达式。但是,我知道它们的用法存在争议。

我考虑使用intval()(int)强制 $company_id 是一个整数。但是,我最终可能会得到一些意想不到的值,我希望它快速失败

另一个选项是:

if (!ctype_digit((string) $company_id)) exit('Invalid parameter');

这种情况是正则表达式的有效使用吗?一种方式优于另一种方式吗?如果是这样,为什么?有没有我没有考虑过的问题?

【问题讨论】:

  • ctype_digit 有什么问题?
  • 我看到ctype_digit 的唯一缺点是它必须先转换为字符串。但是,我发现regex 更易于阅读,而且我已经习惯了。我试图确定是否有令人信服的理由转换。

标签: php regex validation


【解决方案1】:

目标

最初的问题是关于验证未知数据类型的值并丢弃所有值,除了那些只包含数字的值。似乎只有两种方法可以达到预期的效果。

如果目标是快速失败,则需要检查无效值然后失败,而不是检查有效值并将所有代码包装在if 块中。

问题选项 1

if (preg_match('/\D/', $company_id)) exit('Invalid parameter');

如果匹配非数字,则使用 regex 失败。缺点:正则表达式引擎有开销

问题中的选项 2

if (!ctype_digit((string) $company_id)) exit('Invalid parameter');

如果为 FALSE,则使用 ctype_digit 失败。缺点:必须将值转换为字符串,这是一个(小)额外步骤

您必须将值转换为字符串,因为ctype_digit 需要一个字符串,PHP 不会为您将参数转换为字符串。如果你将一个整数传递给ctype_digit,你会得到意想不到的结果。

这是记录在案的行为。例如:

ctype_digit('42'); // true
ctype_digit(42); // false (ASCII 42 is the * character)

选项 1 和 2 的区别

由于正则表达式引擎的开销,选项二可能是最好的选择。但是,担心这两个选项之间的差异可能属于过早优化类别。

注意:上述两个选项之间也存在功能差异。第一个选项将NULL 和空字符串视为有效值,第二个选项不考虑(从 PHP 5.1.0 开始)。这可能会使一种方法比另一种方法更受欢迎。要使regex 选项功能与ctype_digit 版本相同,请改用它。

if (!preg_match('/^\d+$/', $company_id)) exit('Invalid parameter');

注意:上述regex中的'字符串开始'^和'字符串结束'$锚点非常重要。否则,abc123def 将被视为有效。

其他选项

此处和其他问题中提出了其他方法可能会帮助别人。

  • is_numeric 允许指数部分、浮点数和十六进制值

  • is_int 检查数据类型而不是值,如果 '1' 被视为有效,则该值对验证没有用处。表单输入始终是一个字符串。如果您不确定值的来源,则无法确定数据类型。

  • filter_varFILTER_VALIDATE_INT 允许负整数和值,例如 1.0。无论数据类型如何,这似乎都是实际验证整数的最佳功能。但如果你想要 only 个数字,则不起作用。 注意:如果0 被视为有效值,则检查FALSE 身份 而不仅仅是真假是很重要的。

【讨论】:

    【解决方案2】:

    这两种方法都会将变量转换为字符串。 preg_match 不接受整数类型的主题,因此一旦传递给函数,它将被强制转换为字符串。 ctype_digit 绝对是这种情况下最好的解决方案。

    【讨论】:

    • Both methods will cast the variable into a string. 确实如此...除了preg_match,PHP 会为您做到这一点。而对于ctype_digit,您需要自己动手。
    【解决方案3】:

    filter_var + FILTER_VALIDATE_INT 呢?

    if (FALSE === ($id = filter_var($_GET['id'], FILTER_VALIDATE_INT))) {
        // $_GET['id'] does not look like a valid int
    } else {
        // $id is a int because $_GET['id'] looks like a valid int
    }
    

    此外,它还有 min_range/max_range 选项。

    这个函数的基本思想或多或少等价于:

    function validate_int($string) {
        if (!ctype_digit($string)) {
            return FALSE;
        } else {
            return intval($string);
        }
    }
    

    另外,如果您期望一个整数,您可以使用is_int。不幸的是,类型提示仅限于对象和数组。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-30
      • 1970-01-01
      • 2021-06-06
      • 1970-01-01
      • 1970-01-01
      • 2012-02-19
      • 1970-01-01
      相关资源
      最近更新 更多