Загрузка файлов на сервер средствами PHP
На данный момент загрузка файлов является одной из необходимых функций любого сайта, будь то загрузка изображения в профиль пользователя, отправка документов при регистрации, размещение прайс листов, создание галереи и т.д. В статье пойдёт речь о реализации загрузки различных файлов на сервер средствами PHP.
Настройка параметров PHP
Для начала, нам потребуется настроить некоторые параметры php, для этого необходимо отредактировать конфигурационный файл php.ini. Если у вас нет доступа к этому файлу, обратитесь в техническую поддержку вашего хостинга. Я же использую локальный сервер OpenServer и для настройки php нужно перейти в раздел Дополнительно -> Конфигурация -> PHP (ваша версия PHP). Укажем следующие настройки:
;Время выполнения скрипта в секундах (максимальное), обычно стараются укладывать в 30-60 секунд, для примера задам 3 минуты max_execution_time = 180 ;Максимальное потребление памяти одним php скриптом memory_limit = 128M ;Флаг загрузки файлов (On - можно Off - нельзя) file_uploads = On ;Максимально разрешённое количество одновременно загружаемых файлов max_file_uploads = 20 ;Максимально допустимый размер данных, отправляемых методом POST post_max_size = 100M ;Папка для временного хранения файлов во время загрузки, я использую OpenServer поэтому в пути присутсвует спец.переменная %sprogdir% upload_tmp_dir = "%sprogdir%/userdata/temp/" ;Максимально допустимый размер загружаемого файла upload_max_filesize = 5M
Перезагружаем сервер, чтобы изменения вступили в силу. Можно приступать к коду.
Загрузка одного файла из веб-формы
Описываем на примере загрузки аватара в профиль пользователя на форуме. Чтобы форма имела какой-нибудь «приличный» вид, я подключил css bootstrap используя cdn.Сама форма максимально простая, выглядит так:
Загрузка файла на сервер
Файл profile.php который будет отвечать за обработку загружаемого изображения пока содержит следующий код:
echo ''; print_r($_FILES); echo '';
Все передаваемые на сервер файлы попадают в так называемый «суперглобальный массив» $_FILES, приведённый выше код покажет нам его содержимое. Отправим тестовый файл, у меня это картинка формата jpg размером 100×100 пикселей. Получим следующее содержимое $_FILES:
Array( [user_avatar] => Array ( [name] => avatar.jpg [type] => image/jpeg [tmp_name] => F:\OpenServer\userdata\php_upload\php6F8A.tmp [error] => 0 [size] => 6933 ) )Обратите внимание что все данные о загружаемом файле хранятся в виде ассоциативного массива, при этом ключ массива user_avatar равен значению атрибута name в форме загрузки файла. Сам файл при этом попадает во временную директорию на сервере tmp_name которую мы указывали в php.ini нашего сервере.
- UPLOAD_ERR_OK — Ошибок не возникло, файл был успешно загружен на сервер;
- UPLOAD_ERR_INI_SIZE — Размер принятого файла превысил максимально допустимый размер;
- 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-расширение остановило загрузку файла.
Давайте выполним ряд проверок загружаемого файла:
// Массив c описанием ошибок $uploadErrorMessages = [ '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-расширение остановило загрузку файла.', ]; // Проверяем что $_FILES есть наш файл if (isset($_FILES['user_avatar'])) < $image = $_FILES['user_avatar']; // Получаем нужные элементы массива "user_avatar" $tmpFileName = $_FILES['user_avatar']['tmp_name']; $uploadErrorCode = $_FILES['user_avatar']['error']; //Если есть ошибка или файл был загружен не через HTTP POST вернём ошибку if ($uploadErrorCode !== UPLOAD_ERR_OK || !is_uploaded_file($tmpFileName)) < //Выводим соответствующее $errorCode сообщение об ошибка или "ошибка неизвестна" $message = isset($uploadErrorMessages[$uploadErrorCode]) ? $uploadErrorMessages[$uploadErrorCode] : 'При загрузке файла произошла неизвестная ошибка.'; //Завершаем работу скрипта, выводим сообщение об ошибке echo json_encode(['status'=>'error', 'msg'=>$message]); > else < //Если всё ок, выполняем манипуляции с файлом echo json_encode(['status'=>'ok', 'msg'=>'Ошибок нет']); > >
Здесь я проверяю что если код ошибки не равен UPLOAD_ERR_OK или функция is_uploaded_file() вернула false (т.е. файл был загружен не через HTTP POST а как-то иначе), то подготавливаем переменную $message и возвращаем JSON строку с ошибкой. Если всё ок, то выводится сообщение что ошибок нет, опять таки в виде JSON. Это сделано для того, чтобы более удобно взаимодействовать с фронт-частью нашего приложения.
Давайте сохраним файл в папку /img/ на нашем учебном сервере. Добавим следующий код в условие, где не возникло ошибок при загрузке:
//Если всё ок, выполняем манипуляции с файлом if (move_uploaded_file($_FILES['user_avatar']['tmp_name'], $uploadDir . $_FILES['user_avatar']['name'])) < echo json_encode(['status'=>'ok', 'msg'=>'Файл загружен в директорию ' . $uploadDir]); > else < echo json_encode(['status'=>'error', 'msg'=>'Ошибка загрузки файла']); >
А так же выведем список файлов в папке /img/:
Получаем такую картину
В случае успешной загрузки, в списке файлов справа появиться ссылка на загруженный файл. Давайте добавим дополнительную проверку на тип файла, например, нас интересуют только изображения.
Множественная загрузка файлов на сервер
Добавим ещё одну форму в наш код.
Обратите внимание на то, что в name поля загрузки файла появились квадратные скобки gallery[] а так же атрибут multiple. С такими параметрами вы сможете выбрать несколько файлов зажав кнопку Ctrl в окне просмотра файлов. Форма приобрела следующий вид.

