web-dev-qa-db-ja.com

URLがPHP

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

編集:エミール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;
  }
51
danio

HTTP HEAD リクエストを使用して、content-typeを確認できます。これは良い妥協かもしれません。 PHP Streams を使用して実行できます。 Wez Furlongには、このアプローチを使用して投稿リクエストを送信する方法を示す article がありますが、代わりにHEADリクエストを送信するように簡単に調整できます。ヘッダーを取得できます stream_get_meta_data() を使用したhttp応答から。

もちろん、これは実際には100%ではありません。一部のサーバーは、誤ったヘッダーを送信します。ただし、スクリプトを介して画像が配信され、正しいファイル拡張子が利用できない場合は処理します。本当に確実にする唯一の方法は、イメージを実際に取得することです-thomasrutterが示唆するように、イメージのすべて、または最初の数バイトのいずれかです。

28
Emil H
if(is_array(getimagesize($urlImg)))
    echo 'Yes it is an image!';
14
Pedro Soares

いくつかの異なるアプローチがあります。

  • ファイルの先頭でマジックナンバーを探してコンテンツを探ります。たとえば、GIFはGIF87またはGIF89をファイルの最初の5バイトとして(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の最初の小さな部分(ヘッダーまたはマジックナンバー)を取得する必要があります。

残念ながら、ファイルは有効な画像であると同時に、Javaとして実行される有害なコンテンツを含むZipファイルである可能性があります- GIFARエクスプロイト 。Gdなどのライブラリに画像をロードし、その上でわずかなフィルタを実行することにより、この脆弱性をほぼ確実に防ぐことができます。 )そしてそれを新しいファイルに保存しますwithoutメタデータを転送します。

コンテンツタイプだけで何かがイメージであるかどうかを判断しようとすると、ファイル拡張子をチェックするのとほぼ同じくらい信頼性が低くなります。 <img要素を使用して画像を読み込むと、ブラウザはマジックストリングを探ります。

13
thomasrutter

エミールHの答えに加えて:

get_headers()を使用してファイル全体をダウンロードせずにgetimagesize()でURLのコンテンツタイプを確認する

    $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

        }
    }
10
RafaSashi

編集:一般的な画像拡張子を持つ静的画像用。

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

?>
6
TheMonkeyKing

与えられた答えに似ていますが、ロジックがわずかに異なります。

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

@は エラー制御演算子 です。

ユースケースがhaystackで見つかった場合、strpos($headers['Content-Type'], 'image/')はユースケースで_=== FALSE_を返すため、条件で「厳密な」演算子_0_を使用したことに注意してください。誤ってFALSEとして解釈される_==_を使用した型キャスト。

2
Martin Postma

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

詳細: リンク

1

壊れたまたは見つからない画像リンクの高速ソリューション

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イメージを識別するのに役立ちます。これは、イメージタイプまたはヘッダーを識別するのに役立ちません。

0
Hassan Saeed