web-dev-qa-db-ja.com

アップロードされたファイルがMIMEタイプのない画像かどうかを確認するにはどうすればよいですか?

アップロードしたファイルが画像ファイル(png、jpg、jpeg、gif、bmpなど)か、別のファイルかを確認したい。問題は、Uploadifyを使用してファイルをアップロードしていることです。これにより、MIMEタイプが変更され、アップロードするファイルタイプに関係なく、MIMEタイプとして「テキスト/ 8進数」などが表示されます。

PHPを使用してファイル拡張子を確認する以外に、アップロードされたファイルが画像かどうかを確認する方法はありますか?

27
Click Upvote

非画像ではサイズにゼロを返す getimagesize() を使用できます。

33
Scott C Wilson

主題についての私の考えは単純です。アップロードされたすべての画像は悪です。

また、悪意のあるコードが含まれている可能性があるだけでなく、特にメタタグが原因です。 Webを閲覧して、隠されたメタタグを使用して保護された画像を見つけ、著作権で遊ぶクローラーについて知っています。おそらく少し偏執狂かもしれませんが、ユーザーがアップロードした画像は著作権の問題を制御できないため、真剣に考慮しています。

これらの問題を取り除くために、私は体系的にGdを使用してすべてのアップロードされた画像をpngに変換します。これには多くの利点があります。画像は最終的な悪意のあるコードやメタタグからクリーンであり、アップロードしたすべての画像に1つの形式しかないため、標準に合わせて画像サイズを調整できます...画像が有効かどうかすぐにわかります!画像を変換のために開くことができない場合(- imagecreatefromstring)を使用 これは画像に関係ありません形式)、私は画像を無効と見なします。

単純な実装は次のようになります。

function imageUploaded($source, $target)
{
   // check for image size (see @DaveRandom's comment)
   $size = getimagesize($source);
   if ($size === false) {
      throw new Exception("{$source}: Invalid image.");
   }
   if ($size[0] > 2000 || $size[1] > 2000) {
      throw new Exception("{$source}: Too large.");
   }

   // loads it and convert it to png
   $sourceImg = @imagecreatefromstring(@file_get_contents($source));
   if ($sourceImg === false) {
      throw new Exception("{$source}: Invalid image.");
   }
   $width = imagesx($sourceImg);
   $height = imagesy($sourceImg);
   $targetImg = imagecreatetruecolor($width, $height);
   imagecopy($targetImg, $sourceImg, 0, 0, 0, 0, $width, $height);
   imagedestroy($sourceImg);
   imagepng($targetImg, $target);
   imagedestroy($targetImg);
}

テストするには:

header('Content-type: image/png');
imageUploaded('http://www.dogsdata.com/wp-content/uploads/2012/03/Companion-Yellow-dog.jpg', 'php://output');

これはあなたの質問に正確に答えるものではありません。これは受け入れられた答えと同じ種類のハッキングですが、少なくとも:-)を使用する私の理由を説明します。

38
Alain Tiemblo

Uploadifyが本当にMIMEタイプを変更する場合-私はそれをバグと見なします。これは、開発者がPHPでMIMEタイプベースの関数を操作するのを妨げるため、まったく意味がありません。

これは、ファイルの最初の6バイトに基づいてMIMEタイプを返す小さなヘルパー関数です。

/**
 * Returns the image mime-type based on the first 6 bytes of a file
 * It defaults to "application/octet-stream".
 * It returns false, if problem with file or empty file.
 *
 * @param string $file 
 * @return string Mime-Type
 */
function isImage($file)
{
    $fh = fopen($file,'rb');
    if ($fh) { 
        $bytes = fread($fh, 6); // read 6 bytes
        fclose($fh);            // close file

        if ($bytes === false) { // bytes there?
            return false;
        }

        // ok, bytes there, lets compare....

        if (substr($bytes,0,3) == "\xff\xd8\xff") { 
            return 'image/jpeg';
        }
        if ($bytes == "\x89PNG\x0d\x0a") { 
            return 'image/png';
        }
        if ($bytes == "GIF87a" or $bytes == "GIF89a") { 
            return 'image/gif';
        }

        return 'application/octet-stream';
    }
    return false;
}
5
Jens A. Koch

ファイルの先頭でマジックナンバーを確認することで、イメージタイプを確認できます。

例:すべてのJPEGファイルは、 "FF D8 FF E0"ブロックで始まります。

マジックナンバー の詳細はこちら

5
rcode

exif_imagetype を使用して、画像の実際のタイプを取得してみてください。ファイルが小さすぎる場合はエラーがスローされ、ファイルが見つからない場合はfalseが返されます

3
kaore

ファイルの最初の数バイトで マジックナンバー を確認して、画像形式を確認できます。

3
Kibbee

finfo_file でファイルに問い合わせることはできませんか?

$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimetype = finfo_file($finfo, $filename); //should contain mime-type
finfo_close($finfo);

この回答はテストされていませんが、Uploadifyフォーラムの このフォーラムディスカッション に基づいています。

私はまた、finfoが "ファイル内の特定の位置で特定のマジックバイトシーケンスを探すことにより、ファイルのコンテンツタイプとエンコーディングを推測してみてください" であることを指摘します。 Uploadifyは誤ったMIMEタイプを指定していますが。

2