Безопасная загрузка файлов на сервер php. Загрузка файлов с помощью PHP. Обычная загрузка файла

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

Давайте напомню код, который мы вчера рассматривали:

$uploadfile = "images/".$_FILES["somename"]["name"];
move_uploaded_file($_FILES["somename"]["tmp_name"], $uploadfile);
?>

Фактически, на данный момент может быть загружено абсолютно всё, что угодно: любые исполняемые файлы, скрипты, HTML-страницы и другие весьма опасные вещи. Поэтому обязательно надо проверять загружаемые файлы очень тщательно. И сейчас мы с Вами займёмся их тщательной проверкой.

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

  1. Тип - только jpg (jpeg ).
  2. Размер - менее 100 КБ .
" в соответствии с этими требованиями:

$blacklist = array(".php", ".phtml", ".php3", ".php4", ".html", ".htm");
foreach ($blacklist as $item)
if(preg_match("/$item\$/i", $_FILES["somename"]["name"])) exit;
$type = $_FILES["somename"]["type"];
$size = $_FILES["somename"]["size"];
if (($type != "image/jpg") && ($type != "image/jpeg")) exit;
if ($size > 102400) exit;
$uploadfile = "images/".$_FILES["somename"]["name"];
move_uploaded_file($_FILES["somename"]["tmp_name"], $uploadfile);
?>

Теперь давайте подробно поясню, что здесь происходит. Первым делом мы проверяем на расширение загружаемого файла . Если оно представляет собой PHP-скрипт , то мы такой файл просто не пропускаем. Дальше мы получаем MIME-type и размер. Проверяем их на удовлетворение нашим условиям. Если всё хорошо, то мы загружаем файл.

Вы, наверное, можете спросить: "А зачем надо проверять и расширение, и MIME-type? ". Тут очень важно понимать, что это далеко не одно и то же. Если злоумышленник попытается отправить PHP-файл через браузер , то и одной проверки MIME-type хватит, чтобы его попытка провалилась. А вот если он напишет какой-нибудь скрипт, который будет формировать запрос и отсылать вредосный файл, то этого не хватит. Почему? А потому, что MIME-type задаётся клиентом, а не сервером! И фактически, злоумышленник может поставить любой MIME-type (и картинки тоже), но при этом отсылать PHP-скрипт . И вот именно такую хитрую попытку мы и ломаем, проверяя на расширение файла.

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

В той статье я лишь раскрыл сам процесс загрузки и не касался вопросов безопасности.

Часто загрузка файлов без обеспечения надлежащего контроля безопасности приводит к образованию уязвимостей, которые, как показывает практика, стали настоящей проблемой в веб-приложениях на PHP .

Если Вы не обеспечите необходимый уровень безопасности, то злоумышленник сможет закачать произвольный файл на сервер , например, php-скрипт , при помощи которого он сможет просмотреть любой файл на сервере или что еще хуже выполнить произвольный код!

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

Итак, приступим. Первое что приходит в голову каждому разработчику это проверять Content-Type файлов. Другими словами — разрешить загрузку файлов строго определенного типа. Давайте взглянем на код:

Если обычный пользователь попытается загрузить любой другой файл, кроме gif-картинки, то ему будет выдано предупреждение!Но злоумышленник не будет использовать веб-форму на Вашем сайте.

Он может написать небольшой Perl-скрипт(возможно на любом языке) , который будет эмулировать действия пользователя по загрузке файлов , дабы изменить отправляемые данные на свое усмотрение.Так как проверяемый MIME-тип приходит вместе с запросом, то ничего не мешает злоумышленнику установить его в «image/gif», поскольку с помощью эмуляции клиента он полностью управляет запросом, который посылает.

Если вы загружаете только изображения,то не стоит доверять заголовку Content-Type, а лучше проверить фактическое содержание загруженного файла, чтобы удостовериться что это действительно изображение. Для этого в РНР очень часто используют функцию getimagesize() .

Функция getimagesize() определяет размер изображения GIF, JPG, PNG, SWF, PSD, TIFF или BMP и возвращает размеры, тип файла и высоту/ширину текстовой строки, используемой внутри нормального HTML-тэга IMG.

Давайте посмотрим, как можно использовать эту функцию в нашем скрипте:

