PHP读取Linux /dev/input/event*结果与C程序不符问题排查
PHP解析Linux输入事件异常的解决方法
问题场景
用PHP读取/dev/input/event0获取键盘事件时,仅sec参数解析正确,usec、type、code、value均异常,和同逻辑的C程序输出完全不符。
PHP代码
<?php $fd = fopen("/dev/input/event0", "rb"); while (true) { $ev = fread($fd, 24); $event = unpack("Lsec/Lusec/Stype/Scode/Ivalue", $ev); var_dump($event); } fclose($fd); ?>
C语言对比代码
#include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <linux/input.h> int main() { struct input_event ev; int fd = open("/dev/input/event0", O_RDONLY); // 打印结构体大小,用于验证PHP读取字节数 printf("Size of input_event: %zu\n", sizeof(struct input_event)); while(1) { read(fd, &ev, sizeof(ev)); printf ("Event sec: %lu\n", ev.time.tv_sec); printf ("Event usec: %lu\n", ev.time.tv_usec); printf("Event type: %d\n", ev.type); printf("Event code: %d\n", ev.code); printf("Event value: %d\n", ev.value); printf("-------------------------\n"); } close(fd); }
输出对比
C程序输出片段:
Event sec: 1700377522 Event usec: 896483 Event type: 4 Event code: 4 Event value: 31 ------------------------- Event sec: 1700377522 Event usec: 896483 Event type: 1 Event code: 31 Event value: 1 -------------------------
PHP程序输出片段:
array(5) { ["sec"]=> int(1700377522) ["usec"]=> int(0) ["type"]=> int(44515) ["code"]=> int(13) ["value"]=> int(0) } array(5) { ["sec"]=> int(1700377522) ["usec"]=> int(0) ["type"]=> int(44515) ["code"]=> int(13) ["value"]=> int(0) }
问题根源
核心错误是PHP unpack格式与C结构体的类型字节长度不匹配:
- Linux的
struct timeval中,tv_sec和tv_usec是long类型,在x86_64系统下占8字节;但你用了L(PHP中对应4字节无符号长整型)来解析,导致后续字段全部错位。 - 部分平台的结构体对齐填充也会影响,但主要原因是类型长度不匹配。
解决步骤
确认结构体实际大小
编译运行上面修改后的C程序,查看sizeof(struct input_event)的输出,确保PHP中fread的字节数和这个值一致(通常x86_64下是24字节)。修正unpack格式
根据系统架构调整格式:x86_64小端系统(绝大多数桌面/服务器Linux):
$event = unpack("Psec/Pusec/vtype/vcode/Vvalue", $ev);格式说明:
P:小端8字节无符号长整型,匹配C的longv:小端2字节无符号短整型,匹配unsigned shortV:小端4字节无符号整型,匹配unsigned int
32位x86系统:
$event = unpack("Vsec/Vusec/vtype/vcode/Vvalue", $ev);32位系统中
long是4字节,用V解析。
验证结果
修改后运行PHP程序,应该能得到和C程序一致的解析结果。
内容的提问来源于stack exchange,提问作者behrad
相关产品推荐
相关产品推荐

