Upload com curl php

PHP 8.1: Curl: File uploads from strings with CURLStringFile

PHP Curl extension supports making HTTP(s) requests with file uploads. Since PHP 5.5, PHP Curl extension provides a CURLFile class that accepts a URI or a path to a file, a mime type, and a file name to upload it as.

With CURLFile class, it accepts a path or a URI, and not the contents itself. For files already stored on disk or any other stream, using CURLFile class is quite straight-forward:

$txt_curlfile = new \CURLFile('test.txt', 'text/plain', 'test.txt'); $ch = curl_init('http://example.com/upload.php'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, ['file' => $txt_curlfile]); curl_exec($ch);

Using CURLFile was difficult if the file being uploaded is already stored in the memory, or not written to disk. It was possible to use data:// URIs with Base64 encoding, but it was not straight forward.

$txt = 'test content'; $txt_file = 'data://application/octet-stream;base64,' . base64_encode($txt); $txt_curlfile = new \CURLFile($txt_file, 'text/plain', 'test.txt'); $ch = curl_init('http://example.com/upload.php'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, ['file' => $txt_curlfile]); curl_exec($ch);

From PHP 8.1 and later, Curl extension has a new CURLStringFile class, that works similar to CURLFile class, but accepts the contents of the file instead of a path or a URI.

$txt = 'test content'; $txt_curlfile = new \CURLStringFile($txt, 'text/plain', 'test.txt'); $ch = curl_init('http://example.com/upload.php'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, ['file' => $txt_curlfile]); curl_exec($ch);

The new CURLStringFile class makes it easy to make a Curl file upload request using data that is already stored in memory. Some example use cases include uploading an image that PHP processes and is stored in a PHP variable, a processed XML file, or a PDF file generated from a PHP library.

CURLStringFile class synopsis

  • Unlike CURLFile class, CURLStringFile class objects allow serializing and unserializing.
  • CURLStringFile objects can be clone. This is true for CURLFile instances as well.
  • CURLStringFile class enforces typed properties. It is not allowed to set values other than string values.

CURLStringFile Polyfill

Curl extension treats CURLFile class objects as a file upload, and it treats the same way for all classes that extend CURLFile .

Taking advantage of that, it is possible to create a polyfill for CURLStringFile .

class CURLStringFile extends CURLFile < public function __construct(string $data, string $postname, string $mime = "application/octet-stream") < $this->name = 'data://'. $mime .';base64,' . base64_encode($data); $this->mime = $mime; $this->postname = $postname; > >

Internally, the polyfilled CURLStringFile class behaves exactly same as a CURLFile class with a data:// URI, but it is not handled inside CURLStringFile::__construct hiding the complexity, and working as a polyfill.

Читайте также:  Python replace all occurrences

The polyfill above should work in all PHP versions >= 7.0.

Backwards Compatibility Impact

CURLStringFile is a new class from the Curl extension, and it will not be possible to use it in PHP versions older than PHP 8.1. However, it is possible to polyfill this class to older PHP versions.

© 2018-2023 PHP.Watch, with ❤ from Ayesh • About PHP.Watch

Источник

Загрузка файла на сервер без использования формы

Для HTTP запроса типа POST существует два варианта передачи полей из HTML форм, а именно, используя алгоритм application/x-www-form-urlencoded и multipart/form-data . Алгоритм первого типа создавался давным-давно, когда в языке HTML еще не предусматривали возможность передачи файлов через HTML формы.

Со временем возникла необходимость через формы отсылать еще и файлы. Тогда консорциум W3C взялся за доработку формата POST запроса. К тому времени уже достаточно широко применялся формат MIME (Multipurpose Internet Mail Extensions — многоцелевые расширения протокола для формирования Mail сообщений), поэтому, чтобы не изобретать велосипед заново, решили использовать часть данного формата формирования сообщений для создания POST запросов в протоколе HTTP.

