Nginx
nginx + fcgiwrap:fastcgi_param 的順序如何重要?
我正在執行
Debian 6.0.3
(squeeze
),nginx-0.7.67
,fcgiwrap-1.0-1+squeeze1
. 這是測試腳本:#!/usr/bin/perl use 5.010; use warnings; use strict; use Data::Dumper; print "Content-Type: text/html\n\n"; say Dumper {map {$_ => $ENV{$_}} 'SCRIPT_NAME', 'DOCUMENT_ROOT', 'WHATEVER'}; say "$<, $>, $(, $)";
這是
nginx
配置:server { server_name domain.com; root /home/yuri/6; access_log /var/log/nginx/domain.com-access.log; error_log /var/log/nginx/domain.com-error.log; location /cgi-bin/ { fastcgi_pass unix:/var/run/fcgiwrap.socket; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param DOCUMENT_ROOT /home/yuri/7/; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param WHATEVER 1; fastcgi_param WHATEVER 2; } location /1.php { fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_param PHP_ADMIN_VALUE cgi.fix_pathinfo=1; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param SCRIPT_FILENAME whatever; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } }
如果轉到 url http://domain.com/cgi-bin/1.pl ,這就是我在瀏覽器中得到的內容:
$VAR1 = { 'SCRIPT_NAME' => '/cgi-bin/1.pl', 'DOCUMENT_ROOT' => '/home/yuri/7/', 'WHATEVER' => '2' };
看起來,它
fcgiwrap
使用第一個DOCUMENT_ROOT
來查找腳本,但腳本獲取參數的最後一個值。如果您更改DOCUMENT_ROOT
指令的順序,Web 伺服器將返回403
. 問題是……怎麼會?
php
雖然按預期工作:第二個SCRIPT_FILENAME
覆蓋第一個。
fastcgi 庫只是將它提供的任何參數傳遞給
environ
指針。getenv()
由fcgiwrap
使用任何環境變數首先出現(優化?)。PHP FPM 很可能將此環境視為數組數據類型,任何後面的鍵都會覆蓋第一個鍵。您不應該依賴順序並確保只有一個鍵。我沒有查看 FastCGI 規範,是否記錄了正確的行為。
至於你為什麼得到403,我猜是沒有
/home/yuri/7/1.pl
文件。(請記住,第一個參數由 fcgiwrap 匹配)。由於它不可執行,因此 fcgiwrap 返回 403。測試
下面的更新檔列印了由給出的環境
FCGI_Accept()
:diff --git a/fcgiwrap.c b/fcgiwrap.c index e86ff9d..0dff2e6 100644 --- a/fcgiwrap.c +++ b/fcgiwrap.c @@ -470,6 +470,11 @@ static void inherit_environment(void) char * const * p; char *q; + for (p = environ; *p; p++) + fprintf(stderr, "ENV: %s\n", *p); + + fprintf(stderr, "ENV[FOO] = %s\n", getenv("FOO")); + for (p = inherited_environ; *p; p++) { q = strchr(*p, '='); if (!q) {
用於測試的 nginx 配置:
events { worker_connections 768; } pid pid; error_log error_log; http { server { access_log off; listen 5555; location / { fastcgi_param FOO BAR; fastcgi_param FOO BARRED; fastcgi_pass unix:/tmp/sock; } } }
啟動伺服器的命令(假設
nginx.conf
在目前目錄中):$ nginx -p . -c nginx.conf $ env -i ./fcgiwrap -p /dev/null -s unix:/tmp/sock
現在,執行
curl http://localhost:5555/
,stderr 將列印:ENV: FCGI_ROLE=RESPONDER ENV: FOO=BAR ENV: FOO=BARRED ENV: HTTP_USER_AGENT=curl/7.30.0 ENV: HTTP_HOST=localhost:5555 ENV: HTTP_ACCEPT=*/* ENV[FOO] = BAR Cannot get script name, are DOCUMENT_ROOT and SCRIPT_NAME (or SCRIPT_FILENAME) set and is the script executable?
除此之外,這是一個開發版本。目前的穩定版(1.1.0)不包含上述
-p
參數。對於結果並不重要,您也可以放棄它並收到一個錯誤,即 noSCRIPT_NAME
is given 之類的。