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
核心疑问:
- 为什么
PHP_VERSION=$(php -r 'echo PHP_VERSION;')在DigitalOcean Droplet上生成的Bash脚本中无法正常工作? - 是否有可靠的替代方法可在脚本内确定已安装的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版本检测,脚本还有两个关键问题需要修正:
- 转义错误导致Nginx配置失效:
fastcgi_param中的\\$应改为\$,生成的Nginx配置中不需要转义$符号;- 正则表达式中的
\\\\.应改为\\.,避免生成多余的反斜杠。
- 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
相关产品推荐
相关产品推荐

