使用PHP,给定URL,我如何确定它是否是图像?
URL没有上下文 - 它只是在纯文本文件的中间,或者可能只是一个字符串.
我不希望高开销(例如,读取URL的内容),因为可以在页面上调用许多URL.鉴于这种限制,所有图像都不是必需的,但我想要一个相当不错的猜测.
目前我只是在查看文件扩展名,但感觉应该有比这更好的方法.
这是我目前拥有的:
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; }
编辑:如果它对其他任何人有用,最后的功能是使用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; }
Emil H.. 28
您可以使用HTTP HEAD请求并检查内容类型.这可能是一个很好的妥协.它可以使用PHP Streams完成.Wez Furlong有一篇文章展示了如何使用这种方法发送帖子请求,但它可以很容易地适应发送HEAD请求.您可以使用stream_get_meta_data()从http响应中检索标头.
当然这不是100%.有些服务器发送错误的标头 但是,它将处理通过脚本传送图像并且没有正确的文件扩展名的情况.真正确定的唯一方法是实际检索图像 - 全部或者前几个字节,如thomasrutter所建议的那样.
您可以使用HTTP HEAD请求并检查内容类型.这可能是一个很好的妥协.它可以使用PHP Streams完成.Wez Furlong有一篇文章展示了如何使用这种方法发送帖子请求,但它可以很容易地适应发送HEAD请求.您可以使用stream_get_meta_data()从http响应中检索标头.
当然这不是100%.有些服务器发送错误的标头 但是,它将处理通过脚本传送图像并且没有正确的文件扩展名的情况.真正确定的唯一方法是实际检索图像 - 全部或者前几个字节,如thomasrutter所建议的那样.
if(is_array(getimagesize($urlImg))) echo 'Yes it is an image!';
有几种不同的方法.
通过在文件开头查找幻数来嗅探内容.例如,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头.但是,您可以尝试根据链接的上下文确定某个图像是否为图像.在
不幸的是,文件既可以是有效图像,也可以是包含有害内容的ZIP文件,可以由有害网站作为Java执行 - 请参阅GIFAR漏洞.您几乎可以肯定通过将图像加载到像GD这样的库中并对其执行一些非平凡的过滤器来防止此漏洞,例如软化或锐化它(即使用卷积滤镜)并将其保存到新文件而不传输任何元数据.
试图通过单独的内容类型确定某些内容是否是图像是非常不可靠的,几乎与检查文件扩展名一样不可靠.使用
除了Emil H的回答:
使用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 } }
编辑:适用于具有常用图像扩展名的静态图像