You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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字节无符号长整型)来解析,导致后续字段全部错位。
  • 部分平台的结构体对齐填充也会影响,但主要原因是类型长度不匹配。

解决步骤

  1. 确认结构体实际大小
    编译运行上面修改后的C程序,查看sizeof(struct input_event)的输出,确保PHP中fread的字节数和这个值一致(通常x86_64下是24字节)。

  2. 修正unpack格式
    根据系统架构调整格式:

    • x86_64小端系统(绝大多数桌面/服务器Linux):

      $event = unpack("Psec/Pusec/vtype/vcode/Vvalue", $ev);
      

      格式说明:

      • P:小端8字节无符号长整型,匹配C的long
      • v:小端2字节无符号短整型,匹配unsigned short
      • V:小端4字节无符号整型,匹配unsigned int
    • 32位x86系统:

      $event = unpack("Vsec/Vusec/vtype/vcode/Vvalue", $ev);
      

      32位系统中long是4字节,用V解析。

  3. 验证结果
    修改后运行PHP程序,应该能得到和C程序一致的解析结果。

内容的提问来源于stack exchange,提问作者behrad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 05:45:57