GetImageSize() не возвращает FALSE, когда должен

Работаем над небольшим скриптом загрузки здесь. Я пытаюсь проверить, действительно ли загруженное изображение является изображением, а не просто переименованным файлом PHP.

Когда сценарий опубликован, я могу распечатать массив с помощью

foreach ($_FILES['images']['name'] as $key => $value){             
        print_r(getimagesize($_FILES['images']['tmp_name'][$key]));

Это работает просто отлично, поэтому он не вернет false. Но даже если я загружу файл, который не является изображением, он не даст false. Он просто ничего не возвращает, а остальная часть моего скрипта просто обрабатывает это как изображение.

Может ли кто-нибудь сказать мне, что я делаю неправильно?


person user1362916    schedule 05.05.2012    source источник


Ответы (5)


Загрузить

вы не можете использовать getimagesize на $_FILES['images']['tmp_name'][$key] напрямую .. вам нужно сначала скопировать его в свою систему, прежде чем вы сможете его использовать

Временно использовать $_FILES['images']['size'][$key]

Or

  move_uploaded_file($_FILES['images']['tmp_name'][$key], $destination);
  print_r(getimagesize($destination));

Поддельное изображение

Пожалуйста, не то, что $_FILES['images']['type'][$key] можно подделать

Использование поддельных заголовков изображений

Пример

file_put_contents("fake.png", base64_decode('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABGdBTUEAALGPC/xhBQAAAAZQTFRF////
AAAAVcLTfgAAAAF0Uk5TAEDm2GYAAAABYktHRACIBR1IAAAACXBIWXMAAAsSAAALEgHS3X78AAAAB3RJTUUH0gQCEx05cq
KA8gAAAApJREFUeJxjYAAAAAIAAUivpHEAAAAASUVORK5CYII='));

Загрузка fake.png

array
  'name' => 
    array
      0 => string 'fake.png' (length=8)
  'type' => 
    array
      0 => string 'image/png' (length=9)
  'tmp_name' => 
    array
      0 => string 'C:\Apache\xampp\tmp\php44F.tmp' (length=30)
  'error' => 
    array
      0 => int 0
  'size' => 
    array
      0 => int 167

Проверить изображение

Применение

var_dump ( getimagesizeReal ( "fake.png" ) );

Используемая функция

function getimagesizeReal($image) {

    $imageTypes = array (
            IMAGETYPE_GIF,
            IMAGETYPE_JPEG,
            IMAGETYPE_PNG,
            IMAGETYPE_SWF,
            IMAGETYPE_PSD,
            IMAGETYPE_BMP,
            IMAGETYPE_TIFF_II,
            IMAGETYPE_TIFF_MM,
            IMAGETYPE_JPC,
            IMAGETYPE_JP2,
            IMAGETYPE_JPX,
            IMAGETYPE_JB2,
            IMAGETYPE_SWC,
            IMAGETYPE_IFF,
            IMAGETYPE_WBMP,
            IMAGETYPE_XBM,
            IMAGETYPE_ICO 
    );
    $info = getimagesize ( $image );
    $width = @$info [0];
    $height = @$info [1];
    $type = @$info [2];
    $attr = @$info [3];
    $bits = @$info ['bits'];
    $channels = @$info ['channels'];
    $mime = @$info ['mime'];

    if (! in_array ( $type, $imageTypes )) {
        return false; // Invalid Image Type ;
    }
    if ($width <= 1 && $height <= 1) {
        return false; // Invalid Image Size ;
    }

    if($bits === 1)
    {
        return false; // One Bit Image .. You don't want that  ;
    }
    return $info ;
}
person Baba    schedule 05.05.2012
comment
Да, но я не хочу перемещать загруженный файл, если я не уверен на 100%, что это изображение - person user1362916; 05.05.2012
comment
сначала вы помещаете его во временный каталог.. если это недопустимое изображение, используйте unlink, чтобы удалить его - person Baba; 05.05.2012
comment
Ааа я понимаю, что вы имеете в виду! Не думал об этом. Я попробую это прямо сейчас. - person user1362916; 05.05.2012
comment
Или вы можете использовать $_FILES['images']['type'][$key] для проверки типа MIME, чтобы убедиться, что это изображение/png, изображение/gif ... и т. д. и т. д., прежде чем вы загрузите его. - person Jamie Bicknell; 05.05.2012
comment
Это легко обмануть... getimagesize - лучший вариант, который когда-либо видел @Jamie Bicknell - person Baba; 05.05.2012
comment
@Baba Я согласен, что это можно обмануть, изменив расширение файла, в то время как getimagesize() вернет настоящий MIME. Однако, с точки зрения первичных проверок, в любом случае стоит выполнить $_FILES['images']['type'], а затем, как только он будет загружен, также проверить getimagesize(). - person Jamie Bicknell; 05.05.2012
comment
@Baba Кроме того, вы можете напрямую использовать getimagesize() для $_FILES['images']['tmp_name'] , но его использование для файла, отличного от изображения, ничего не вернет - person Jamie Bicknell; 05.05.2012
comment
вы также можете подделать заголовок содержимого изображения, а не только расширение «‰PNG IHDR%ÛVÊgAMA±üaPLTEÿÿÿUÂÓ~tRNS@æØfbKGDˆH pHYsÒÝ~ütIMEÒ9r¢€ò IDATxœcH¯¤qIEND®B», которое является поддельным изображением. - person Baba; 05.05.2012
comment
Переименование или изменение расширения файла не меняет тип MIME. Я не пробовал, но этого не должно происходить, потому что тип MIME не может быть изменен или изменен. - person SachinGutte; 05.05.2012
comment
Я уже проверяю [type] , но я также хотел убедиться, что никто не может загружать переименованные файлы. Сначала я попытался переместить его следующим образом: move_uploaded_file($_FILES['images']['tmp_name'][$key], $tmpmap.$value); print_r(getimagesize($tmpmap.$value)); , но он по-прежнему ничего не возвращает... изображение загружается - person user1362916; 05.05.2012
comment
См. обновленный ответ для поддельного изображения, которое будет показывать допустимый тип png mime. - person Baba; 05.05.2012
comment
@Baba С вашим поддельным изображением даже getimagesize() возвращает его как изображение / png. Для всех интенсивных целей это PNG, так как на сервере он будет работать как PNG. - person Jamie Bicknell; 05.05.2012
comment
@Baba: да, он изменяет тип MIME, но затем он становится нечитаемым файлом изображения с некоторыми мусорными (даже если в нем написан php-код) данными. В конечном итоге это станет изображением. С сервера он может быть доступен только как изображение. Никто не может отменить его и запустить на том же сервере. JamieBicknell: Да, это станет изображением, и его нельзя будет изменить, чтобы получить из него какие-то данные или код, которые могут причинить вред. Даже если кто-то будет следовать этому процессу, он не сможет ничего сделать, кроме как загрузить поддельное изображение с мусором в нем. - person SachinGutte; 05.05.2012
comment
Я бы обновил свой код соответствующей функцией, чтобы показать вам, как это делается... 10 минут - person Baba; 05.05.2012
comment
@phazorRise Точно, если сервер думает, что это PNG, он будет работать как PNG, поэтому код не запускается. - person Jamie Bicknell; 05.05.2012
comment
есть много способов атаковать / спамить сайт с поддельным изображением ... это просто добавление PHP в изображение .. я думаю, это будет для другой темы Hacking Site with Image : D - person Baba; 05.05.2012
comment
@ Джейми Бикнелл. Насколько интенсивны ваши цели? - person TRiG; 27.04.2017

Я хотел бы порекомендовать не доверять результатам getimagesize() при принятии решения о размещении загруженного файла в корневом каталоге вашего документа. Это связано с тем, что PHP-код, встроенный в GIF-файлы (названные вроде image.gif.php), будет идентифицирован как изображения с помощью getimagesize(), но их обслуживание будет запускать внутри них PHP-код в дополнение к отображению изображения. Здесь дополнительная информация по вопросу.

В статье, указанной выше, рекомендуется настроить отдельный контроллер, через который обслуживаются все загруженные пользователем файлы. Файлы, прочитанные с помощью readfile(), не анализируются при доступе через локальную файловую систему.

person Kaivosukeltaja    schedule 05.05.2012

Во-первых, вы можете использовать getimagesize для $_FILES['images']['tmp_name'], так что это не проблема.

Если вы хотите проверить, является ли файл изображением, попробуйте следующее:

if(isset($_POST['submit'])) {
    $check = getimagesize($_FILES['images']['tmp_name']);
    if($check !== false) {
        echo 'File is an image - ' . $check['mime'];
    }
    else {
        echo 'File is not an image';
    }
}
person Jamie Bicknell    schedule 05.05.2012
comment
Я использовал именно ваш код (в цикле foreach), но он ВСЕГДА возвращает файл, не являющийся изображением, независимо от того, является ли он действительным или нет =( - person user1362916; 05.05.2012
comment
@user1362916 user1362916 Вы точно скопировали мой код, так как у меня есть тип и я использую $_FILES['image'] вместо ваших $_FILES['images']. Я обновлю фрагмент сейчас - person Jamie Bicknell; 05.05.2012

Вы можете просто использовать $_FILES['images']['type'] . это даст вам тип загруженного файла. Затем проверьте еще раз поток октата или другой исполняемый файл. Если да, то не позволяйте этого.

person SachinGutte    schedule 05.05.2012

@user1362916 user1362916 Если вы загружаете несколько изображений с помощью HTML, возможно, вам нужно добавить еще один такой массив.

if(isset($_POST['submit'])) {
    $check = getimagesize($_FILES['images']['tmp_name'][$i]);
    if($check !== false) {
        echo 'File is an image - ' . $check['mime'];
    }
    else {
        echo 'File is not an image';
    }
}

Здесь отметьте [i], потому что это для загрузки нескольких файлов.

Ниже полный скрипт

<!DOCTYPE html>
<html>
<body>

<form action="#" method="post" enctype="multipart/form-data">
    Select image to upload:
    <input name="my_files[]" type="file" multiple="multiple" />
    <input type="submit" value="Upload Image" name="submit">
</form>


<?php

 if (isset($_FILES['my_files']))
 {
    $myFile = $_FILES['my_files'];
    $fileCount = count($myFile["name"]);


        for ($i = 0; $i <$fileCount; $i++)
         {
           $error = $myFile["error"][$i]; 

            if ($error == '4')  // error 4 is for "no file selected"
             {
               echo "no file selected";
             }
            else
             {
               if(isset($_POST['submit'])) {
                 $check = getimagesize($_FILES['my_files']['tmp_name'][$i]);
                 if($check !== false) {
                 echo 'File is an image - ' . $check['mime'];
                 }
                 else {
                 echo 'File is not an image';
                   }
                 }

             }
       }  
 }
        ?>


</body>
</html>
person shiv    schedule 24.07.2015