Можно подумать, что теперь мы можем пребывать в уверенности, что будут загружаться только файлы GIF или JPEG. К сожалению, это не так. Файл может быть действительно в формате GIF или JPEG, и в то же время PHP-скриптом. Большинство форматов изображения позволяет внести в изображение текстовые метаданные. Возможно создать совершенно корректное изображение, которое содержит некоторый код PHP в этих метаданных. Когда getimagesize() смотрит на файл, он воспримет это как корректный GIF или JPEG. Когда транслятор PHP смотрит на файл, он видит выполнимый код PHP в некотором двоичном «мусоре», который будет игнорирован.

Вы наверное спросите, а почему бы не проверять просто расширение файла? Если мы не позволим загружать файлы *.php , то сервер никогда не сможет выполнить этот файл как скрипт . Давайте рассмотрим и этот подход.

Вы можете составить белый список расширений и проверять имя загружаемого файла на соответствие белому списку.

Выражение!preg_match ("/$item\$/i", $_FILES["uploadFile"]["name"]) проверяет соответствие имени файла, определенному пользователем в массиве белого списка. Модификатор «i» говорит, что наше выражение регистронезависимое. Если расширение файла соответствует одному из пунктов в белом списке, файл будет загружен, иначе

1 53

GreyCat

1 ответ:

модель процессора, описанная в руководстве по процессору Intel/AMD, является довольно несовершенной моделью для real двигатель исполнения современного ядра. В частности, понятие регистров процессора не соответствует действительности, нет такого понятия, как регистр EAX или RAX.

одной из основных задач декодера инструкций является преобразование устаревших инструкций x86 / x64 в micro-ops , инструкции RISC-подобного процессора. Небольшие инструкции, которые легки для того чтобы исполнить одновременно и мочь принять преимущество множественных подблоков исполнения. Позволяет одновременно выполнять до 6 инструкций.

чтобы сделать эту работу, понятие регистров процессора также виртуализируется. Декодер команд выделяет регистр из большого банка регистров. Когда инструкция пенсии , значение этого динамически выделенного регистра записывается обратно в любой регистр, который в настоящее время содержит значение ну, скажем, РАКС.

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

такая же проблема с тем, как вы как его на работу. Большая проблема, она требует, чтобы два значения регистра были объединены когда инструкция будет удалена. Создание зависимости данных, которая будет засорять ядро. Заставляя верхний 32-бит равняться 0, эта зависимость мгновенно исчезает, больше не нужно сливаться. Скорость выполнения деформации 9.

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

Первая и самая очевидная - это имена файлов . Их обязательно нужно проверять на спецсимволы, так как пользователь может подделать HTTP-запрос, в результате чего загружаемый файл будет иметь имя, например, ../index.php. и при попытке его сохранения затрет корневой индекс. Кроме того, название может содержать русские буквы в кодировке windows-1251 или koi-8, которые некорректно сохранятся в файловой системе. Вывод: нужно сохранять файл не под тем именем, под которым его загрузил пользователь, а под случайным, например MD5-хешем от имени файла, времени загрузки и IP пользователя. Имя же этого файла где-нибудь в базе, а потом отдавать файл скритом, который предварительно будет выдавать заголовок Content-disposition: attachment; filename="имя_файла".

Вторая проблема - нельзя доверять расширению или MIME-типу , их при желании можно подделать. Поэтому если тип файла важен, его нужно проверять на соответствие формату уже на сервере (для картинок хорошо подойдет функция getimagesize из модуля GD, для других типов - чтение заголовков) и отвергать те файлы, у которых формат не соответствует.

И наконец, третья, самая главная проблема - . Тут есть несколько решений. Первое - если предполагается загрузка только определенных видов файлов (например, автар может быть только картинкой в PNG, JPG, GIF) и отвергать все, что не подходит. Но иногда требуется разрешить загружать файлы любых типов. Тогда возникает второй вариант: проверять расширение загруженного файла и, если оно небезопасно, переименовывать его (например, замена расширения с.php на.phps приведет к тому, что скрипт не будет выполняться, а будет показан его код с подсветкой синтаксиса). Главный недостаток этого решения - может оказаться, что на каком-то сервере настроено исполнение скриптов с необычном расширением, например, .php3, и отфильтровать это не получится. И наконец, третий вариант - это отключить обработку скриптов, например через.htaccess:

RemoveHandler .phtml .php .php3 .php4 .php5 .php6 .phps .cgi .exe .pl .asp .aspx .shtml .shtm .fcgi .fpl .jsp .htm .html .wml
AddType application/x-httpd-php-source .phtml .php .php3 .php4 .php5 .php6 .phps .cgi .exe .pl .asp .aspx .shtml .shtm .fcgi .fpl .jsp

