Как загрузить файл на сервер c

Обновлено: 03.07.2024

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

Теперь подключим необходимые библиотеки:

Если вы используете Windows:

Кроме того следует подключить (если вы пользуетесь Visual Studio, это делается в свойствах проекта - настройках компановщика) необходимые в Windows lib файлы: Ws2_32.lib и Wsock32.lib

Следующим шагом будет установка управляющего соединения. Создадим для этого функцию init_sock() . Для упрощения кода преобразование доменного имени в IP адрес опустим. Соединение будем устанавливать на локальный ftp сервер (127.0.0.1), на стандартный 21 порт.

Итак мы установили управляющее соединение с сервером. Теперь необходимо считать ответ сервера. Для этого воспользуемся функцией select, которая проверяет наличие данных в потоке; recv - для получения данных из потока.
Немного об этих функциях:

Таким образом вы можете посылать команды на сервер и считывать его ответ. Имея две эти функции можно построить такую функцию main:

Теперь приступим к созданию соединения данных. Для этого создадим функцию init_data()

Теперь поговорим об этой функции. Прежде всего она отправляет запрос на пассивное соединение данных. Что это? Это такой вид соединения, когда мы создаём сокет на указанный сервером адрес и порт. После этого запроса мы получаем ответ сервера - строку, которая содержит адрес и порт - затем выводим её на экран.

Для независимости от языка сервера, разберём строку оставив только выражение в скобках. Для этого будем пользоваться функцией strtok(). Подробнее о ней можно прочитать здесь.
Разобрав строку - считаем из неё переменные адреса и порта в целочисленные переменные при помосчи sscanf().
Теперь вычислим необходимый порт: а*256 + b
Затем всё аналогично управляющему соединению. Оговорюсь лишь о том, что переменная addr, которая используется для хранения адреса - глобальная. Вы можете получить адрес заново использую sprintf() и полученные данные в переменных c,d,e,f.

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

В этой функции мы формируем строку с именем, отправляем её, считываем ответ. После чего проделываем тоже самое с паролем пользователя. Я не предохранял его от чужих глаз. это не важно для понимания структуры ftp.

После того как мы удачно залогинились на сервере отправим запрос на закачку файла:

Эта довольно громоздкая функция получает в качестве параметра имя загружаемого файла, передаёт запрос на его закачку, из ответа вычисляет при помощи strtok размер файла и пока не загрузится весь файл считывается по 2048 байт и записывается в него.

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

На сервере принимает контроллер

5,560 10 10 золотых знаков 64 64 серебряных знака 152 152 бронзовых знака Какой сервер, какие примеры, что не работает? Приведите свой код.

Если вам очень-очень не хочется асинхронный код, можно сделать и блокирующий вызов (но я бы не рекомендовал):


202k 25 25 золотых знаков 273 273 серебряных знака 501 501 бронзовый знак @RakzinRoman, проверь name . И вообще, по шагам из моего ответа посмотри. И ещё Expect100Continue выключи. @VladD, await не забыл? UPDATE: А, не, там Result . Ну не надо же так делать?!

Файл передаётся в кодировке multipart/form-data . Соответственно надо:

Сгенерировать разлелитель (например, Asrf456BGe4h )

Обращаю внимание на два дефиса в конце.

А то над просто вещью вроде бы ломаю голову несколько часов

  1. Устанавливаешь Fiddler
  2. Отправляешь файл через браузер, откуда всё работает.
  3. Смотришь в фиддлере, что именно отправилось.
  4. Отправляешь своим кодом. Смотришь в фиддлере, что отправилось.
  5. Допиливаешь свой код, пока отправляемое на шаге 4 не совпадёт с тем, что было на 3.
110k 24 24 золотых знака 98 98 серебряных знаков 262 262 бронзовых знака а можно по проще? Мне нужно один файл за раз передавать. Лиж бы оно работало. Ато над просто вещью вроде бы ломаю голову несколько часов @RakzinRoman, нельзя проще. Либо переделывай сервер, чтобы он принимал Stream (в WCF так можно было, про webapi не в курсе) и шли как написано в соседнем ответе.

Кажется так:
Записываете файл в поток:


