2011-06-26 10 views
24

Tôi muốn kiểm tra xem tệp đã tải lên có phải là tệp hình ảnh hay không (ví dụ: png, jpg, jpeg, gif, bmp) hoặc một tệp khác. Vấn đề là tôi đang sử dụng Uploadify để tải lên các tệp, thay đổi loại mime và cung cấp 'văn bản/bát phân' hoặc thứ gì đó làm loại mime, bất kể bạn đang tải lên loại tệp nào.Cách kiểm tra xem tệp được tải lên có phải là hình ảnh không có loại mime không?

Có cách nào để kiểm tra xem tệp đã tải lên có phải là hình ảnh ngoài việc kiểm tra phần mở rộng tệp bằng PHP không?

Trả lời

32

Bạn có thể sử dụng getimagesize() để trả về số không cho kích thước trên hình ảnh không phải.

+2

Theo như tôi biết, đây thực sự là lỗi được chấp nhận để thực hiện việc này. Tôi muốn được nghe những phương pháp tốt hơn nếu chúng tồn tại. –

+0

Các tài liệu nói rằng nó trả về một mảng với 7 phần tử, yếu tố nào tôi cần phải kiểm tra xem nó có phải là hình ảnh hay không? –

+0

số không và một cho chiều rộng và chiều cao. –

3

Bạn có thể kiểm tra vài byte đầu tiên của tệp cho magic number để tìm ra định dạng hình ảnh.

6

Bạn có thể xác minh loại hình ảnh bằng cách kiểm tra các số ma thuật ở đầu tệp. Ví dụ: Mỗi tệp JPEG bắt đầu bằng một khối "FF D8 FF E0".

Dưới đây là thông tin thêm về magic numbers

+6

không an toàn, kẻ tấn công có thể "FF D8 FF E0" byte đầu tiên, sau đó thêm một số mã php có khả năng được thực hiện – Reacen

+2

Phản ứng, không có gì an toàn, mã PHP có thể cũng được đưa vào một tệp JPG hợp lệ bằng cách sử dụng phần siêu dữ liệu JPG. – rcode

3

Hãy thử sử dụng exif_imagetype để lấy các loại thực tế của hình ảnh. Nếu tệp quá nhỏ, nó sẽ phát ra lỗi và nếu không thể tìm thấy nó, nó sẽ trả về false

37

Suy nghĩ của tôi về chủ đề rất đơn giản: tất cả ảnh tải lên đều là điều ác.

Và không chỉ vì chúng có thể chứa mã độc, mà đặc biệt là do thẻ meta. Tôi biết về các trình thu thập thông tin duyệt web để tìm một số hình ảnh được bảo vệ bằng thẻ meta ẩn của chúng và sau đó phát bằng bản quyền của chúng. Có lẽ một chút hoang tưởng, nhưng khi hình ảnh do người dùng tải lên nằm ngoài tầm kiểm soát đối với các vấn đề bản quyền, tôi xem xét nghiêm túc vấn đề này.

Để loại bỏ những vấn đề đó, tôi chuyển đổi có hệ thống tất cả hình ảnh đã tải lên thành png bằng gd. Điều này có rất nhiều ưu điểm: hình ảnh được xóa sạch từ các mã độc hại cuối cùng và thẻ meta, tôi chỉ có một định dạng cho tất cả hình ảnh đã tải lên, tôi có thể điều chỉnh kích thước hình ảnh cho phù hợp với tiêu chuẩn của mình và ... Tôi biết ngay nếu hình ảnh là hợp lệ hay không! Nếu không thể mở hình ảnh để chuyển đổi (sử dụng imagecreatefromstring không quan tâm đến định dạng hình ảnh), thì tôi xem hình ảnh là không hợp lệ.

Một thực hiện đơn giản có thể trông như thế này:

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

Để kiểm tra nó:

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

này không chính xác trả lời câu hỏi của bạn như thế này là cùng một loại xe cho thuê hơn là câu trả lời được chấp nhận, nhưng tôi cung cấp cho bạn lý do để sử dụng nó, ít nhất :-)

+0

Tôi hoàn toàn đồng ý với @Alain Tiemblo "Tôi có hệ thống chuyển đổi tất cả hình ảnh đã tải lên thành png bằng gd". Đây là cách để đi về an ninh. – PauloASilva

+0

Thật vậy, một trong những đồng nghiệp của tôi đã chỉ ra rằng điều này không hiệu quả nếu bạn cho phép các hình động. Thật. –

+0

Tôi đồng ý với bạn NHƯNG ... Mọi người đều biết rằng GIF có thể được khai thác ([ví dụ] (http://www.phpclasses.org/blog/post/67-PHP-security-exploit-with-GIF-images.html)). Nếu bạn được yêu cầu hỗ trợ GIF, có thể bạn sẽ phải đầu tư một chút thời gian và công sức để lọc/khử trùng định dạng. – PauloASilva

5

Nếu Uploadify thực sự thay đổi loại mime - tôi sẽ coi đó là lỗi. Nó không có ý nghĩa gì cả, vì các nhà phát triển các khối làm việc với mime-type chức năng có trụ sở tại PHP:

Đây là một hàm trợ giúp nhỏ trả về loại mime dựa trên 6 byte đầu tiên của tệp.

/** 
* 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; 
} 
2

Không thể thẩm vấn tệp với finfo_file?

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

Câu trả lời này chưa được kiểm tra nhưng dựa trên this forum discussion trên diễn đàn Tải lên.

Tôi cũng chỉ ra rằng finfo nên "try to guess the content type and encoding of a file by looking for certain magic byte sequences at specific positions within the file" vì vậy trong tâm trí của tôi điều này vẫn sẽ hoạt động mặc dù Uploadify đã chỉ định loại mime sai.