我所能找到的最好的,是if fclose fopen类型的东西,会使页面加载真的很慢。

基本上,我想做的是以下操作:我有一个网站列表,我想在它们旁边显示它们的收藏夹图标。但是,如果一个站点没有站点,我想用另一个图像代替它,而不是显示损坏的图像。

评论

我认为您可以使用CURL并检查其返回码。但是,如果速度是一个问题,那就离线进行缓存吧。

是的,但是我仍然建议使用脱机脚本(从cron运行)来解析网站列表,检查网站是否具有网站图标并为前端缓存该数据。如果您不使用cron,请至少为您检查的每个新URL缓存结果。

要在浏览器中用占位符图像替换损坏的图像,请考虑使用图像错误的客户端解决方案,例如使用jQuery的解决方案

PHP的可能重复项:如何检查图像文件是否存在?

#1 楼

您可以通过CURLOPT_NOBODY指示curl使用HTTP HEAD方法。

或多或少
$ch = curl_init("http://www.example.com/favicon.ico");

curl_setopt($ch, CURLOPT_NOBODY, true);
curl_exec($ch);
$retcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
// $retcode >= 400 -> not found, $retcode = 200, found.
curl_close($ch);


无论如何,您只节省HTTP传输的成本,而不节省TCP连接的建立和关闭。而且图标的大小很小,您可能看不到太大的改进。

如果结果太慢,则在本地缓存结果似乎是个好主意。
HEAD检查文件的时间,然后在标题中返回它。您可以像浏览器一样使用并获取图标的CURLINFO_FILETIME。
您可以在URL缓存中存储URL => [favicon,时间戳记]。然后,您可以比较时间戳记并重新加载图标。

评论


只是一个注释:重新编码所有400个代码上的错误,因此验证将不只是> =

–贾斯汀·布尔(Justin Bull)
2012年4月30日22:07在

如果您不提供用户代理字符串,则某些站点会阻止访问,因此,我建议遵循此指南,在CURLOPT_NOBODY之外添加CURLOPT_USERAGENT:davidwalsh.name/set-user-agent-php-curl-spoof

– rlorenzo
2012年8月17日在22:30



@Lyth 3XX重新编码不是错误,而是重定向。这些应该手动处理或使用CURLOPT_FOLLOWLOCATION处理。

–拉蒙·波卡(Ramon Poca)
13-10-14在14:48

使用curl_setopt($ ch,CURLOPT_SSL_VERIFYPEER,false);同时确保以HTTPS开头的URL可以使用相同的代码!

–克里山·戈帕尔(Krishan Gopal)
2014年4月23日在9:57

#2 楼

正如Pies所说的,您可以使用cURL。您可以获得cURL只给您标题,而不给正文,这可能会使它更快。一个错误的域可能总是需要一段时间,因为您将等待请求超时。您可能可以使用cURL更改超时时间。

以下示例:



function remoteFileExists($url) {
    $curl = curl_init($url);

    //don't fetch the actual page, you only want to check the connection is ok
    curl_setopt($curl, CURLOPT_NOBODY, true);

    //do request
    $result = curl_exec($curl);

    $ret = false;

    //if request did not fail
    if ($result !== false) {
        //if request was ok, check response code
        $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);  

        if ($statusCode == 200) {
            $ret = true;   
        }
    }

    curl_close($curl);

    return $ret;
}

$exists = remoteFileExists('http://stackoverflow.com/favicon.ico');
if ($exists) {
    echo 'file exists';
} else {
    echo 'file does not exist';   
}


评论


remoteFileExists('stackoverflow.com/')也会返回true,但它只是一个链接。此功能不检查链接内容类型是否为文件。

– Donatas Navidonskis
2014-12-12 9:41



#3 楼

CoolGoose的解决方案很好,但是对于大文件来说,速度更快(因为它仅尝试读取1个字节):

if (false === file_get_contents("http://example.com/path/to/image",0,null,0,1)) {
    $image = $default_image;
}


评论


+1。针对CURL的这种解决方案有什么缺点?

– Adriano Varoli广场
2010-4-15 13:50



