PHP调用Python时subprocess.run无法执行命令的求助
排查PHP调用Python+unoconv转换失败的问题
以下是针对性的排查步骤,按优先级排序:
1. 强制使用绝对路径调用所有程序
web用户(www-data)的环境变量PATH通常比终端用户窄很多,直接用unoconv可能找不到可执行文件。修改Python脚本里的subprocess调用,用绝对路径:
# 先在终端执行 `which unoconv` 拿到绝对路径,比如 /usr/bin/unoconv subprocess.run(['/usr/bin/unoconv', '-f', 'pdf', 'your_file.docx'], check=True, capture_output=True, text=True)
同时PHP里调用Python时也尽量用绝对路径,加上2>&1把错误输出重定向到标准输出,方便排查:
$output = shell_exec('/usr/bin/python3 /path/to/conv_docx_pdf.py 2>&1'); var_dump($output);
2. 捕获并查看所有错误输出
不管是PHP还是Python,都要把错误信息打出来:
- Python端:给subprocess加上参数捕获异常并打印stderr:
try: result = subprocess.run(['/usr/bin/unoconv', '-f', 'pdf', '/path/to/your.docx'], check=True, capture_output=True, text=True) except subprocess.CalledProcessError as e: print(f"Error: {e.stderr}") raise
这些错误信息是排查核心,比如可能提示"LibreOffice not found"或者权限不足。
3. 用www-data身份手动测试执行
直接模拟PHP的执行环境,用www-data身份运行Python脚本:
sudo -u www-data python3 /path/to/conv_docx_pdf.py
如果这里报错,说明问题出在www-data用户的环境或权限上,而非PHP调用逻辑。
4. 检查LibreOffice/OpenOffice的运行权限
unoconv依赖LibreOffice/OpenOffice的后台服务,www-data用户可能无法启动或访问这个服务:
- 如果报错无法连接到LibreOffice,手动启动一个headless服务给www-data用:
sudo -u www-data libreoffice --headless --invisible --nocrashreport --nodefault --nofirststartwizard --norestore --accept="socket,host=127.0.0.1,port=2002;urp;" &
然后修改Python脚本里的unoconv调用,指定这个服务:
subprocess.run(['/usr/bin/unoconv', '-c', 'socket,host=127.0.0.1,port=2002;urp;', '-f', 'pdf', '/path/to/your.docx'], check=True)
5. 检查临时文件目录权限
unoconv在转换时会用到临时目录(比如/tmp),确保www-data对这个目录有读写权限。也可以在Python脚本里指定自定义临时目录:
import tempfile import os # 创建www-data可写的临时目录 with tempfile.TemporaryDirectory(dir='/var/www/tmp') as tmpdir: os.environ['TMPDIR'] = tmpdir subprocess.run(['/usr/bin/unoconv', '-f', 'pdf', '/path/to/your.docx'], check=True)
注意先创建并设置目录权限:
sudo mkdir /var/www/tmp && sudo chown www-data:www-data /var/www/tmp && sudo chmod 700 /var/www/tmp
6. 排查AppArmor限制(如果开启)
如果Ubuntu开启了AppArmor,可能限制了www-data调用外部程序的权限。可以临时关闭AppArmor对apache2/php-fpm的限制测试:
sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.apache2 # 针对php-fpm:sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.php-fpm8.1
如果关闭后能正常运行,再调整AppArmor规则允许相关调用。
内容的提问来源于stack exchange,提问作者Roffy
相关产品推荐
相关产品推荐