Главное отличие multipart/form-data от application/x-www-form-urlencoded в том, что тело запроса теперь можно поделить на разделы, которые разделяются границами. Каждый раздел может иметь свой собственный заголовок для описания данных, которые в нем хранятся, т.е. в одном запросе можно передавать данные различных типов (как в теле письма можно одновременно с текстом передавать файлы). Пример запроса:

Content-Type: multipart/form-data; boundary=ff4ed67396bc8e1d6dbf19d65b6c6348 Content-Length: 417339 --ff4ed67396bc8e1d6dbf19d65b6c6348 Content-Disposition: form-data; name="name" Евгений --ff4ed67396bc8e1d6dbf19d65b6c6348 Content-Disposition: form-data; name="message" Какое-то сообщение от пользователя --ff4ed67396bc8e1d6dbf19d65b6c6348 Content-Disposition: form-data; name="upload"; filename="image.jpg" Content-Type: image/jpeg Content-Transfer-Encoding: binary . содержимое файла image.jpg. --ff4ed67396bc8e1d6dbf19d65b6c6348--

Boundary (граница) — это последовательность байтов, которая не должна встречаться внутри передаваемых данных. Content-Length — суммарный объём, включая дочерние заголовки. Само содержимое полей при этом оставляется «как есть».

CURL, multipart/form-data

$file = 'image.jpg'; $postdata = array( 'name' => 'Евгений', 'message' => 'Какое-то сообщение от пользователя', 'upload' => '@'.$file ); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, 'http://server.com/get.php'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, false); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30); curl_exec($ch); curl_close($ch);

Файл get.php на сервере http://server.com:

print_r($_POST); print_r($_FILES); move_uploaded_file($_FILES['upload']['tmp_name'], 'image.jpg');
Array ( [name] => Евгений [message] => Какое-то сообщение от пользователя ) Array ( [upload] => Array ( [name] => image.jpg [type] => application/octet-stream [tmp_name] => C:\Windows\Temp\php504D.tmp [error] => 0 [size] => 416919 ) )

Важный момент: на форуме PHPCLUB.RU встретил упоминание, что может потребоваться указание полного пути файла — иначе CURL выдает ошибку.

$file = 'C:/work/localhost/www/image.jpg';

CURL, application/x-www-form-urlencoded

$file = 'image.jpg'; // данные POST-запроса $postdata = array( 'name' => 'Евгений', 'message' => 'Какое-то сообщение от пользователя', 'upload' => file_get_contents($file) ); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, 'http://server.com/get.php'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, false); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30); curl_exec($ch); curl_close($ch);

Файл get.php на сервере http://server.com:

print_r($_POST); file_put_contents('image.jpg', $_POST['upload']);
Array ( [name] => Евгений [message] => Какое-то сообщение от пользователя [upload] => . содержимое файла image.jpg. )

Сокеты, multipart/form-data

// устанавливаем соединение с сервером $fp = fsockopen('server.com', 80, $errno, $errstr, 30); if (!$fp) die($errstr.' ('.$errno.')'); $name = 'Евгений'; $message = 'Какое-то сообщение от пользователя'; $file = 'image.jpg'; // содержимое файла $content = file_get_contents($file); // разделитель $boundary = md5(uniqid(time())); $body = '--'.$boundary."\r\n"; $body = $body.'Content-Disposition: form-data; name="name"'."\r\n\r\n"; $body = $body.$name."\r\n"; $body = $body.'--'.$boundary."\r\n"; $body = $body.'Content-Disposition: form-data; name="message"'."\r\n\r\n"; $body = $body.$message."\r\n"; $body = $body.'--'.$boundary."\r\n"; $body = $body.'Content-Disposition: form-data; name="upload"; filename="image.jpg"'."\r\n"; $body = $body.'Content-Type: image/jpeg'."\r\n"; $body = $body.'Content-Transfer-Encoding: binary'."\r\n\r\n"; $body = $body.$content."\r\n"; $body = $body.'--'.$boundary.'--'; // пишем в сокет метод, URI и протокол fwrite($fp, 'POST /get.php HTTP/1.1'."\r\n"); // а также имя хоста fwrite($fp, 'Host: server.com'."\r\n"); // отправляем заголовки fwrite($fp, 'Content-Type: multipart/form-data; boundary='.$boundary."\r\n"); fwrite($fp, 'Content-Length: '.strlen($body)."\r\n\r\n"); // теперь передаем данные fwrite($fp, $body); // получаем ответ $result = ''; while ( !feof($fp) ) $result .= fgets($fp, 1024); // закрываем соединение fclose($fp); // выводим ответ в браузер echo $result;

