PHP的pcntl_signal_dispatch和posix_kill、pcntl_signal配合发送信号

本文深入解析了PHP中如何使用pcntl_signal函数注册信号处理器,并通过实例展示了如何响应SIGINT和SIGUSR2信号,执行特定的业务操作。

先看下以下代码:

//注册SIGINT和SIGUSR2信号的响应
pcntl_signal(SIGINT, 'signalHandler', false);  //SIGINT : 2
pcntl_signal(SIGUSR2, 'signalHandler', false); //SIGINT : 12

function signalHandler($signal)
{
    echo "收到了信号:" . $signal;

    if ($signal == SIGUSR2) {
        echo "进行业务操作1" . PHP_EOL;
    } elseif ($signal == SIGINT) {
        echo "进行业务操作2" . PHP_EOL;
    }
    // 其他的else if逻辑...
}

while (true) {
    sleep(1);
    //调用该方法,信号处理函数才会被执行
    pcntl_signal_dispatch();
}

先解释下上面的代码的含义:

//官方手册解释如下:
bool  pcntl_signal( int $signo, callback $handler[, bool $restart_syscalls = true] )
函数pcntl_signal()为signo指定的信号安装一个新的信号处理器。 返回一个布尔值

首先pcntl_signal()函数,他是注册某一个信号与处理该信号的一个回调函数。那么信号是什么呢,也就是linux命令中:kill 命令后面的那个数字。可以用下面的方法查看所有信号:

root@ubuntu-virtual-machine:/var/www/html/test# kill -l
 1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP
 6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
63) SIGRTMAX-1	64) SIGRTMAX	

我们常用的kill -9 杀死某个进程,其中这个9指的就是SIGKILL 。

所以上面的这段代码:

pcntl_signal(SIGINT, 'signalHandler', false); //SIGINT : 2

含义就是,当你输入的是SIGINT(也就是kill 2)时,他将使用回调函数"signalHandler( )",来处理逻辑。

而其中的while循环:

while (true) {
    sleep(1);
    //调用该方法,信号处理函数才会被执行
    pcntl_signal_dispatch();
}

其中的sleep(1),是为了减轻CPU的压力,毕竟该循环是一个死循环。而函数 pcntl_signal_dispatch();说明如下:

          bool pcntl_signal_dispatch ( void )

         函数pcntl_signal_dispatch()调用每个等待信号通过pcntl_signal() 安装的处理器。

其实就是调用上面写的那个回调方法“signalHandler()”,在调用该方法的同时,将从命令行输入的那个kill后面的那个数字当做参数传递到这个回调方法中(或者将posix_kill()方法中的信号,当做参数传递到这个方法中去),然后开始执行那个回调方法中的逻辑 。比如下面的这个代码块儿,就是传递的posix_kill()中的信号:

echo "安装信号处理器...\n";
pcntl_signal(SIGHUP, function ($signo) {
    echo "信号处理器被调用\n";
});

echo "为自己生成SIGHUP信号...\n";
posix_kill(posix_getpid(), SIGHUP);//posix_getpid()函数是获取当前进程号

echo "分发...\n";
pcntl_signal_dispatch();

echo "完成\n";

参考:https://blog.youkuaiyun.com/weixin_42075590/article/details/80740968

