确定URL是否是PHP中的图像的最佳方式

使用PHP,给定一个URL,我怎样才能确定它是否是一个图像?

没有URL的上下文 – 它只是在纯文本文件的中间,或者可能只是一个string本身。

我不想要很高的开销(例如读取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:

  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; } 

您可以使用HTTP HEAD请求并检查内容types。 这可能是一个很好的妥协。 可以使用PHP Streams来完成。 Wez Furlong有一篇文章展示了如何使用这个方法来发送post请求,但是它可以很容易地适应发送HEAD请求。 您可以使用stream_get_meta_data()从http响应中检索标头。

当然这不是100%。 某些服务器发送错误的标题 然而,它将处理通过脚本传送图像的情况,并且正确的文件扩展名不可用。 要真正确定的唯一方法是根据thomasrutter的build议实际检索图像 – 全部或前几个字节。

有几种不同的方法。

  • 通过在文件开始处查找幻数来嗅探内容。 例如,GIF使用GIF87或GIF89作为文件的前五个字节(以ASCIIforms)。 不幸的是,这不能告诉你图像是否有错误,或者图像是否包含恶意内容。 这里有一些神奇的数字为各种types的图像文件(随意使用这些):

     “\ 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上的尝试,但这是另一回事)。 这会告诉你是否有东西是作为一个图像。 它不会告诉你图像是否实际可用或有效; 您必须至less抓取图片url的第一个小部分(标题或幻数)才能find。

不幸的是,一个文件既可能是一个有效的图像,也可能是一个包含有害内容的ZIP文件,这些文件可能被一个有害的网站作为Java执行,参见GIFAR漏洞利用 。 几乎可以肯定的是,通过将图像加载到像GD这样的库中,并对其执行一些非平凡的filter(例如软化或锐化一小部分(即使用卷积filter)并将其保存到新文件而不传送任何元数据。

试图通过其内容types来确定某个图像是否是图像是相当不可靠的,几乎与检查文件扩展名一样不可靠。 当使用<img元素加载图片时,浏览器嗅探一个魔术string。

 if(is_array(getimagesize($urlImg))) echo 'Yes it's an image!'; 

除了Emil H的回答:

使用get_headers()检查url的内容types,而不用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 } } 

编辑:为stream行的图像扩展的静态图像。

 <?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'; } ?> 

我们可以使用exif_imagetype来检查图像types,所以不允许其他内容types。 它只允许图像,我们可以限制它们为几个图像types,下面的示例代码显示如何允许GIF图像types。

 if (exif_imagetype('image.gif') != IMAGETYPE_GIF) { echo 'The picture is not a gif'; } 

您可以使用以下图像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 

更多细节: 链接

类似于一些给定的答案,但逻辑稍有不同。

 $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. } 

@是一个错误控制操作符 。

注意我们在条件中使用了“strict”运算符=== FALSE ,因为如果在干草堆中find针strpos($headers['Content-Type'], 'image/')在我们的用例中返回0 。 使用==types转换将被错误地解释为FALSE

快速解决scheme破碎或找不到图像的链接
我build议你不要使用getimagesize(),因为它会首先下载图像,然后它会检查图像大小+如果这将不会形象,那么它会抛出exception,所以使用下面的代码

 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; } } 

注意:这个当前的代码可以帮助您识别破损或未find的url图片,这不会帮助您识别图片types或标题