Файл get.php на сервере http://server.com:

print_r( $_POST ); print_r( $_FILES ); move_uploaded_file($_FILES['upload']['tmp_name'], 'image.jpg')
HTTP/1.1 200 OK Server: Apache/2.0 (Win32) PHP/5.1 X-Powered-By: PHP/5.1 Content-Length: 310 Array ( [name] => Евгений [message] => Какое-то сообщение от пользователя ) Array ( [upload] => Array ( [name] => image.jpg [type] => image/jpeg [tmp_name] => C:\Windows\Temp\phpA457.tmp [error] => 0 [size] => 416919 ) )

Сокеты, application/x-www-form-urlencoded

// устанавливаем соединение с сервером $fp = fsockopen('server.com', 80, $errno, $errstr, 30); if (!$fp) die($errstr.' ('.$errno.')'); $file = 'image.jpg'; // содержимое файла $content = file_get_contents($file); // данные POST-запроса $data = 'name=' . urlencode('Евгений') . '&message=' . urlencode('Какое-то сообщение от пользователя') . '&upload='.urlencode($content); // заголовоки запроса $headers = 'POST /get.php HTTP/1.1'."\r\n"; $headers .= 'Host: server.com'."\r\n"; $headers .= 'Content-type: application/x-www-form-urlencoded'."\r\n"; $headers .= 'Content-Length: '.strlen($data)."\r\n\r\n"; // отправляем запрос серверу fwrite($fp, $headers.$data); // получаем ответ $result = ''; while ( !feof($fp) ) $result .= fgets($fp, 1024); // закрываем соединение fclose($fp); // выводим ответ в браузер echo $result;

Файл get.php на сервере http://server.com:

print_r($_POST); file_put_contents('image.jpg', $_POST['upload']);
HTTP/1.1 200 OK Server: Apache/2.0 (Win32) PHP/5.1 X-Powered-By: PHP/5.1 Transfer-Encoding: chunked Array ( [name] => Евгений [message] => Какое-то сообщение от пользователя [upload] => . содержимое файла image.jpg. )

Метод PUT

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

$url = 'http://server.com/get.php'; $file = 'image.jpg'; // Открываем передаваемый файл на чтение для дальнейшей его передачи $fp = fopen($file, 'r'); // Инициализируем сеанс CURL $ch = curl_init(); // Указываем URL скрипта, который примет наш запрос. К имени скрипта // добавляем еще две переменные, передаваемые методом GET curl_setopt($ch, CURLOPT_URL, $url . '?name=' . urlencode('Евгений') . '&message=' . urlencode('Какое-то сообщение от пользователя')); // Дескриптор файла, который собираемся передать curl_setopt($ch, CURLOPT_INFILE, $fp); // Указываем размер отправляемого файла curl_setopt($ch, CURLOPT_INFILESIZE, filesize($file)); // Указываем, что файл передается методом PUT curl_setopt($ch, CURLOPT_PUT, 1); // Указываем, что будет производиться закачка на удаленный сервер curl_setopt($ch, CURLOPT_UPLOAD, 1); // Выполняем запрос CURL curl_exec($ch); // Завершаем сеанс CURL curl_close($ch);

Файл get.php на сервере http://server.com:

print_r($_GET); file_put_contents ('image.jpg', file_get_contents('php://input'));
Array ( [name] => Евгений [message] => Какое-то сообщение от пользователя )

Источник

Оцените статью