PHP中判断URL是否为图片的最佳方法

vql8enpb  于 11个月前  发布在  PHP
关注(0)|答案(9)|浏览(120)

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

a64a0gku

a64a0gku1#

您可以使用HTTP HEAD请求并检查内容类型。这可能是一个很好的折衷方案。它可以使用PHP Streams完成。Wez Furlong有一个article,展示了如何使用这种方法发送post请求,但它可以很容易地调整为发送HEAD请求。您可以使用stream_get_meta_data()从http响应中检索头。
当然,这并不是100%。有些服务器会发送不正确的头。但是,它会处理通过脚本发送的图像和正确的文件扩展名不可用的情况。真正确定的唯一方法是实际检索图像-要么全部,要么前几个字节,正如thomasrutter所建议的那样。

xlpyo6sf

xlpyo6sf2#

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

字符串

6tr1vspr

6tr1vspr3#

有几种不同的方法。

  • 通过查找文件开头的幻数来嗅探内容。例如,GIF使用GIF 87或GIF 89作为文件的前五个字节(以asynchronous方式)。不幸的是,这不能告诉您图像中是否存在错误或图像是否包含恶意内容。以下是各种类型图像文件的幻数(请随意使用):
"\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的第一小部分(头部或幻数)才能找到它。

不幸的是,一个文件既可能是有效的图像,也可能是包含有害内容的ZIP文件,这些内容可能会被有害网站作为Java执行-参见the GIFAR exploit。您几乎可以通过将图像加载到GD等库中并对其执行一些重要的过滤器来防止此漏洞,像软化或锐化它一个微小的量(即使用卷积过滤器),并保存到一个新的文件 * 没有 * 传输任何元数据。
试图仅通过内容类型来确定某个东西是否是图像是非常不可靠的,几乎和检查文件扩展名一样不可靠。当使用<img元素加载图像时,浏览器会嗅探魔法字符串。

vd2z7a6w

vd2z7a6w4#

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

        }
    }

字符串

xcitsw88

xcitsw885#

编辑:用于带有流行图像扩展的静态图像。

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

?>

字符串

xriantvc

xriantvc6#

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

$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
注意,我们在条件中使用了“严格”运算符=== FALSE,因为在我们的用例中,如果在干草堆中找到针,strpos($headers['Content-Type'], 'image/')确实会返回0。使用==的类型转换会错误地解释为FALSE

u7up0aaq

u7up0aaq7#

我们可以使用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

fnvucqvd

fnvucqvd8#

最简单但不是最安全的一条线:

if (in_array(pathinfo(parse_url($url, PHP_URL_PATH), PATHINFO_EXTENSION), ['gif', 'jpg', 'jpeg', 'png', 'webp'])) { 
..Do semething..
 }

字符串

mhd8tkvw

mhd8tkvw9#

快速解决损坏或找不到图像链接

我建议你不要使用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;
    }
}

字符串

**注意:**此当前代码可帮助您识别损坏或未找到的URL图像,但不会帮助您识别图像类型或标题

相关问题