Справочник по PHP : Советы : Как отправить файл на сервер

смотрим также
    Какой официальный сайт футбольного клуба эвертон.

Материал из Справочник Web-языков

Перейти к: навигация, поиск


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

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

Я решил эту задачу двумя методами, и хочу поделиться ими с вами ...

Метод №1: отправка файла методом POST

Идея заключается в том, что на сайте "A" формируется POST-запрос, который в себе содержит название и содержимое файла, который нужно передать, и посылается на сайт "B". На сайте "B" POST-запрос принимается, и в указанный файл пишется указанное содержимое.

Технологию передачи POST-запроса из PHP-скрипта я возложил на сокеты.

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

Примерный вид строки, отсылаемый на сервер, может быть таким:

$zapros = <<
EQQ;

Как вы видите, переменные в POST-запросе задаются как при GET-запросе, т.е. var1=val1&var2=val2

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

$fp = fsockopen('server_B', 80, $errno, $errstr, 30);

Отдаем данные в открытый сокет и читаем ответ сервера "B":

fwrite($fp, $zapros);
while (!feof($fp)) {
	$this->res .= fgets($fp, 128);
}

Закрываем сокет:

fclose($fp);

В результате работы скрипта с сайта "A" уходит POST-запрос на сайт "B", а именно в скрипт import.php, находящийся в корне сайта "B". Т.е. запускается скрипт import.php, где в сценарии будет доступен массив $_POST, содержащий переменные filename и content.

Все, что нам нужно, так это открыть на запись файл с именем $_POST['filename'], и записать туда данные из переменной $_POST['content']:

$file = fopen($_POST['filename'], 'w+');
fwrite($file, $_POST['content']);
fclose($file);

Все! Файл принят и сохранен!

Но есть одно НО: передаваемый файл может быть любого типа. И бинарный и текстовой. Как вы видели, содержимое файла передается в POST-запросе в виде var1=val1&var2=val2, т.е. если <здесь содержимое файла file.zip> будет бинарным, или содержать URL-значащие символы, то целостность передаваемого файла может быть нарушена, или файл не будет передан вообще!

Чтобы этого избежать, содержимое файла перед отправкой необходимо преобразовать к URL-неактивному виду. Сделать это можно при помощи функции base64_encode():

$file_content = base64_encode("<содержимое файла>");

и уже переменную $file_content вставлять в POST-запрос:


$zapros = <<

В этом случае содержимое файла будет передано в "безопасном" виде.

Прием и "дешифрацию" содержимого файла на сайте "B" можно осуществить при помощи функции base64_decode():


$file = fopen($_POST['filename'], 'w+');
fwrite($file, base64_decode($_POST['content']));
fclose($file);

Стоит отметить, что данный способ прекрасно работает для относительно небольших файлов (примерно до 2-х мегабайт, для получения более точного значения необходимо смотреть в настройках PHP максимальный объем принимаемых данных методом POST).

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

Метод №2: отправка файла методом PUT

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

Для этого воспользуемся библиотекой curl.

Краткая аннотация:

В PHP включена поддержка libcurl - библиотеки функций, написанной Daniel Stenberg, которая позволяет взаимодействовать с
различными серверами по различным протоколам. В настоящее время libcurl поддерживает протоколы http, https, ftp, gopher, telnet,
dict, file, и ldap. libcurl также умеет работать с сертификатами HTTPS, посылать запросы к HTTP серверам методами POST и PUT,
закачивать файлы по протоколам HTTP и FTP (последнее можно сделать также используя модуль FTP), использовать прокси-серверы,
cookies и аутентификацию пользователей.

Для передачи файла методом PUT нам необходимо инициализировать сеанс CURL, задать для сеанса необходимые параметры, выполнить запрос CURL и закрыть сеанс.

Следующий пример демонстрирует передачу файла file.zip серверу "B":

<?php
// Задаем скрипт на сайте B, который примет наш запрос и обработает его
$url = 'http://server_B/import.php';

// Указываем файл, который мы хотим передать сайту B
// Если файл находится не в текущей дирректории, то необходимо
// указать путь до файла
$file = 'file.zip';

// Узнаем размер передаваемого файла
$filesize = filesize($file);

// Узнаем имя файла (в случае, если в $file указан полный путь до файла)
$pathinfo = pathinfo($file);
$filename = $pathinfo['basename'];

// Открываем передаваемый файл на чтение
// для дальнейшей его передачи
$fp = fopen($file, 'r');

// Инициализируем сеанс CURL
$ch = curl_init();

// Задаем параметры для открытого сеанса CURL

// Указываем URL скрипта, который примет наш запрос
// К имени скрипта добавляем переменную, содержащую имя передаваемого файла
// Чтобы это имя было доступно в принимающем скрипте из массива $_GET
curl_setopt($ch, CURLOPT_URL, $url . '?filename=' . $filename);

// Указываем файл (а вернее дескриптор открытого на чтение файла), который собираемся передать
curl_setopt($ch, CURLOPT_INFILE, $fp);

// Указываем предполагаемый размер отправляемого файла
curl_setopt($ch, CURLOPT_INFILESIZE, $filesize);

// Указываем, что файл передается методом PUT
curl_setopt($ch, CURLOPT_PUT, true);

// Указываем, что будет производиться закачка на удаленный сервер
curl_setopt($ch, CURLOPT_UPLOAD, true);

// Выполняем запрос CURL
curl_exec($ch);

// Завершаем сеанс CURL
curl_close($ch);

?>

После выполнения этого сценария с сайта "A" на сайт "B" уйдет PUT-запрос, в котором будет находится содержимое передаваемого файла, а в GET-запросе будет содержаться название передаваемого файла.

Далее нам необходимо организовать прием файла на сайте "B".

Для этого в скрипте import.php, находящегося на сайте "B", из массива $_GET мы должны получить название файла, а из входного потока - содержимое файла:

<?php

// Определяем имя файла
// Если не определено, задаем как unknow.dat
$filename = (isset($_GET['filename'])) ? $_GET['filename'] : 'unknow.dat';

// Получаем содержимое входящего потока
$content = file_get_contents('php://input');

// Записываем содержимое потока в файл
$file = fopen($filename, 'w+');
fwrite($file, $content);
fclose($file);

?>

Таким методом можно передавать файлы больших объемов.

Стоит наверное также упомянуть, что приведенные выше два способа передачи файлов не являются единственно возможными способами. Например, можно передавать файлы из PHP-скриптов на удаленные сервера по FTP-протоколу (используя тот же CURL или специальные функции PHP, такие как ftp_connect(), ftp_login(), ftp_put() и т.д.). Но ведь доступ к сайту по FTP может быть затруднен (не известны имя пользователя и пароль, или они были изменены на сервере но не изменены в скриптах и т.д.). А указанный здесь способ будет корректно работать на любых типах хостинга (исключая разве что некоторые бесплатные хостинги, где запрещен прием данных с других сайтов).

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

Добавить страницу в закладки:
РАЗРЕШАЕТСЯ перепечатывать и копировать информацию ТОЛЬКО ПРИ РАЗМЕЩЕНИИ ссылки на оригинал!
(<A href="http://www.spravkaweb.ru/">Справочник Web-языков</A>)
другие проекты
Rambler\'s Top100 Индекс цитирования