Apache下PHP调用shell_exec执行Shell脚本重启Java进程失效排查
问题原因排查与修复方案
核心故障原因
- 权限不足:PHP作为Apache的子进程运行,默认使用低权限业务用户(常见为
apache、www-data),没有启停系统服务、强杀其他用户进程的权限。手动在终端执行脚本时用的是登录账号(一般是root或有sudo权限的运维账号),所以能正常运行,PHP触发时所有需要高权限的操作都会被系统拦截。 - 相对路径失效:脚本里启动jar包用的是相对路径
RSN_API_Controller.jar,PHP执行shell命令时的工作目录不是脚本所在的/opt/APIController/,会直接报找不到jar文件,启动失败。 - 环境变量缺失:PHP触发shell执行时不会加载用户全局/个人的环境变量配置,经常出现找不到
java、service等命令的情况,导致命令执行中断。 - 输出流阻塞:nohup启动进程时没有重定向标准输出和错误输出,
shell_exec函数会等待所有输出流关闭才会结束执行,容易导致进程挂死、启动异常。
分步修复操作
第一步:修正Shell脚本内容
替换原有脚本为以下版本,补全绝对路径、环境变量加载、输出重定向逻辑:
#!/bin/bash # 加载系统环境变量 source /etc/profile [ -f ~/.bashrc ] && source ~/.bashrc # 强制切换到脚本所在工作目录 WORK_DIR=/opt/APIController cd $WORK_DIR # 注意:如果不知道命令的绝对路径,可以在服务器执行which service、which java查询对应路径 /usr/sbin/service cassandra start /usr/sbin/service httpd start prid=$(ps aux| egrep '[R]SN_API_Controller.jar' | awk '{print $2}') if [ -z "$prid" ] then echo "No process to kill" else kill -9 $prid echo "Successfully service stopped" fi pridold=$(ps aux| egrep '[R]snBlacklist.jar' | awk '{print $2}') if [ -z "$pridold" ] then echo "No process to kill" else kill -9 $pridold echo "Successfully service stopped old jar file" fi # 重定向所有输出到日志文件,避免流阻塞 nohup /usr/bin/java -Djsse.enableSNIExtension=false -jar RSN_API_Controller.jar > $WORK_DIR/api_controller.log 2>&1 & echo "Successfully service started"
修改完成后给脚本加可执行权限:chmod +x /opt/APIController/RSN_API_Controller_start.sh
第二步:配置最小化sudo权限
不要给PHP运行用户全量root权限,仅开放该脚本的执行权限即可:
- 执行
visudo命令打开sudo配置文件 - 先找到
Defaults requiretty配置行,前面加#注释掉,否则sudo执行会报无tty终端的错误 - 在文件末尾新增一行(如果你的Apache运行用户是www-data,就把下面的
apache替换成实际用户,可通过ps aux | grep httpd查看第一列的运行用户确认):apache ALL=(ALL) NOPASSWD: /opt/APIController/RSN_API_Controller_start.sh - 保存退出配置文件
第三步:调整PHP调用代码
修改原有调用逻辑,加sudo执行,同时保留输出方便调试:
<?php //some lines // 2>&1 会把错误输出也合并到返回结果里,方便定位问题 $exec_result = shell_exec('sudo /bin/bash /opt/APIController/RSN_API_Controller_start.sh 2>&1'); // 调试阶段可以打印结果看具体报错,功能正常后可注释 var_dump($exec_result); //some lines ?>
快速排查技巧
如果配置后仍无法正常执行,可以先写一个测试PHP文件,内容为<?php echo shell_exec('whoami');,访问该文件确认PHP实际运行用户,再对应调整sudo配置即可。
内容的提问来源于stack exchange,提问作者Harish Mahi
相关产品推荐
相关产品推荐

