You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ARM64服务器AppArmor阻止Chromium转HTML为PDF及PHP执行故障解决

问题排查与修复方案

1. 先修正最直观的问题:路径拼写错误

你PHP代码里的命令存在两处明显的路径拼写错误:

  • 生成PDF的路径写为/home/joedoe/...,但命令行实际使用的是/home/johndoe/...
  • 移动文件时又误写为/home/joendoe/...,和前后路径都不匹配

因为命令用&&串联,前面的步骤失败会直接终止整个流程,这是PHP执行失败的直接原因之一。

2. PHP运行用户的权限差异问题

命令行使用的是johndoe用户,但PHP默认以www-data用户运行,两者权限范围完全不同:

  • /home/johndoe目录默认仅对johndoe用户开放读写权限,www-data无法在此创建PDF文件
  • 即便PDF生成成功,mv到/var/www/files.domain.com/docs/时,www-data也需要该目录的写入权限

修复方式:

  • 放弃使用用户主目录作为临时路径,改用系统临时目录/tmp(所有用户均有读写权限),或专门创建一个给www-data使用的临时目录:
    sudo mkdir /var/www/chromium-tmp
    sudo chown www-data:www-data /var/www/chromium-tmp
    sudo chmod 755 /var/www/chromium-tmp
    
  • 确保目标目录对www-data开放写入权限:
    sudo chown -R www-data:www-data /var/www/files.domain.com/docs/
    

3. Snap版Chromium的AppArmor沙箱限制

你当前使用的是Snap安装的Chromium,它的AppArmor沙箱机制会严格限制进程的系统资源访问权限。命令行中johndoe用户能生成PDF,是因为Snap默认允许访问用户主目录,但www-data不在授权范围内,导致PHP执行时Chromium被直接拦截。

修复方式:

  • 卸载Snap版Chromium,改用系统官方仓库的版本,彻底避开Snap的沙箱限制:
    sudo snap remove chromium
    sudo apt update && sudo apt install chromium-browser
    
    之后可直接使用chromium-browser命令,或创建软链接简化调用:sudo ln -s /usr/bin/chromium-browser /usr/bin/chromium
  • 若必须使用Snap版,需修改AppArmor策略,但操作复杂且存在安全风险,不推荐。

4. PHP exec的环境变量缺失问题

PHP的exec运行时的PATH环境变量与命令行用户的环境变量不一致,可能导致无法找到chromium命令。解决办法是直接使用Chromium的绝对路径:

  • Snap版路径:/snap/bin/chromium
  • 仓库版路径:/usr/bin/chromium-browser

修正后的PHP代码示例

<?php
// 使用系统临时目录存放生成的PDF,避免权限问题
$tmpPdfPath = '/tmp/407163caf78c6deedcb8bf732e7e1326-fr.pdf';
$targetPdfPath = '/var/www/files.domain.com/docs/407163caf78c6deedcb8bf732e7e1326-fr.pdf';
$htmlUrl = 'https://files.domain.com/docs/407163caf78c6deedcb8bf732e7e1326.html';

// 使用仓库版Chromium的绝对路径,避免环境变量找不到命令
$command = "/usr/bin/chromium-browser --headless --disable-gpu --no-sandbox --no-pdf-header-footer --print-to-pdf='$tmpPdfPath' '$htmlUrl' && mv '$tmpPdfPath' '$targetPdfPath' && echo 'files.domain.com/docs/407163caf78c6deedcb8bf732e7e1326-fr.pdf'";

$output = [];
$returnStatus = 0;

exec($command . ' 2>&1', $output, $returnStatus);

echo "Return Status: $returnStatus\n";
echo "Output:\n" . implode("\n", $output);

if ($returnStatus !== 0) {
    echo "Command failed.\n";
} else {
    echo "Command succeeded.\n";
}
?>

内容的提问来源于stack exchange,提问作者Richardson Oge

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 08:56:03