PHP Conference Japan 2024

file_put_contents

(PHP 5, PHP 7, PHP 8)

file_put_contents將資料寫入檔案

說明

file_put_contents(
    字串 $filename,
    混合 $data,
    整數 $flags = 0,
    ?資源 $context = null
): 整數|false

此函式與依次呼叫 fopen()fwrite()fclose() 將資料寫入檔案的功能相同。

如果 filename 不存在,則會建立該檔案。否則,除非設定了 FILE_APPEND 旗標,否則現有檔案將被覆蓋。

參數

filename

要寫入資料的檔案路徑。

data

要寫入的資料。可以是 字串陣列串流 資源。

如果 data 是一個 串流 資源,則該串流的剩餘緩衝區將會被複製到指定的檔案。這與使用 stream_copy_to_stream() 類似。

您也可以將 data 參數指定為單維陣列。這等同於 file_put_contents($filename, implode('', $array))

flags

flags 的值可以是以下任何旗標的組合,並以二元 OR (|) 運算子連接。

可用旗標
旗標 說明
FILE_USE_INCLUDE_PATH 在 include 目錄中搜尋 filename。詳情請參閱 include_path
FILE_APPEND 如果檔案 filename 已存在,則將資料附加到檔案,而不是覆蓋它。
LOCK_EX 在進行寫入時取得檔案的獨佔鎖定。換句話說,在 fopen() 呼叫和 fwrite() 呼叫之間會發生 flock() 呼叫。這與使用模式 "x" 的 fopen() 呼叫不同。

context

使用 stream_context_create() 建立的有效上下文資源。

回傳值

此函式會傳回寫入檔案的位元組數,如果失敗則傳回 false

警告

此函式可能會傳回布林值 false,但也可能傳回評估為 false 的非布林值。請閱讀 布林值 的章節以了解更多資訊。使用 === 運算子 來測試此函式的回傳值。

範例

範例 #1 簡單用法範例

<?php
$file
= 'people.txt';
// 開啟檔案以取得現有內容
$current = file_get_contents($file);
// 將新的人名附加到檔案中
$current .= "John Smith\n";
// 將內容寫回檔案
file_put_contents($file, $current);
?>

範例 #2 使用旗標

<?php
$file
= 'people.txt';
// 要添加到檔案的新人名
$person = "John Smith\n";
// 將內容寫入檔案,
// 使用 FILE_APPEND 旗標將內容附加到檔案的結尾
// 並使用 LOCK_EX 旗標防止其他人在同一時間寫入檔案
file_put_contents($file, $person, FILE_APPEND | LOCK_EX);
?>

注意事項

注意此函式是二進位安全的。

提示

如果已啟用 fopen wrappers,則可以使用 URL 作為此函式的檔名。有關如何指定檔名的更多詳細資訊,請參閱 fopen()。有關各種 wrappers 的功能、使用方法的注意事項,以及它們可能提供的任何預定義變數的資訊,請參閱 支援的協定和 Wrappers

參見

新增註解

使用者貢獻的註解 19 則註解

134
TrentTompkins at gmail dot com
16 年前
如果您嘗試將檔案放入不存在的目錄中,則 file_put_contents 會失敗。這會建立目錄。

<?php
函式 file_force_contents($dir, $contents){
$parts = explode('/', $dir);
$file = array_pop($parts);
$dir = '';
foreach(
$parts as $part)
if(!
is_dir($dir .= "/$part")) mkdir($dir);
file_put_contents("$dir/$file", $contents);
}
?>
56
justin dot carlson at gmail dot com
13 年前
很明顯地,這個函式只適用於單次寫入的情況。如果您需要多次寫入同一個檔案,則應該自行使用 fopen 和 fwrite 處理,並在寫入完成後使用 fclose 關閉檔案。

以下為效能測試

file_put_contents() 執行 1,000,000 次寫入 - 3 次測試的平均值

實際時間 0 分 3.932 秒
使用者時間 0 分 2.487 秒
系統時間 0 分 1.437 秒

fopen() fwrite() 執行 1,000,000 次寫入,fclose() - 3 次測試的平均值

實際時間 0 分 2.265 秒
使用者時間 0 分 1.819 秒
系統時間 0 分 0.445 秒
20
maksam07 at gmail dot com
5 年前
這個方法的簡化版本:https://php.dev.org.tw/manual/ru/function.file-put-contents.php#84180

<?php
函式 file_force_contents( $fullPath, $contents, $flags = 0 ){
$parts = explode( '/', $fullPath );
array_pop( $parts );
$dir = implode( '/', $parts );

if( !
is_dir( $dir ) )
mkdir( $dir, 0777, true );

file_put_contents( $fullPath, $contents, $flags );
}

