Mac下PHP exec调用at命令报无权限打开锁文件如何修复
MAMP环境下PHP调用
at命令报锁文件无权限的解决方案 问题复现
在搭载MAMP运行环境的Mac设备上,网页端通过PHPexec()函数执行调度命令,代码如下:
$output = array(); $result_code = 0; $command = "echo /Applications/MAMP/bin/php/php7.4.21/bin/php -q " . DOCUMENT_ROOT . "/custom/massimport/scripts/massimport.php param1 param2 | at now 2>&1"; exec($command, $output, $result_code);
执行时返回固定报错:
at: cannot open lockfile /usr/lib/cron/jobs/.lockfile: Operation not permitted
已尝试的无效操作:
- 将
at、crontab、php、httpd全部加入Mac「完全磁盘访问权限」列表 - 手动修改
/usr/lib/cron/jobs/.lockfile的读写权限、所有者及所属用户组
根因说明
报错核心是MacOS的系统完整性保护(SIP)机制默认锁定/usr/lib下的系统路径,非苹果原生授权进程无法写入该路径下的文件,手动修改权限、加普通的完全磁盘访问权限都无法绕过SIP的拦截;另外之前授权的进程列表遗漏了at命令实际执行调度的atrun服务进程,也是权限配置不生效的原因之一。
可行解决方案
方案1:绕开at命令,用PHP原生后台执行(最简便,推荐)
如果你的需求只是触发脚本后让它后台异步运行,不需要依赖at的任务排队、定时调度能力,可以直接用Linux/Mac下的进程后台运行语法改写命令,完全不触碰系统at相关路径,从根源避免权限问题:
$output = array(); $result_code = 0; $phpBin = '/Applications/MAMP/bin/php/php7.4.21/bin/php'; $scriptPath = DOCUMENT_ROOT . "/custom/massimport/scripts/massimport.php param1 param2"; // 转义特殊字符避免路径空格等问题,重定向输出后挂入后台执行,不阻塞当前请求 $command = sprintf("%s -q %s > /dev/null 2>&1 &", escapeshellarg($phpBin), escapeshellarg($scriptPath) ); exec($command, $output, $result_code);
方案2:保留at调度,自定义作业路径绕开SIP限制
如果必须使用at的调度能力,可以通过BSD版at支持的ATJOB_DIR环境变量,把作业存储路径改到非系统保护的目录下:
- 创建自定义at作业目录并给MAMP的web运行用户(默认是
_www)分配权限:sudo mkdir -p /Applications/MAMP/atjobs sudo chown _www:_www /Applications/MAMP/atjobs sudo chmod 700 /Applications/MAMP/atjobs - 把
/usr/libexec/atrun(at命令的实际调度执行进程)加入Mac「完全磁盘访问权限」列表,之前的授权列表遗漏了这个核心进程。 - 重新加载atrun服务确保配置生效:
sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.atrun.plist 2>/dev/null sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.atrun.plist - 修改PHP执行代码,注入环境变量指定自定义作业路径:
$output = array(); $result_code = 0; $phpBin = '/Applications/MAMP/bin/php/php7.4.21/bin/php'; $scriptPath = DOCUMENT_ROOT . "/custom/massimport/scripts/massimport.php param1 param2"; $command = sprintf("echo %s -q %s | ATJOB_DIR=/Applications/MAMP/atjobs at now 2>&1", escapeshellarg($phpBin), escapeshellarg($scriptPath) ); exec($command, $output, $result_code);
方案3:临时关闭SIP(不推荐,存在安全风险)
如果上述方案都不适用,可以关闭系统完整性保护来放开系统路径权限:
- 重启Mac,按住
Command+R进入恢复模式 - 打开终端执行
csrutil disable - 重启设备后即可正常修改
/usr/lib/cron路径下的文件权限
该方案会降低系统对恶意程序的防护能力,非必要不要使用。
注意事项
给进程加完全磁盘访问权限时,要选择MAMP安装目录下的对应二进制文件(比如httpd路径是/Applications/MAMP/Library/bin/httpd,PHP路径是/Applications/MAMP/bin/php/php7.4.21/bin/php),不要选择系统自带的同名二进制,否则授权不会生效。
内容的提问来源于stack exchange,提问作者karozans
相关产品推荐
相关产品推荐

