我能找到的最好的if
fclose
fopen
东西,就是使页面加载非常缓慢。
基本上,我想做的是以下操作:我有一个网站列表,并且我想在它们旁边显示它们的收藏夹图标。但是,如果一个站点没有站点,我想用另一个图像代替它,而不是显示损坏的图像。
我能找到的最好的if
fclose
fopen
东西,就是使页面加载非常缓慢。
基本上,我想做的是以下操作:我有一个网站列表,并且我想在它们旁边显示它们的收藏夹图标。但是,如果一个站点没有站点,我想用另一个图像代替它,而不是显示损坏的图像。
onerror
图像的客户端解决方案,例如使用jQuery的解决方案
Answers:
您可以通过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 => [favicon,timestamp]。然后,您可以比较时间戳记并重新加载图标。
retcode
所有400个代码都存在错误,因此验证>=
不仅是>
正如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';
}
CoolGoose的解决方案很好,但是对于大文件来说这更快(因为它仅尝试读取1个字节):
if (false === file_get_contents("http://example.com/path/to/image",0,null,0,1)) {
$image = $default_image;
}
fopen
-如果请求返回代码为404,则fopen返回false。
这不是您原始问题的答案,而是一种更好的方法来做您想做的事情:
与其直接尝试直接获取网站的图标(这可能是/favicon.png、/favicon.ico、/favicon.gif甚至是/path/to/favicon.png),这是一种皇家痛苦,而是使用google:
<img src="http://www.google.com/s2/favicons?domain=[domain]">
做完了
投票最多的答案的完整功能:
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
}
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
。我已经更新了答案来处理302
重定向。
如果要处理图像,请使用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";
}
exif_imagetype
,并且它要快得多stackoverflow.com/a/38295345/1250044
这可以通过获取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";
如果您不想遵循重定向,则可以执行类似的操作(Demo):
$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。
$http_response_header
请参见php.net/manual/en/reserved.variables.httpresponseheader.php。
如果出于安全原因将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开头。
要检查图像是否存在,exif_imagetype
应优先考虑getimagesize
,因为它快得多。
要取消显示E_NOTICE
,只需在错误控制运算符(@
)前面添加。
if (@exif_imagetype($filename)) {
// Image exist
}
另外,使用返回的值(IMAGETYPE_XXX
),exif_imagetype
我们还可以使用image_type_to_mime_type
/获得mime类型或文件扩展名image_type_to_extension
。
一种根本的解决方案是将图标图标显示为默认图标上方的div中的背景图像。这样,所有开销都将放在客户端上,同时仍不显示损坏的图像(所有浏览器AFAIK中都会忽略缺少的背景图像)。
您应该发出HEAD请求,而不是GET请求,因为您根本不需要URI内容。正如Pies所说,您应该检查状态代码(范围为200-299,并且可以选择遵循3xx重定向)。
答案问题包含很多可能对您有所帮助的代码示例:PHP / Curl:HEAD请求在某些站点上花费很长时间
还有一个更复杂的选择。您可以使用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:\/\/[^\/]+).*$/, '$1')+'/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/(原始博客目前处于关闭状态)
使用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或true。
var_dump(is_file('http://cdn.sstatic.net/stackoverflow/img/sprites.png')); bool(false)
如果文件不是外部托管的,则可以将远程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' );
注意:您的网络服务器必须填充DOCUMENT_ROOT才能使用此功能
如果您使用的是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