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

时间:2009-03-24 11:14:31

标签: php image url

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

8 个答案:

答案 0 :(得分:28)

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

当然这不是100%。有些服务器发送错误的标头但是,它将处理通过脚本传送图像并且没有正确的文件扩展名的情况。真正确定的唯一方法是实际检索图像 - 全部或者前几个字节,如thomasrutter所建议的那样。

答案 1 :(得分:14)

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

答案 2 :(得分:13)

有几种不同的方法。

  • 通过在文件开头查找幻数来嗅探内容。例如,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,但这是另一个故事)。这将告诉您某些内容是否可用作图像。它不会告诉您图像是否实际可用或有效;你必须至少获取图片网址的第一个小部分(标题或幻数)才能找到它。

不幸的是,文件既可以是有效图像,也可以是包含有害内容的ZIP文件,有害内容可以作为Java执行 - 请参阅the GIFAR exploit。您几乎可以肯定通过在像GD这样的库中加载图像并在其上执行一些非平凡的过滤器来防止此漏洞,例如软化或锐化它(即使用卷积滤镜)并将其保存到新文件没有传输任何元数据。

尝试通过单独的内容类型来确定某个图像是否是图像是非常不可靠的,几乎与检查文件扩展名一样不可靠。使用< img元素加载图像时,浏览器会嗅探魔术字符串。

答案 3 :(得分:10)

除了Emil H的回答:

使用get_headers()检查网址的内容类型,而不使用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

        }
    }

答案 4 :(得分:6)

编辑:适用于具有常用图像扩展名的静态图像。

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

?>

答案 5 :(得分:2)

与某些给出的答案类似,但逻辑略有不同。

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

@是error control operator

注意我们在条件中使用了“strict”运算符=== FALSE,因为如果在大海捞针中找到针,strpos($headers['Content-Type'], 'image/')会在我们的用例中返回0。使用==的类型转换会被错误地解释为FALSE

答案 6 :(得分:1)

我们可以使用exif_imagetype来检查图像类型,因此不允许使用任何其他内容类型。它只允许图像,我们可以将它们限制为几种图像类型,下面的示例代码显示了如何允许GIF图像类型。

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

您可以使用以下图片类型

 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

更多详情:link

答案 7 :(得分:0)

破解或未找到图像链接的快速解决方案
我建议你不要使用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;
    }
}

注意: 此当前代码可帮助您识别损坏或未找到的网址图像,这无法帮助您识别图像类型或标题