PHP中json_decode的整型溢出问题

本文探讨了在PHP中使用JSON处理大整数值时遇到的问题,特别是在32位操作系统上,由于整数溢出导致的数据损坏现象。文章提供了两种解决方案:升级PHP版本或在编码时将大整数转化为字符串。

编码过程中遇到个错误,就是在处理json时,数值较大的int值在解码后数据被损坏,比如:

$array = array(
    "id1" => 2147483647,
    "id2" => 2147483648
);
$json = json_encode($array);
$out = json_decode($json, true);
var_dump($out);

理论上应该看到:

array(2) {
    ["id1"]=>int(2147483647)
    ["id2"]=>int(2147483648)
}

但实际在我的电脑上却得到:

array(2) {
    ["id1"]=>int(2147483647)
    ["id2"]=>int(-2147483646)
}

这是由PHP整数值范围决定的,而这个范围依赖于操作系统。在32位操作系统中,PHP的整数最大值是2147483647,你可以通过输出PHP_INT_MAX看到。

一般情况下,你赋值一个很大的数,PHP会自动判定这个数值的范围并自动转换类型,如:

$large_number = 2147483647;
var_dump($large_number);                     // int(2147483647)
 
$large_number = 2147483648;
var_dump($large_number);                     // float(2147483648)
 
$million = 1000000;
$large_number =  50000 * $million;
var_dump($large_number);                     // float(50000000000)

但是在json_decode方法中没有进行这种检测,这是PHP(旧版本)的bug,在5.3以后的版本,就不存在这个问题了。

如果你不想更新你的PHP,那还有个办法,就是将数字转为字符串。还是以上面的代码为例:

$array = array(
    "id1" => 2147483647,
    "id2" => 2147483648
);
$json = json_encode($array);
 
$json = preg_replace('/("id\d":)(\d{9,})/i', '${1}"${2}"', $json);
 
$out = json_decode($json, true);
var_dump($out);

当然,这个怎么替换是按需而定的,而且需要比较细致的测试。

帮我精简优化这段代码,可以随意改动static void *get_spectrum_thread(void *arg) { int sockfd = init_udp_ser(12307); if (sockfd < 0) { log_error("Failed to initialize UDP server \r\n"); pthread_exit(NULL); } struct sockaddr_in client_addr; socklen_t addr_len = sizeof(client_addr); size_t max_size = 4096; parse_spectrum_msg parse_spectrum_data = {0}; unsigned char *decoded_data = NULL; char *splice_data = calloc((2 * max_size), sizeof(char)); char *recv_udp_buffer = calloc(max_size, sizeof(char)); char *float_data = calloc(max_size, sizeof(float)); char *freq_data = calloc(max_size, sizeof(float)); char *dbm_data = calloc(max_size, sizeof(float)); if (float_data == NULL || freq_data == NULL || dbm_data == NULL || recv_udp_buffer == NULL || splice_data == NULL) { log_error("Memory allocation failed \r\n"); goto cleanup; } int expected_chunks = 0; int received_chunks = 0; while (1) { // 等待开启标志 if (!sharedData->spectrumInfo.spectrum_flag) { usleep(4 * 1000); //4ms检测一次频谱功能是否开启 continue; } ssize_t recv_len = recvfrom(sockfd, recv_udp_buffer, sizeof(recv_udp_buffer) - 1, 0, (struct sockaddr*)&client_addr, &addr_len); if (recv_len < 0) { log_error("failed to recvfrom \r\n"); goto cleanup; } recv_udp_buffer[recv_len] = '\0'; // 检查是否包含 RealResult if (recv_len == 0 || strstr(recv_udp_buffer, "RealResult") == NULL) { continue; } parse_spectrum_json_data(&parse_spectrum_data, recv_udp_buffer); int chunk_id = parse_spectrum_data.chunk_id; int total_chunks = parse_spectrum_data.total_chunks; // 多包拼接 if (chunk_id == 0) { memset(data, 0, sizeof(data)); strcat(data, parse_spectrum_data.data); expected_chunks = total_chunks; received_chunks = 1; } else if (chunk_id == received_chunks && expected_chunks == total_chunks) { strncat(data, parse_spectrum_data.data, sizeof(data) - strlen(data) - 1); received_chunks++; } else { // 乱序或错误序列号,重置状态 fprintf(stderr, "Out-of-order or inconsistent chunks, resetting\n"); expected_chunks = 0; received_chunks = 0; continue; } // 所有分片接收完成 if (received_chunks == expected_chunks) { decoded_data = base64_decode(data, &recv_len); if (!decoded_data || recv_len == 0) { fprintf(stderr, "Final base64 decode failed\n"); expected_chunks = 0; received_chunks = 0; continue; } size_t float_count = recv_len / sizeof(float); if (float_count > max_size) { fprintf(stderr, "Combined data too large: %zu floats\n", float_count); free(decoded_data); expected_chunks = 0; received_chunks = 0; continue; } memcpy(float_data, decoded_data, recv_len); free(decoded_data); parse_spectrum_array_data(float_data, float_count, freq_data, dbm_data); pthread_mutex_lock(&spectrum_mutex); if (sharedData->spectrumInfo.spectrum_array) { free(sharedData->spectrumInfo.spectrum_array); sharedData->spectrumInfo.spectrum_array = NULL; } sharedData->spectrumInfo.spectrum_array = create_json_spectrum_arrays(sharedData->spectrumInfo.spectrum_flags, sharedData->spectrumInfo.start_freq, sharedData->spectrumInfo.end_freq, freq_data, float_count / 2, dbm_data, float_count / 2); if (log_file_state) log_info("get_spectrum_array = %s \r\n", sharedData->spectrumInfo.spectrum_array); pthread_mutex_unlock(&spectrum_mutex); expected_chunks = 0; received_chunks = 0; memset(data, 0, sizeof(data)); } usleep(2 * 1000); } cleanup: close(sockfd); free(float_data); free(freq_data); free(dbm_data); free(splice_data); free(recv_udp_buffer); pthread_exit(NULL); }
最新发布
11-30
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值