file_force_contents( ROOT.'/newpath/file.txt', 'message', LOCK_EX );
?>
20
chris at ocportal dot com
11 年前
理解 LOCK_EX 並不會阻止讀取檔案這點很重要,除非你也明確地使用 PHP 的 'flock' 函式取得讀取鎖定(共享鎖定)。

也就是說,在併發場景下,如果不這樣包裝 `file_get_contents`,它可能會返回空值。

<?php
$myfile
=fopen('test.txt','rt');
flock($myfile,LOCK_SH);
$read=file_get_contents('test.txt');
fclose($myfile);
?>

如果你的程式碼使用 `file_get_contents` 讀取檔案、修改字串,然後使用 `file_put_contents` 重新儲存,你最好確保操作正確,否則你的檔案會隨機被清空。
26
deqode at felosity dot nl
14 年前
請注意,當使用 FTP 主機儲存時,必須傳遞一個額外的串流上下文,告知 PHP 覆蓋檔案。

<?php
/* 設定 FTP 主機名稱 */
$user = "test";
$pass = "myFTP";
$host = "example.com";
$file = "test.txt";
$hostname = $user . ":" . $pass . "@" . $host . "/" . $file;

/* 檔案內容 */
$content = "this is just a test.";

/* 建立一個串流上下文,告知 PHP 覆蓋檔案 */
$options = array('ftp' => array('overwrite' => true));
$stream = stream_context_create($options);

/* 最後,寫入內容 */
file_put_contents($hostname, $content, 0, $stream);
?>
4
匿名
2 年前
建立子目錄的簡化方法

function path_put_contents($filePath, $contents, $flags = 0) {

if (! is_dir($dir = implode('/', explode('/', $filePath, -1))))
mkdir($dir, 0777, true);
file_put_contents($filePath, $contents, $flags);
}
9
匿名
7 年前
確保在發生錯誤時不會損毀任何資料。

<?php

函式 file_put_contents_atomically($filename, $data, $flags = 0, $context = null) {
if (
file_put_contents($filename."~", $data, $flags, $context) === strlen($contents)) {
return
rename($filename."~",$filename,$context);
}

@
unlink($filename."~", $context);
return
FALSE;
}

?>
7
egingell at sisna dot com
18 年前
回覆先前的留言

如果您想在 PHP4 中模擬此函式,您需要回傳寫入的位元組數,並且支援陣列和旗標。

我只想出 FILE_APPEND 旗標和陣列支援。如果我能理解「資源上下文」和其他旗標,我也會將它們包含在內。

<?

define('FILE_APPEND', 1);
function file_put_contents($n, $d, $flag = false) {
$mode = ($flag == FILE_APPEND || strtoupper($flag) == 'FILE_APPEND') ? 'a' : 'w';
$f = @fopen($n, $mode);
if ($f === false) {
return 0;
} else {
if (is_array($d)) $d = implode($d);
$bytes_written = fwrite($f, $d);
fclose($f);
return $bytes_written;
}
}

?>
7
aidan at php dot net
20 年前
此功能現已在 PEAR 套件 PHP_Compat 中實作。

更多關於在不升級 PHP 版本的情況下使用此函式的資訊,請參考以下連結

http://pear.php.net/package/PHP_Compat
1
vaneatona at gmail dot com
7 年前
我正在更新一個已發布的函式,因為如果沒有目錄,它會失敗。它還會回傳最終值,以便您可以判斷實際檔案是否已寫入。

public static function file_force_contents($dir, $contents){
$parts = explode('/', $dir);
$file = array_pop($parts);
$dir = '';

foreach($parts as $part) {
if (! is_dir($dir .= "{$part}/")) mkdir($dir);
}

return file_put_contents("{$dir}{$file}", $contents);
}
2
ravianshmsr08 at gmail dot com
13 年前
要將檔案從您的本機主機上傳到任何 FTP 伺服器。
請注意,已使用 'ftp_chdir' 而不是直接放置遠端檔案路徑....在 ftp_put 中...遠端檔案應該只是檔名

<?php
$host
= '*****';
$usr = '*****';
$pwd = '**********';
$local_file = './orderXML/order200.xml';
$ftp_path = 'order200.xml';
$conn_id = ftp_connect($host, 21) or die ("無法連線到主機");
ftp_pasv($resource, true);
ftp_login($conn_id, $usr, $pwd) or die("無法登入");
// 執行檔案上傳
ftp_chdir($conn_id, '/public_html/abc/');
$upload = ftp_put($conn_id, $ftp_path, $local_file, FTP_ASCII);
if(
$upload) { $ftpsucc=1; } else { $ftpsucc=0; }
// 檢查上傳狀態:
print (!$upload) ? '無法上傳' : '上傳完成';
print
"\n";
// 關閉 FTP 串流
ftp_close($conn_id);
?>
3
Brandon Lockaby
13 年前
在解構函式中呼叫 file_put_contents 會導致檔案被寫入 SERVER_ROOT...
2
wjsams at gmail dot com
15 年前
file_put_contents() 會移除最後一行的換行符號