您可以只使用fopen-如果请求返回代码为404,则fopen返回false。

– s3v3n
2011年5月2日在17:05

这确实很慢,对我不起作用(这意味着如果文件路径不正确,它仍然显示损坏的图像)

– Helmut
2012年7月29日9:00

如果服务器在不存在图像或文件的情况下进行重定向,则此方法不起作用。当站点使用mod_rewrite或某种其他“规则”应如何处理请求时,就会发生这种情况。

– ErikČerpnjak
15年8月7日在8:59

#4 楼

这不是对原始问题的答案,而是做您想做的事情的更好方法:

而不是实际尝试直接获取站点的图标(这是皇家的痛苦)可能是/favicon.png、/favicon.ico、/favicon.gif甚至是/path/to/favicon.png),请使用google:

<img src="http://www.google.com/s2/favicons?domain=[domain]">


完成。

评论


语法有点混乱。因此,这里是一个示例:

– Habeeb Perwad
2012年11月5日下午6:15

#5 楼

投票最多的答案的完整功能:
function remote_file_exists($url)
{
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_NOBODY, 1);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); # handles 301/2 redirects
    curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    if( $httpCode == 200 ){return true;}
}


您可以像这样使用它:
if(remote_file_exists($url))
{
    //file exists, do something
}


评论


哦!我已经过去了几天,但本月初几乎是24/7。谢谢你让我知道!

– Pedro Lobito
16年5月20日在22:33



如果服务器没有响应任何HTTP代码(或者cUrl没有捕获到它),则此方法不起作用。这经常困扰着我。例如。如果有图像。

– Vaci
19年4月8日在8:20

如果url重定向到另一个URL或https版本怎么办?在这种情况下,该卷曲代码将无法完成工作。最好的方法是获取标头信息并搜索不区分大小写的字符串“ 200 ok”。

– Infoconic
8月8日10:19

@Infoconic您可以添加curl_setopt($ ch,CURLOPT_FOLLOWLOCATION,1);。我已经更新了答案来处理302重定向。

– Pedro Lobito
8月8日15:08



#6 楼

如果要处理图像,请使用getimagesize。与file_exists不同,此内置函数支持远程文件。它将返回一个包含图像信息(宽度,高度,类型..etc)的数组。您要做的就是检查数组中的第一个元素(宽度)。使用print_r输出数组的内容

$imageArray = getimagesize("http://www.example.com/image.jpg");
if($imageArray[0])
{
    echo "it's an image and here is the image's info<br>";
    print_r($imageArray);
}
else
{
    echo "invalid image";
}


评论


当远程资源不可用时,将显示404警告。暂时,我通过在getimagesize前面使用@来抑制错误来处理它,但是对此黑客感到内。

–user216084
15年4月11日在11:54

就我而言,这是最好的方法,因为只要不存在图像/文件,我都会被重定向。我第二个结论是@禁止显示错误是行不通的,但在这种情况下,这是必需的。

– ErikČerpnjak
15年8月7日在9:05

我发现我们也可以使用exif_imagetype,它的堆栈速度要快得多stackoverflow.com/a/38295345/1250044

– yckart
16年7月10日在19:00



#7 楼

这可以通过获取HTTP状态代码(404 =找不到)来完成,这可以通过使用上下文选项的file_get_contents文档来实现。以下代码将重定向考虑在内,并将返回最终目标(Demo)的状态代码:

$url = 'http://example.com/';
$code = FALSE;

$options['http'] = array(
    'method' => "HEAD",
    'ignore_errors' => 1
);

$body = file_get_contents($url, NULL, stream_context_create($options));

foreach($http_response_header as $header)
    sscanf($header, 'HTTP/%*d.%*d %d', $code);

echo "Status code: $code";


如果您不想遵循重定向,则可以做类似的操作(演示):

$url = 'http://example.com/';
$code = FALSE;

$options['http'] = array(
    'method' => "HEAD",
    'ignore_errors' => 1,
    'max_redirects' => 0
);

$body = file_get_contents($url, NULL, stream_context_create($options));