你已经找到了关键配置文件,并且当前的 `disable_functions` 列表如下: ```ini disable_functions = passthru,exec,system,putenv,chroot,chgrp,chown,shell_exec,popen,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv ``` ✅ **好消息是:** 👉 `proc_open` `proc_close` 并不在这个列表中! --- ## ❓那为什么还会报错? ```text Error: Cannot do 'Process::run': The PHP functions `proc_open()` and/or `proc_close()` are disabled. ``` ### 🔍 原因分析 虽然你在 `php-cli.ini` 中没有禁用 `proc_open`,但可能有以下几种情况导致函数仍然不可用: --- ### ✅ 排查 1:确认是否真的加载了正确的 php.ini 运行命令查看 CLI 模式下实际生效的配置: ```bash /www/server/php/74/bin/php -c /www/server/php/74/etc/php-cli.ini --ini ``` 或者更直接地: ```bash /www/server/php/74/bin/php -i | grep "Configuration File" ``` 🎯 正确输出应为: ``` Configuration File (php.ini) Path => /www/server/php/74/etc Loaded Configuration File => /www/server/php/74/etc/php-cli.ini ``` 如果这里显示的是另一个文件(比如 `/usr/local/lib/php.ini`),说明你改错了地方! --- ### ✅ 排查 2:检查是否有 Suhosin 或其他安全模块拦截 Suhosin 是一个增强型安全补丁,会额外限制函数调用。 运行: ```bash /www/server/php/74/bin/php -m | grep -i suhosin ``` - 如果无输出 → 没装 Suhosin,排除此项 - 如果有 → 需要修改 Suhosin 配置允许 `proc_open` > ⚠️ 宝塔默认不安装 Suhosin,所以大概率不是这个问题。 --- ### ✅ 排查 3:测试 `proc_open` 是否真能用(最直接的方法) 创建一个测试脚本: ```bash cat > test_proc.php << 'EOF' <?php if (function_exists('proc_open')) { echo "✅ proc_open() is available.\n"; } else { echo "❌ proc_open() is DISABLED!\n"; } $process = proc_open('echo hello', [ 0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w'] ], $pipes); if (is_resource($process)) { fclose($pipes[0]); $output = stream_get_contents($pipes[1]); fclose($pipes[1]); fclose($pipes[2]); proc_close($process); echo "✔️ proc_open() works! Output: '$output'\n"; } else { echo "❌ proc_open() failed to run.\n"; } EOF ``` 然后执行: ```bash /www/server/php/74/bin/php test_proc.php ``` 🎯 正常输出应该是: ``` ✅ proc_open() is available. ✔️ proc_open() works! Output: 'hello' ``` 🔴 如果出现“DISABLED”或“failed”,说明确实被禁用了。 --- ### ✅ 排查 4:宝塔面板的“PHP 执行目录”限制(常见坑!) 宝塔有一个隐藏机制:某些站点设置了“防跨站攻击”,会自动添加: ```php disable_functions=...proc_open... ``` 通过 PHP-FPM 的 `env[PATH]` 或 `php_admin_value[disable_functions]` 注入。 #### 检查方法: 查看你的网站对应的 PHP-FPM 配置文件: ```bash # 查看所有池配置(通常每个网站一个) ls /www/server/php/74/etc/php-fpm.d/ # 编辑某个池(例如 www.conf 或 your-site.conf) cat /www/server/php/74/etc/php-fpm.d/www.conf | grep -A 5 -B 5 "disable_functions" ``` 🔍 查找是否有类似: ```ini php_admin_value[disable_functions] = ...proc_open... ``` 📌 这种设置即使 php.ini 允许也会被强制关闭! #### 解决方案: 进入 **宝塔面板 → 网站 → 对应站点 → PHP 设置 → 关闭“防跨站攻击”(open_basedir)** 或者手动编辑该 `.conf` 文件,删除或修改 `php_admin_value[disable_functions]` 中对 `proc_open` 的限制。 --- ### ✅ 排查 5:使用了错误的 PHP 二进制? 确认 WP-CLI 调用的是哪个 PHP: ```bash which php ``` 你应该看到: ```text /bin/php ``` 但这个符号链接可能指向旧版或受限版本。 强制让 WP-CLI 使用宝塔的 PHP: ```bash export PATH="/www/server/php/74/bin:$PATH" ``` 然后重试: ```bash wp --info ``` 或者临时指定 PHP: ```bash /usr/bin/env /www/server/php/74/bin/php /usr/local/bin/wp --info ``` --- ## ✅ 最终解决方案建议(推荐操作顺序) ### ✅ 第一步:确保使用正确 PHP 并启用 proc_open ```bash # 明确使用宝塔 PHP export PATH="/www/server/php/74/bin:$PATH" # 测试函数可用性 /www/server/php/74/bin/php -r "var_dump(function_exists('proc_open'));" ``` 预期输出:`bool(true)` --- ### ✅ 第二步:创建软链接统一环境 ```bash ln -sf /www/server/php/74/bin/php /usr/bin/php ln -sf /www/server/php/74/bin/php /bin/php ``` 避免路径混乱。 --- ### ✅ 第三步:重启终端并验证 ```bash wp --info ``` 现在应该不再报错。 --- ## 🧩 补充知识:为什么 WP-CLI 需要 `proc_open`? WP-CLI 使用 `Symfony\Component\Process` 组件来执行外部命令,例如: - `wp db export` → 调用 `mysqldump` - `wp core download` → 调用网络请求或 git - `wp eval-file` → 子进程隔离运行 而 `proc_open` 比 `exec/system` 更安全、可控性强(可以捕获输出、设置超时、管理管道),所以现代工具都优先使用它。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值