Я так же добавил отдельный скрипт для обработки множественной загрузки gallery.php. В целом он имеет ту же структуру, однако файлы теперь обрабатываются в цикле из заранее подготовленного массива $arFiles.
header('Content-Type: application/json'); // Массив c описанием ошибок $uploadErrorMessages = [ '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-расширение остановило загрузку файла.', ]; // Проверяем что $_FILES есть наш файл if (isset($_FILES['gallery'])) < $uploadDir = $_SERVER['DOCUMENT_ROOT'] . '/fileupload/img/'; $arFiles = []; //Изменим структуру массива $_FILES для удобства работы с файлами foreach($_FILES['gallery'] as $field =>$arValues) < foreach($arValues as $key =>$value) < $arFiles[$key][$field] = $value; >> foreach ($arFiles as $key => $file)< // Получаем нужные элементы массива "user_avatar" $tmpFileName = $file['tmp_name']; $uploadErrorCode = $file['error']; //Если есть ошибка или файл был загружен не через HTTP POST вернём ошибку if ($uploadErrorCode !== UPLOAD_ERR_OK || !is_uploaded_file($tmpFileName)) < //Выводим соответствующее $errorCode сообщение об ошибка или "ошибка неизвестна" $message = isset($uploadErrorMessages[$uploadErrorCode]) ? $uploadErrorMessages[$uploadErrorCode] : 'При загрузке файла произошла неизвестная ошибка.'; //Завершаем работу скрипта, выводим сообщение об ошибке echo json_encode(['status'=>'error', 'msg'=>$message], JSON_UNESCAPED_UNICODE); > else < //Добавим проверку на тип файла $allowedFormats = ['image/jpeg', 'image/gif', 'image/png']; $finfo = finfo_open(FILEINFO_MIME_TYPE); $fileInfo = finfo_file($finfo, $tmpFileName); if(in_array($fileInfo, $allowedFormats))< //Если всё ок, выполняем манипуляции с файлом if (move_uploaded_file($file['tmp_name'], $uploadDir . $file['name'])) < echo json_encode(['status'=>'ok', 'msg'=>'Файл загружен в директорию ' . $uploadDir], JSON_UNESCAPED_UNICODE); > else < echo json_encode(['status'=>'error', 'msg'=>'Ошибка загрузки файла'], JSON_UNESCAPED_UNICODE); > > else < echo json_encode(['status'=>'error', 'msg'=>'Можно загружать только изображения jpg, png или gif формата'], JSON_UNESCAPED_UNICODE); > > > >
А текущем варианте скрипта отсутствует ajax и всякий js способный улучшить пользовательский опыт. Полную версию скрипта я опишу в разделе bitrix этого сайта где буду делать простой компонент множественной ajax загрузки файлов на сервер.
Как в битрикс 24 залить файл через API?
Как закачать файл в пользовательское поле типа «файл» через api? Есть у кого пример кода на php?
- Вопрос задан более трёх лет назад
- 7789 просмотров
Комментировать
Решения вопроса 1
Алексей Уколов @alexey-m-ukolov Куратор тега PHP
Методы REST-сервиса получают файлы в виде строки, закодированной в base64. Также можно отправить обычный массив, первым элементом которого будет имя файла, вторым — содержимое в base64.
POST https://my.bitrix24.com/rest/entity.item.add.json HTTP/1.1 Host: my.bitrix24.com Content-Length: 186 Content-Type: text/plain; charset=UTF-8 auth=xxx&ENTITY=menu&NAME=yyy&DETAIL_PICTURE[0]=1.gif&DETAIL_PICTURE[1]=R0lGODlhAQABAIAAAP%2F%2F%2FwAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw%3D%3D
Ответ написан более трёх лет назад
Нравится 3 2 комментария
Битрикс. Как загрузить файл и получить его id?
Здравствуйте! Прошу помощи в реализации. В общем есть форма по загрузке изображений, которую я пишу сам, не используя встроенные компоненты. Форма должна грузить в свойство типа «файл» картинку. Как это реализовать в Битрикс? Проблема именно в загрузке и получении id, запись в свойство происходит если написать вручную id уже загруженной картинки.
- Вопрос задан более трёх лет назад
- 10080 просмотров
Комментировать
Решения вопроса 1
Кирилл Михайлович @rollbackTNV
Программист Bitrix & other CMS
Твою задачу решил так, правда не понимаю смысла
$item):?>IncludeComponent("bitrix:main.file.input", "drag_n_drop", array( "INPUT_NAME"=>"NEW_FILE_UPLOAD", "MULTIPLE"=>"Y", "MODULE_ID"=>"main", "MAX_FILE_SIZE"=>"", "ALLOW_UPLOAD"=>"A", "ALLOW_UPLOAD_EXT"=>"", "INPUT_CAPTION" => "Добавить фото", "INPUT_VALUE" => $_POST['NEW_FILE_UPLOAD'] ), false );?>
в script.js компонента вставил в конец window.BlogBFileDialogUploader.prototype.Callback
var inp = BX("newF"); BX.adjust(inp, >);
Можно после загрузки файла получить в поле формы id, отобразить изображения после загрузки — да тут куча возможностей
Ответ написан более трёх лет назад
Нравится 1 3 комментария