Однако следует учесть, что файл.htaccess влияет только на Apache (да и то его использование нужно включить в настройках), а на других серверах он будет проигнорирован. (Особенно важно это для скриптов, которые выкладываются в публичный доступ: рано или поздно найдется пользователь с каким-нибудь IIS, который не примет должных мер, поэтому лучше сочетать этот способ с предыдущим.)

И последнее: после прочтения этого текста может возникнуть желание хранить пользовательские файлы вообще в базе данных. Не стоит этого делать: хотя это и кажется простым решением, но следует учитывать, что современные поисковики индексируют не только обычные HTML-страницы, но и файлы других типов. И в момент прохождения поискового робота нагрузка на SQL-сервер будет резко возрастать из-за необходимости отдать сразу большой объем данных, что будет приводить к проблемам в работе сайта.

В этой статье подробно разберём механизм загрузки изображений на сервер с помощью PHP не прибегая к сторонним компонентам и фреймворкам. Научимся безопасно загружать изображения не только с локальной машины пользователя, но и удалённые файлы по ссылке. Все примеры кода я буду писать в процедурном стиле, дабы вы быстрее могли читать код, а не перескакивать с одного метода на другой. Руководство полностью авторское и не претендует на какую-либо академичность изложения .

§1. Общие принципы

Всю последовательность загрузки изображения на сервер можно отобразить следующим образом: настройка php.ini получение файла проверка безопасности валидация данных сохранение на диск . Процесс загрузки картинки с компьютера пользователя или по URL ничем не отличаются, за исключением способа получения изображения и его сохранения. Общая схема загрузки картинки на сервер выглядит следующим образом:

Для валидации картинки по URL мы будем использовать функцию getimagesizefromstring() , т. к. cURL скачает её в переменную для дальнейших манипуляций.

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

§2. Правила безопасности

Безопасность загрузки изображений сводится к недопущению попадания на сервер чужеродного кода и его выполнения. На практике загрузка картинок наиболее уязвимое место в PHP-приложениях: попадание shell-скриптов , запись вредоносного кода в бинарные файлы , подмена EXIF-данных . Для того, чтобы избежать большинства методов взлома нужно придерживаться следующих правил:

а не доверять данным из $_FILES;
б не проверять MIME-тип картинки из функции getimagesize();
в загружаемому файлу генерировать новое имя и расширение;
г запретить выполнение PHP-скриптов в папке с картинками;
д не вставлять пользовательские данные через require и include;
е для $_FILES использовать is_uploaded_file() и move_uploaded_file().

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

§3. Конфигурация php.ini

PHP позволяет внести определённые конфигурационные значения в процесс загрузки любых файлов. Для этого необходимо в файле php.ini найти блоки «Resource Limits », «Data Handling » и «File Uploads », а затем отредактировать, по необходимости, следующие значения:

; Максимальное время выполнения скрипта в секундах max_execution_time = 60 ; Максимальное потребление памяти одним скриптом memory_limit = 64M ; Максимально допустимый размер данных отправляемых методом POST post_max_size = 5M ; Разрешение на загрузку файлов file_uploads = On ; Папка для хранения файлов во время загрузки upload_tmp_dir = home/user/temp ; Максимальный размер загружаемого файла upload_max_filesize = 5M ; Максимально разрешённое количество одновременно загружаемых файлов max_file_uploads = 10

Исходя из указанных значений, пользователь не сможет за один раз загрузить больше десяти файлов, причём каждый файл не должен превышать 5 Мбайт. Параметры из блока «Resource Limits » больше нужны для загрузки удалённого файла, т. к. с помощью cURL мы будем скачивать содержимое в переменную и проверять её по нужным нам критериям, а для этого необходимо дополнительное время и память.

Конфигурационный файл php.ini всегда необходимо настраивать согласно бизнес-логики разрабатываемого веб-приложения. Например, мы планируем загружать не более десяти файлов до 5 Мбайт, а это значит нам понадобиться ~50 Мбайт памяти. Кроме того, нам нужно знать максимальное время загрузки одного файла с локальной машины и по ссылке, дабы установить достаточное время выполнения скрипта в max_execution_time и не пугать пользователей ошибками.

§4. Загрузка картинок из формы

Сейчас мы не будем рассматривать загрузку нескольких файлов на сервер, а разберём лишь саму механику загрузки на примере одного файла. Итак, для загрузки картинки с компьютера пользователя необходимо с помощью HTML-формы отправить файл PHP-скрипту методом POST и указать способ кодирования данных enctype="multipart/form-data" (в данном случае данные не кодируются и это значение применяется только для отправки бинарных файлов). С формой ниже мы будем работать дальше:

Для поля выбора файла мы используем имя name="upload" в нашей HTML-форме, хотя оно может быть любым. После отправки файла PHP-скрипту file-handler.php его можно перехватить с помощью суперглобальной переменной $_FILES["upload"] с таким же именем, которая в массиве содержит информацию о файле:

Array ( => picture.jpg // оригинальное имя файла => image/jpeg // MIME-тип файла => home\user\temp\phpD07E.tmp // бинарный файл => 0 // код ошибки => 17170 // размер файла в байтах )

Не всем данным из $_FILES можно доверять: MIME-тип и размер файла можно подделать, т. к. они формируются из HTTP-ответа, а расширению в имени файла не стоит доверять в силу того, что за ним может скрываться совершенно другой файл. Тем не менее, дальше нам нужно проверить корректно ли загрузился наш файл и загрузился ли он вообще. Для этого необходимо проверить ошибки в $_FILES["upload"]["error"] и удостовериться, что файл загружен методом POST с помощью функции is_uploaded_file() . Если что-то идёт не по плану, значит выводим ошибку на экран.

// Перезапишем переменные для удобства $filePath = $_FILES ["upload" ]["tmp_name" ]; $errorCode = $_FILES ["upload" ]["error" ]; // Проверим на ошибки if ($errorCode !== UPLOAD_ERR_OK || ! is_uploaded_file ($filePath )) { // Массив с названиями ошибок $errorMessages = [ UPLOAD_ERR_INI_SIZE => "Размер файла превысил значение upload_max_filesize в конфигурации PHP." , UPLOAD_ERR_FORM_SIZE => "Размер загружаемого файла превысил значение MAX_FILE_SIZE в HTML-форме." , UPLOAD_ERR_PARTIAL => "Загружаемый файл был получен только частично." , UPLOAD_ERR_NO_FILE => "Файл не был загружен." , UPLOAD_ERR_NO_TMP_DIR => "Отсутствует временная папка." , UPLOAD_ERR_CANT_WRITE => "Не удалось записать файл на диск." , UPLOAD_ERR_EXTENSION => "PHP-расширение остановило загрузку файла." , ]; // Зададим неизвестную ошибку $unknownMessage = "При загрузке файла произошла неизвестная ошибка." ; // Если в массиве нет кода ошибки, скажем, что ошибка неизвестна $outputMessage = isset ($errorMessages [$errorCode ]) ? $errorMessages [$errorCode ] : $unknownMessage ; // Выведем название ошибки die ($outputMessage ); }

Для того, чтобы злоумышленник не загрузил вредоносный код встроенный в изображение, нельзя доверять функции getimagesize() , которая также возвращает MIME-тип. Функция ожидает, что первый аргумент является ссылкой на корректный файл изображения . Определить настоящий MIME-тип картинки можно через расширение FileInfo . Код ниже проверит наличие ключевого слова image в типе нашего загружаемого файла и если его не окажется, выдаст ошибку:

// Создадим ресурс FileInfo $fi = finfo_open (FILEINFO_MIME_TYPE); // Получим MIME-тип $mime = (string) finfo_file ($fi , $filePath ); );

На данном этапе мы уже можем загружать абсолютно любые картинки на наш сервер, прошедшие проверку на MIME-тип, но для загрузки изображений по определённым характеристикам нам необходимо валидировать их с помощью функции getimagesize() , которой скормим сам бинарный файл $_FILES["upload"]["tmp_name"] . В результате мы получим массив максимум из 7 элементов :

Array ( => 1280 // ширина => 768 // высота => 2 // тип => width="1280" height="768" // аттрибуты для HTML => 8 // глубина цвета => 3 // цветовая модель => image/jpeg // MIME-тип )

Для дальнейшей валидации изображения и работы над ним нам необходиом знать только 3 значения: ширину , высоту и размер файла (для вычисления размера применим функцию filesize() для бинарного файла из временной папки).

// Результат функции запишем в переменную $image = getimagesize ($filePath ); $limitBytes = 1024 * 1024 * 5 ; $limitWidth = 1280 ; $limitHeight = 768 ; // Проверим нужные параметры if (filesize ($filePath ) > $limitBytes ) die ("Размер изображения не должен превышать 5 Мбайт." ); if ($image > $limitHeight ) die (); if ($image > $limitWidth ) die ();

После всех проверок мы можем с уверенностью переместить наш загружаемый файл в какую-нибудь папку с картинками. Делать лучше это через функцию move_uploaded_file() , которая работает в безопасном режиме. Перед перемещением файла нельзя забыть сгенерировать случайное имя и расширение из типа изображения для нашего файла. Вот так это выглядит:

// Сгенерируем новое имя файла на основе MD5-хеша $name = md5_file ($filePath ); // Сократим.jpeg до.jpg // Переместим картинку с новым именем и расширением в папку /pics if (! move_uploaded_file ($filePath , __DIR__ . "/pics/" . $name . $format )) { die ("При записи изображения на диск произошла ошибка." ); }

На этом загрузка изображения завершена. Для более удобной загрузки файлов можете использовать класс UploadedFile из пакета Symfony HttpFoundation , который является обёрткой для $_FILES и также сохраняет файл через move_uploaded_file() .

§5. Загрузка изображения по ссылке

Для загрузки изображения по ссылке нам понадобиться библиотека cURL , которая работает с удалёнными ресурсами. С помощью неё мы скачаем контент в переменную. С одной стороны может показаться, что для этих целей подойдёт file_get_contents() , но на самом деле мы не сможем контролировать объём скачиваемых данных и нормально обрабатывать все возникшие ошибки. Для того, чтобы cURL корректно скачал данные нам нужно: разрешить следовать перенаправлениям , включить проверку сертификата , указать максимальное время работы cURL (формируется за счёт объёма скачиваемых данных и средней скорости работы с ресурсом). Как правильно скачать файл в переменную показано ниже с необходимыми параметрами :

// Каким-то образом получим ссылку $url = "https://site.ru/picture.jpg" ; // Проверим HTTP в адресе ссылки if (! preg_match ("/^https?:/i" , $url ) && filter_var ($url , FILTER_VALIDATE_URL)) { die ("Укажите корректную ссылку на удалённый файл." ); } // Запустим cURL с нашей ссылкой $ch = curl_init ($url ); // Укажем настройки для cURL curl_setopt_array ($ch , [ // Укажем максимальное время работы cURL CURLOPT_TIMEOUT => 60 , // Разрешим следовать перенаправлениям CURLOPT_FOLLOWLOCATION => 1 , // Разрешим результат писать в переменную CURLOPT_RETURNTRANSFER => 1 , // Включим индикатор загрузки данных CURLOPT_NOPROGRESS => 0 , // Укажем размер буфера 1 Кбайт CURLOPT_BUFFERSIZE => 1024 , // Напишем функцию для подсчёта скачанных данных // Подробнее: http://stackoverflow.com/a/17642638 CURLOPT_PROGRESSFUNCTION => function ($ch , $dwnldSize , $dwnld , $upldSize , $upld ) { // Когда будет скачано больше 5 Мбайт, cURL прервёт работу if ($dwnld > 1024 * 1024 * 5 ) { return - 1 ; } }, // Включим проверку сертификата (по умолчанию) CURLOPT_SSL_VERIFYPEER => 1 , // Проверим имя сертификата и его совпадение с указанным хостом (по умолчанию) CURLOPT_SSL_VERIFYHOST => 2 , // Укажем сертификат проверки // Скачать: https://curl.haxx.se/docs/caextract.html CURLOPT_CAINFO => __DIR__ . "/cacert.pem" , ]); $raw = curl_exec ($ch ); // Скачаем данные в переменную $info = curl_getinfo ($ch ); // Получим информацию об операции $error = curl_errno ($ch ); // Запишем код последней ошибки // Завершим сеанс cURL curl_close ($ch );

Если всё прошло успешно и cURL уложился в 60 секунд, тогда содержимое по ссылке будет скачано в переменную $raw . Кроме того, функция curl_getinfo() вернёт информацию о проделанном запросе, откуда мы можем получить дополнительную информацию для анализа работы с удалёнными ресурсами:

Array ( => image/jpeg // MIME-тип из Content-Type => 200 // последний HTTP-код => 0 // количество перенаправлений => 0.656 // общее время работы cURL => 0.188 // время на соединение с хостом => 4504 // реальный размер полученных данных => 4504 // размер данных из Content-Length /* ... */ )

Дальше нам нужно проверить нет ли ошибок в curl_errno() и удостовериться, что ресурс отдаёт HTTP-код равный 200, иначе мы скажем, что по такому-то URL ничего не найдено. После всех проверок переменную $raw передаём в getimagesizefromstring() и работаем уже по отработанной схеме как в случае с загрузкой картинок из формы.

Обратите внимание, что мы валидируем размер файла в момент получения данных, т. к. мы не можем на 100% доверять curl_getinfo(), поскольку значения content_type, http_code, download_content_length формируются на основе полученных HTTP-заголовков. Скачивать файл полностью, а потом проверять количество байт потребует много времени и памяти. Поэтому мы контролировали размер получаемых данных с помощью опции CURLOPT_PROGRESSFUNCTION: как только cURL получит больше данных, чем наш лимит, он прекратит работу и выдаст ошибку CURLE_ABORTED_BY_CALLBACK.

// Проверим ошибки cURL и доступность файла if ($error === CURLE_OPERATION_TIMEDOUT) die ("Превышен лимит ожидания." ); if ($error === CURLE_ABORTED_BY_CALLBACK) die ("Размер не должен превышать 5 Мбайт." ); if ($info ["http_code" ] !== 200 ) die ("Файл не доступен." ); // Создадим ресурс FileInfo $fi = finfo_open (FILEINFO_MIME_TYPE); // Получим MIME-тип используя содержимое $raw $mime = (string) finfo_buffer ($fi , $raw ); // Закроем ресурс FileInfo finfo_close ($fi ); // Проверим ключевое слово image (image/jpeg, image/png и т. д.) if (strpos ($mime , "image" ) === false ) die ("Можно загружать только изображения." ); // Возьмём данные изображения из его содержимого $image = getimagesizefromstring($raw ); // Зададим ограничения для картинок $limitWidth = 1280 ; $limitHeight = 768 ; // Проверим нужные параметры if ($image > $limitHeight ) die ("Высота изображения не должна превышать 768 точек." ); if ($image > $limitWidth ) die ("Ширина изображения не должна превышать 1280 точек." ); // Сгенерируем новое имя из MD5-хеша изображения $name = md5 ($raw ); // Сгенерируем расширение файла на основе типа картинки $extension = image_type_to_extension ($image ); // Сократим.jpeg до.jpg $format = str_replace ("jpeg" , "jpg" , $extension ); // Сохраним картинку с новым именем и расширением в папку /pics if (! file_put_contents (__DIR__ . "/pics/" . $name . $format , $raw )) { die ("При сохранении изображения на диск произошла ошибка." ); }

Для сохранения изображения на диск можно воспользоваться file_put_contents() , которая запишет контент в файл. Новое имя файла мы создадим через функцию md5() , а расширение сделаем из image_type_to_extension() . Теперь мы можем загружать любые картинки по ссылке.

§6. Настройка выбора нескольких файлов

В этом параграфе разберём способы загрузки нескольких изображений за один раз с локальной машины пользователя и по удалённым ссылкам. Для отправки ссылок мы задействуем $_POST и передадим ей все данные с помощью тега textarea . Для загрузки файлов из формы мы продолжим дальше работать с $_FILES . Наша новая HTML-форма будет немного отличаться от старой.

В конец имени поля выбора файла name="upload" добавились фигурные скобки и аттрибут multiple , который разрешает браузеру выбрать несколько файлов. Все файлы снова загрузятся во временную папку, если не будет никаких ошибок в php.ini . Перехватить их можно в $_FILES , но на этот раз суперглобальная переменная будет иметь неудобную структуру для обработки данных в массиве. Решается эта задача небольшими манипуляциями с массивом:

// Изменим структуру $_FILES foreach ($_FILES ["upload" ] as $key => $value ) { foreach ($value as $k => $v ) { $_FILES ["upload" ][$k ][$key ] = $v ; } // Удалим старые ключи unset ($_FILES ["upload" ][$key ]); } // Загружаем все картинки по порядку foreach ($_FILES ["upload" ] as $k => $v ) { // Загружаем по одному файлу $_FILES ["upload" ][$k ]["tmp_name" ]; $_FILES ["upload" ][$k ]["error" ]; }

Для загрузки нескольких картинок по URL передадим наши ссылки через textarea с именем name="upload" , где их можно указать через пробел или с новой строки. Функция preg_split разберёт все данные из $_POST["upload"] и сформирует массив, по которому нужно пройтись циклом и каждый валидный URL отправить в обработчик.

$data = preg_split ("/\s+/" , $_POST ["upload" ], - 1 , PREG_SPLIT_NO_EMPTY); foreach ($data as $url ) { // Валидируем и загружаем картинку по URL }

Понравилась статья? Поделиться с друзьями: