遇到问题
某业务需要将mime非application/msword的文件转成doc格式,在网上查询了一下,unoconv可以,安装好后,通过web的url访问后发现居然报错。
PHP代码
$cmd = "unoconv --connection \"socket,host=127.0.0.1,port=8100;urp;StarOffice.ComponentContext\" -f doc -o {$file} {$textfile}"
exec($cmd,$arrRet);
报错信息如下
Array
(
[0] => Traceback (most recent call last):
[1] => File “/usr/bin/unoconv”, line 993, in
[2] => office_environ(of)
[3] => File “/usr/bin/unoconv”, line 150, in office_environ
[4] => os.environ[‘PATH’] = os.path.join(office.basepath, ‘program’) + os.pathsep + os.environ[‘PATH’]
[5] => File “/usr/lib64/python2.6/UserDict.py”, line 22, in getitem
[6] => raise KeyError(key)
[7] => KeyError: ‘PATH’
)
环境变量PATH找不到。
将命令放到命令行上执行,居然可以执行成功。
思考过程
- 权限问题:php-fpm执行用户是www,命令行运行是root用户。(事后感觉这种思考有点浅陋,因为后续查看www用户的变量是包含PATH的)
- 命令行与web到底有何不同?
解决过程
针对权限问题
在命令行上使用 sudo -uwww unoconv …,居然可以执行成功。
各种百度搜索有关python的env的相关知识,发现env[‘PATH’]是用户变量的内容,去服务器上查了下www用户的PATH,是定义了的。查询了下python中设置环境变量的内容,然后莫名奇妙的想到一种思路:写一个python脚本,先临时修改变量,再执行unoconv;最后php通过exec执行这个python脚本
python
import os
os.environ['PATH'] = ''
disfile = ''
sourcefile = ''
cmd = 'unoconv --connection "socket,host=127.0.0.1,port=8100;urp;StarOffice.ComponentContext" -f doc -o {} {}'.format(disfile,sourcefile)
os.system(cmd)
php脚本
exec('python脚本路径',$arrRet);
发现这样可以。但是为什么命令行和web环境不一样,web环境为什么获取不到path,这个一直想不通,也从来没有遇到过。下面深入思考这个问题
命令行与web的不同
命令行是在终端直接执行命令,而web方式是通过web服务器->cgi->php解释器来执行命令的,我上面命令行是直接执行的命令,web还要经过这3到坎。
首先排除是不是php解释器的问题。在命令行通过php解释器执行unoconv
php 第一段代码
结果发现命令可以生成
排除是不是cgi的问题,打开lnmp的cgi是php-fpm,打开php-fpm的配置文件,看到以下说明
; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from
; the current environment.
; Default Value: clean env
;env[HOSTNAME] = $HOSTNAME
;env[PATH] = /usr/local/bin:/usr/bin:/bin
;env[TMP] = /tmp
;env[TMPDIR] = /tmp
;env[TEMP] = /tmp
这就应该是问题所在吧,好激动啊。
打开注释,重启php-fpm,web访问第一段代码,成功