Загрузка изображений с помощью PHP - PullRequest
2 голосов
/ 19 июля 2010

Последние пару месяцев я создавал сайт продвижения событий на PHP и MySQL, где каждый мог зарегистрироваться и добавить подробности о своем локальном событии вместе с постером, размер которого я изменил.

В настоящее время у меня весь процесс работает нормально локально и на хостинге, но прежде чем сайт заработает, у меня есть пара вопросов о том, как я это делаю.

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

$extension = substr($filename, strpos($filename,'.'), strlen($filename)-1); 
$filetypes = array('.jpg', '.jpeg', '.gif', '.bmp', '.png', '.JPG', '.PNG', '.JPEG', '.GIF', '.BMP');
if($_FILES['image']['error'] == 4){
  $error = "No image";
  return $error; 
}
else if(($_FILES['image']['error'] == 2) || ($_FILES['image']['error'] == 1)){
  $error = "File size too big";
  return $error;
}
else if(!in_array($extension, $filetypes)){
  $error = "This isn't an image that is supported";
  return $error;
}
else if(($_FILES['image']['error'] == 7) || ($_FILES['image']['error'] == 3)){
  $error = "Error occurred. Try again";
  return $error;
}
else{
  if(($extension == '.jpg') || ($extension == '.jpeg')){
    $source = imagecreatefromjpeg($uploaded);
  }
  else if($extension == '.png'){
    $source = imagecreatefrompng($uploaded);
  }
  else{
    $source = imagecreatefromgif($uploaded);
  }
  list($width, $height) = getimagesize($uploaded);
  $ratio = $width / $height;
  $new_width = 300;
  $new_height = round(300 / $ratio); 
  $canvas = imagecreatetruecolor($new_width, $new_height);
  imagecopyresampled($canvas, $source, 0, 0, 0, 0, $new_width, $new_height, $width,       $height);
  $name = date("dmyHis").rand(0, 9);
  $path = $_SERVER[ 'DOCUMENT_ROOT' ] . '/images/uploaded/'.$name.'.jpg';
  $new_image = imagejpeg($canvas, $path,  100);
  $poster['name'] = $name.'.jpg';
  $poster['width'] = $new_width;
  $poster['height'] = $new_height;
  return $name.'.jpg';
}

Насколько я понимаю, есть пара ошибок, о которых я знаю, или о которых я не до конца изучил, например, некоторые изображения выдают ошибку из imagecreate от чего бы то ни было, и если имя изображения имеет «.» в нем также будет выдано сообщение об ошибке.

Как только процесс будет завершен, я сохраню имя изображения в поле 'poster' в MySQL, которое будет использоваться для получения правильного изображения из папки при просмотре.

Что я действительно хотел знать, так это то, есть ли другие проблемы, с которыми я могу столкнуться при загрузке изображений?

  • Я ожидаю достаточного количества трафика, поэтому этот код будет работать нормально при интенсивном использовании?
  • Есть ли еще какие-нибудь подводные камни или вещи, на которые я должен обратить внимание?
  • Использую ли я лучший метод для работы?
  • В настоящее время мой размер файла составляет 2 МБ, это слишком много?
  • Даже если пользователь загрузит что-то более 2 МБ, скрипт все равно будет работать, и я предполагаю, что файл будет загружен на сервер для разборки имен, сравнения размеров файлов и т. Д., Как это повлияет на использование моей пропускной способности?
  • Как долго оригинальные файлы остаются на сервере?

Если у кого-то есть хорошее прочтение на эту тему, я был бы очень признателен!

Спасибо.

редактировать: форматирование.

edit 2: Я не давал понять, что такое исходные файлы. Я имею в виду исходные файлы, для доступа к которым я использую переменную $ _FILES. Скажем, это 1,9 МБ, будет ли изображение на сервере в 1,9 МБ сидеть на сервере все время, пока я возился с расширениями и так далее? Должен ли я очистить это после создания нового изображения?

Ответы [ 4 ]

4 голосов
/ 19 июля 2010

Рич, я сделал подобное, в первую очередь с iMagick.GD функционально похож, поэтому я не ожидаю никаких проблем.Мой сайт обрабатывал сотни изображений в неделю без проблем и надежно обслуживал до ~ 1 тыс. В неделю.Я выполнил всю обработку на бэкэнде, так как кажется, что вы делаете в этом примере, поэтому мало кто беспокоится о тяжелом входящем трафике (например, при получении на DIGG), который сокрушит ваш сервер.

Самая большая проблема, которую вы делаетеоткрывая себя уязвимостям, позволяя загружать файлы любого рода.Вы, наверное, слышали, как парни из отдела ИТ-безопасности говорят, что единственный способ защитить себя от хакеров - это выйти из Интернета ... это так.Я бы не жил в полном страхе, потому что похоже, что вы предприняли справедливые шаги для аудита типов и размеров файлов.Дополнительным соображением является просмотр разрешений на вашем сервере - откройте каталог с возможностью записи только в пользовательский агент сервера и заблокируйте просмотр в каталоге для дополнительной безопасности.Если вы хотите быть в безопасности вдвойне, напишите в другую учетную запись (если она у вас есть), чтобы ограничить доступ к вашему коду.Это не обязательно, но это хороший дополнительный шаг, если у вас есть проблемы.Наконец, поместите ваш загрузчик за простую систему паролей с капчей, чтобы заблокировать автоматические эксплойты .... предоставьте пользователям бесплатный доступ с простым шагом регистрации.Это небольшая проблема с пользовательским интерфейсом, но она может иметь решающее значение с точки зрения безопасности.

