getcwd() 會傳回 URL 中引用的「主要」腳本的路徑。
dirname(__FILE__) 會傳回目前正在執行的腳本的路徑。
我寫了一個腳本,需要從同一個目錄中的多個類別定義腳本。它會根據檔案名稱比對來擷取它們,並使用 getcwd 來判斷它們的位置。
當我需要從不同目錄中的新檔案呼叫第一個腳本時,就沒那麼順利了。
(PHP 4, PHP 5, PHP 7, PHP 8)
getcwd — 取得目前的工作目錄
此函式沒有參數。
成功時傳回目前的工作目錄,失敗時傳回 false
。
在某些 Unix 變體中,如果任何父目錄沒有設定可讀或可搜尋模式,即使目前目錄有,getcwd() 也會傳回 false
。有關模式和權限的更多資訊,請參閱 chmod()。
範例 1 getcwd() 範例
<?php
// 目前的目錄
echo getcwd() . "\n";
chdir('cvs');
// 目前的目錄
echo getcwd() . "\n";
?>
上面的範例將會輸出類似於以下內容
/home/didou /home/didou/cvs
如果 PHP 直譯器是使用啟用 ZTS (Zend Thread Safety) 編譯的,則 getcwd() 傳回的目前工作目錄可能與作業系統介面傳回的不同。依賴於目前工作目錄的外部函式庫(透過 FFI 呼叫)將會受到影響。
getcwd() 會傳回 URL 中引用的「主要」腳本的路徑。
dirname(__FILE__) 會傳回目前正在執行的腳本的路徑。
我寫了一個腳本,需要從同一個目錄中的多個類別定義腳本。它會根據檔案名稱比對來擷取它們,並使用 getcwd 來判斷它們的位置。
當我需要從不同目錄中的新檔案呼叫第一個腳本時,就沒那麼順利了。
我使用這段程式碼在 PHP 中複製 pushd 和 popd DOS 命令
<?php
$g_DirStack = array();
function pushd( $dir )
{
global $g_DirStack;
array_push( $g_DirStack, getcwd() );
chdir( $dir );
}
function popd( )
{
global $g_DirStack;
$dir = array_pop( $g_DirStack );
assert( $dir !== null );
chdir( $dir );
}
?>
這可讓您使用 pushd 變更目前目錄,然後在完成時使用 popd 來「還原」目錄變更。
當在命令列上執行 PHP 時,如果您想要包含與主腳本位於同一目錄中的另一個檔案,僅執行以下操作
<?php
include './otherfile.php';
?>
如果您像這樣執行您的腳本,可能無法運作
/$ /path/to/script.php
因為目前的工作目錄將會設定為 '/',而且檔案 '/otherfile.php' 不存在,因為它在 '/path/to/otherfile.php' 中。
因此,要取得腳本所在的目錄,您可以使用這個函式
<?php
function get_file_dir() {
global $argv;
$dir = dirname(getcwd() . '/' . $argv[0]);
$curDir = getcwd();
chdir($dir);
$dir = getcwd();
chdir($curDir);
return $dir;
}
?>
因此您可以像這樣使用它
<?php
include get_file_dir() . '/otherfile.php';
// 甚至是...
chdir(get_file_dir());
include './otherfile.php';
?>
花了一些時間思考這個問題,也許可以幫助到某人:)
「在某些 Unix 變體中,如果任何父目錄沒有設定可讀或可搜尋模式,即使目前目錄有,getcwd() 也會傳回 FALSE。」
只是讓您知道,MacOS X 是其中一種變體(至少 10.4 對我來說是如此)。您可以對您的站點資料夾向上套用 'chmod a+rx' 來使其正常運作。
假設有連結
/some/link->/some/location/path
使用 Linux bash,
如果在連結的抽屜 /some/link 中
cd .. 會前往上層連結 /some/
cd -P .. 會前往上層目的地 /some/location/
使用 php
fopen ("../file") 會向上層目錄尋找 /some/location/file
有些人評論了以下取得路徑的方法。
我發現使用 $_SERVER['DOCUMENT_ROOT'] 比較幸運
來重新建立絕對路徑。
當使用 CLI 工具時,PHP5 的功能似乎與 PHP4 有所不同。以下是一個範例:-
cd /tmp
cat > foo.php << END
<?php
print getcwd() . "\n";
?>
END
cd /
php -q /tmp/foo.php
PHP4 回傳 /tmp
PHP5 回傳 /
這點需要注意。
此函數經常與 basename() 一起使用,例如:
https://php.dev.org.tw/manual/en/function.basename.php
如果要在位於相同目錄樹之外的腳本中包含(使用 include、require 或 *_once)檔案,請小心使用 getcwd()。
範例
<?php
//在 /var/www/main_document_root/include/MySQL.inc.php 中
if (strpos(getcwd(),'main_')>0) {
//設定主要資料庫連線的程式碼
}
?>
<?php
//在 home/cron_user/maintenance_scripts/some_maintenance_script.php 中
require_once ('/var/www/main_document_root/include/MySQL.inc.php');
?>
在以上範例中,不會建立資料庫連線,因為呼叫 getcwd() 會回傳相對於呼叫腳本的路徑 ( /home/cron_user/maintenance_scripts ),而不是相對於呼叫 getcwd() 函數的檔案的路徑。
有些伺服器具有封鎖 getcwd() 的安全性選項
替代選項
str_replace($_SERVER['SCRIPT_NAME'],'', $_SERVER['SCRIPT_FILENAME']);
當在包含符號連結的目錄中呼叫 getcwd() 時,請注意。
getcwd() 等同於 shell 命令 "pwd -P",它會解析符號連結。
shell 命令 "pwd" 等同於 "pwd -L",它會使用環境變數 PWD 而不解析符號連結。這也等同於呼叫 getenv('PWD')。
這是一個將路徑轉換為像這樣的函數
/home/www/somefolder/../someotherfolder/../
轉換為正確的目錄路徑
<?php
function simplify_path($path) {
//將我們目前的工作目錄儲存到變數中
$oldcwd = getcwd();
//將目錄變更為要轉換的目錄
//$path是要轉換(清理)的目錄,作為字串傳遞給函數
chdir($path);
return gstr_replace('\\', '/', getcwd());
//將 cwd 變更回舊值,以免干擾腳本
chdir($oldcwd);
}
如果您想比較兩個不一定處於"清理過"狀態的檔案路徑,這個函數非常有用。它在 *NIX 和 WINDOWS 中都適用
?>
正如您在
https://php.dev.org.tw/manual/en/features.commandline.differences.php
中看到的,CLI SAPI 與其他 SAPI 不同,它不會自動將目前的工作目錄變更為啟動腳本所在的目錄。
一個非常簡單的解決方法,可以重新獲得您從「一般」網頁腳本中習慣的行為,是在腳本開頭加入類似這樣的程式碼
<?php
chdir( dirname ( __FILE__ ) );
?>
但因為這與讀取或「尋找」路徑有關,您可能會喜歡我分享一些我經常在 CLI 腳本中使用的更複雜的技巧...
<?php
// 注意:後續變數中儲存的所有路徑都以 DIRECTORY_SEPARATOR 結尾
// 如何儲存腳本被呼叫「來自何處」的工作目錄:
$initial_cwd = preg_replace( '~(\w)$~' , '$1' . DIRECTORY_SEPARATOR , realpath( getcwd() ) );
// 如何無符號連結地切換到目前檔案所在的資料夾:
chdir( dirname ( realpath ( __FILE__ ) ) );
// 如何將先前的資料夾儲存到變數中:
$my_folder = dirname( realpath( __FILE__ ) ) . DIRECTORY_SEPARATOR;
// 如果 $my_folder 以 \class\ 或 /class/ 結尾,如何取得上一層資料夾的路徑:
$my_parent_folder = preg_replace( '~[/\\\\]class[/\\\\]$~' , DIRECTORY_SEPARATOR , $my_folder );
// 在任何情況下,如何取得上一層資料夾的路徑:
$my_parent_folder = preg_replace( '~[/\\\\][^/\\\\]*[/\\\\]$~' , DIRECTORY_SEPARATOR , $my_folder );
// 如何從一組 unix 風格的路徑中建立一組作業系統風格路徑的陣列
// (如果您使用設定檔等,這會很方便):
foreach( $unix_style_pathes as $unix_style_path )
$os_independent_path[] = str_replace( '/' , DIRECTORY_SEPARATOR , $unix_style_path );
?>
如果您將 php 連結到 /bin/linkedphp,而您的 php 位於例如 /home/actual.php
當您在檔案系統的某處執行 linkedphp 時,
getcwd 回傳 /bin 而不是工作目錄,
解決方法:改用 dirname(__FILENAME__)
針對我自己的回應:該函數不適用於以下情況
/usr/bin$: /home/johndoe/Work/script.php
所以這裡有一個更好且更簡單的方法(我認為這個方法適用於所有情況)
<?php
function get_file_dir() {
global $argv;
return realpath($argv[0]);
}
?>
放手去做吧:)
如果在 Solaris 中使用 NFS 掛載的子目錄時,getcwd() 沒有回傳任何內容,您可能遇到了 Solaris 10 最近版本中據說已修正的作業系統錯誤。這個相同的作業系統錯誤也會影響 include() 和 require() 函數。
如果您的 PHP cli 二進位檔是作為 cgi 二進位檔建置的(使用 php_sapi_name 檢查),cwd 函數的行為會與您預期的不同。
假設您有一個腳本 /usr/local/bin/purge
您位於 /home/username
php CLI:getcwd() 給您 /home/username
php CGI:getcwd() 給您 /usr/local/bin
如果您使用 php 編寫命令列腳本,這可能會讓您感到困惑。您可以將 -C 加入到 php 呼叫中來覆蓋 CGI 行為
#!/usr/local/bin/php -Cq
然後 getcwd() 的行為就如同 CLI 編譯的版本。