Денис Всяченков @vsyakiyjr Автор вопроса
На сайте есть форма, которая разрабатывалась другим программистом. В нее я хочу добавить загрузку картинки к свойству типа «файл». Но в таком случае не могу реализовать саму загрузку файла, запрос в итоге пустой получается. Реализовал сейчас так, что рядом с формой вставил компонент скрытый main.file.input (Ваше решение), а в форму вставил кнопку, которая взаимодействует с компонентом main.file.input и вставляет уже id загруженного файла в общую форму. Так в свойство попадает файл, но как реализовать все ручками в этой общей форме не понятно пока. Наверняка надо дописать обработчик загрузки файлов в форму. За Ваше решение спасибо, работает все так. Но буду изучать далее, чтобы в итоге реализовать все одним кастомизированным компонентом.
Кирилл Михайлович @rollbackTNV
Денис Всяченков: грамотнее всего это сделать через ajax, но мне нужно представлять общую структуру, а там вышлю код из наработанного — стучи в скайп
ID картинок можно получить прямо из шаблона, после их успешной загрузки. На странице создается html таблица и в ее тегах tr в атрибутах указаны id картинок с добавлением какого-то текстового префикса, который нужно обрезать.
Загрузка файлов через BX drag_n_drop — загрузчик

Не так давно в свет вышел довольно интересный и красивый загрузчик файлов, который сейчас во всю используется в блогах и живой ленте.
А вот описания к нему я не нашел. Восполним пробел.
Компонент называется main.file.input и лежит в системных компонентах. Все что он умеет — это загружать и сохранять файлы через CFile::SaveFile(), удалять через CFile::Delete() и все. Файлы по дефолту привязываются к главному модулю main и сохраняются в одноименной папке относительно /upload. Сам компонент возвращает некий универсальный идентификатор. Без него невозможна работа callback-ов при загрузки файла и после.
Сценарий работы компонента
Все основные js-функции лежат в script.js. При загрузке страницы формируется js-объект с заданными параметрами (это происходит в шаблоне). Далее, либо при загрузке страницы, либо по событию (клик, аякс-загрузка контента, ховер и пр.) срабатывают кастомные js-события, они вызывают функции, которые открывают нужные дивы и таблицы, ибо, по дефолту они скрыты. При этом срабатывает функция window.BlogBFileDialogUploader.prototype.GetUploadFileName, которая формирует форму для отправки файла и фрейм.
При отправке формы срабатывает window.BlogBFileDialogUploader.prototype.CallSubmit, которая отправляет файл. По дефолту файл отправляется на ту страницу, на которой находится сам компонент. Путь берется из параметра this.uploadFileUrl, а он из параметров при создании объекта. При случае можно менять на какой угодно. В общем и целом, лучше чтоб файл загружался на страницу, где находится компонент, потому как в самом компоненте идет проверка основных параметров и там формируется объект для работы с callback-ами. Без него у вас файл может загрузиться и сохраниться нормально, но индикатор загрузки зависнет, как будто файл не загрузился и процесс завис. Но обо всем по порядку.
Пользование компонента.
Вызываем компонент:
IncludeComponent("bitrix:main.file.input", "drag_n_drop", array( "INPUT_NAME"=>"TEST_NAME_INPUT", "MULTIPLE"=>"Y", "MODULE_ID"=>"main", "MAX_FILE_SIZE"=>"", "ALLOW_UPLOAD"=>"A", "ALLOW_UPLOAD_EXT"=>"" ), false );?>
Параметры:
INPUT_NAME // уникальный name инпута, без него выдает ошибку
MULTIPLE => Y || N — позволяет или не позволяет множественную загрузку
MODULE_ID => main || iblock || blog || forum и пр. имя модуля, к которому файл привязан будет и в какую папку попадет относительно upload.
MAX_FILE_SIZE // максимальный размер файла (вроде в байтах)
ALLOW_UPLOAD A || F || I — какой тип файлов будем грузить: F — файлы, I — картинки, A — все подряд.
ALLOW_UPLOAD_EXT => «*.zip,*.rar,*.doc и пр.» // какие расширения файлов можно грузить. Работает если ALLOW_UPLOAD => F
Шаблон компонента всяко придется править, так что можно сразу копировать в шаблон .default. при этом в самом шаблоне поправьте пути к js и css файлам, которые грузятся по средствам js-функций.