Вопрос был, как передать файл на обычный сервер. Это вообще не ответ.

Правда там пример на 1С но это не особо важно

// Вот как выглядит отправляемый запрос //POST http://localhost:40320/api/values/SendFiles HTTP/1.1 //Content-Type: multipart/form-data; boundary="9f2d525a-7383-46ab-8fc7-419d73486c02" //Host: localhost:40320 //Content-Length: 811 //Expect: 100-continue //Connection: Keep-Alive

//--9f2d525a-7383-46ab-8fc7-419d73486c02 //Content-Type: text/plain; charset=utf-8 //Content-Disposition: form-data; name=Name

//name //--9f2d525a-7383-46ab-8fc7-419d73486c02 //Content-Type: text/plain; charset=utf-8 //Content-Disposition: form-data; name=id

39) Выгрузка файлов по HTTP описана в RFC-1867. Этот механизм позволяет выгружать большие файлы, используя бинарное кодирование передаваемых данных. Для этой цели используется тип кодировки "multipart/form-data".

Простая HTML-форма с возможностью выгрузки файлов показана в примере кода ниже. Бинарный тип кодирования устанавливается заданием атрибута enctype формы со значением "multipart/form-data":

В строке 1 мы явно задаем кодирование "multipart/form-data" (атрибут `enctype) для использования эффективного бинарного кодирования передачи данных формы.

В строке 2 мы определяем поле ввода с типом "file" и именем "myfile". Это поле позволит посетителям сайта выбирать файл для выгрузки.

Если вы сохраните представленную выше разметку в файл .html и откроете его в своем браузере, вы увидите страницу как на рисунке 10.1.

Рисунок 10.1. Простая HTML-форма с возможностью выгрузки файлов

Рисунок 10.1. Простая HTML-форма с возможностью выгрузки файлов

Строка 5 устанавливает заголовок Content-Type" со значением "multipart/form-data". Форма собирается из полей, отмеченных "границами" -- уникальными случайно сгенерированными последовательностями символов, отделяющими поля формы друг от друга.

По умолчанию, настройки PHP-движка не позволяют выгружать большие файлы (больше 2МБ). Для выгрузки таких файлов нужно изменить файл конфигурации php.ini, а также параметры post_max_size и upload_max_filesize . О том, как это сделать, можете прочитать в Приложение А. Организация среды веб-разработки.. Установив эти настройки на 100M позволит выгружать на сервер файлы размером до 100 Мб, и этого, как правило, будет достаточно. Если вы планируете выгрузку очень больших файлов вплоть до 1 ГБ, лучше задайте в настройках 1024М. Не забудьте перезапустить веб-сервер Apache после изменения файла конфигурации.

10.1.2. Суперглобальный массив $_FILES в PHP

При выгрузке посетителем сайта файлов на ваш веб-сервер Apache, эти файлы помещаются во временное хранилище (обычно в системный временный каталог - /tmp в Linux и C:\Windows\Temp в Windows). PHP-скрипт принимает информацию о файле в специальный суперглобальный массив $_FILES .

Массив $_FILES аналогичен суперглобальным $_GET и $_POST . Два последних используются для хранения переменных GET и POST соответственно, в то время как первый используется для хранения информации о выгружаемых на сервер файлах.

Например, для вышеупомянутой формы выгрузки суперглобальный массив $_FILES будет выглядеть следующим образом (выходные данные генерируются с помощью PHP-функции var_dump() ):

Как видите из этого примера, массив $_FILES содержит запись для каждого выгружаемого на сервер файла. Для каждого файла он содержит следующую информацию:

  • name -- исходное имя файла (строка 4).
  • type -- MIME-тип 41 файла (строка 5).
  • tmp_name -- временное имя для выгружаемого файла (строка 6).
  • error -- код ошибки, сигнализирующий о статусе выгрузки (строка 7); нулевой код ошибки означает, что файл был корректно выгружен на сервер.
  • size -- размер файла в байтах (строка 8).

41) MIME-тип (Multipurpose Internet Mail Extension - Многоцелевое расширение почты Интернета), также известный как "тип содержимого" - стандартный идентификатор, используемый в Интернете для указания типа данных, которые содержит файл. Например, MIME-тип "text/plain" присваивается текстовому файлу, а MIME-тип "application/octet-stream" - бинарному.

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

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

Следующий фрагмент кода показывает, как перемещать файл, выгруженный на сервер с помощью простой формы, которую мы рассмотрели выше:

В строке 1 этого примера мы задаем $destPath - имя каталога, куда нужно сохранить выгруженный файл.

В строке 2 мы вызываем функцию move_uploaded_file() и передаем ей два аргумента: путь к временному файлу и путь назначения.

Передача имени каталога в качестве второго аргумента функции move_uploaded_file() подходит для тех случаев, когда вы не хотите переименовывать файл. Если вам нужно сохранить выгруженный файл под другим именем, можете вместо имени директории указать полный путь к файлу.

В строке 3 мы проверяем возвращаемое значение функции. При успешной операции функция вернет true . Если произошли какие-либо ошибки (например, если прав доступа к каталогу недостаточно для сохранения файла), вернется булевое false .

Как загрузить файлы на сервер

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

Поэтому, перед программистами, которые создают такие порталы, всегда стоит вопрос, как загрузить файлы на сервер.

Вот эту задачу мы и разберем в данной статье.

Создание формы для загрузки файла (изображения)

Начнем с простого. Для начала разберёмся как загрузить на сервер один файл.

Например, мы хотим загрузить какое-то изображение в одном из форматов jpg или png.

Создаем файл index.php. Добавляем в него базовую структуру HTML

Теперь, создаем CSS файл styles.css и подключаем его к странице.

Также подключим через CDN CSS фреймворк Bootstrap

Теперь, создаем HTML форму. Для красоты, оформляем страницу с помощью классов CSS фреймворка Bootstrap.

Поле для загрузки изображения будет иметь имя file_img. Данное имя будет использоваться в названии ячейки из суперглобального массива $_FILES, которая будет содержать массив с данными о загруженном файле.

Так как мы хотим, чтобы пользователь загружал только изображения в формате jpg или png, то необходимо сообщит пользователю об этом.

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

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

В итоге страница имеет такой код:

Для того чтобы разместить форму по центру страницы, в файле styles.css добавляем эти стили:

форма для загрузки файла

Отправка формы на сервер

В значение атрибута action тега формы, мы указали что данные с формы будут обрабатываться в файле upload-one-file.php, поэтому создаем этот файл.

Для того чтобы нагляднее увидеть, что находится в массиве $_FILES, выведем его содержимое на экран.

Как было упомянуто выше, в суперглобальном массиве $_FILES, добавляется массив с данными о загруженном файле, имя которого указано в значение атрибута name, поля загрузки файла.

Открываем страницу в браузере, выбираем какое-то изображение и нажимаем на кнопку ‘Загрузить изображение’.

В результате, мы видим содержимое суперглобального массива $_FILES.

Разберемся с каждой ячейкой из массива file_img, с данными о загруженном файле.

  • name – название загруженного файла
  • type – MIME-type . То есть тип загруженного файла.
  • tmp_name - это временный путь где был загружен файл. То есть интерпретатор PHP, загруженному файлу задал некое временное имя (в нашем случае php34B6.tmp) и поместил его в временную папку (D:\OpenServer-5.3.7\userdata\php_upload\). Нам остается, специальной функцией переместить данный файл из временного хранилище в нужную папку на сервере.
  • error - код ошибки. Значение 0, означает что ошибок нет.
  • size - размер загруженного файла в байтах. В нашем случае, изображение cart.jpg имеет 164358 байтов.

И так, приступим. В начале файла обработчика upload-one-file.php, открываем сессию.

В самом начале файла index.php, пишем:

Теперь, после формы добавляем такую проверку, если в массиве $_SESSION, существует ячейка server_messages, то выводим ее содержимое.

Добавим некие стили для данного блока в файле styles.css:

Переходим обратно в файл upload-one-file.php, и удаляем тестовую проверку.

То есть удаляем этот код:

Теперь, необходимо добавить проверку, была ли нажата кнопка "Загрузить изображение".

Проверяем тип ( MIME-type ) загруженного файла

Теперь, поговорим немного о параметре type из массива с данными о файле file_img из суперглобального массива $_FILES.

Как мы знаем, существуют много типов файлов с разными расширениями.

  • Аудио файлы с расширением .mp3 имеют MIME-тип audio/mpeg
  • Видео файлы с расширением .avi, имеют MIME-тип video/avi
  • Документы с расширением .pdf, имеют MIME-тип application/pdf
  • Изображения с расширением .jpg, имеют MIME-тип image/png
  • И другие

Также, существуют и опасные файлы, например, с расширением .bat, которые имеют MIME-тип application/octet-stream. В таких файлах злоумышленник может записать какой-то вредоносный скрипт или команду.

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

Для этого, создаем массив, в котором указываем какие MIME-типы разрешены для загрузки.

В нашем случае указываем что разрешены для загрузки файлы которые имеют MIME-тип "image/jpeg" либо "image/png"

Теперь пишем проверку типа файла, после метки "// (1) Место для следующего куска кода":

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

Файл не является изображением

Проверяем расширение загруженного файла

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

Проверяем размер загруженного файла

И последнее что нам осталось проверить, это размер загруженного файла.

Мы указали что максимальный размер изображения, не должно превысить 3MB.

В массиве $_FILES мы имеем ячейку size, с размером загруженного файла в байтах.

И для того чтобы посчитать сколько байтов содержит 3 мегабайта, воспользуемся функцией return_bytes(),

Добавляем эту функцию в конце обработчика:

Передаем в функцию return_bytes значение '3M' и выводим на экран результат данной функции.

Мы видим, что 3MB = 3145728 байта.

Считаем это вручную.

1 мегабайт (MB) = 1048576 байт.

1048576 байт умножаем на 3 и узнаем, что 3MB это 3145728 байта.

В указанное место "// (3) метка: Место для следующего куска кода" пишем следующею проверку:

Пытаемся загрузить изображение с размером в 5MB и в результате получаем ошибку:

Размер загруженного изображения

Конфигурация интерпретатора PHP

Также мы должны учесть, что в конфигурации интерпретатора PHP (в файле php.ini) существуют 4 опции, которые влияют на загрузку файла.

upload_max_filesize - Устанавливает максимальный допустимый размер для загруженного файла.

post_max_size - Устанавливает максимально допустимый размер данных, отправляемых методом POST. В случае если необходимо загрузить большой файл, то значение этой опции должно быть больше значении, которое указано в опции upload_max_filesize.

max_execution_time – Устанавливает максимальное время в секундах, в которой может выполниться скрипт. По умолчанию это 30-60 секунд.

max_input_time – Устанавливает время в секундах, в течении которой будут обрабатываться приходящие данные на сервер. По умолчанию установлено значение '-1'. Это означает что в качестве значения для этого параметра будет использоваться значение max_execution_time.

Для того чтобы увидеть текущие значения этих опции, можно открыть страницу с результатом функции phpinfo();.

Сейчас у меня установлено что upload_max_filesize = 10M и post_max_size равен 20M.

Как определить, что значение post_max_size было превышено?

Теперь, если мы по пытаемся загрузить данные методом POST, размер которых превышает значение 20MB (это значение указано в настройках сервера, в параметре post_max_size ), то, согласно документации, в таком случае в суперглобальных массивах $_POST и $_FILES не записываются данные.

В результате мы увидим ошибку о том, что, нет данных для обработки.

Для того чтобы убедиться в этом, временно, выведем на экран содержимое суперглобальных массивов $_POST и $_FILES внутри первой проверки.

Для примера, попытаемся загрузить файл методом POST, размер которого превышает значение 20MB.

Загрузка большого файла методом POST

И в результате видим что суперглобальные массивы $_POST и $_FILES пустые.

Массивы $_POST и $_FILES могут быть пустыми в двух случаях:

  • Пользователь зашел через браузерную строку напрямую в обработчик
  • Пользователь отправил методом POST данные, размер которых превышает значение, указанное в параметре post_max_size

Согласно документации, мы можем определить, почему массивы $_POST и $_FILES пустые, следующим образом:

В конце значения атрибута action формы, необходимо прикрепить некий параметр, который будет выступать в качестве флага. Этот параметр будет передаваться на сервер методом GET.

Соответственно, на стороне сервера, внутри проверки существования ячейки 'upload_image' в массиве $_POST, мы можем сделать проверку.

Если в суперглобальном массиве $_GET, существует параметр 'flag', значит пользователь попытался загрузить слишком большой файл, иначе, он зашел в обработчик напрямую.

Меняем содержимое блока

Теперь, если пользователь пытается загрузить на сервер файл, размер которого превышает значение, указанное в параметре post_max_size, то в результате он увидит ошибку о том, что, размер загруженного файла превышает 3MB.

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

Переход в обработчик напрямую

Ошибка в результате перехода в обработчик напрямую

Данная ячейка содержит информацию откуда пришел пользователь.

Значит к проверке

добавляем еще одно условие

В результате мы имеем такую проверку:

Как определить, что значение upload_max_filesize было превышено?

Далее, необходимо определить ошибку о том, что превышено значение, указанное в upload_max_filesize.

Для этого попытаемся загрузить файл размер которого превышает 10MB, но не достигает 20MB.

Если размер файла превышает значение, указанное в параметре upload_max_filesize, то в ячейке errors из массива с данными о загруженном файле появляется значение 1.

Также в таком случае отсутствует MIME-тип файла и адрес к временной папке, а в значение ячейки size, появляется 0.

Для того чтобы убедиться в этом, в файле upload-one-file.php до проверки существования ячейки 'upload_image' в массиве $_POST, выведем содержимое суперглобального массива $_FILES.

содержимое массива FILES

Содержимое массива $_FILES при возникновения ошибки upload_max_filesize

Теперь, удаляем код, который выводит содержимое суперглобального массива $_FILES и обновляем страницу.

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

Это случается из-за того, что отсутствует значение в ячейки type. А у нас в коде существует такая проверка:

Так как, ячейка type пустая, то ее значение не находится в массиве $allow_types, и в результате получаем эту ошибку.

Перемещаем загруженный файл в нужную папку

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

Как было сказано выше, изначально загруженный файл добавляется в некоторое временное хранилище. Адрес которой указано в ячейке tmp_name из суперглобального массива $_FILES.

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

Делается это с помощью функции move_uploaded_file($parametr1, $parametr2).

В первом параметре указываем адрес откуда хотим переместить файл, а во втором параметре указываем адрес куда хотим переместить файл.

В адресе из второго параметра необходимо указать и название файла.

Формируем название файла

И здесь хочу обратить внимание на один момент.

Допустим некий пользователь, загрузил на сервер какое-то изображение с собакой, файл которой имеет название dog.jpg.

Потом, другой пользователь, загрузил какое-то изображение с другой собакой, файл которой также имеет название dog.jpg.

Для примера, я создал две папки. В каждой папки добавил по изображению с названием dog.jpg.

Картинки пользователей

Два пользователя хотят загрузить изображения с именем dog Согласно документации, если на сервере уже существует файл с названием dog.jpg, то при загрузки файла с таким же именем, функция move_uploaded_file() перезапишет первый файл.

Поэтому, при перемещении файла с временной папки в нужную папку, необходимо сделать название файла уникальным. Например, добавить в конце названия файла, метку текущей времени в секундах. Делается это с помощью функции time().

В нашем случае указываем что хотим переместить файл из временного хранилища в папку images.

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

Теперь, вызываем функцию move_uploaded_file().

В случае успешной загрузки, функция move_uploaded_file() возвращает true, иначе false.

Файл успешно загружен на сервер

Готово, функционал загрузки файла на сервер реализован.

Как вывести на страницу загруженные изображения

Теперь, после того как загрузили изображение на сервер, мы хотим вывести ее на страницу.

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

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

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

Для этого в файле index.php, перед тем как закрыть тег div с классом container, открываем php и пишем следующий код:

Переходим к тестированию реализованного функционала.

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

Вот что у нас получилось в результате:

Как загрузить изображения на сервер

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

Также можно почитать:

Понравилась статья?

Тогда поделитесь ею с друзьями и подпишитесь на новые интересные статьи.

Читайте также: