当我以 root 用户身份运行以下脚本时,powerpoint 文件会转换为 pdf。当我以非 root 用户或我的 web 服务器上的用户身份运行以下脚本时,我收到以下错误。在搜索此问题的解决方案时,我发现很多参考资料都提到了与 .config 文件或 .libreoffice 文件有关的解决方案。我不相信我有这些文件。我使用 apt-get install libreoffice 安装了 libreoffice。
这是我正在执行的 .php 文件:
exec("libreoffice --headless --invisible --convert-to pdf ./general.pptx 2>&1", $output, $return);
print_r($output);
这是非 root 用户的结果:
Array
(
[0] => [Java framework] Error in function createSettingsDocument (elements.cxx).
[1] => javaldx failed!
[2] => Warning: failed to read path from javaldx
)
答案1
我通过添加以下内容解决了我的问题:
export HOME=/tmp &&
在开头,例如:
export HOME=/tmp && libreoffice --headless --invisible --convert-to pdf ./general.pptx 2>&1
这在 Ubuntu 16.04 上对我有用,就像shell_exec()
在 PHP 中一样
答案2
经过一番谷歌搜索和检查源代码后,我可以解释锁定从同一用户帐户运行的后续 libreoffice 实例的根本原因是什么。首先,这看起来像是故意的行为,因为所有正在运行的实例都共享相同的缓存和配置目录,并且在以非同步方式使用它时可能会破坏它。启动时,所有正在运行的实例都通过 /tmp/OSL_blabla unix 套接字相互同步。以下是提到此套接字文件的相关错误报告(https://bugzilla.redhat.com/show_bug.cgi?id=666603 https://bz.apache.org/ooo/show_bug.cgi?id=55154)。
您可以仔细查看源代码以了解如何确定套接字文件的名称以及如何同步实例: https://code.woboq.org/libreoffice/libreoffice/desktop/unx/source/start.c.html#get_pipe_path 和 https://code.woboq.org/libreoffice/libreoffice/desktop/unx/source/start.c.html#connect_pipe
获取管道名称非常复杂。它们首先检测“bootstraprc”文件名,打开它并从中读取变量“UserInstallation”(https://wiki.openoffice.org/wiki/Bootstraprcbootstraprc 的位置因发行版而异,在我的情况下(OracleLinux 7.5),它位于“/usr/lib64/libreoffice/program/bootstraprc”:
[ErrorReport]
ErrorReportPort=80
ErrorReportServer=report.libreoffice.org
[Bootstrap]
InstallMode=<installmode>
ProductKey=LibreOffice 5.3
UserInstallation=$SYSUSERCONFIG/libreoffice/4
在 Linux 中,$SYSUSERCONFIG 是“$HOME/.config”。然后他们从配置文件路径位置获取“md5”总和,并使用它来确定套接字位置。因此配置文件位置映射到套接字名称。您应该只更改多个实例的配置目录路径,这样它们就不会锁定。但配置目录并不是唯一可能被锁定或数据崩溃的地方。还有其他库(如 libGL)使用共享缓存 ($HOME/.cache/mesa)
您可以使用“ltrace”检查哪些库尝试读取哪些环境变量:
ltrace -e getenv -f sh -c "libreoffice --headless --convert-to pdf ./general.pptx"
您可以看到所有库都依赖于“HOME”目录,因此在运行多个实例之前更改它更容易。只需使它对每次运行都是唯一的(而不是对所有运行都使用“/tmp”,这限制我们只能运行 2 个并发转换器,但不能更多)。
我建议每次需要转换时都创建临时路径,并在转换后将其删除,这可以使用简单的包装器“/usr/bin/libreoffice_run_many”完成:
#!/bin/sh
dir=`mktemp -d`
if [ -d $dir ]; then
HOME=$dir
export HOME
libreoffice $@
rm -Rf $dir
fi
然后只需调用包装器而不是“libreoffice”:
exec("/usr/bin/libreoffice_run_many --headless --invisible --convert-to pdf ./general.pptx 2>&1", $output, $return);
print_r($output);