注意:此函数的结果会被缓存。有关详细信息,请参阅 clearstatcache()。
这是一个非常重要的注释。不要忘记这一点,因为它会让你的 file_exists() 的行为变得异常 - 可能会在生产环境中出现;)
(PHP 4, PHP 5, PHP 7, PHP 8)
file_exists — 检查文件或目录是否存在
filename
文件或目录的路径。
在 Windows 上,使用 //computername/share/filename 或 \\computername\share\filename 检查网络共享上的文件。
如果由 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() 的行为变得异常 - 可能会在生产环境中出现;)
我需要为一个项目衡量性能,所以我用一百万次 file_exists() 和 is_file() 检查进行了一个简单的测试。在一种情况下,只有七个文件存在。在第二种情况下,所有文件都存在。is_file() 在第一种情况下需要 3.0 秒,在第二种情况下需要 3.3 秒。file_exists() 分别需要 2.8 秒和 2.9 秒。当然,绝对数字是依赖于系统的,但它清楚地表明 file_exists() 速度更快。
请注意,如果文件不存在,realpath() 将返回 false。因此,如果你要将路径绝对化并解析符号链接,你可以直接检查 realpath() 的返回值,而不是先调用 file_exists()
WordPress 总是将完整 URL 添加到它存储在数据库中的任何文件,因此,如其他地方所述,file_exists() 无法找到该文件,因为它使用的是“文档根目录”,而不是 URL。一个简单的解决方法是使用
file_exists (str_replace (home_url(), $_SERVER['DOCUMENT_ROOT'], $file) )
来检查文件 $file 是否存在。注意:从 PHP8 开始,'DOCUMENT_ROOT' 必须用方括号括起来,而不是像 ferodano at gmail dot com 所建议的那样用花括号括起来
或者,如果你没有使用 WP,将上面的 home_url() 替换为绝对 URL 名称,例如 'https://mywebsite.com' - 放在引号中,并且没有尾部斜杠。
file_exists() 不会在 PHP 的 include_path 中搜索你的文件,因此在尝试 include 或 require 之前不要使用它。
使用
@$result = include $filename;
是的,include 在文件找不到时会返回 false,但它也会生成一个警告。这就是你需要 @ 的原因。不要尝试通过使用 file_exists() 来避免警告问题。这会让你抓耳挠腮,直到你弄明白或偶然发现 file_exists() 不会在 PHP 的 include_path 中搜索这一事实。
作为对 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;
}
在 Ubuntu 17.04 上使用 PHP 7.0 以及 allow_url_fopen=On 选项,在尝试通过 HTTP 检查远程文件时,file_exists() 总是返回 false。
所以
$url="http://www.somewhere.org/index.htm";
if (file_exists($url)) echo "Wow!\n";
else echo "missing\n";
总是返回“missing”,即使是存在的 URL。
我发现,在相同的情况下,file() 函数可以读取远程文件,所以我将我的例程更改为
$url="http://www.somewhere.org/index.htm";
if (false!==file($url)) echo "Wow!\n";
else echo "missing\n";
这显然慢一些,尤其是当远程文件很大时,但它解决了这个问题。
注意:此函数需要完整的与服务器相关的路径名才能正常工作。
例如,如果你从网站的根目录中运行一个 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
如果你尝试访问 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.net/manual/en/function.flock.php)。确保在您完成操作后解锁并关闭文件,而不是在上述函数中。
<?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); // 关闭
}
?>
另请参阅:https://linux.die.net/man/2/open 关于 O_CREAT|O_EXCL(与 fopen() 的 'x' 修饰符一起使用)以及 NFS 的问题
您可以使用文档根目录以确保安全,因为该函数不接受相对路径
<?php
if( file_exists( $_SERVER{'DOCUMENT_ROOT'} . "/my_images/abc.jpg")) {
...
}
?>
不要忘记添加斜杠“/”,例如,我在 Ubuntu 中的文档根目录是 /var/www,没有斜杠。
我编写了这个简单实用的函数来检查目录中是否存在图像,如果存在,则返回一个不存在的文件名,例如,如果您尝试使用“flower.jpg”并且它存在,那么它会尝试使用“flower[1].jpg”,如果该文件存在,则尝试使用“flower[2].jpg”等等。在我这里工作正常。当然,您也可以将其用于图像以外的其他文件类型。
<?php
function 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;
}
?>
这里有一个函数可以检查特定 URL 是否存在
<?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); //for now
} else {
$this->f_exist[$image]['exist'] = ($fimage!='' && file_exists($fimage) && is_file($fimage) && is_readable($fimage) && filesize($fimage)>0);
}
}
?>
关于 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){
$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 用户拥有时),则 file_exists 将无法找到您的文件。我以为是目录名称中包含空格导致了问题(/users/andrew/Pictures/iPhoto Library/AlbumData.xml),但实际上是 Pictures、iPhoto Library 或 AlbumData.xml 没有读取权限。修复后,file_exists 就能正常工作了。
在使用 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
{
// 未找到
}
}
?>
这样就能正常工作了。
至少在我的运行着 php 5.2.5 和 apache 2.2.3 的 Windows 系统上就是这样。
我不确定是由于连接还是常量存在导致的,我马上要进行测试以确认...。
我编写了一段代码,可以检查通过 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;
}
?>
这段代码用于检查文件是否在另一台服务器上存在。
<?php
function fileExists($path){
return (@fopen($path,"r")==true);
}
?>
不幸的是,file_exists 无法访问远程服务器,因此我使用了 fopen 函数。
这是一个更简单的 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 (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;
}
?>
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)
stream_resolve_include_path() 是 file_exists() 的一个很好的替代方法
我在使用 url 时遇到了 file_exists 的问题,所以我创建了这个函数
<?php
function file_exists_2($filePath)
{
return ($ch = curl_init($filePath)) ? @curl_close($ch) || true : false;
}
?>
干杯!
如果 file_exists() 测试的文件位于符号链接目录结构中,则结果取决于链接树下方目录树节点的权限。Web 服务器(例如 apache)下的 PHP 将尊重符号链接下方文件系统的权限,这与作为 shell 脚本的 PHP 相反,后者尊重链接的目录(即在顶部,可见)的权限。
这会导致文件在符号链接上似乎不存在,即使它们确实存在并且确实可以被 Web 服务器读取。
以下脚本检查是否存在同名文件,并在文件名末尾添加 _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);
?>
该代码可用于生成可用于创建新文件名的文件名。
<?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('invalid folder given!'); }
// 生成文件路径
$filepath = $folder . "/" . generateRandomString(128) . $extension;
// 检查该文件路径是否已存在,如果存在,则重新生成,
// 直到得到一个不存在的路径
while(file_exists($filepath))
{
$filepath = $folder . "/" . generateRandomString(128) . $extension;
}
return $filepath;
}
?>
我花了两个小时思考我的 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 这样的“简化快捷方式”最终只会造成更多麻烦。
我确保文件存在后才包含它们的方式如下(示例:在自动加载器中包含类文件)
<?php
function __autoload($name)
{
$path = explode(":", ini_get('include_path')); //获取所有可能的路径到文件(预先加载了项目的目录结构)
foreach($path as $tryThis)
{
//尝试每个可能的迭代的文件名,并使用第一个出现的
//name.class.php first
$exists = file_exists($tryThis . '/' . $name . '.class.php');
if ($exists)
{
include_once($name . '.class.php');
return;
}
//如果上面不起作用,尝试另一种方法
$exists = file_exists($tryThis . '/' . 'class.' . $name . '.php');
if ($exists)
{
include_once('class.' . $name . '.php');
return;
}
//两者都不起作用…让我们尝试作为inc.php
$exists = file_exists($tryThis . '/' . $name . '.inc.php');
if ($exists)
{
include_once($name . '.inc.php');
return;
}
}
//找不到…
die("Class $name could not be found!");
}
?>
如果在 Windows 中检查由外部程序新创建的文件,则 file_exists() 不会立即识别它。似乎需要短暂的超时。
<?
$file = 'file.tmp';
if ($h = popen("start \"bla\" touch $file", "r")) {
pclose($h);
// 现在我想知道是否创建了一个文件
// 注意:usleep 不支持
$start = gettimeofday();
while (!file_exists(trim($file, " '\""))) {
$stop = gettimeofday();
if ( 1000000 * ($stop['sec'] - $start['sec']) + $stop['usec'] - $start['usec'] > 500000) break; // 等待片刻
}
if (file_exists($file)) // 现在应该可靠了
?>