pcntl_alarm()的示例

本文详细解析了如何使用PHP的pcntl_alarm函数创建定时器,通过向进程发送SIGALRM信号实现周期性的任务执行。文章通过一个示例程序展示了信号的注册、发送和处理流程。

pcntl_alarm — 为进程设置一个alarm闹钟信号 

创建一个计时器,在指定的秒数后向进程发送一个SIGALRM信号。每次对 pcntl_alarm()的调用都会取消之前设置的alarm信号。

<?php

pcntl_signal(SIGALRM, function () {
    pcntl_alarm(2);
    echo 'Received an alarm signal !' . PHP_EOL;
}, false);

pcntl_alarm(2);

while (true) {
    pcntl_signal_dispatch();
    sleep(1);
}

上面程序的执行流程是:

1、首先pcntl_signal()函数注册一个SIGALRM信号到它的第二个参数(闭包函数)上去。-----意思就是:当你收到这个SIGALRM信号后,执行那个闭包函数。(首先,先去掉闭包函数中的  pcntl_alarm(2); 这一项,然后再加上这一项,两次做对比可以看大不同)然后闭包函数中是echo了一个字符串。

2、pcntl_alarm(2)的含义是,系统就会在 2 秒之后给当前进程发一个SIGALRM信号

3、一直循环调用pcntl_signal_dispatch()函数,去捕捉传进来的信号

4、捕捉到信息后,执行第一个中的闭包函数,该函数echo字符串后,再次调用pcntl_alrm(2),然后在过2秒钟后再次向当前进程发送一个SIGALRM信号,如果往复...(可以在linux命令行用:php  demo.php测试下看看效果)

你已经找到了关键配置文件,并且当前的 `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、付费专栏及课程。

余额充值