После этого на странице вы не увидите ничего Для этого надо в шаблоне избавиться от некоторых мало понятных проверок и функции.
Убираем php-вставки в скрипте, в шаблоне, примерно строки 117, 154 и 171. Тут идет проверка php — callback — функции, в момент загрузки страницы, она пустая и компонент скрыт. Активируется после перетаскивания файла в дропзону. После этого компонент нормально отображается на странице при ее загрузке.
Сам загрузчик формируется объектом:
BfileFD = new BlogBFileDialog(< 'mode' : variant, // simple | extended вариант отображения - простой загрузчик или драг-н-дроп 'CID' : "", // контрольная строка 'upload_path' : "", // путь, куда грузить файлы 'multiple' : =( $arParams['MULTIPLE'] == 'N' ? 'false' : 'true' )?>, // загрузка нескольких файлов одновременно 'controller': , // #id - основного div-а 'inputName' : "", 'fileInput' : "file-fileUploader-", 'fileInputName' : "mfi_files[]", // массив, который формируется отправке файлов 'msg' : < // всякие сообщения 'loading' : "", 'file_exists':"", 'upload_error':"", 'access_denied':" " > >);
Если посмотреть функцию window.BlogBFileDialogUploader.prototype.CreateElements — там формируется фрейм и форма для отправки файла. Если нужно вместе с файлом передать еще какие-либо параметры, то добавляем свои инпуты.
window.BlogBFileDialogUploader.prototype.Callback — срабатывает после загрузки и содержит массив с инфой о файле. Сюда можно впихнуть все что получится в $arResult. С этим массивом можно работать и использовать дальше после загрузки.
При использовании компонента в режиме ajax — т.е. при загрузке компонента на страницу или в popup-окно с помощью аякса, не забудьте поменять параметр «upload_path» в объекте формирования загрузчика в шаблоне компонента. И если не хочется заморачиваться файлом-приемником, то поставьте туда этот же компонент.
