請注意,即使可以寫入查詢的路徑,`is_writable` 對於不存在的檔案也會返回 `false`。
(PHP 4, PHP 5, PHP 7, PHP 8)
is_writable — 判斷檔案是否可寫入
如果 filename
存在且可寫入,則返回 true
。filename 參數可以是目錄名稱,允許您檢查目錄是否可寫入。
請記住,PHP 可能以網路伺服器執行的使用者 ID(通常為 'nobody')存取檔案。
filename
要檢查的檔案名稱。
如果 filename
存在且可寫入,則返回 true
。
失敗時,會發出 E_WARNING
。
範例 #1 is_writable() 範例
<?php
$filename = 'test.txt';
if (is_writable($filename)) {
echo '檔案可寫入';
} else {
echo '檔案不可寫入';
}
?>
注意:此函式的結果會被快取。詳情請參閱 clearstatcache()。
致 Darek 和 F Dot:關於群組權限,在 php.ini 檔案中有以下註釋
; 預設情況下,安全模式在開啟檔案時會進行 UID 比對檢查。
; 如果您想將其放寬為 GID 比對,
; 請開啟 safe_mode_gid。
safe_mode_gid = Off
遞迴檢查目錄是否可寫入。要返回 `true`,所有目錄內容都必須可寫入。
<?php
函式 is_writable_r($dir) {
如果 (is_dir($dir)) {
如果(is_writable($dir)){
$objects = scandir($dir);
foreach ($objects as $object) {
如果 ($object != "." && $object != "..") {
如果 (!is_writable_r($dir."/".$object)) 返回 false;
否則 continue;
}
}
返回 true;
}否則{
返回 false;
}
}否則如果(file_exists($dir)){
返回 (is_writable($dir));
}
}
?>
看起來 is_writable() 並不會完整檢查檔案的權限來判斷目前的使用者是否可以寫入。例如,當 Apache 以 'www' 使用者身分執行,並且是 'wheel' 群組的成員時,is_writable() 在像是以下的檔案會回傳 false
-rwxrwxr-x root wheel /etc/some.file
關於您可能會發現您的 PHP 腳本在您的網站上建立的檔案被歸類為 NOBODY 群組,您可以透過設定 FTP 連線("ftp_connect", "ftp_raw" 等)並使用像是 "ftp_fput" 的方法來建立這些檔案 [而不是直接賦予權限,這樣您就可以使用一般的「不安全」方法] 來避免這個問題。這將使建立的檔案不會被歸類到 NOBODY 群組,而是會被歸類到您的 FTP 連線透過 FTP 程式所使用的群組。
此外,您可能需要將 FTP 連線的密碼雜湊,那麼請參考
https://mysqldev.dev.org.tw/doc/mysql/en/Password_hashing.html
這個 file_write() 函式會在將 $content 寫入 $filename 之前,賦予 $filename 寫入權限。
請注意,許多伺服器不允許 PHP 使用者更改檔案權限。
<?php
函式 file_write($filename, &$content) {
if (!is_writable($filename)) {
if (!chmod($filename, 0666)) {
echo "無法變更檔案 ($filename) 的權限";
exit;
};
}
if (!$fp = @fopen($filename, "w")) {
echo "無法開啟檔案 ($filename)";
exit;
}
if (fwrite($fp, $content) === FALSE) {
echo "無法寫入檔案 ($filename)";
exit;
}
if (!fclose($fp)) {
echo "無法關閉檔案 ($filename)";
exit;
}
}
?>
這個函式的結果似乎沒有被快取
在 Linux 和 Windows 上測試過
<?php
chmod($s_pathFichier, 0400);
echo'<pre>';var_dump(is_writable($s_pathFichier));echo'</pre>';
chmod($s_pathFichier, 04600);
echo'<pre>';var_dump(is_writable($s_pathFichier));echo'</pre>';
exit;
?>
在 Linux 中,您可能會遇到即使檔案具有 644 權限,也無法寫入的問題!問題出在 SELinux 上,只需將其停用或新增規則以允許它即可。
當您檢查網路磁碟機時,此函式在 Windows 上始終返回 false。
參見 PHP Bug https://bugs.php.net/bug.php?id=68926
參見 https://stackoverflow.com/q/54904676
回覆 Darek
我們有兩台伺服器:一台執行 PHP 5.0.4 和 Apache 1.3.33,另一台執行 PHP 4.3.5 和 Apache 1.3.27。PHP 4 伺服器會出現您所描述的行為,即使 www 使用者位於擁有檔案的群組中,`is_writable()` 仍會返回 'false',但 PHP 5 伺服器會返回 'true'。
這是我能想到的最新版 `is_writable()`。
它可以接受檔案或資料夾,但資料夾應以斜線結尾!該函式會嘗試實際寫入檔案,因此當使用者具有 ACL 寫入權限時,它會正確地返回 true。
<?php
function is__writable($path) {
//即使 Windows ACLs 有錯誤也能運作
//注意:資料夾路徑必須加上結尾斜線!!!
//參考 http://bugs.php.net/bug.php?id=27609
//參考 http://bugs.php.net/bug.php?id=30931
if ($path{strlen($path)-1}=='/') // 遞迴回傳一個暫存檔案路徑
return is__writable($path.uniqid(mt_rand()).'.tmp');
else if (is_dir($path))
return is__writable($path.'/'.uniqid(mt_rand()).'.tmp');
// 檢查暫存檔案的讀寫權限
$rm = file_exists($path);
$f = @fopen($path, 'a');
if ($f===false)
return false;
fclose($f);
if (!$rm)
unlink($path);
return true;
}
?>
由於 Windows ACLs 的錯誤似乎「不會修復」(參見 http://bugs.php.net/bug.php?id=27609),我建議使用這個替代函式。
<?php
function is__writable($path) {
if ($path{strlen($path)-1}=='/')
return is__writable($path.uniqid(mt_rand()).'.tmp');
if (file_exists($path)) {
if (!($f = @fopen($path, 'r+')))
return false;
fclose($f);
return true;
}
if (!($f = @fopen($path, 'w')))
return false;
fclose($f);
unlink($path);
return true;
}
?>
它應該在 *nix 和 Windows 系統上都能正常運作。
注意:您必須使用結尾斜線來識別目錄。
檢查目錄是否可寫入。也適用於掛載的 SMB 共享。
function isWritablePath($home, $xpath) {
$isOK = false;
$path = trim($xpath);
if ( ($path!="") && (strpos($path,$home)!==false) && is_dir($path) && is_writable($path) ) {
$tmpfile = "mPC_".uniqid(mt_rand()).'.writable';
$fullpathname = str_replace('//','/',$path."/".$tmpfile);
$fp = @fopen($fullpathname,"w");
if ($fp !== false) {
$isOK = true;
}
@fclose($fp);
@unlink($fullpathname);
}
return $isOK;
}
在 Windows 下,它只會傳回唯讀屬性狀態,而不是實際的權限 (ACL)。
請參閱 http://bugs.php.net/bug.php?id=27609