PHP Conference Japan 2024

umask

(PHP 4, PHP 5, PHP 7, PHP 8)

umask變更目前的 umask

說明

umask(?int $mask = null): int

umask() 將 PHP 的 umask 設定為 mask & 0777 並返回舊的 umask。當 PHP 作為伺服器模組使用時,umask 會在每個請求完成後恢復。

參數

mask

新的 umask。

傳回值

如果 masknullumask() 只會傳回目前的 umask,否則會傳回舊的 umask。

更新日誌

版本 說明
8.0.0 mask 現在可以為 null。

範例

範例 #1 umask() 範例

<?php
$old
= umask(0);
chmod("/path/some_dir/some_file.txt", 0755);
umask($old);

// 檢查
if ($old != umask()) {
die(
'更改 umask 回去時發生錯誤');
}
?>

注意事項

注意:

避免在多執行緒網頁伺服器中使用此函數。最好在建立檔案後使用 chmod() 來更改檔案權限。使用 umask() 可能會導致同時執行的腳本和網頁伺服器本身出現非預期的行為,因為它們都使用相同的 umask。

新增筆記

使用者貢獻的筆記 14 則筆記

librodot at ciberpiula dot net
15 年前
我認為理解 umask 的最佳方式是說 umask 用於撤銷權限,而不是設定權限。

umask 設定在建立檔案或目錄時必須從系統預設值中移除哪些權限。

例如,遮罩 0022 表示您不希望群組和其他人修改檔案。

預設值 0666 rw-.rw-.rw-
umask 0022 ---.-w-.-w-
最終 0644 rw-.r--.r--

這表示從現在起任何檔案都將具有 0644 權限。

重要的是要理解 umask 會從系統預設值中撤銷、刪除權限,因此它無法授予系統預設值沒有的權限。在上面的範例中,使用 666 系統預設值,您無法使用 umask 建立具有執行權限的檔案。如果您想授予更多權限,請使用 chmod。

請注意,系統預設權限與 PHP 無關(它們取決於伺服器設定)。PHP 有一個預設的 umask,它會在系統預設基本權限之後套用。檔案和目錄有不同的系統預設基本權限。

通常,檔案的系統預設權限為 666,目錄的系統預設權限為 0777。通常,預設的 PHP umask 為 0022
sean at awesomeplay dot com
17 年前
「在建立檔案後,最好使用 chmod() 來更改檔案權限。」

PHP 團隊一如既往地缺乏安全知識,這點再次體現出來。你*永遠*應該在建立檔案時就設定正確的權限。讓我來說明為什麼:

(a) 你建立了一個具有讀取權限的新檔案
(b) 攻擊腳本打開了該檔案
(c) 你使用 chmod 修改檔案權限以移除讀取權限
(d) 你將敏感數據寫入檔案

現在,你可能會認為在 chmod 之前,攻擊腳本成功打開檔案的機率很低。你是對的。但低機率永遠不夠低 —— 你想要的是零機率。

當建立需要更高權限的檔案時,你必須始終使用正確的權限建立檔案,並且使用 O_EXCL 設定。如果你沒有進行獨佔建立,就會出現以下情況:

(a) 攻擊者建立檔案,並將其設定為任何人都可寫入
(b) 你使用受限的權限打開檔案,但由於檔案已存在,檔案只是被打開,權限保持不變
(c) 你將敏感數據寫入不安全的檔案

偵測後一種情況是可能的,但需要一些額外的工作。你必須檢查檔案的所有者和群組是否與腳本的相符(也就是 posix_geteuid(),而不是 myuid()),並檢查權限 —— 如果其中任何一項不正確,則檔案是不安全的 —— 你可以嘗試 unlink() 檔案並重試,當然,同時也要記錄警告。

只有在你想授予額外權限而不是移除權限時,在建立檔案後使用 chmod() 才是合理或安全的。例如,將 umask 設定為 0077,然後 chmod 你之後建立的檔案是完全安全的。

在 PHP 中進行真正安全的程式設計已經很困難,而文件中這樣的建議只會讓事情變得更糟。記住,孩子們,任何適用於 C 或 UNIX 世界的安全原則都 100% 適用於 PHP。身為 PHP 程式設計師,你能為自己做的最好的事情就是學習和理解安全的 C 和 UNIX 程式設計技巧。
匿名
18 年前
使用 (cmask - umask) 計算新的遮罩是錯誤的

0022 - 0700 = 0656 錯誤
0700 & ~0022 = 0700 正確

正確的 PHP 程式碼
<?php
$rmask
= ($cmask & ~$umask);
?>
neon at neonjs dot com
13 年前
如果你不明白為什麼需要「避免在多執行緒網頁伺服器中使用此函式」

這是因為此函式會在行程層級更改 umask,而不是僅針對 PHP 或目前的腳本。如果在執行 PHP 腳本的行程中同時執行多個執行緒,則更改將同時套用至所有這些執行緒,因此這對於多執行緒使用是不安全的。

我知道如果您使用 PHP 模組和 Apache 的 prefork MPM(非多執行緒),那麼您至少不會遇到像這樣的競爭條件問題。然而,仍然值得注意的是,umask 設定(如果未重新設定)將在該程序的整個生命週期中持續存在,即使該程序被重新用於處理未來的 PHP 或非 PHP 請求。
Richard Snell
9 年前
需要注意的是,mask 參數可以接受八進制以外的值,這可能會導致意外的結果。

設定 umask(22) 預期會通過應用 0022 的遮罩將預設權限為 0666 的檔案減少到 0644,但由於參數是以十進制提供的,它會被靜默地轉換為八進制,實際上應用了 0026 的遮罩,導致最終檔案權限為 0642。

