注意:此函式的結果會被快取。詳情請參閱 clearstatcache()。
這是一個非常重要的注意事項。不要忘記這一點,因為它可能會讓你的 file_exists() 表現異常 - 可能是在正式環境中 ;)
(PHP 4, PHP 5, PHP 7, PHP 8)
file_exists — 檢查檔案或目錄是否存在
filename
檔案或目錄的路徑。
在 Windows 上,使用 //電腦名稱/分享/檔案名稱 或 \\電腦名稱\分享\檔案名稱 來檢查網路共用上的檔案。
如果 filename
指定的檔案或目錄存在,則返回 true
;否則返回 false
。
注意事項:
對於指向不存在檔案的符號連結,此函式將返回
false
。
注意事項:
檢查是使用真實的 UID/GID 而不是有效的 UID/GID 進行的。
注意:由於 PHP 的整數類型是有號的,許多平台使用 32 位元整數,因此某些檔案系統函式對於大於 2GB 的檔案可能會返回非預期的結果。
失敗時,會發出 E_WARNING
。
範例 #1 測試檔案是否存在
<?php
$filename = '/path/to/foo.txt';
if (file_exists($filename)) {
echo "檔案 $filename 存在";
} else {
echo "檔案 $filename 不存在";
}
?>
注意:此函式的結果會被快取。詳情請參閱 clearstatcache()。
注意:此函式的結果會被快取。詳情請參閱 clearstatcache()。
這是一個非常重要的注意事項。不要忘記這一點,因為它可能會讓你的 file_exists() 表現異常 - 可能是在正式環境中 ;)
請注意,如果檔案不存在,realpath() 將返回 false。因此,如果您打算將路徑絕對化並解析符號連結,則可以直接檢查 realpath() 的返回值,而不是先呼叫 file_exists()
我需要測量一個專案的效能,所以我對一百萬個 `file_exists()` 和 `is_file()` 檢查做了一個簡單的測試。在第一種情況下,只有七個檔案存在。在第二種情況下,所有檔案都存在。`is_file()` 在第一種情況下需要 3.0 秒,在第二種情況下需要 3.3 秒。`file_exists()` 分別需要 2.8 秒和 2.9 秒。絕對數字當然取決於系統,但它清楚地表明 `file_exists()` 更快。
回應 seejohnrun 檢查 URL 是否存在的版本。即使檔案不存在,您仍然會收到 404 標頭。如果您無法使用 CURL,仍然可以使用 `get_headers()`。
$file = 'http://www.domain.com/somefile.jpg';
$file_headers = @get_headers($file);
if($file_headers[0] == 'HTTP/1.1 404 Not Found') {
$exists = false;
}
else {
$exists = true;
}
`file_exists()` 並不會在 PHP 的 `include_path` 中搜尋您的檔案,所以在嘗試 `include` 或 `require` 之前不要使用它。
使用
@$result = include $filename;
是的,當找不到檔案時,`include` 會返回 `false`,但它也會產生警告。這就是為什麼您需要 `@`。不要試圖通過使用 `file_exists()` 來繞過警告問題。這會讓您摸不著頭緒,直到您弄清楚或偶然發現 `file_exists()` 並不會搜尋 PHP 的 `include_path` 這個事實。
我寫了這個方便的小函式來檢查目錄中是否存在圖片,如果存在,則返回一個不存在的檔名,例如,如果您嘗試 `flower.jpg` 且它存在,則它會嘗試 `flower[1].jpg`,如果該檔案存在,則它會嘗試 `flower[2].jpg`,依此類推。它在我這裡運作良好。當然,您也可以將其用於圖片以外的其他檔案類型。
<?php
函式 imageExists($image,$dir) {
$i=1; $probeer=$image;
while(file_exists($dir.$probeer)) {
$punt=strrpos($image,".");
if(substr($image,($punt-3),1)!==("[") && substr($image,($punt-1),1)!==("]")) {
$probeer=substr($image,0,$punt)."[".$i."]".
substr($image,($punt),strlen($image)-$punt);
} else {
$probeer=substr($image,0,($punt-3))."[".$i."]".
substr($image,($punt),strlen($image)-$punt);
}
$i++;
}
return $probeer;
}
?>
在 Ubuntu 17.04 上使用 PHP 7.0 並啟用 allow_url_fopen=On 選項時,使用 file_exists() 檢查遠端檔案 (透過 HTTP) 時,總是會回傳 false。
所以
$url="http://www.somewhere.org/index.htm";
if (file_exists($url)) echo "Wow!\n";
else echo "missing\n";
即使 URL 存在,也總是回傳 "missing"。
我發現在同樣情況下,file() 函式可以讀取遠端檔案,所以我將我的程式碼改成
$url="http://www.somewhere.org/index.htm";
if (false!==file($url)) echo "Wow!\n";
else echo "missing\n";
這顯然會比較慢,尤其是遠端檔案很大的時候,但它解決了這個小問題。
如果您嘗試存取 Windows 網路共用,您必須將 Web 伺服器設定為具有足夠的權限,例如
$file = fopen("\\siscomx17\c\websapp.log",'r');
您會收到一個錯誤訊息,指出路徑不存在,這是因為 Apache 或 IIS 以 LocalSystem 身份執行,所以您必須進入「服務」,並在 Apache 的「以...身分登入」中建立一個具有足夠權限的新使用者,並且確保目標共用具有適當的權限。
希望這可以為大家省下一些研究時間。
file_exists() 容易受到競爭條件的影響,而 clearstatcache() 不足以避免它。
以下函式是一個很好的解決方案
<?php
function file_exists_safe($file) {
if (!$fd = fopen($file, 'xb')) {
return true; // 檔案已存在
}
fclose($fd); // 檔案已建立,我們不再需要檔案控制代碼
return false;
}
?>
如果檔案不存在,這個函式會建立一個檔案,後續呼叫會因為檔案存在而失敗(實際上是一種鎖定機制)。
重要:如果檔案成功建立,它將會保留在磁碟上,您必須自行清理,例如刪除或覆蓋它。這個步驟特意從函式中省略,以便讓腳本在執行計算的同時確保檔案不會被其他程序「佔用」。
注意:如果其他腳本/程序沒有使用上述函式進行檢查,則此方法會失敗,因為它實際上並沒有鎖定檔案。
修正:您可以使用 flock() 鎖定檔案來防止這種情況(儘管所有其他腳本也必須使用 flock() 進行檢查,請參閱 https://php.dev.org.tw/manual/en/function.flock.php)。請確保在您使用完檔案後才解鎖並使用 fclose() 關閉檔案,而不是在上述函式內。
<?php
function create_and_lock($file) {
if (!$fd = fopen($file, 'xb')) {
return false;
}
if (!flock($fd, LOCK_EX|LOCK_NB)) { // 可能因為其他原因失敗,LOCK_NB 將防止阻塞
fclose($fd);
unlink($file); // 清理
return false;
}
return $fd;
}
if ($lock = create_and_lock("foo.txt")) {
// 執行操作
flock($fd, LOCK_UN); // 解鎖
fclose($fd); // 關閉
}
?>
另請參閱:關於 O_CREAT|O_EXCL(fopen() 的 'x' 修飾符會使用它)以及 NFS 問題的 https://linux.die.net/man/2/open
我寫了一小段程式碼,可以查看透過 RTSP 提供的檔案是否存在。
<?php
function rtsp_exists($url) {
$server = parse_url($url, PHP_URL_HOST);
$port = "554";
$hdrs = "DESCRIBE " . $url ." RTSP/1.0"."\r\n\r\n";
// 開啟連線(逾時 15 秒)
$sh = fsockopen($server, $port, $err, $err_otp, 15);
// 檢查連線
if (!$sh) return false;
// 發送標頭
fputs($sh, $hdrs);
// 接收資料(1KB)
$rtds = fgets($sh, 1024);
// 關閉連線
fclose($sh);
return strpos($rtds, "200 OK") > 0;
}
?>
基於某些原因,這裡發佈的所有 url_exists() 函式對我來說都沒作用,因此這是我的調整版本。
<?php
function url_exists($url){
$url = str_replace("http://", "", $url);
if (strstr($url, "/")) {
$url = explode("/", $url, 2);
$url[1] = "/".$url[1];
} else {
$url = array($url, "/");
}
$fh = fsockopen($url[0], 80);
if ($fh) {
fputs($fh,"GET ".$url[1]." HTTP/1.1\nHost:".$url[0]."\n\n");
if (fread($fh, 22) == "HTTP/1.1 404 Not Found") { return FALSE; }
else { return TRUE; }
} else { return FALSE;}
}
?>
這是一個用來檢查特定網址是否存在的功能。
<?php
function url_exists($url) {
$a_url = parse_url($url);
if (!isset($a_url['port'])) $a_url['port'] = 80;
$errno = 0;
$errstr = '';
$timeout = 30;
if(isset($a_url['host']) && $a_url['host']!=gethostbyname($a_url['host'])){
$fid = fsockopen($a_url['host'], $a_url['port'], $errno, $errstr, $timeout);
if (!$fid) return false;
$page = isset($a_url['path']) ?$a_url['path']:'';
$page .= isset($a_url['query'])?'?'.$a_url['query']:'';
fputs($fid, 'HEAD '.$page.' HTTP/1.0'."\r\n".'Host: '.$a_url['host']."\r\n\r\n");
$head = fread($fid, 4096);
fclose($fid);
return preg_match('#^HTTP/.*\s+[200|302]+\s#i', $head);
} else {
return false;
}
}
?>
在我的 CMS 中,我用以下幾行程式碼來使用它
<?php
if(!isset($this->f_exist[$image]['exist']))
if(strtolower(substr($fimage,0,4)) == 'http' || strtolower(substr($fimage,0,4)) == 'www.'){
if(strtolower(substr($image,0,4)) == 'www.'){
$fimage = 'http://'.$fimage;
$image = 'http://'.$image;
}
$this->f_exist[$image]['exist'] = $this->url_exists($fimage); //暫時如此
} else {
$this->f_exist[$image]['exist'] = ($fimage!='' && file_exists($fimage) && is_file($fimage) && is_readable($fimage) && filesize($fimage)>0);
}
}
?>
為了安全起見,您可以使用文件根目錄,因為該函數不接受相對路徑
<?php
if( file_exists( $_SERVER{'DOCUMENT_ROOT'} . "/my_images/abc.jpg")) {
...
}
?>
別忘了加上斜線 '/',例如,我的 Ubuntu 文件根目錄是 /var/www(不含斜線)。
當使用 file_exists 時,似乎不能這樣做
<?php
foreach ($possibles as $poss)
{
if ( file_exists(SITE_RANGE_IMAGE_PATH .$this->range_id .'/ '.$poss .'.jpg') )
{
// 檔案存在
}
else
{
// 找不到檔案
}
}
?>
所以你必須這樣做
<?php
foreach ($possibles as $poss)
{
$img = SITE_RANGE_IMAGE_PATH .$this->range_id .'/ '.$poss .'.jpg'
if ( file_exists($img) )
{
// 存在
}
else
{
// 找不到
}
}
?>
這樣就沒問題了。
至少在我的 Windows 系統上運行 php 5.2.5 和 apache 2.2.3 的情況是如此。
不確定是字串串接的問題還是裡面有常數的問題,我正要測試看看...
如果檔案權限沒有設定為「其他人」可讀取,而檔案又不屬於你的 php 使用者,`file_exists` 就會找不到你的檔案。我原本以為我的問題是目錄名稱裡有空格 (/users/andrew/Pictures/iPhoto Library/AlbumData.xml),但實際上是 Pictures、iPhoto Library 和 AlbumData.xml 沒有讀取權限。設定好權限後,`file_exists` 就正常運作了。
如果你想檢查其他伺服器上的檔案是否存在,可以使用以下程式碼:
<?php
function fileExists($path){
return (@fopen($path,"r")==true);
}
?>
可惜 `file_exists` 無法連到遠端伺服器,所以我使用了 `fopen` 函式。
關於 openspecies 項目的注意事項(順帶一提,寫得非常好,謝謝!)。
如果你的伺服器無法解析自己的 DNS,請使用以下程式碼:
$f = preg_replace('/www\.yourserver\.(net|com)/', getenv('SERVER_ADDR'), $f);
就在 $h = @get_headers($f); 這一行之前。
請根據需要修改正規表達式中的副檔名 (net|com|...)。
範例
你要檢查的檔案:http://www.youserver.net/myfile.gif
伺服器 IP:10.0.0.125
`preg_replace` 會有效地幫你解析網址,將 `$f` 賦值如下:
http://10.0.0.125/myfile.gif
這是 `url_exists` 的簡化版本
<?php
function url_exists($url) {
$hdrs = @get_headers($url);
return is_array($hdrs) ? preg_match('/^HTTP\\/\\d+\\.\\d+\\s+2\\d\\d\\s+.*$/',$hdrs[0]) : false;
}
?>
這段程式碼可用於產生一個檔名,這個檔名可以用來建立一個新的檔案。
<?php
function generateRandomString($length = 8)
{
$string = "";
// 可使用的字元
$possible = "0123456789bcdfghjkmnpqrstvwxyz";
for($i=0;$i < $length;$i++)
{
$char = substr($possible, rand(0, strlen($possible)-1), 1);
if (!strstr($string, $char))
{
$string .= $char;
}
}
return $string;
}
function randomFile($folder = '', $extension = '')
{
$folder = trim($folder);
$folder = ($folder == '') ? './' : $folder;
// 檢查目錄是否存在
if (!is_dir($folder)){ die('給定的目錄無效!'); }
// 產生檔案路徑
$filepath = $folder . "/" . generateRandomString(128) . $extension;
// 檢查檔案路徑是否已存在,如果存在則重新產生
// 直到找到一個不存在的路徑
while(file_exists($filepath))
{
$filepath = $folder . "/" . generateRandomString(128) . $extension;
}
return $filepath;
}
?>
如果您懷疑您正在測試的檔案路徑包含空格,請勿將您的路徑放在引號中,不管是單引號還是雙引號。 file_exists() 會將引號解釋為屬於檔案路徑的字元。反之,什麼都不用做:file_exists() 會自動正確地跳脫空格。
注意:此函式需要完整的伺服器相關路徑才能正常運作。
例如,如果您從網站的根目錄下執行 PHP 常式,並詢問
$bstr = file_exists("/images/Proofreading_patients.jpg");
即使該檔案確實存在於根目錄之外,您也會得到 FALSE。
您需要加入
$bstr = file_exists(__DIR_."/images/Proofreading_patients.jpg");
要讓它返回 TRUE,例如:/srv/www/mywebsite.com/public/images/Proofreading_patients.jpg
我在使用網址時,file_exists 出現了一些問題,所以我寫了這個函式
<?php
function file_exists_2($filePath)
{
return ($ch = curl_init($filePath)) ? @curl_close($ch) || true : false;
}
?>
加油!
對於失效的連結,file_exists() 會返回 FALSE
$ ln -s does_not_exist my_link
$ ls -l
lrwxr-xr-x 1 user group 14 May 13 17:28 my_link -> does_not_exist
$ php -r "var_dump(file_exists('my_link'));"
bool(false)
以下腳本會檢查是否存在同名檔案,並在檔名末尾添加 _n,其中 n 會遞增。如果伺服器上存在 img.jpg,它會嘗試 img_0.jpg,檢查它是否存在於伺服器上,然後嘗試 img_1.jpg。
<?php
$img = "images/".$_FILES['bilde']['name'];
$t=0;
while(file_exists($img)){
$img = "images/".$_FILES['bilde']['name'];
$img=substr($img,0,strpos($img,"."))."_$t".strstr($img,".");
$t++;
}
move_uploaded_file($_FILES['bilde']['tmp_name'], $img);
?>
如果 file_exists() 測試的檔案位於符號連結的目錄結構中,則結果取決於連結樹下的目錄樹節點的權限。網頁伺服器(例如 Apache)下的 PHP 會遵守符號連結下檔案系統的權限,這與作為 shell 腳本的 PHP 形成對比,後者遵守連結的目錄(即頂層和可見目錄)的權限。
這會導致檔案看起來不存在於符號連結上,即使它們確實存在並且網頁伺服器可以讀取它們。
我花了兩個小時想弄清楚我的 if 陳述式出了什麼問題:`file_exists($file)` 一直返回 false,但是我可以毫秒問題地呼叫 `include($file)`。
結果發現我沒有意識到我在 `.htaccess` 檔案中設定的 PHP `include_path` 值並不會套用到 `file_exists`、`is_file` 等函式。
因此
<?PHP
// .htaccess php_value include_path '/home/user/public_html/';
// includes 位於 /home/user/public_html/includes/
// 無法運作,file_exists 返回 false
if ( file_exists('includes/config.php') )
{
include('includes/config.php');
}
// 可以運作,file_exists 返回 true
if ( file_exists('/home/user/public_html/includes/config.php') )
{
include('includes/config.php');
}
?>
這正好說明了像在 `.htaccess` 中設定 `include_path` 這種「為了簡潔而使用的捷徑」從長遠來看反而會造成更多麻煩。
WordPress 總是會在它儲存到資料庫中的任何檔案前面加上完整的網址,所以,正如其他地方所指出的,`file_exists()` 找不到檔案,因為它使用的是「文件根目錄」,而不是網址。一個簡單的解決方法是使用
`file_exists(str_replace(home_url(), $_SERVER['DOCUMENT_ROOT'], $file))`
來檢查檔案 `$file` 是否存在。注意:從 PHP 8 開始,`'DOCUMENT_ROOT'` 必須用方括號括起來,而不是像 ferodano at gmail dot com 建議的那樣用大括號。
或者,如果不是使用 WordPress,請將上面的 `home_url()` 替換為絕對網址名稱,例如 `'https://mywebsite.com'`,用引號括起來,並且沒有結尾的斜線。
較舊的 PHP (v4.x) 無法使用 `get_headers()` 函式。所以我寫了這個函式,而且可以運作。
<?php
function url_exists($url) {
// 支援 4.x 版本
$handle = curl_init($url);
if (false === $handle)
{
return false;
}
curl_setopt($handle, CURLOPT_HEADER, false);
curl_setopt($handle, CURLOPT_FAILONERROR, true); // 這個有效
curl_setopt($handle, CURLOPT_NOBODY, true);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, false);
$connectable = curl_exec($handle);
curl_close($handle);
return $connectable;
}
?>