2015-04-17 97 views
18

php用作apache模塊,從Apache SetEnv指令來了一個環境變量是提供給PHP的getenv(),但它不會出現通過STDLIB的getenv()可用來C擴展。至少它發生在pgsql模塊中。爲什麼在已定義的環境變量上需要putenv()?

如果變量重新實例與PHP代碼:

putenv("varname=".getenv("varname")); 

然後將其變成可供擴展的代碼。

問題:爲什麼需要重新實施?核心php環境與「標準」(stdlib)環境有什麼不同?

這發生在:Ubuntu 12.04中的PHP Version 5.3.10-1ubuntu3.17,作爲apache模塊。從命令行運行時,上述解決方法不是必需的。 從這個其他問題:Using .pgpass from Apache libphp5.so看來,這種解決方法對於FreeBSD下的php-5.4也是必要的,所以它不僅僅是Ubuntu或者php-5.3。

它不取決於其中有Evariables_order。我試過EGPCSGPCS,$_ENV不是E不在那裏,如預期的那樣,但這不會改變getenv()的結果,如documented,或顯然是從擴展內部stdlib的getenv()的結果。問題的


演示與pgsql模塊。它建立在編寫於Clibpq共享庫之上,該庫在幾個可選的PG*環境變量上調用getenv()

在Apache的配置文件,下<VirtualHost>,我設置這使連接嘗試失敗:

SetEnv PGHOST doesnotexist 

,而不是在pg_connect呼叫指定主機,所以PGHOST必須採取時存在。

首先嚐試

$v=getenv("PGHOST"); 
echo "PGHOST=$v\n"; 

$cnx=pg_connect("user=daniel"); 
if ($cnx) { 
    echo "Connection is successful."; 
} 

結果:

 
PGHOST=doesnotexist 
Connection is successful. 

所以PGHOST是越來越忽視,儘管在環境之中。

第二次嘗試,現在又PGHOST投入到環境中,即使它已經存在:

$v=getenv("PGHOST"); 
echo "PGHOST=$v\n"; 
putenv("PGHOST=".getenv("PGHOST")); 
$cnx=pg_connect("user=daniel"); 
if ($cnx) { 
    echo "Connection is successful."; 
} 

結果(無法連接到指定的主機,如預期):

PGHOST=doesnotexist 
Warning: pg_connect(): Unable to connect to PostgreSQL server: 
could not translate host name "doesnotexist" to address: 
Name or service not known in /var/www/test/pgtest2.php on line 8 
+0

我看到你有unix路徑,但是你碰巧是像cygwin那樣的東西嗎?在這個鄰域中存在一個Windows問題,它基於C運行時不同的共享庫被鏈接到。 – covener

+0

沒有這種情況與Linux Ubuntu的12.04 –

+0

也發生在FreeBSD 10.1與PHP 5.4。 – CXJ

回答

8

原因是這樣的:

您從getenv()[PHP](php func )與使用getenv()[C](C庫函數)查詢的環境不同。 getenv()[PHP]做什麼,正在與註冊的sapi進行比賽(http://lxr.php.net/xref/PHP_5_6/ext/standard/basic_functions.c#3999)。

apache2 sapi通過自己的環境上下文(http://lxr.php.net/xref/PHP_5_6/sapi/apache2handler/sapi_apache2.c#253)執行此操作,而不是來自apache進程本身的標準操作系統環境。

只有當找不到匹配時,纔會檢查實際過程的環境。所以這就是爲什麼getenv()[PHP]返回一個值,但getenv()[C]沒有。

現在,「破解」也很簡單:putenv()[PHP]將給定的鍵/值存儲在正在運行的進程的環境中,這就是爲什麼它可以在以後被getenv()[c]找到的原因。

相關問題