同樣,umask 返回的值也是十進制格式。如果您使用 umask(0022) 正確應用遮罩,然後使用 umask() 查詢新設定,它將返回 18 的值(八進制 0022 等於十進制 18)。

簡而言之,在應用權限時,最好用零填充提供的值以建立八進制值(22 變為 0022),如果您想分析返回值,請記住將其轉換為八進制以便於理解。
malcolm.murphy
8 年前
關於「mask & 0777」的說明

手冊中的註釋「umask() 將 PHP 的 umask 設定為 mask & 0777 [...]」僅僅意味著該方法只影響檔案權限,而不影響特殊模式,例如 setuid、setgid 或 sticky 位元。奇怪的是,PHP 並沒有實際執行位元運算,而是假設它將由同名的系統呼叫完成。在某些系統上,例如 OS X,umask 有效地將 umask 設定為 mask & 07777,但額外的位元不適用於後續的 PHP 呼叫,例如 mkdir()。Linux 的 umask 確實使用 0777。它的man頁有一個與 PHP 類似的註釋,但有一個括號內的陳述有助於解釋它的含義

「umask() 將呼叫程序的檔案模式建立遮罩 (umask) 設定為 mask & 0777(即,只使用 mask 的檔案權限位元)[...]」

儘管 $mask & ~0777 與 $mask & 0777 看起來很相似,但權限可以通過使用 $mask & ~0777 運算反轉遮罩來確定這一事實是無關緊要的。後一個運算將 $mask 截斷為前九個低階位元(即,最右邊的三個八進制數字[請注意,八進制表示法的開頭零本身不是數字])。它不會改變其餘的位元。

例如,以下所有呼叫都具有相同的效果:umask(0022)、umask(07022)、umask(261650)(0777022 的十進制值)和 umask(0b111000010010)(07022 的二進制表示法)。
jphansen at uga dot edu
16 年前
在大多數 UNIX 環境中,在 /home/user/.profile 或 /etc/profile 中定義的檔案的建議預設 umask 是 022 (chmod: 644)。在受信任的系統上,它是 002。應用更寬鬆的設定時要小心。
webmaster at iacomputing dot co dot uk
14 年前
您可以使用 umask 來解決多個 PHP 版本中出現的 PHP session bug。

<?php
umask
(0022);
session_start();
?>

這將防止建立權限不足的 session。
bishop
14 年前
「在建立檔案後,最好使用 chmod() 來更改檔案權限。」

如果您認真看待這個建議,請考慮設定您的 umask,以便在建立檔案時將其設定為僅供您的使用者存取,然後使用 chmod 來開放它們的權限。

<?php
// 檔案將會以 -rw------- 的權限建立
umask(0077);

// 建立一個檔案,例如使用 fopen()

// 賦予權限:-rw-r--r--
chmod('/path/to/file', 0644);
?>

在合理的情況下,預設應為關閉,並根據需要開放(如上所示),而不是預設為開放,並根據需要關閉。上述方法仍然存在競爭條件,但競爭條件將會拒絕適當的存取,而不是授予不適當的存取。
ahmad dot mayahi at gmail dot com
7 年前
簡單來說,umask 指的是新檔案/目錄的預設權限。

<?php
umask
(022);
?>

這分別設定了使用者、群組和其他人的預設權限。

• 0 - 讀取、寫入和執行
• 1 - 讀取和寫入
• 2 - 讀取和執行
• 3 - 唯讀
• 4 - 寫入和執行
• 5 - 唯寫
• 6 - 唯執行
• 7 - 無權限
andi<at>splitbrain.org
19 年前
要試驗 umask 和權限,請使用以下這段程式碼片段:

<?
$umask = 0012;
$perm = 0777;
printf("umask: %04o perm: %04o result: %04o\n",
$umask,$perm,$perm & (0777 - $umask));
?>
maulwuff at gmx dot de
17 年前
umask 會從標準遮罩 777 中去除給定的值。
圖形化檢視可以更好地說明這一點:

標準
rwxrwxrwx = 777
使用 umask 002 後會得到
rwxrwxr-x = 775
或者使用 umask 077 後會得到
rwx------ = 700

等等。
sam at totallydigital dot co dot nz
22 年前
第一個註解可能沒有很清楚地說明 umask 和權限之間的關係。

傳遞給指令的權限會先與目前 umask 的「反向」進行位元 AND 運算,然後再應用於檔案。

例如,umask = 0011 且權限 = 0775
0011 的反向 = 0766

0775 AND 0766
= 111.111.101 AND 111.110.110
= 111.110.100
= 0764
ShaD@TW
18 年前
請注意,目錄和檔案有時會有不同的結果。

<?php
umask
(0670); //- 設定 umask
$handle = fopen('file', 'w'); //- 0006
mkdir("/path/dir"); //- 0107
?>

計算結果
<?php
$umask
= 0670;
umask($umask);
//- 如果您正在創建一個新的目錄,$permission = 0777;
//- 如果您正在創建一個新的檔案,$permission = 0666.
printf( "結果:%04o", $permission & ( 0777 - $umask) );
?>

順帶一提,如同手冊所述,umask() 的形式是「int umask ( [int mask] )」,所以如果您想打印/輸出任何 umask,別忘了將其從十進位(因為它返回一個「int」)轉換為八進位。

<?php
$umask
= umask(); //- 返回目前的 umask,它是一個「int」
$umask = decoct($umask); //- 現在,$umask 是一個「字串」
echo $umask;
?>

別忘了參數也是一個「int」。

<?php
umask
(777); //- 錯誤!即使您可能在某些作業系統中使用「umask 777」。
umask(0777); //- 正確
?>

如果有任何錯誤,請更正我的陳述。
To Top