<?php
// 從字符串開頭提取數字,直到遇到非數字字符
var_dump(intval("123abc")); // 123
var_dump(intval("abc123")); // 0
var_dump(intval("-456")); // -456
var_dump(intval(" 789 ")); // 789 (忽略前導空格)
var_dump(intval("0xFF")); // 0 (不識別十六進制,除非 base=16)
var_dump(intval("0xFF", 16)); // 255
var_dump(intval("077", 8)); // 63 (八進制)
var_dump(intval(3.14)); // 3 (截斷小數)
var_dump(intval(true)); // 1
var_dump(intval(false)); // 0
<?php
// 危險代碼
$id = $_GET['id'];
if (intval($id)) { // 意圖:確保是數字
$sql = "SELECT * FROM users WHERE id = $id"; // 直接拼接!
// 攻擊輸入: id=1 UNION SELECT password FROM admin--
// intval("1 UNION...") => 1 (true)
// SQL 變為: SELECT * FROM users WHERE id = 1 UNION SELECT password FROM admin--
}
intval() 基於 C 標準庫 strtol(),其語義是**「解析前導數字」**,而非**「驗證整個字符串是純整數」**。
intval("1 evil") === 1 → 邏輯判斷通過,但原始字符串含惡意內容。intval("") === 0、intval("abc") === 0 → 非數字開頭返回 0,可能被誤判為「合法的 0」。<?php
function isPositiveIntString(string $val): bool {
return ctype_digit($val) && $val !== '' && $val[0] !== '0'; // 可選:禁止前導零
}
if (isPositiveIntString($_GET['id'])) {
$id = (int)$_GET['id']; // 安全轉換
}
<?php
$id = filter_var($_GET['id'], FILTER_VALIDATE_INT, [
'options' => ['min_range' => 1, 'max_range' => PHP_INT_MAX]
]);
if ($id !== false) {
// $id 已是 int 類型,安全
}
<?php
if (preg_match('/^[1-9]\d*$/', $_GET['id'])) {
$id = (int)$_GET['id'];
}
<?php
class UserId {
public function __construct(public readonly int $value) {
if ($value < 1) throw new InvalidArgumentException('ID 必須為正整數');
}
}
try {
$id = new UserId((int)$_GET['id']); // 先轉換再驗證
} catch (Throwable $e) { /* 400 Bad Request */ }
intval('FF', 16)。WordPress ≤ 2.0.6 wp-trackback.php 使用 intval($charset) 驗證字符集參數,攻擊者傳入 1 UNION SELECT... 繞過檢查導致 SQL 注入。修復改用 ctype_digit + 預處理語句。
intval($_GET[x]) 作為安全檢查,代碼審查工具標記為高危模式。filter_var 或專門驗證類。"1 OR 1=1", "0; DROP TABLE", " 123 ", "0xFF", ""。Psalm/PHPStan 檢測 intval($_GET|_POST|_REQUEST) 模式。intval() 是「解析器」,不是「驗證器」。**永遠不要用 intval() 返回值的真假作為安全判斷依據**。轉型用 (int) 或 intval(),驗證用 filter_var/ctype_digit/正則/值對象,查詢用預處理。三層防線,方能破解「數字開頭」的萬惡之源。