За последние 24 часа нас посетил 21421 программист и 1381 робот. Сейчас ищут 644 программиста ...

Проверка файла-изображения при загрузке

Тема в разделе "Решения, алгоритмы", создана пользователем Hight, 5 мар 2008.

  1. Hight

    Hight Старожил
    Команда форума Модератор

    С нами с:
    5 мар 2006
    Сообщения:
    7.153
    Симпатии:
    0
    Адрес:
    из злой параллельной вселенной
    Как определить при загрузке файла на сервер, что это изображение?!

    Ответ:
    PHP:
    1. <?php
    2.  
    3. # Функция для определения параметров изображения
    4. # Возвращает массив параметров если файл изображение и FALSE при ошибке
    5.  
    6. function get_image_info($file = NULL)
    7. {
    8.     if(!is_file($file)) return false;
    9.  
    10.     if(!$data = getimagesize($file) or !$filesize = filesize($file)) return false;
    11.  
    12.     $extensions = array(1 => 'gif',     2 => 'jpg',
    13.                         3 => 'png',     4 => 'swf',
    14.                         5 => 'psd',     6 => 'bmp',
    15.                         7 => 'tiff',    8 => 'tiff',
    16.                         9 => 'jpc',     10 => 'jp2',
    17.                         11 => 'jpx',    12 => 'jb2',
    18.                         13 => 'swc',    14 => 'iff',
    19.                         15 => 'wbmp',   16 => 'xbmp');
    20.  
    21.     $result = array('width'     =>  $data[0],
    22.                     'height'    =>  $data[1],
    23.                     'extension' =>  $extensions[$data[2]],
    24.                     'size'      =>  $filesize,
    25.                     'mime'      =>  $data['mime']);
    26.  
    27.     return $result;
    28. }
    29.  
    30.  
    31.  
    32. # Пример (отрывок) проверки файла при загрузке
    33.  
    34. $valid_extensions = array('gif', 'jpg', 'png');
    35.  
    36. if(!$image_info = get_image_info($_FILES['upload_image']['tmp_name']) or !in_array($image_info['extension'], $valid_extensions))
    37. {
    38.     die('Ошибка');
    39. }
    40. else
    41. {
    42.     $upload_file_name = uniqid(NULL, true).'.'.$image_info['extension'];
    43.  
    44.     if(!@move_uploaded_file($_FILES['upload_image']['tmp_name'], 'upload_folder/'.$upload_file_name)) die('Ошибка');
    45. }
    46.  
    Комментарии?
     
  2. Sergey89

    Sergey89 Активный пользователь

    С нами с:
    4 янв 2007
    Сообщения:
    4.796
    Симпатии:
    0
    Проверку по сигнатуре зафигачить:
    PHP:
    1. <?php
    2. function get_image_type($file) {
    3.     if (!$f = fopen($file, 'rb')) {
    4.         return false;
    5.     }
    6.  
    7.     $data = fread($f, 8);
    8.     fclose($f);
    9.  
    10.     if (
    11.         @array_pop(unpack('H12', $data)) == '474946383961' ||
    12.         @array_pop(unpack('H12', $data)) == '474946383761'
    13.     ) {
    14.         return 'GIF';
    15.     } else if (
    16.         @array_pop(unpack('H4', $data)) == 'ffd8'
    17.     ) {
    18.         return 'JPEG';
    19.     } else if (
    20.         @array_pop(unpack('H16', $data)) == '89504e470d0a1a0a'
    21.     ) {
    22.         return 'PNG';
    23.     } else if (
    24.         @array_pop(unpack('H4', $data)) == '424d'
    25.     ) {
    26.         return 'BMP';
    27.     }
    28.  
    29.     return false;
    30. }
    31. ?>
     
  3. Hight

    Hight Старожил
    Команда форума Модератор

    С нами с:
    5 мар 2006
    Сообщения:
    7.153
    Симпатии:
    0
    Адрес:
    из злой параллельной вселенной
    Sergey89
    Мой вариант функциональнее и универсальнее 8)
     
  4. Sergey89

    Sergey89 Активный пользователь

    С нами с:
    4 янв 2007
    Сообщения:
    4.796
    Симпатии:
    0
    Не спорю. Предлагаю совместить :) Сначала проверка расширения, потом сигнатуры, а уже потом попытка узнать размер.
     
  5. lexa

    lexa Активный пользователь

    С нами с:
    22 июл 2007
    Сообщения:
    1.746
    Симпатии:
    0
    Адрес:
    Санкт-Петербург
    Hight, твоя проверка пропустит некартинки (любая проверка по расширению/мим типу их пропустит), а версия Sergey89 - нет. По идеи.
     
  6. Hight

    Hight Старожил
    Команда форума Модератор

    С нами с:
    5 мар 2006
    Сообщения:
    7.153
    Симпатии:
    0
    Адрес:
    из злой параллельной вселенной
    RTFM. Ничего она не пропустит. Внимательнее код функции "get_image_info" изучай и почитай мануал по функции getimagesize.
    http://ru2.php.net/manual/ru/function.getimagesize.php
     
  7. lexa

    lexa Активный пользователь

    С нами с:
    22 июл 2007
    Сообщения:
    1.746
    Симпатии:
    0
    Адрес:
    Санкт-Петербург
    Сам RTFM, умник. GIF89ad в начала файла сунь и пройдёт как gif.
     
  8. Hight

    Hight Старожил
    Команда форума Модератор

    С нами с:
    5 мар 2006
    Сообщения:
    7.153
    Симпатии:
    0
    Адрес:
    из злой параллельной вселенной
    Тебе надо ты и суй, алёшка блин. Пока пример обхода моей функции не покажешь будешь RTFM.
     
  9. lexa

    lexa Активный пользователь

    С нами с:
    22 июл 2007
    Сообщения:
    1.746
    Симпатии:
    0
    Адрес:
    Санкт-Петербург
    test.gif:
    Код (Text):
    1. GIF89ad
    2. <?
    3. echo 'PHP';
    4. ?>
    Вся твоя проверка - псевдо-полезная херня. Набор лишних букв.

    Кстати, почитай про getimagesize() и массив $_FILES глазами, а не тем, чем читал до этого.
     
  10. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    Hight
    lexa

    девочки. завязываем...
     
  11. Hight

    Hight Старожил
    Команда форума Модератор

    С нами с:
    5 мар 2006
    Сообщения:
    7.153
    Симпатии:
    0
    Адрес:
    из злой параллельной вселенной
    lexa
    Давай разбираться

    То-есть, если мы подсунем этой функции не изображение, то получим false, а если изображение, то набор его параметров. Так ведь?! Так. Моя функция 'get_image_info' - это расширение 'getimagesize'. Возвращает массив параметров: 'width', 'height', 'extension', 'size' ,'mime' на основе данных полученных от 'getimagesize' и false в случае если файл не изображение. При этом отличие моей 'get_image_info' от 'getimagesize' состоит в том, что моя функция возвращает расширение файла в виде строки, а не числового значения и возвращает размер файла изображения. При этом хочу заметить, что расширение файла изображения определяется на основании данных полученных от 'getimagesize', а не всякими там строковыми функциями и регулярными выражениями. По-этому всё отлично работает и функция отлично справляется со своей задачей.
     
  12. Hight

    Hight Старожил
    Команда форума Модератор

    С нами с:
    5 мар 2006
    Сообщения:
    7.153
    Симпатии:
    0
    Адрес:
    из злой параллельной вселенной
    прикол
     
  13. Hight

    Hight Старожил
    Команда форума Модератор

    С нами с:
    5 мар 2006
    Сообщения:
    7.153
    Симпатии:
    0
    Адрес:
    из злой параллельной вселенной
    Подумаю вечерком
     
  14. lexa

    lexa Активный пользователь

    С нами с:
    22 июл 2007
    Сообщения:
    1.746
    Симпатии:
    0
    Адрес:
    Санкт-Петербург
    Hight, я только показал, как может пройти некартинка при всей твоей лишней проверке. Массив $_FILES содержит и мим-тип, и размер, а простым движением можно вынуть расширение из имени файла и будет так же хорошо работать. getimagesize() нужна только для получения ширины и высоты (ну и как формальная проверка на "картинкость"). Все остальные манипуляции - излишни. Как например функция filesize().

    В идеале, у тега form есть атрибут access (кажется) в котором через запятую указываются доступные для загрузки типы файлов: image/*, text/plain и т.д.

    Вообще не понятно с чего ты так неадекватно среагировал.
     
  15. antonn

    antonn Активный пользователь

    С нами с:
    10 июн 2007
    Сообщения:
    2.996
    Симпатии:
    0
    тег form находится далеко у клиента, а значит рассматриваться в контексте безопасности не может.
     
  16. Hight

    Hight Старожил
    Команда форума Модератор

    С нами с:
    5 мар 2006
    Сообщения:
    7.153
    Симпатии:
    0
    Адрес:
    из злой параллельной вселенной
    Прости старик, нервный я стал, совсем плохой.
     
  17. ONK

    ONK Активный пользователь

    С нами с:
    4 фев 2006
    Сообщения:
    281
    Симпатии:
    0
    Адрес:
    СПб
    Гарантировать, что в файле нет ничего кроме картинки можно только после удачного ресайза (например 1 в 1), и только для результатов этого ресайза.
     
  18. Hight

    Hight Старожил
    Команда форума Модератор

    С нами с:
    5 мар 2006
    Сообщения:
    7.153
    Симпатии:
    0
    Адрес:
    из злой параллельной вселенной
    Тогда вот ресайзилка:
    PHP:
    1. <?php
    2. function image_resize($img_file, $target_file, $width, $height)
    3. {
    4.     if(!file_exists($img_file)) return false;
    5.  
    6.     if(!$source_im_info = @getimagesize($img_file)) return false;
    7.  
    8.     $valid_im_types = array(1 => 'gif', 2 => 'jpeg', 3 => 'png');
    9.  
    10.     if(!array_key_exists($source_im_info[2], $valid_im_types)) return false;
    11.  
    12.     $img_open_func = 'imagecreatefrom'.$valid_im_types[$source_im_info[2]];
    13.  
    14.     $source_im = $img_open_func($img_file);
    15.  
    16.     $result_im = imagecreatetruecolor($width, $height);
    17.  
    18.     if(!@imagecopyresampled($result_im, $source_im, 0, 0, 0, 0, $width, $height, $source_im_info[0], $source_im_info[1])) return false;
    19.  
    20.     $img_close_func = 'image'.$valid_im_types[$source_im_info[2]];
    21.  
    22.     if(!$img_close_func($result_im, $target_file)) return false;
    23.  
    24.     imagedestroy($source_im);
    25.  
    26.     imagedestroy($result_im);
    27.  
    28.     return true;
    29. }
     
  19. vasa_c

    vasa_c Активный пользователь

    С нами с:
    22 мар 2006
    Сообщения:
    1.760
    Симпатии:
    0
    Адрес:
    гор.Ленинград
    Вопрос, зачем проверять? Если для того, чтобы не грузили на сервер запускаемые сценарии, то здесь хватит правильного расширения и вменяемых настроек сервера.

    Кстати, можно создать корректное изображение, которое в то же время будет исполняемым сценарием. В bmp это вообще без проблем.
     
  20. antonn

    antonn Активный пользователь

    С нами с:
    10 июн 2007
    Сообщения:
    2.996
    Симпатии:
    0
    можно пример?
     
  21. vasa_c

    vasa_c Активный пользователь

    С нами с:
    22 мар 2006
    Сообщения:
    1.760
    Симпатии:
    0
    Адрес:
    гор.Ленинград
    В bmp после заголовка (и, возможно, палитры) тупо идут коды точек.
    Для изображения 100x100x256 цветов - 10 000 байт, которые соответствуют точкам, никаких ограничений на последовательность нет.
    В эту часть вполне можно вставить теги <? ?> и написать внутри всё что угодно.
    В других форматах посложнее, но думаю тоже лазейки найдутся.
     
  22. Hight

    Hight Старожил
    Команда форума Модератор

    С нами с:
    5 мар 2006
    Сообщения:
    7.153
    Симпатии:
    0
    Адрес:
    из злой параллельной вселенной
    Чтобы мусор не грузить и отслеживать потенциальных хацкеров.
     
  23. Anonymous

    Anonymous Guest

    валидные изображения == 95% мусора )
     
  24. Hight

    Hight Старожил
    Команда форума Модератор

    С нами с:
    5 мар 2006
    Сообщения:
    7.153
    Симпатии:
    0
    Адрес:
    из злой параллельной вселенной
    да не об этом речь ;)
     
  25. antonn

    antonn Активный пользователь

    С нами с:
    10 июн 2007
    Сообщения:
    2.996
    Симпатии:
    0
    vasa_c
    и смысл? я могу отстенографировать в любой файл что угодно.
    а 31 байт заголовка не помешает выдать интепритатору ексепшн? он не выполнит ведь его