sscanf($http_response_header[0], 'HTTP/%*d.%*d %d', $code);

echo "Status code: $code";


我写的博客文章更详细地说明了所使用的某些功能,选项和变量:HEAD首先使用PHP Streams。

评论


相关:PHP:get_headers设置临时stream_context

– hakre
2012年9月1日上午11:14

相关:检查PHP中是否存在URL的最佳方法是什么? (2010年12月14日)

– hakre
2012年9月29日12:31



有关PHP的$ http_response_header的更多信息,请参见php.net/manual/en/reserved.variables.httpresponseheader.php。

–Big McLargeHuge
2014年5月17日18:00



第二个变体对我有用,并且与默认的file_get_contents调用(没有自定义stream_context)相比,它的速度提高了50%,即请求的速度从3,4s到1,7s。

– ErikČerpnjak
15年8月7日在10:27

@ErikČerpnjak:如果没有“自定义” stream_context,则为默认值。您可以从默认上下文中获取选项,并查看它们与自定义上下文的不同之处。这应该使您了解为什么计时会有所不同。 -php.net/stream-context-get-default和php.net/stream-context-get-options

– hakre
2015年8月7日14:00



#8 楼

if (false === file_get_contents("http://example.com/path/to/image")) {
    $image = $default_image;
}


应该工作;)

评论


在函数之前添加@

–Tebe
16年8月8日在8:33

#9 楼

如果出于安全原因将allow_url_fopen设置设置为off,则PHP的内置函数可能无法用于检查URL。 Curl是一个更好的选择,因为我们在以后不需要更改代码。下面是我用来验证有效URL的代码:

$url = str_replace(' ', '%20', $url);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_exec($ch);
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);  
curl_close($ch);
if($httpcode>=200 && $httpcode<300){  return true; } else { return false; } 


请注意CURLOPT_SSL_VERIFYPEER选项,该选项还验证URL以HTTPS开头。

#10 楼

要检查是否存在图像,应该优先使用exif_imagetype而不是getimagesize,因为它要快得多。

要抑制E_NOTICE,只需在错误控制运算符(@)前面添加。

if (@exif_imagetype($filename)) {
  // Image exist
}


作为奖励,使用IMAGETYPE_XXX的返回值(exif_imagetype),我们还可以使用image_type_to_mime_type / image_type_to_extension获得mime类型或文件扩展名。

#11 楼

一种根本的解决方案是将图标图标显示为默认图标上方的div中的背景图像。这样,所有开销都将放在客户端上,同时仍然不会显示损坏的图像(所有浏览器AFAIK中都会忽略缺少的背景图像)。

评论


+1如果您不检查其favicon的多个位置(favicon.ico,favicon.gif,favicon.png),这似乎是最好的解决方案

–加伦
09年6月11日在20:20

#12 楼

function remote_file_exists($url){
   return(bool)preg_match('~HTTP/1\.\d\s+200\s+OK~', @current(get_headers($url)));
}  
$ff = "http://www.emeditor.com/pub/emed32_11.0.5.exe";
    if(remote_file_exists($ff)){
        echo "file exist!";
    }
    else{
        echo "file not exist!!!";
    }


#13 楼

您可以使用以下代码:

$file = 'http://mysite.co.za/images/favicon.ico';
$file_exists = (@fopen($file, "r")) ? true : false;


尝试检查URL上是否存在图像时为我工作了

#14 楼

您可以使用:

