Blog. Just Blog
Отправка файла на сервер с помощью сокетов
Иногда при разработке проектов возникает задача отправки данных на другие серверы. В случае текстовых данных или небольших объемов бинарных данных можно ограничиться POST- или GET-запросами. Этот способ никаких сложностей не представляет и здесь описываться не будет. А как быть, если на сторонний сервер требуется передать не только данные, но и файлы? Например, вы загружаете картинки через форму на своем сервере, но фактически храните их на каком-нибудь другом. В этом случае нам надо полностью проэмулировать работу браузера, а именно его обмен данными с удаленным сервером, как будто бы пользователь заполнил и отправил форму с web-страницы. Предположим, что для загрузки файлов на сервер используется следующая форма:Code (HTML) : Убрать нумерацию
- <form action="/uploader.php" method="post" enctype="multipart/form-data">
- Выберите файл: <input type="file" name="my_file"><br>
- Описание: <input type="text" name="ext_field_1"><br>
- <input type="submit" value="Загрузить">
- </form>
Каждое текстовое поле в теле запросе кодируется следующим образом:
--boundary
Content-Disposition: form-data; name="имя_поля_в_форме"
значение поляФайлы при передаче кодируются несколько иначе:
--boundary
Content-Disposition: form-data; name="имя_поля" filename="имя_файла"
Content-Type: mime-тип файла
двоичное содержимое файлаКак узнать mime-тип файла по его расширению, написано в этой статье. В заголовках запроса также обязательно должны присутствовать данные об общем размере тела запроса, а именно длина всех кодированных полей формы. Эта информация передается заголовком "Content-Length: NNNN". То есть сперва в вашем обработчике формируется тело запроса, а только после него заголовок.
Теперь мы знаем какие данные и в каком виде надо передавать, осталось сделать рабочий скрипт. Сперва, как я говорил выше, формируем тело запроса.
Code (PHP) : Убрать нумерацию
- // Данные для формирования запроса
- $boundary=md5(rand());
- $crlf = "\r\n";
- // Название поля в форме отправки файла
- $field_name='my_file';
- // Имя файла
- $file_name='my_file.bin';
- // Тип файла
- $file_type='application/octet-stream';
- // Содержимое файла
- $file_data=str_repeat('x',100);
- // Подготовить тело запроса с файлом
- $body = '--'.$boundary.$crlf;
- $body .= 'Content-Disposition: form-data; ';
- $body .= 'name="'.$field_name.'"; filename="'.$file_name.'"'.$crlf;
- $body .= 'Content-Type: '.$file_type.$crlf;
- $body .= $crlf;
- $body .= $file_data;
- $body .= $crlf;
- // Дополнительные поля формы (если надо)
- $body .= '--'.$boundary.$crlf;
- $body .= 'Content-Disposition: form-data; name="ext_field_1"'.$crlf;
- $body .= $crlf;
- $body .= 'Some text data....'.$crlf;
- // Конец тела запроса
- $body .= '--'.$boundary.$crlf;
- $body .= $crlf;
Code (PHP) : Убрать нумерацию
- $host='www.example.ru'; // Хост для приема файла
- $url='/uploader.php'; // URL скрипта для приема файла
- // Подготовить заголовок POST-запроса
- $header = 'POST '.$url.' HTTP/1.1'.$crlf;
- $header .= 'Host: '. $host . $crlf;
- $header .= 'User-Agent: Uploader/1.0.0'.$crlf;
- $header .= 'Content-Type: multipart/form-data; boundary='.$boundary.$crlf;
- $header .= 'Content-Length: '.strlen($body).$crlf;
- $header .= 'Connection: keep-alive'.$crlf;
- $header .= 'Keep-Alive: 300'.$crlf;
- $header .= $crlf;
Code (PHP) : Убрать нумерацию
- $port=80;
- $timeout=30;
- // Открыть соединение с сервером
- $f=fsockopen($host, $port, $errno, $errstr, $timeout);
- // Отправить файл на сервер данные
- fputs($f, $header.$body);
- // Получить ответ от удаленного сервера
- $response='';
- while(!feof($f)) {
- $line=fgets($f,1000);
- if ($line=='') { break; }
- $response.=$line;
- }
- echo $response;
- // Закрыть соединение с сервером
- fclose($f);
Code (PHP) : Убрать нумерацию
- echo 'Данные $_POST:<br>';
- print_r($_POST);
- echo 'Данные $_FILES:<br>';
- print_r($_FILES);
Данные $_POST:
Array (
[ext_field_1] => Some text data....
)
Данные $_FILES:
Array (
[my_file] => Array (
[name] => my_file.bin
[type] => application/octet-stream
[tmp_name] => /tmp/php1P8imr
[error] => 0
[size] => 100
)
)
Как видите, данные из несуществующей формы отправляются и принимаются успешно, в том числе и файлы. Обратите внимание, что в качестве $file_data могут быть любые данные, то есть мы можем отправлять на удаленные серверы "виртуальные" файлы, которые сгенерированы динамически и существуют только в памяти нашего процесса. Для больших объемов данных информацию на сервер можно отправлять по частям, однако заголовок Content-Length в любом случае должен содержать правильное значение.
Это не единственный способ передачи файлов, можно также воспользоваться cURL с методом PUT или функциями PHP file_put_contents и ftp_put, все зависит от поставленной задачи. Ну и конечно же не забывайте о безопасности ваших проектов и всегда проверяйте все полученные данные.
Просмотров: 1629 | Комментариев: 1
Комментарии
Отзывы посетителей сайта о статье
morgot
(03.02.2012 в 16:22):
Спасибо за статью, очень актуально и в тему!
Добавить комментарий
Заполните форму для добавления комментария