Я мог бы рассмотреть возможность остановки процесса, если размер пользовательского файла превышает 2 МБ.Это всего лишь я.Вы не хотели бы, чтобы система зависала и сгорала, если какой-либо пользователь пытается принудительно создать на вашем сервере плохой файл с расширением .jpg.Пропускная способность, вероятно, будет проблемой только в том случае, если вы размещаете хостинг самостоятельно или платите в мегаполисе - конечно, это увеличит пропускную способность, но даже при сотне загрузок в день вы, скорее всего, не будете продвигатьстандартный сервер за его пределами, если соответствующий трафик, посещающий сайт, исчисляется тысячами.Большинство хостов позволит вам отслеживать нагрузку на сервер.Лично мне не повезло с дешевкой лично с HostGator

Файлы остаются на сервере неограниченное время, при условии, что с вашей учетной записью ничего плохого не случится и вы оплатите свои счета.По этой причине не забудьте отделить папку для загрузки от папки с любым другим контентом - это станет кошмаром после загрузки нескольких сотен файлов.Резервное копирование часто, просто чтобы быть в безопасности.

4 голосов
/ 19 июля 2010

Прежде всего, молодец, похоже, что вы вложили в него много работы.

Есть несколько вещей, которые могут немного облегчить вам жизнь. Приведенный ниже список не разочаровывает вас, а научит вас!

Вы берете все из первого . как расширение, как оно есть сейчас. Поэтому ошибка, когда кто-то вставляет . в имя файла. Это можно сделать лучше.

$extension = '';
if ( preg_match("/\\.([a-z]+)$/i",$filename,$match) )
{
    $extension = strtolower($match[1]);
}

даст вам расширение, в нижнем регистре, без точки, что означает, что вам не нужно проверять JPG, а также JPG и т. Д. (На самом деле, при загрузке браузер сообщит вам тип файла, независимо от того, расширение, но давайте пока пропустим это - тест на расширение подойдет)

Чтение изображения с if JPG else if PNG else GIF не совсем чистое: вы должны также проверить gif и только , затем перейти в категорию "else" и просто выдать ошибку. (то есть вы можете отказаться от чека, который вы делали раньше!)

Когда вы говорите $source = imagecreatefrom...($filename), вам лучше добавить к нему @, чтобы избежать предупреждения о поврежденных изображениях (обычно не используйте @, но в этом случае вы не можете знать, повреждено ли изображение). Затем всегда проверяйте возвращаемые значения (ВСЕГДА это делайте), например

$source = @imagecreatefrompng($filename);
if ( !$source ) return "Error parsing image";

Изображение теперь загружено, поэтому размер, если известен; Вам не нужно запрашивать файл снова. Вместо getimagesize() вы можете использовать imagesx($source) и imagesy($source)

Этого достаточно, чтобы исправить, я думаю. ; -)

edit: Крошечная проблема, кстати, с rand (0,9) в имени файла, означая, что велика вероятность того, что вы перепутаете файлы, если более чем один клиент загружает в течение одной секунды. (при 11 загрузках в секунду у вас наверняка есть проблема)

3 голосов
/ 19 июля 2010

Расширение, отправленное пользователем в имени файла, нельзя доверять или полагаться на него.Некоторые пользователи думают, что изменение «jpg» на «gif» делает его gif и т. Д.

Я предлагаю использовать getimagesize FIRST, чтобы проверить, является ли это изображение правильным, и получить тип exif.Не беспокойтесь об извлечении расширения, так как оно бесполезно.Тип exif будет в 2 массива, возвращаемого getimagesize.

Кроме того, изображения CYMK являются проблемой.Некоторым удается загрузить jpegs CYMK.Проверка каналов обнаружит эти изображения.Это должно быть 3, RGB.

$image_info=getimagesize($your_image_file);
if($image_info['channels']==4)
  {
  //it's invalid - cymk
  //browsers cannot display these images. It might be possible to convert them to RGB explicitly...
  }

$real_exif=$image_info[2];
if($real_exif>0 && $real_exif<4){
 //it is a png, gif or jpg
 }

Тип exif возвращается как константа, такая как IMAGETYPE_GIF, где численно, 1 - это gif, 2 - jpg и 3 - png.Вы можете использовать image_type_to_extension для преобразования в расширение текстового файла.

Теперь иногда я обнаружил, что getimagesize не смог найти тип exif для изображений, которые были действительны, и мог работать с imagemagick / GD,Не удалось вернуть EXIF ​​для них, поэтому они были неправильно отклонены.Я придумал этот мерзкий взлом, чтобы, по крайней мере, определить тип и попробовать ...

  $handle=@fopen($temp_name,'r');
  if($handle)
    {
    $chars=fread($handle,24);
    if(stripos($chars,'jfif')!==false)
        {$type=2;} // found a jpg
    elseif(stripos($chars,'png')!==false)
      {$type=3;} // found a png
    elseif(stripos($chars,'gif')!==false)
      {$type=1;} // found a gif
    else
      {
      //file type could not be determined
      }
    }
3 голосов
/ 19 июля 2010

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

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

Я использовал функцию CHMOD для изменения разрешений после загрузки, а затем он работал надежно.* Вот статья об этом (не моя статья, но она была полезна): http://drupal.org/node/34028

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...