$url=getimagesize(“http://www.flickr.com/photos/27505599@N07/2564389539/”);

if(!is_array($url))
{
   $default_image =”…/directoryFolder/junal.jpg”;
}


#15 楼

这适用于我检查PHP中是否存在远程文件:

$url = 'https://cdn.sstatic.net/Sites/stackoverflow/img/favicon.ico';
    $header_response = get_headers($url, 1);

    if ( strpos( $header_response[0], "404" ) !== false ) {
        echo 'File does NOT exist';
        } else {
        echo 'File exists';
        }


#16 楼

您应该发出HEAD请求,而不是GET请求,因为您根本不需要URI内容。正如Pies所说,您应该检查状态代码(范围为200-299,并且可以选择遵循3xx重定向)。

答案问题包含许多可能有用的代码示例:PHP /卷曲:HEAD请求在某些网站上花费很长时间

#17 楼

还有一个更复杂的选择。您可以使用JQuery技巧来检查所有客户端。

$('a[href^="http://"]').filter(function(){
     return this.hostname && this.hostname !== location.hostname;
}).each(function() {
    var link = jQuery(this);
    var faviconURL =
      link.attr('href').replace(/^(http:\/\/[^\/]+).*$/, '')+'/favicon.ico';
    var faviconIMG = jQuery('<img src="favicon.png" alt="" />')['appendTo'](link);
    var extImg = new Image();
    extImg.src = faviconURL;
    if (extImg.complete)
      faviconIMG.attr('src', faviconURL);
    else
      extImg.onload = function() { faviconIMG.attr('src', faviconURL); };
});


来自http://snipplr.com/view/18782/add-a-favicon-near-external-links-with-jquery/(原始博客正在下降)

#18 楼

使用get_headers()的所有答案都在执行GET请求。
执行HEAD请求要更快/更便宜。

要确保get_headers()进行HEAD请求而不是GET,您应该添加以下内容:

stream_context_set_default(
    array(
        'http' => array(
            'method' => 'HEAD'
        )
    )
);


因此,要检查文件是否存在,您的代码应如下所示:

stream_context_set_default(
    array(
        'http' => array(
            'method' => 'HEAD'
        )
    )
);
$headers = get_headers('http://website.com/dir/file.jpg', 1);
$file_found = stristr($headers[0], '200');


$ file_found将返回false或正确,很明显。

#19 楼

如果文件不存在远程is_file(),不知道此方法是否会更快,但是您可以试一下。

$favIcon = 'default FavIcon';
if(is_file($remotePath)) {
   $favIcon = file_get_contents($remotePath);
}


评论


从文档中:“从PHP 5.0.0开始,此功能还可以与某些URL包装器一起使用。请参阅支持的协议和包装器,以确定哪些包装器支持stat()系列功能。”

–PatrikAkerstrand
2012年3月30日20:29在

您是说如果注册流包装器,这可能有效吗?编辑您的问题以显示一个有效的示例,我将删除我的不赞成(如果可以的话,请赞成)。但是目前,我使用远程文件从php cli测试了is_file,并得到了错误。

– greg0ire
2012年3月31日上午11:20

没有可用的示例:var_dump(is_file('http://cdn.sstatic.net/stackoverflow/img/sprites.png'));布尔值(false)

– greg0ire
2012年3月31日上午11:27

#20 楼

如果文件不是外部托管的,则可以将远程URL转换为Web服务器上的绝对路径。这样,您不必调用CURL或file_get_contents等。

 function remoteFileExists($url) {

    $root = realpath($_SERVER["DOCUMENT_ROOT"]);
    $urlParts = parse_url( $url );

    if ( !isset( $urlParts['path'] ) )
        return false;

    if ( is_file( $root . $urlParts['path'] ) )
        return true;
    else
        return false;

}

remoteFileExists( 'https://www.yourdomain.com/path/to/remote/image.png' );
 



注意:您的Web服务器必须填充DOCUMENT_ROOT才能使用此功能


#21 楼

如果您使用的是Symfony框架,那么使用HttpClientInterface还有一种更简单的方法:
private function remoteFileExists(string $url, HttpClientInterface $client): bool {
    $response = $client->request(
        'GET',
        $url //e.g. http://example.com/file.txt
    );

    return $response->getStatusCode() == 200;
}

HttpClient的文档也非常好,如果您需要一种更具体的方法,也许值得研究:https://symfony.com/doc/current/http_client.html

#22 楼

您可以使用文件系统:
使用Symfony \ Component \ Filesystem \ Filesystem;
使用Symfony \ Component \ Filesystem \ Exception \ IOExceptionInterface;

并检查
$ fileSystem = new Filesystem();
如果($ fileSystem-> exists('path_to_file')== true){...