如果您真的希望使用 file_put_contents() 寫入檔案時,在檔案結尾處加上額外的換行符號,則必須在該行的結尾附加一個額外的 PHP_EOL,如下所示。

<?php
$a_str
= array("these","are","new","lines");
$contents = implode(PHP_EOL, $a_str);
$contents .= PHP_EOL . PHP_EOL;
file_put_contents("newfile.txt", $contents);
print(
"|$contents|");
?>

您可以看到,當您列印 $contents 時,會得到兩個額外的換行符號,但如果您檢視 newfile.txt 檔案,則只會得到一個。
-2
curda222 at gmail dot com
10 個月前
來自 TrentTompkins at gmail dot com 的改良和令人欣喜的程式碼

備註:已新增錯誤回應
備註:已新增目錄偵測
備註:已新增根目錄偵測
備註:已新增建立資料夾時的權限設定

function file_force_contents($dir, $contents, $flags = 0){
if (strpos($dir, "../") === 0){
$dir = str_replace("..", substr(__DIR__, 0, strrpos(__DIR__, "/")), $dir);
}
$parts = explode('/', $dir);
if(is_array($parts)){
$file = array_pop($parts);
$dir = '';
foreach($parts as $part)
if(!is_dir($dir .= "/$part")){
mkdir($dir, 0777, true);
}
if(file_put_contents("$dir/$file", $contents, $flags) === false ){
return false;
}
}else{
if(file_put_contents("$dir", $contents, $flags) === false ){
return false;
}
}
}

-Oliver Leuyim Angel
1
John Galt
15 年前
我使用 file_put_contents() 作為一個非常簡單的點擊計數器方法。以下是用一行代碼編寫的兩個極簡點擊計數器的不同範例。

請記住,它們的效率並不是那麼高。您必須有一個名為 counter.txt 的檔案,初始值為 0。

文字點擊計數器:
<?php
$counter
= file_get_contents("counter.txt"); $counter++; file_put_contents("counter.txt", $counter); echo $counter;
?>

圖形點擊計數器:
<?php
$counter
= file_get_contents("counter.txt"); $counter++; file_put_contents("counter.txt", $counter); for($i = 0; $i < strlen($counter); $i++) echo "<img src=\"counter/".substr($counter, $i, 1).".gif\" alt=\"".substr($counter, $i, 1)."\" />";
?>
0
aabaev arroba gmail coma com
8 年前
我建議擴展 TrentTompkins at gmail dot com 的 file_force_contents() 函式,加入驗證路徑是否類似 "../foo/bar/file"

if (strpos($dir, "../") === 0)
$dir = str_replace("..", substr(__DIR__, 0, strrpos(__DIR__, "/")), $dir);
0
gurjindersingh at SPAM dot hotmail dot com
10 年前
如果嘗試將檔案放入不存在的目錄中,File put contents 會失敗。此函式會建立該目錄。

我已經更新了 "TrentTompkins at gmail dot com" 的程式碼。謝謝
<?php
/**
* @param string $filename <p>包含資料夾的檔案名稱。
* 範例:: /path/to/file/filename.ext 或 filename.ext</p>
* @param string $data <p>要寫入的資料。
* </p>
* @param int $flags 與 file_put_contents 使用相同的旗標。
* 更多資訊: https://php.dev.org.tw/manual/en/function.file-put-contents.php
* @return bool <b>TRUE</b> 成功建立檔案 <br> <b>FALSE</b> 建立檔案失敗。
*/
function file_force_contents($filename, $data, $flags = 0){
if(!
is_dir(dirname($filename)))
mkdir(dirname($filename).'/', 0777, TRUE);
return
file_put_contents($filename, $data,$flags);
}
// 使用範例

file_force_contents('test1.txt','test1 content'); // 建立 test1.txt

file_force_contents('test2/test2.txt','test2 content');
// 建立 test2/test2.txt 和 "test2" 資料夾。

file_force_contents('~/test3/test3.txt','test3 content');
// 在使用者目錄中建立 /path/to/user/directory/test3/test3.txt 和 "test3" 資料夾 (在 Linux 上使用 "ll ~/ | grep test3" 檢查)。
?>
0
error at example dot com
13 年前
值得注意的是,使用此函式時必須確保使用正確的路徑。我曾用它來協助錯誤處理器的記錄,有時它可以正常運作,但有時卻不行。最後發現是因為它有時會從不同的路徑被呼叫,導致無法寫入日誌檔。

__DIR__ 是你的好幫手。
-1
vahkos at mail dot ru
12 年前
如果檔名不正確(例如檔名結尾有不正確的符號 /n、/t),file_put_contents 不會發出錯誤訊息。
這就是為什麼要使用 trim() 處理檔名。
$name=trim($name);
file_put_contents($name,$content);
To Top