先上程式碼,再解釋。
<?php
rename ("/folder/file.ext", "newfile.ext");
?>
這並不會如您所想的重新命名資料夾中的檔案,而是將檔案移動到 PHP 的工作目錄... 您很可能在 FTP 樹中找不到它。請改用以下方法
<?php
rename ("/folder/file.ext", "/folder/newfile.ext");
?>
(PHP 4, PHP 5, PHP 7, PHP 8)
rename — 重新命名檔案或目錄
嘗試將 from
重新命名為 to
,必要時會在目錄之間移動。如果重新命名檔案且 to
存在,它將會被覆寫。如果重新命名目錄且 to
存在,此函式將會發出警告。
範例 1 使用 rename() 的範例
<?php
rename("/tmp/tmp_file.txt", "/home/user/login/docs/my_file.txt");
?>
先上程式碼,再解釋。
<?php
rename ("/folder/file.ext", "newfile.ext");
?>
這並不會如您所想的重新命名資料夾中的檔案,而是將檔案移動到 PHP 的工作目錄... 您很可能在 FTP 樹中找不到它。請改用以下方法
<?php
rename ("/folder/file.ext", "/folder/newfile.ext");
?>
來自變更日誌的註記
「如果目標檔案系統不允許對檔案進行 chown() 或 chmod() 系統呼叫,則可能會產生警告 — 例如,如果目標檔案系統是 FAT 檔案系統。」
更明確地說,儘管基礎呼叫 chown() 或 chmod() 導致警告,rename() 仍然可能傳回 (bool) true。如果沒有對基礎機制的更深入理解,此行為可能會產生誤導。為了跨檔案系統重新命名,PHP 會呼叫 copy()、unlink()、chown() 和 chmod() 來「偽造」它(不一定按照該順序)。如需更多資訊,請參閱 PHP 錯誤 #50676。
在類 UNIX 作業系統上,檔案系統可能會以明確的 uid 和/或 gid 掛載(例如,使用掛載選項 "uid=someuser,gid=somegroup")。嘗試使用此類目標檔案系統呼叫 rename() 將會導致「不允許的操作」警告,即使檔案確實被重新命名且 rename() 傳回 (bool) true。
這不是錯誤。您可以視使用案例的需要處理警告,或呼叫 copy() 然後呼叫 unlink(),這將避免對 chown() 和 chmod() 的註定呼叫,從而消除警告。
重要注意事項 - rename() 無法跨檔案系統或裝置處理 *目錄*。只能處理 *檔案*
您將收到兩個警告
「PHP 警告:rename():copy() 函式的第一個引數不能是 <whatever> 中第 <whatever> 行的目錄」
「PHP 警告:rename(t2,/var/run/test/t2):<whatever> 中第 <whatever> 行的跨裝置連結無效」
我假設提到的 copy() 是 C 的 copy(),而不是 PHP 的 copy() 函式。在 Ubuntu 錯誤系統中也有一個相關的錯誤,該錯誤已升級到 bugs.php.net
https://bugs.php.net/bug.php?id=54097
目前我認為唯一的解決方案是使用 PHP copy($source, $dest),然後在成功時使用 PHP unlink($source),或執行 system("mv $source $dest"),這是不自然的,並且應該用引號括住具有空格或其他 shell 元字元的路徑,並且可能為了安全性而逸脫。
請注意,在 Unix 上,重新命名是獲取檔案原子更新的絕佳方法。
只需複製舊內容(如果需要),並將新內容寫入新檔案,然後將原始檔案重新命名。
從檔案讀取的所有程序都將繼續這樣做,任何嘗試在您寫入檔案時開啟檔案的程序都將取得舊檔案(因為您將寫入暫存檔),並且在有檔案與沒有檔案(或有半個檔案)之間沒有「中間」時間。
哦,只有當暫存檔和目標檔在同一個檔案系統(例如,分割區/硬碟)上時,這才有效。
rename() 在 Linux/UNIX 上運作,但在 Windows 上不適用於包含先前在同一個指令碼中開啟的檔案的目錄。即使在正確關閉檔案並刷新緩衝區後,問題仍然存在。
<?php
$fp = fopen ("./dir/ex.txt" , "r+");
$text = fread($fp, filesize("../dir/ex.txt"));
ftruncate($fp, 0);
$text2 = "some value";
fwrite ($fp, $text2 );
fflush($fp);
fclose ($fp);
if (is_resource($fp))
fclose($fp);
rename ("./dir", ".dir2"); // 將會產生「權限遭拒」錯誤
?>
奇怪的是,重新命名命令似乎是在 Windows 上關閉控制代碼 *之前* 執行。
在重新命名之前插入 sleep() 命令可以解決問題。
<?php
$fp = fopen ("./dir/ex.txt" , "r+");
$text = fread($fp, filesize("../dir/ex.txt"));
ftruncate($fp, 0);
$text2 = "some value";
fwrite ($fp, $text2 );
fflush($fp);
fclose ($fp);
if (is_resource($fp))
fclose($fp);
sleep(1); // 這招有效
rename ("./dir", ".dir2"); //沒有錯誤
?>
對於那些仍然對 Linux 和 Windows (Windows XP) 中 rename() 在目標位置已存在時的行為感到困惑的人
我已經在兩個作業系統上使用 PHP 5.3.0 和 PHP 5.2.9 測試了 rename($oldName, $targetName),並且發現如果之前已存在名為 $targetName 的檔案,它將會被 $oldName 的內容覆寫。
如果目標檔案已存在,則無論檔案權限設定為何,在 Windows 下使用 PHP4 和 PHP5 時,rename() 都會失敗。我現在使用與 ddoyle [at] canadalawbook [dot] ca 類似的函式,該函式會先嘗試 rename(),檢查它是否傳回 FALSE,如果失敗則使用 copy()/unlink()。
但是,與 rename() 不同,copy() 不適用於「原子更新」。當 copy() 正在執行時,另一個程序實際上可能會存取目標檔案。在這種情況下,另一個程序會將檔案視為空的或具有不完整的內容(「寫入一半」)。
當作業系統為 32 位元時,即使檔案系統支援,rename() 函式顯然也無法移動大於 4 GB 的檔案。
在這裡使用 PHP 5.5.9 (x86) 在 Linux 環境(Ubuntu 14.04.5 LTS i686)中進行了測試,來源檔案(60 GB RAR 檔案)位於 ext4 檔案系統中,而目的地是具有 NTFS 檔案系統的外部硬碟。只複製了 4 GB,並且 RAR 檔案損毀:「Unexpected end of archive」。
尚未測試 rename() 是否可以在 64 位元環境中移動大於 4 GB 的檔案。
在 Mac 上編譯的 PHP 5.1.4 中,使用帶有空格的 rename 時,應該只使用空格。例如
rename("/tmp/somefile.tar", "/mnt/laptop storage/somefile.tar");
如果像 cd 到該目錄一樣使用反斜線,rename 會失敗。範例
rename("/tmp/somefile.tar", "/mnt/laptop\ storage/somefile.tar");
雖然這不是真正的錯誤,但在我編寫備份腳本時,它確實讓我困惑了一會兒。
實際上,我很確定 rename 遵循 *nix rename(2) 的慣例,在目標位置已存在的情況下,以原子方式覆寫目標位置(這表示即使是一瞬間,也沒有其他程序會看到目標位置停止存在)。這很有用,因為它允許您將檔案建立為暫存檔案,然後將其重新命名為您想要的位置,並且沒有人會在檔案完成一半時看到它。
如果現有的新檔案執行 rename($old, $new) 可能是由於權限問題所導致。我敢說您遇到的其他問題是沒有呼叫 clearstatcache() 所造成的,這可能會導致 PHP 表現得好像檔案存在,儘管它已被刪除。
您好!
對於 unix/linux 使用者:知道如果您將 rename() 用於目錄,則新的目錄將使用目前的 umask 建立,這很有用!
在 Windows (XP, vista, 7...) 上,如果您的檔案名稱包含重音符號,則基本上無法運作。http://fr.wikipedia.org/wiki/Windows-1252", 因此請使用 iconv 函式將 utf-8 轉換為 cp1252,如下所示
<?php
$nomfichierinitial=iconv("UTF-8", "CP1252", "C:\\wamp\\www\\tést.txt");
$nomfichierfinal="C:\\wamp\\www\\test.txt";
rename($nomfichierinitial, $nomfichierfinal);
?>
目前尚不清楚 rename 的引數應該使用什麼編碼;對於 PHP 4.3,在 HFS+ 檔案系統上,rename() 無法處理 UTF-8 字串,並傳回錯誤。
我需要將檔案移動到另一個資料夾,無論該檔案是否已存在於目標位置,所以我寫了一小段程式碼,將唯一編號附加到每個檔案。
$rem = $_GET['file'];
$ticket = uniqid(rand(), true);
rename("$rem", "www/home/storefile/$ticket$rem");
輸出看起來像這樣 - 6881432893ad4925a1.70147481filename.txt
如果您想要儲存不同版本的檔案,這也很有幫助。
在 WinXP 上使用 PHP 5 時,rename() 絕對不遵循 *nix rename 慣例。如果 $newname 存在,它將會傳回 FALSE,並且 $oldname 和 $newname 將保持其原始狀態。您可以改為執行類似這樣的操作
function rename_win($oldfile,$newfile) {
if (!rename($oldfile,$newfile)) {
if (copy ($oldfile,$newfile)) {
unlink($oldfile);
return TRUE;
}
return FALSE;
}
return TRUE;
}
請注意,如果嘗試將目錄重新命名為網路共用磁碟機,這將無法運作。
例如
rename('/home/user/me/dir1', '/mnt/shares/nfsmount/dir2')
會在共用磁碟機上建立一個名為 'dir2' 的檔案,而不是目錄。
這讓我措手不及,而我(最快)的解決方案是使用 exec 和 mv 命令
<?php
$cmd = 'mv "/home/user/me/dir1" "/mnt/shares/nfsmount/dir2"';
exec($cmd, $output, $return_val);
if ($return_val == 0) {
echo "成功";
} else {
echo "失敗";
}
?>
這很有趣,在 Win XP 上,如果您嘗試跨磁碟區重新命名,rename 會拋出「拒絕存取」的錯誤。例如,rename("c:\windows\temp\x.txt", "g:\destination") 會失敗。
關於「php at stock-consulting dot com」的註解
這取決於作業系統。
在 Windows 系統上,您無法將檔案重新命名為現有的目標位置(好的,使用工具可以 - 但它們會先取消連結現有的檔案)。
- 重新命名檔案的副檔名
changeext($directory, $ext1, $ext2, $verbose)
我寫了這個函式來重新命名資料夾及其內部子資料夾中某些檔案的副檔名。
參數 1:目錄名稱
參數 2:我們要取代的第一個副檔名
參數 3:檔案的新副檔名
如需簡單使用,請呼叫該函式
changeext('dir', 'html', 'php', 'false');
將目錄 dir 中每個副檔名為 html 的檔案名稱變更為 php
<?php
function changeext($directory, $ext1, $ext2, $verbose = false) {
$num = 0;
if($curdir = opendir($directory)) {
while($file = readdir($curdir)) {
if($file != '.' && $file != '..') {
$srcfile = $directory . '/' . $file;
$string = "$file";
$str = strlen($ext1);
$str++;
$newfile = substr($string, 0, -$str);
$newfile = $newfile.'.'.$ext2;
$dstfile = $directory . '/' . $newfile;
if (eregi("\.$ext1",$file)) { # 只處理具有預定義副檔名的檔案
$fileHand = fopen($srcfile, 'r');
fclose($fileHand);
rename($srcfile, $dstfile );
}
if(is_dir($srcfile)) {
$num += changeext($srcfile, $ext1, $ext2, $verbose);
}
}
}
closedir($curdir);
}
return $num;
}
changeext('dir', 'html', 'php', 'false');
?>
若要移除檔案的副檔名,只需將參數 $ext2 留空 '' 即可
這段程式碼會將特定目錄中的所有檔案和資料夾重新命名為小寫
<?php
$path = "my_doc";
function getDirectory( $path = '.', $level = 0 ){
$ignore = array( 'cgi-bin', '.', '..' );
$dh = @opendir( $path );
while( false !== ( $file = readdir( $dh ) ) )
{
if( !in_array( $file, $ignore ) )
{
$spaces = str_repeat( ' ', ( $level * 4 ) );
if( is_dir( "$path/$file" ) )
{
echo "<strong>$spaces $file</strong><br />";
rename($path."\\".$file, strtolower($path."\\".$file));
getDirectory( "$path/$file", ($level+1) );
}
else {
echo "$spaces $file<br />";
rename($path."\\".$file, strtolower($path."\\".$file));
}
}
}
closedir( $dh );
}
getDirectory( $path , 0 )
?>
如 unlink() 頁面所述
您必須先釋放任何對檔案的控制代碼,才能重新命名它(至少在 Windows 上是這樣)。
這將無法運作,您會收到權限拒絕錯誤
<?php
$fileHand = fopen('tempFile.txt', 'r');
rename( 'tempFile.txt', 'tempFile2.txt' ); // 權限拒絕!
?>
只需關閉控制代碼即可解決此問題
<?php
$fileHand = fopen('tempFile.txt', 'r');
fclose($fileHand);
rename( 'tempFile.txt', 'tempFile2.txt' );
?>
這讓我困惑了一段時間,因為控制代碼是在一個合併函數的頂部開啟的,而重新命名則在底部。
如果 $oldname 和 $newname 是指向同一個檔案的現有硬連結,則 rename() 不會執行任何操作,並傳回成功狀態。
(來自底層 libc rename() 手冊)
另一方面,「/bin/mv oldname newname」會導致移除「oldname」。
[編輯註記:之所以有效,是因為 SplFileObject 具有 __toString() 方法,該方法會傳回檔案路徑]
請注意,您可以將 SplFileInfo 物件作為任一引數傳遞
<?php
# 假設目前目錄中有一個檔案 'foo'
rename('foo', new SplFileInfo('bar'));
# foo 現在是 bar!
rename(new SplFileInfo('bar'), 'foo');
# bar 現在又變回 foo 了
?>
如果您對同一個檔案使用 SplFileObject
您想要重新命名,您必須先移除 SplFileObject 物件。
<?php
$filePath = 'testFile.txt';
$fileObj = new SplFileObject( $filePath );
rename( $filePath, 'newName.txt' );
// 您將會收到 - 權限拒絕錯誤
$filePath = 'testFile.txt';
$fileObj = new SplFileObject( 'filePath.txt' );
$fileObj = null;
rename( $filePath, 'newName.txt' );
// 現在它可以運作了。
?>
如果將一個目錄重新命名為另一個已存在的空目錄,它不會發出任何警告。
這不是我預期的行為。
[pearcec@abe tmp]$ mkdir test1
[pearcec@abe tmp]$ mkdir test2
[pearcec@abe tmp]$ touch test1/test
[pearcec@abe tmp]$ php
<?php
rename("test1","test2");
?>
X-Powered-By: PHP/4.0.5
Content-type: text/html
[pearcec@abe tmp]$ ls -al
總計 12
drwxr-xr-x 3 pearcec commnav 4096 6月 15 13:17 .
drwxr-xr-x 18 pearcec commnav 4096 6月 15 13:15 ..
drwxr-xr-x 2 pearcec commnav 4096 6月 15 13:16 test2
[pearcec@abe tmp]$ ls -la test2/
總計 8
drwxr-xr-x 2 pearcec commnav 4096 6月 15 13:16 .
drwxr-xr-x 3 pearcec commnav 4096 6月 15 13:17 ..
-rw-r--r-- 1 pearcec commnav 0 6月 15 13:16 test
[pearcec@abe tmp]$