Проглатывание — внешний файл «сквозной»

#php #guzzle

#php #guzzle

Вопрос:

Мне нужен способ загрузить большой файл с внешнего URL-адреса и отправить его в другое место назначения, фактически временно не сохраняя его локально. Загрузка обрабатывается внешним пакетом, который принимает либо ресурс, либо StreamInterface в качестве источника. Я просмотрел документацию guzzle, но не могу найти подходящего решения.

Пока я застрял с чем-то вроде этого:

 # Download
$client = new GuzzleHttpClient(['base_uri' => 'https://host.com']);
$resource = fopen('tmp_file', 'w');
$stream = GuzzleHttpPsr7stream_for($resource);
$client->request('GET', '/test.zip', [
    'sink' => $stream,
]);

# Upload
$uploadHandler->upload($stream);
  

К сожалению, это вообще не работает. Файл загружается полностью перед началом загрузки. Адресат также не получает полезный файл — я не могу видеть, что именно он получает, но он либо пуст, либо поврежден.

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

Выполнимо ли это вообще?

Ответ №1:

Вы пробовали потоковую передачу файла с помощью curl. Я пишу это здесь, поэтому может потребоваться дополнительное тестирование, но что-то вроде следующего:

 $curl = curl_init();
curl_setopt($curl, CURLOPT_URL, "http://remote.server/file_handler.php");
curl_setopt($curl, CURLOPT_USERPWD, "user:pass");

// to return the result as a string and not output it directly
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_PUT, true);

// This is the remote file and if it is a stream you will need it's content length
// meta_data will provide you with this
$file = 'http://host.com/test.zip';
$fp = fopen($file, "r");
$meta = stream_get_meta_data($fp);

curl_setopt($curl, CURLOPT_INFILESIZE, $meta['unread_bytes']);
curl_setopt($curl, CURLOPT_INFILE, $fp);

curl_exec($curl);

curl_close($curl);
fclose($fp); 
  

Для более интенсивной работы с сервером вы также можете взглянуть на службу ftp, предоставляемую php: https://www.php.net/manual/en/ref.ftp.php а точнее что-то вроде ftp_append или ftp_put.

Но моим предложением было бы сначала попробовать с вышеупомянутым скриптом.

P.S

переменная $file указывает на удаленный файл, как вы сказали http://host.com/test.zip а удаленный сервер — это строка внутри CURLOPT_URL. Теоретически, по крайней мере, вы передаете поток, который вы читаете, с одного удаленного сервера на другой удаленный сервер.

P.S

Таким образом, вы можете добавлять заголовки в fopen для удаленного файла.

 $options = [
    'http' => [
        'method'=>"GET",
        'header'=>"Accept-language: ENrn ANOTHER-HEADER: test=test"
    ]
];

$defineContext = stream_context_create($options);

$fp = fopen('http://host.com/test.zip', 'r', false, $defineContext);
  

Вы, мужчина, обратитесь к этому для получения более подробной информации: https://www.php.net/stream-context-create

Комментарии:

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

2. Вы не «загружаете» файл. Вы используете fp для открытия удаленного файла в виде потока (здесь вы можете использовать множество функций), а затем с помощью curl напрямую отправляете его на ваш удаленный сервер — обработчик с именем remote server ( http://yourremote.handler ).

3. У меня проблемы с пониманием вашего подхода. Не могли бы вы, пожалуйста, интегрировать исходный файл / URL (через который следует передавать), например host.com/test.zip и вызов обработчика загрузки (который ожидал либо ресурс, либо интерфейс StreamInterface) $uploadHandler->upload($stream); Спасибо

4. Я не могу использовать fopen () для исходного файла. И, как упоминалось, файл должен быть передан определенному методу ( $uploadHandler->upload($stream) ), который принимает либо ресурс, либо потоковый интерфейс.

5. О, теперь я понял.. К сожалению, похоже, что сначала загружается файл. Как только я передаю $ fp обработчику загрузки, я вижу в диспетчере задач, что загрузка на некоторое время ускоряется, только после этого скорость загрузки увеличивается. Таким образом, он по-прежнему сначала загружает его, а затем загружает : (