在 32 位系統上,PHP 整數最大值為 2147483647(PHP_INT_MAX)。當 JSON 包含超過此值的整數時,json_decode() 會發生溢出,導致數值變為負數或浮點數。
<?php
$array = array(
"id1" => 2147483647, // PHP_INT_MAX
"id2" => 2147483648, // 超過最大值
);
$json = json_encode($array);
$out = json_decode($json, true);
var_dump($out);
/* 32位系統輸出:
array(2) {
["id1"]=> int(2147483647)
["id2"]=> int(-2147483646) // 溢出變負數!
}
*/
?>
$x = 2147483648; // floatjson_decode()(PHP 5.3 前)不做此類檢測,直接按有符號 32 位整數解析,導致溢出PHP 5.3+ 已修復此 Bug,大整數會自動解析為 float。現代專案應至少使用 PHP 7.4+。
<?php
$array = array(
"id1" => 2147483647,
"id2" => 2147483648,
);
// 方案 A:預處理陣列,大數值轉字串
function stringify_bigints(&$value) {
if (is_int($value) && ($value > PHP_INT_MAX || $value < -PHP_INT_MAX)) {
$value = (string)$value;
} elseif (is_array($value)) {
array_walk_recursive($value, 'stringify_bigints');
}
}
stringify_bigints($array);
$json = json_encode($array);
// 結果:{"id1":2147483647,"id2":"2147483648"}
$out = json_decode($json, true);
var_dump($out);
/* 輸出:
array(2) {
["id1"]=> int(2147483647)
["id2"]=> string(10) "2147483648" // 保持字串,不溢出
}
*/
?>
<?php
$json = json_encode($array);
// 針對特定欄位名(如 id、uid、snowflake_id)的大數值加引號
$json = preg_replace('/("(?:id|uid|snowflake_id)"\s*:\s*)(\d{10,})/i', '${1}"${2}"', $json);
$out = json_decode($json, true);
?>
風險:正則可能誤匹配非 ID 欄位的大數值,或漏匹配巢狀結構。建議用方案二的遞迴預處理。
<?php
// PHP 5.4.0 新增選項
$out = json_decode($json, true, 512, JSON_BIGINT_AS_STRING);
// 或
$out = json_decode($json, true, 512, JSON_BIGINT_AS_STRING | JSON_OBJECT_AS_ARRAY);
var_dump($out);
/* 輸出:
array(2) {
["id1"]=> int(2147483647)
["id2"]=> string(10) "2147483648"
}
*/
這是最標準、最高效的解決方式,無需預處理,直接在解碼階段處理。
| PHP 版本 | 推薦方案 | 備註 |
|---|---|---|
| PHP 5.4+ | json_decode($json, true, 512, JSON_BIGINT_AS_STRING) | 官方旗標,零代碼入侵 |
| PHP 5.3 - 5.3.x | 預處理陣列轉字串 + json_encode | 手動處理大數值 |
| PHP 5.2 或更老 | 升級 PHP! | 安全、效能、功能全面落後 |
Number.MAX_SAFE_INTEGER = 9007199254740991,超過此值也會精度丟失{"order_id": "123456789012345678", "amount": 100} —— ID 用字串,金額用數字32 位系統 json_decode 整型溢出是歷史遺留問題。**現代專案請直接使用 JSON_BIGINT_AS_STRING 旗標**,或統一升級至 64 位 PHP 7.4+ 環境。API 設計階段即約定「大整數走字串」,從源頭消除跨語言精度問題。