PHP的is_int函数表现不如预期

10
我有一个页面(index.php),它从URL中获取一个GET变量并进行安全检查。这个GET变量应该只是一个整数。我使用以下代码来检查,但在所有情况下,无论是整数还是非整数,我都会得到index.php页面。头部从未出现。在此代码之后,其余页面内容将出现,从html标签开始。
PHP:
<?php ob_start(); session_start();
$q=trim($_GET['q']);
if (!is_numeric($q)){
header("HTTP/1.0 404 Not Found");
}
?>

2
我不知道你是否已经意识到,但在 header(..) 后面应该添加一个 exit();。否则脚本将继续打印页面内容。 - laher
阅读文档会告诉你,is_int()检查变量的类型,因此将字符串“123”传递给is_int()将不会返回true,因为它是一个字符串。另外,你为什么要在帖子中标记http-status-code-404 - Tadeck
@Tadeck 标签已删除。感谢您提供的文档。我现在正在使用 is_numeric,但它仍然无法正常工作。 - kirby
@amir75,你是对的。它起作用了!如果我使用die();代替,可以吗? - kirby
3个回答

31

如果被传递到查询字符串中,则它将不是整数。

尝试使用is_numeric()


3
ctype_digit()可以用于判断一个字符串是否只包含数字。 - leemeichin
@alien,我已经更新了我的代码,但是我得到了与之前相同的行为 :[ - kirby
尝试将 ob_start; 更改为 ob_start(); - AlienWebguy
@AlienWebguy 当我用 die("test") 替换 header 时,它完美地工作了。我的 header 必须有问题。我需要在服务器上设置一个 404 页面吗? - kirby
你可以在你的 .htaccess 文件中轻松实现这个功能:ErrorDocument 404 /notfound.html - AlienWebguy
@maohieng 因为在查询字符串中传递的数字实际上是字符串。 is_int(123) // true is_int('123') // false is_numeric(123) // true is_numeric('123') // true - AlienWebguy

5

有更好的方法来完成这个任务,那就是将其转换为整数:

$q = (int) $_GET['q'];

is_int 如预期般工作,因为 GET 参数始终是字符串。尝试使用 var_dump 来查看它们。


2
想一想,AlienWebguy的答案可能更好,因为您将能够过滤掉任何“奇怪”的值... - Joep

1
有时您需要验证应该是数字的输入,但在$_GET$_POST中,您将其作为字符串获取。is_numeric()可能存在问题,因为它允许十六进制、二进制和八进制格式(来自手册): 因此+0123.45e6是有效的数字值。十六进制(例如0xf4c3b00c)、二进制(例如0b10100111001)和八进制(例如0777)表示法也是允许的,但只能没有符号、小数和指数部分。 您不能使用is_int(),因为它仅适用于整数值(不是字符串!)所以...您可以通过以下方式验证既是字符串又是整数的数字:
/**
 * Validate integer.
 */
class IntegerValidator
{
    /**
     * Run validation.
     * @param string $value
     * @return bool
     */
    public static function isIntVal(string $value): bool
    {
        if (!self::hasValidIntegerFormat($value)) {
            return false;
        }

        return !self::hasLeadingZero($value);
    }

    /**
     * Check if given string looks like valid integer. Negative numbers allowed.
     * @param string $value
     * @return bool
     */
    private static function hasValidIntegerFormat(string $value): bool
    {
        return (bool) preg_match('/^-?[0-9]+$/', $value);
    }

    /**
     * Check if given number has leading 0. Thus it's invalid integer.
     * @param string $number
     * @return bool
     */
    private static function hasLeadingZero(string $number): bool
    {
        return self::extractFirstDigit($number) === 0;
    }

    /**
     * Extract first digit from given number.
     * @param string $number
     * @return int
     */
    private static function extractFirstDigit(string $number): int
    {
        return self::isNegativeInteger($number)
            ? (int) $number[1]
            : (int) $number[0];
    }

    /**
     * Check if number is negative integer. ie. starts with minus sign on the beginning.
     * @param string $number
     * @return bool
     */
    private static function isNegativeInteger(string $number): bool
    {
        return $number[0] === '-';
    }
}

var_dump(IntegerValidator::isIntVal('123'));   // true
var_dump(IntegerValidator::isIntVal('0123'));  // false
var_dump(IntegerValidator::isIntVal('-0123')); // false
var_dump(IntegerValidator::isIntVal('-123'));  // true

还可以使用override_function()来覆盖is_int()函数,但在原始版本中它仍然可能有用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接