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

DigitalOcean Droplet中Bash脚本获取PHP版本失败的排查与替代方案

问题

我正在开发一款Node.js应用,用于在DigitalOcean Droplet上自动化创建Nginx server block,需要动态获取Droplet上已安装的PHP版本,以正确配置Nginx server block中的fastcgi_pass指令。

生成脚本的Node.js代码

function createNginxServerBlockScript(domain, rootDir = "/var/www") {
  const sitePath = `${rootDir}/${domain}`;

  return `
    echo "Creating Nginx server block..."

    # Get PHP version dynamically
    PHP_VERSION=$(php -r 'echo PHP_VERSION;')

    # Print PHP version to check if it's set correctly
    echo "PHP Version: \${PHP_VERSION}"

    cat > /etc/nginx/sites-available/${domain} <<EOF
    server {
      listen 80;
      listen [::]:80;
      server_name ${domain};
      root ${sitePath};
      index index.php index.html index.htm;

      # WordPress permalinks
      location / {
        try_files \\$uri \\$uri/ /index.php?\\$args;
      }

      # Pass PHP scripts to FastCGI server
      location ~ \\.php\\$ {
        include fastcgi_params;
        fastcgi_pass unix:/var/run/php/php\${PHP_VERSION}-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME \\$document_root\\$fastcgi_script_name;
      }

      # Static files (caching images, CSS, JS)
      location ~* \\\\.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|svg|eot)\\$ {
        expires max;
        log_not_found off;
      }

      # Deny access to hidden files
      location ~ /\\\. {
        deny all;
      }

      # Log files
      access_log /var/log/nginx/${domain}.access.log;
      error_log /var/log/nginx/${domain}.error.log;
    }
EOF
  `;
}

function completeScript(domain) {
  return `#!/bin/bash
      
    ${createNginxServerBlockScript(domain)}
      
  `;
}

执行脚本后的错误输出

Executing complete script...
stdout: awk: 
stdout: cmd. line:1: {print $1 \"\.\" $2}
awk: cmd. line:1:           ^ backslash not last character on line

stdout: Setting up site directory...

stdout: Creating Nginx server block...

stdout: PHP Version: 
stdout: 

stdout: Enabling Nginx site...

stdout: Enabled Nginx site configuration.

stdout: Testing Nginx configuration...
stdout: 
stdout: 

stdout: 2025/03/10 18:13:14 [emerg] 75030#75030: invalid number of arguments in "fastcgi_param" directive in /etc/nginx/sites-enabled/test.outreachbuddy.com:18
nginx: configuration file /etc/nginx/nginx.conf test failed

stdout: Nginx configuration test failed

Remote script finished with exit code: 1
Error executing the complete script: Error: Script failed with code 1
Output:
awk: cmd. line:1: {print $1 \"\.\" $2}
awk: cmd. line:1:           ^ backslash not last character on line
Setting up site directory...
Creating Nginx server block...
PHP Version: 
Enabling Nginx site...
Enabled Nginx site configuration.
Testing Nginx configuration...
2025/03/10 18:13:14 [emerg] 75030#75030: invalid number of arguments in "fastcgi_param" directive in /etc/nginx/sites-enabled/test.outreachbuddy.com:18
nginx: configuration file /etc/nginx/nginx.conf test failed
Nginx configuration test failed

核心疑问:

  1. 为什么PHP_VERSION=$(php -r 'echo PHP_VERSION;')在DigitalOcean Droplet上生成的Bash脚本中无法正常工作?
  2. 是否有可靠的替代方法可在脚本内确定已安装的PHP版本?

解答

一、原命令失效的原因

  • PHP CLI缺失或路径错误:DigitalOcean部分默认镜像仅安装PHP-FPM而未安装PHP CLI,或者php命令未指向正确的版本,导致命令执行无输出。
  • 转义损坏命令语法:Node.js模板字符串中的单引号和反斜杠转义处理不当,生成的Bash脚本中php -r命令出现语法错误,无法正常执行。
  • 权限限制:执行脚本的用户可能没有调用PHP CLI的权限,但从输出看,空版本号更可能是命令未执行成功而非权限问题。

二、可靠的PHP版本检测方法

推荐以下几种直接关联PHP-FPM运行状态的检测方式:

方法1:通过PHP-FPM sock文件路径提取版本

直接查找Nginx需要用到的sock文件,确保版本完全匹配:

PHP_VERSION=$(ls /var/run/php/ | grep -Po 'php(\d+\.\d+)-fpm\.sock' | grep -Po '\d+\.\d+')

方法2:通过update-alternatives获取默认PHP版本(Debian/Ubuntu系)

如果系统用update-alternatives管理PHP版本优先级:

PHP_VERSION=$(update-alternatives --query php | grep -Po 'Value: /usr/bin/php(\d+\.\d+)' | grep -Po '\d+\.\d+')

方法3:通过PHP-FPM进程信息提取版本

从运行的进程中直接获取活跃的PHP-FPM版本:

PHP_VERSION=$(ps aux | grep php-fpm | grep -v grep | head -1 | grep -Po 'php(\d+\.\d+)-fpm' | grep -Po '\d+\.\d+')

三、修复脚本中的其他错误

除了PHP版本检测,脚本还有两个关键问题需要修正:

  1. 转义错误导致Nginx配置失效:
    • fastcgi_param中的\\$应改为\$,生成的Nginx配置中不需要转义$符号;
    • 正则表达式中的\\\\.应改为\\.,避免生成多余的反斜杠。
  2. EOF缩进问题:
    <<EOF模式下,缩进会被带入Nginx配置文件,导致语法错误,需去掉EOF和server块的缩进。

修复后的Node.js函数示例

function createNginxServerBlockScript(domain, rootDir = "/var/www") {
  const sitePath = `${rootDir}/${domain}`;

  return `
    echo "Creating Nginx server block..."

    # Get PHP version dynamically via PHP-FPM sock file
    PHP_VERSION=$(ls /var/run/php/ | grep -Po 'php(\\d+\\.\\d+)-fpm\\.sock' | grep -Po '\\d+\\.\\d+')

    # Fallback if sock file not found (try update-alternatives)
    if [ -z "\${PHP_VERSION}" ]; then
        PHP_VERSION=$(update-alternatives --query php | grep -Po 'Value: /usr/bin/php(\\d+\\.\\d+)' | grep -Po '\\d+\\.\\d+')
    fi

    # Print PHP version to check if it's set correctly
    echo "PHP Version: \${PHP_VERSION}"

    cat > /etc/nginx/sites-available/${domain} <<EOF
server {
  listen 80;
  listen [::]:80;
  server_name ${domain};
  root ${sitePath};
  index index.php index.html index.htm;

  # WordPress permalinks
  location / {
    try_files \$uri \$uri/ /index.php?\$args;
  }

  # Pass PHP scripts to FastCGI server
  location ~ \\.php\$ {
    include fastcgi_params;
    fastcgi_pass unix:/var/run/php/php\${PHP_VERSION}-fpm.sock;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name;
  }

  # Static files (caching images, CSS, JS)
  location ~* \\.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|svg|eot)\$ {
    expires max;
    log_not_found off;
  }

  # Deny access to hidden files
  location ~ /\\. {
    deny all;
  }

  # Log files
  access_log /var/log/nginx/${domain}.access.log;
  error_log /var/log/nginx/${domain}.error.log;
}
EOF
  `;
}

function completeScript(domain) {
  return `#!/bin/bash
      
${createNginxServerBlockScript(domain)}
      
  `;
}

内容的提问来源于stack exchange,提问作者Ben Jonson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 22:03:09