确定 URL 是否是 PHP 中图像的最佳方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/676949/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
best way to determine if a URL is an image in PHP
提问by danio
Using PHP, given a URL, how can I determine whether it is an image?
使用PHP,给定一个URL,如何确定它是否是图像?
There is no context for the URL - it is just in the middle of a plain text file, or maybe just a string on its own.
URL 没有上下文——它只是在一个纯文本文件的中间,或者可能只是一个单独的字符串。
I don't want high overhead (e.g. reading the content of the URL) as this could be called for many URLs on a page. Given this restriction, it isn't essential that all images are identified, but I would like a fairly good guess.
我不想要高开销(例如读取 URL 的内容),因为这可能会被页面上的许多 URL 调用。鉴于此限制,识别所有图像并不是必需的,但我想要一个相当好的猜测。
At the moment I am just looking at the file extension, but it feels like there should be a better way than this.
目前我只是在看文件扩展名,但感觉应该有比这更好的方法。
Here is what I currently have:
这是我目前拥有的:
function isImage( $url )
{
$pos = strrpos( $url, ".");
if ($pos === false)
return false;
$ext = strtolower(trim(substr( $url, $pos)));
$imgExts = array(".gif", ".jpg", ".jpeg", ".png", ".tiff", ".tif"); // this is far from complete but that's always going to be the case...
if ( in_array($ext, $imgExts) )
return true;
return false;
}
Edit:In case it's useful to anybody else here is the final function using the technique from Emil H's answer:
编辑:如果它对其他人有用,这里是使用 Emil H 回答中的技术的最终功能:
function isImage($url)
{
$params = array('http' => array(
'method' => 'HEAD'
));
$ctx = stream_context_create($params);
$fp = @fopen($url, 'rb', false, $ctx);
if (!$fp)
return false; // Problem with url
$meta = stream_get_meta_data($fp);
if ($meta === false)
{
fclose($fp);
return false; // Problem reading data from url
}
$wrapper_data = $meta["wrapper_data"];
if(is_array($wrapper_data)){
foreach(array_keys($wrapper_data) as $hh){
if (substr($wrapper_data[$hh], 0, 19) == "Content-Type: image") // strlen("Content-Type: image") == 19
{
fclose($fp);
return true;
}
}
}
fclose($fp);
return false;
}
采纳答案by Emil H
You could use an HTTP HEADrequest and check the content-type. This might be a good compromise. It can be done using PHP Streams. Wez Furlong has an articlethat shows how to use this approach to send post requests, but it can be easily adapted to send HEAD requests instead. You can retrieve the headers from an http response using stream_get_meta_data().
您可以使用HTTP HEAD请求并检查内容类型。这可能是一个很好的妥协。它可以使用PHP Streams来完成。Wez Furlong 有一篇文章展示了如何使用这种方法发送 post 请求,但它可以很容易地改为发送 HEAD 请求。您可以使用stream_get_meta_data()从 http 响应中检索标头。
Of course this isn't really 100%. Some servers send incorrect headers. It will however handle cases where images are delivered through a script and the correct file extension isn't available. The only way to be really certain is to actually retrieve the image - either all of it, or the first few bytes, as suggested by thomasrutter.
当然,这并不是真正的 100%。一些服务器发送不正确的标头。但是,它将处理通过脚本传送图像并且正确的文件扩展名不可用的情况。真正确定的唯一方法是实际检索图像 - 全部或前几个字节,如 thomasrutter 所建议的。
回答by Pedro Soares
if(is_array(getimagesize($urlImg)))
echo 'Yes it is an image!';
回答by thomasrutter
There are a few different approaches.
有几种不同的方法。
Sniff the content by looking for a magic number at the start of the file. For example, GIF uses GIF87 or GIF89 as the first five bytes of the file (in ascii). Unfortunately this can't tell you if there's an error in the image or if the image contains malicious content. Here are some magic numbers for various types of image files (feel free to use these):
"\xff\xd8\xff" => 'image/jpeg', "\x89PNG\x0d\x0a\x1a\x0a" => 'image/png', "II*\x00" => 'image/tiff', "MM\x00*" => 'image/tiff', "\x00\x00\x01\x00" => 'image/ico', "\x00\x00\x02\x00" => 'image/ico', "GIF89a" => 'image/gif', "GIF87a" => 'image/gif', "BM" => 'image/bmp',
Sniffing the content like this is probably going to fit your requirements best; you'll only have to read and therefore download the first few bytes of the file (past the header).
Load the image using the GD library to see if it loads without error. This can tell you if the image is valid, without error or not. Unfortunately this probably doesn't fit your requirements because it requires downloading the complete image.
- If you really don't want to make an HTTP request for the image at all, then this rules out both sniffing and getting HTTP headers. You can, however, try to determine whether something is an image by the context in which it is linked. Something linked using a src attribute in an <img element is almost certainly an image (or an attempt at XSS, but that's another story). This will tell you if something is intended as an image. It won't tell you whether the image is actually available, or valid; you'll have to fetch at least the first small part (header or magic number) of the image URL to find that.
通过查找文件开头的幻数来嗅探内容。例如,GIF 使用 GIF87 或 GIF89 作为文件的前五个字节(ascii)。不幸的是,这无法告诉您图像中是否存在错误或图像是否包含恶意内容。以下是各种类型图像文件的一些幻数(随意使用这些):
"\xff\xd8\xff" => 'image/jpeg', "\x89PNG\x0d\x0a\x1a\x0a" => 'image/png', "II*\x00" => 'image/tiff', "MM\x00*" => 'image/tiff', "\x00\x00\x01\x00" => 'image/ico', "\x00\x00\x02\x00" => 'image/ico', "GIF89a" => 'image/gif', "GIF87a" => 'image/gif', "BM" => 'image/bmp',
像这样嗅探内容可能最适合您的要求;您只需要阅读并下载文件的前几个字节(经过标题)。
使用 GD 库加载图像,看看它是否加载没有错误。这可以告诉您图像是否有效,没有错误。不幸的是,这可能不符合您的要求,因为它需要下载完整的图像。
- 如果您根本不想对图像发出 HTTP 请求,那么这将排除嗅探和获取 HTTP 标头的可能性。但是,您可以尝试通过链接的上下文来确定某物是否为图像。使用 <img 元素中的 src 属性链接的东西几乎可以肯定是图像(或对 XSS 的尝试,但那是另一回事)。这将告诉您某些内容是否旨在作为图像。它不会告诉您图像是否实际可用或有效;您必须至少获取图像 URL 的第一个小部分(标题或幻数)才能找到它。
Unfortunately, it is possible for a file to be both a valid image as well as a ZIP file containing harmful content which could be executed as Java by a harmful site - see the GIFAR exploit. You can almost certainly prevent this vulnerability by loading the image in a library like GD and performing some non-trivial filter on it, like softening or sharpening it a tiny amount (ie using a convolution filter) and saving it to a fresh file withouttransferring any metadata across.
不幸的是,文件可能既是有效图像又是包含有害内容的 ZIP 文件,这些内容可能被有害站点作为 Java 执行 - 请参阅GIFAR 漏洞利用。您几乎可以肯定地通过将图像加载到像 GD 之类的库中并对其执行一些重要过滤器来防止此漏洞,例如将其柔化或锐化少量(即使用卷积过滤器)并将其保存到新文件而不传输任何元数据。
Trying to determine if something is an image by its content-type alone is quite unreliable, almost as unreliable as checking the file extension. When loading an image using an <img element, browsers sniff for a magic string.
试图仅通过内容类型来确定某物是否是图像是非常不可靠的,几乎与检查文件扩展名一样不可靠。使用 <img 元素加载图像时,浏览器会嗅探魔术字符串。
回答by RafaSashi
In addition to Emil H's answer:
除了 Emil H 的回答:
Using get_headers()to check the content type of an url without downloading the entire file with getimagesize()
使用get_headers()来检查URL的内容类型,而无需下载整个文件,getimagesize()
$url_headers=get_headers($url, 1);
if(isset($url_headers['Content-Type'])){
$type=strtolower($url_headers['Content-Type']);
$valid_image_type=array();
$valid_image_type['image/png']='';
$valid_image_type['image/jpg']='';
$valid_image_type['image/jpeg']='';
$valid_image_type['image/jpe']='';
$valid_image_type['image/gif']='';
$valid_image_type['image/tif']='';
$valid_image_type['image/tiff']='';
$valid_image_type['image/svg']='';
$valid_image_type['image/ico']='';
$valid_image_type['image/icon']='';
$valid_image_type['image/x-icon']='';
if(isset($valid_image_type[$type])){
//do something
}
}
回答by TheMonkeyKing
Edit: For static images with popular image extension.
编辑:对于带有流行图像扩展名的静态图像。
<?php
$imgExts = array("gif", "jpg", "jpeg", "png", "tiff", "tif");
$url ='path/to/image.png';
$urlExt = pathinfo($url, PATHINFO_EXTENSION);
if (in_array($urlExt, $imgExts)) {
echo 'Yes, '.$url.' is an Image';
}
?>
回答by Martin Postma
Similar to some given answer but with a slightly different logic.
类似于某些给定的答案,但逻辑略有不同。
$headers = @get_headers($url, 1); // @ to suppress errors. Remove when debugging.
if (isset($headers['Content-Type'])) {
if (strpos($headers['Content-Type'], 'image/') === FALSE) {
// Not a regular image (including a 404).
}
else {
// It's an image!
}
}
else {
// No 'Content-Type' returned.
}
@ is an error control operator.
@ 是一个错误控制运算符。
Note we used the "strict" operator === FALSEin the condition because strpos($headers['Content-Type'], 'image/')does return 0in our use case if the needle is found in the haystack. With type casting using ==that would erroneously be interpreted as FALSE.
请注意,我们=== FALSE在条件中使用了“严格”运算符,因为如果在大海捞针中找到针,则在我们的用例中strpos($headers['Content-Type'], 'image/')确实会返回0。使用类型转换==会错误地解释为FALSE.
回答by Janith Chinthana
we can use exif_imagetype to check the image type, so it's not allow to any other content types. It only allow images and we can restrict them to few image types, following sample code show how to allow GIF image type.
我们可以使用 exif_imagetype 来检查图像类型,因此不允许任何其他内容类型。它只允许图像,我们可以将它们限制为几种图像类型,以下示例代码展示了如何允许 GIF 图像类型。
if (exif_imagetype('image.gif') != IMAGETYPE_GIF) {
echo 'The picture is not a gif';
}
You can use following image types,
您可以使用以下图像类型,
IMAGETYPE_GIF
IMAGETYPE_JPEG
IMAGETYPE_PNG
IMAGETYPE_SWF
IMAGETYPE_PSD
IMAGETYPE_BMP
IMAGETYPE_TIFF_II (intel byte order)
IMAGETYPE_TIFF_MM (motorola byte order)
IMAGETYPE_JPC
IMAGETYPE_JP2
IMAGETYPE_JPX
IMAGETYPE_JB2
IMAGETYPE_SWC
IMAGETYPE_IFF
IMAGETYPE_WBMP
IMAGETYPE_XBM
IMAGETYPE_ICO
more details : link
更多详情:链接
回答by Hassan Saeed
Fast Solution for broken or not found images link
i recommend you that don't use getimagesize() because it will 1st download image then it will check images size+if this will not image then it will throw exception so use below code
损坏或未找到图像链接的快速解决方案
我建议你不要使用 getimagesize() 因为它会第一次下载图像然后它会检查图像大小+如果这不会图像然后它会抛出异常所以使用下面的代码
if(checkRemoteFile($imgurl))
{
//found url, its mean
echo "this is image";
}
function checkRemoteFile($url)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);
// don't download content
curl_setopt($ch, CURLOPT_NOBODY, 1);
curl_setopt($ch, CURLOPT_FAILONERROR, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
if(curl_exec($ch)!==FALSE)
{
return true;
}
else
{
return false;
}
}
Note:this current code help you to identify broken or not found url image this will not help you to identify image type or headers
注意:此当前代码可帮助您识别损坏或未找到的 url 图像,这不会帮助您识别图像类型或标题

