Использование cURL для загрузки данных POST с файлами

#django #curl #django-rest-framework

#оболочка #файл #завиток #Публикация #загрузка файла

Вопрос:

Я хотел бы использовать cURL не только для отправки параметров данных в HTTP POST, но и для загрузки файлов с определенным именем формы. Как мне следует это сделать ?

Параметры HTTP Post:

идентификатор пользователя = 12345 filecomment = Это файл изображения

Загрузка файла HTTP: Расположение файла = /home/user1/Desktop/test.jpg Имя формы для file = image (соответствует $_FILES[‘image’] на стороне PHP)

Я вычислил часть команды cURL следующим образом:

 curl -d "userid=1amp;filecomment=This is an image file" --data-binary @"/home/user1/Desktop/test.jpg" localhost/uploader.php
 

Проблема, с которой я сталкиваюсь, заключается в следующем:

 Notice: Undefined index: image in /var/www/uploader.php
 

Проблема в том, что я использую $_FILES[‘image’] для получения файлов в PHP-скрипте.

Как мне соответствующим образом настроить свои команды cURL ?

Ответ №1:

Вам нужно использовать -F опцию:
-F/--form <name=content> Specify HTTP multipart POST data (H)

Попробуй это:

 curl 
  -F "userid=1" 
  -F "filecomment=This is an image file" 
  -F "image=@/home/user1/Desktop/test.jpg" 
  localhost/uploader.php
 

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

1. Меня смущает часть о кодировании URL-адреса файла. Я загрузил файлы JPG и PNG, подобные этому, не изменяя их, без каких-либо проблем.

2. @DavidGelbart Ты прав. Мой первоначальный ответ ссылался на -d опцию по ошибке, для которой требуется кодирование входного URL. Я должен был удалить это, когда я обновил ответ на этот -F вариант. Спасибо, что уловили это.

3. @user956424 В примере задайте «image» для имени вашего поля. И некоторые языки, такие как PHP, создадут массив, если вы укажете что-то вроде «image []» для входных данных, которые необходимо сгруппировать вместе.

4. Что такое @ in image=@/.. ?

5. @Timo Это означает, что содержимое именованного поля формы должно быть загружено из пути к файлу. Без этого сам строковый аргумент передается.

Ответ №2:

Получение идентификатора пользователя в качестве переменной path (рекомендуется):

 curl -i -X POST -H "Content-Type: multipart/form-data" 
-F "data=@test.mp3" http://mysuperserver/media/1234/upload/
 

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

 curl -i -X POST -H "Content-Type: multipart/form-data" 
-F "data=@test.mp3;userid=1234" http://mysuperserver/media/upload/
 

или:

 curl -i -X POST -H "Content-Type: multipart/form-data" 
-F "data=@test.mp3" -F "userid=1234" http://mysuperserver/media/upload/
 

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

1. использовать -F не нужно устанавливать "Content-Type: multipart/form-data"

2. Я не смог заставить -F работать должным образом с указанным вами разделителем точек с запятой. Вместо этого мне пришлось предоставить два избыточных аргумента -F. Например: -F «data=@test.mp3 » -F «идентификатор пользователя=1234»

Ответ №3:

Вот мое решение, я читал много сообщений, и они были действительно полезны. Наконец, я написал некоторый код для небольших файлов с помощью cURL и PHP, который я считаю действительно полезным.

 public function postFile()
{    
        $file_url = "test.txt";  //here is the file route, in this case is on same directory but you can set URL too like "http://examplewebsite.com/test.txt"
        $eol = "rn"; //default line-break for mime type
        $BOUNDARY = md5(time()); //random boundaryid, is a separator for each param on my post curl function
        $BODY=""; //init my curl body
        $BODY.= '--'.$BOUNDARY. $eol; //start param header
        $BODY .= 'Content-Disposition: form-data; name="sometext"' . $eol . $eol; // last Content with 2 $eol, in this case is only 1 content.
        $BODY .= "Some Data" . $eol;//param data in this case is a simple post data and 1 $eol for the end of the data
        $BODY.= '--'.$BOUNDARY. $eol; // start 2nd param,
        $BODY.= 'Content-Disposition: form-data; name="somefile"; filename="test.txt"'. $eol ; //first Content data for post file, remember you only put 1 when you are going to add more Contents, and 2 on the last, to close the Content Instance
        $BODY.= 'Content-Type: application/octet-stream' . $eol; //Same before row
        $BODY.= 'Content-Transfer-Encoding: base64' . $eol . $eol; // we put the last Content and 2 $eol,
        $BODY.= chunk_split(base64_encode(file_get_contents($file_url))) . $eol; // we write the Base64 File Content and the $eol to finish the data,
        $BODY.= '--'.$BOUNDARY .'--' . $eol. $eol; // we close the param and the post width "--" and 2 $eol at the end of our boundary header.



        $ch = curl_init(); //init curl
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
                         'X_PARAM_TOKEN : 71e2cb8b-42b7-4bf0-b2e8-53fbd2f578f9' //custom header for my api validation you can get it from $_SERVER["HTTP_X_PARAM_TOKEN"] variable
                         ,"Content-Type: multipart/form-data; boundary=".$BOUNDARY) //setting our mime type for make it work on $_FILE variable
                    );
        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/1.0 (Windows NT 6.1; WOW64; rv:28.0) Gecko/20100101 Firefox/28.0'); //setting our user agent
        curl_setopt($ch, CURLOPT_URL, "api.endpoint.post"); //setting our api post url
        curl_setopt($ch, CURLOPT_COOKIEJAR, $BOUNDARY.'.txt'); //saving cookies just in case we want
        curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1); // call return content
        curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, 1); navigate the endpoint
        curl_setopt($ch, CURLOPT_POST, true); //set as post
        curl_setopt($ch, CURLOPT_POSTFIELDS, $BODY); // set our $BODY 


        $response = curl_exec($ch); // start curl navigation

     print_r($response); //print response

}
 

При этом мы должны получить в «api.endpoint.post» следующие опубликованные переменные. Вы можете легко протестировать с помощью этого скрипта, и вы должны получить эту отладку функции postFile() в последней строке.

 print_r($response); //print response

public function getPostFile()
{

    echo "nn_SERVERn";
    echo "<pre>";
    print_r($_SERVER['HTTP_X_PARAM_TOKEN']);
    echo "/<pre>";
    echo "_POSTn";
    echo "<pre>";
    print_r($_POST['sometext']);
    echo "/<pre>";
    echo "_FILESn";
    echo "<pre>";
    print_r($_FILEST['somefile']);
    echo "/<pre>";
}
 

Это должно работать хорошо, они могут быть лучшими решениями, но это работает и действительно полезно для понимания того, как граничный и многокомпонентный / исходящий из данных mime работает в PHP и библиотеке cURL.

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

1. если вам нужно отправить некодированный файл, измените эти строки $BODY.= ‘Content-Transfer-Encoding: multipart/form-data’ . $ eol . $eol; // помещаем последнее содержимое и 2 $eol, $BODY.= file_get_contents($file_url) . $eol; // мы записываем содержимое файла Base64 и $eol для завершения обработки данных,

Ответ №4:

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

 curl -X POST 
    'http://localhost:8080/workers' 
    -H 'authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6ImFjY2VzcyIsInR5cGUiOiJhY2Nlc3MifQ.eyJ1c2VySWQiOjEsImFjY291bnRJZCI6MSwiaWF0IjoxNTExMzMwMzg5LCJleHAiOjE1MTM5MjIzODksImF1ZCI6Imh0dHBzOi8veW91cmRvbWFpbi5jb20iLCJpc3MiOiJmZWF0aGVycyIsInN1YiI6ImFub255bW91cyJ9.HWk7qJ0uK6SEi8qSeeB6-TGslDlZOTpG51U6kVi8nYc' 
    -H 'content-type: application/x-www-form-urlencoded' 
    --data-binary '@/home/limitless/Downloads/iRoute Masters - Workers.csv'
 

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

1. Я хотел бы увидеть пример двоичного файла csv.

2. @polis опция --data-binary указывает curl не выполнять никакой предварительной обработки данных, в отличие от --data флага. чтобы обратиться к вашему комментарию напрямую, обратите внимание, что текст также двоичный, но мы можем интерпретировать его как символы ASCII. Если вам действительно нужен отличный пример, подумайте о CSV, поля которого содержат смайлики. Их байты напрямую не сопоставляются с текстом

3. если кто-нибудь ищет в Google: --data-binary работает с URL-адресом прямой загрузки AzureBlob docs.microsoft.com/en-us/rest/api/storageservices /…

4. Все данные в (типичном) компьютере являются двоичными. ASCII и UTF-8 являются двоичными кодировками для текстовых данных

Ответ №5:

После множества попыток эта команда сработала для меня:

 curl -v -F filename=image.jpg -F upload=@image.jpg http://localhost:8080/api/upload
 

Ответ №6:

Проблема, которая привела меня сюда, оказалась основной ошибкой пользователя — я не включал @ знак в путь к файлу, и поэтому curl отправлял путь / имя файла, а не содержимое. Следовательно, Content-Length значение было 8, а не 479, которые я ожидал увидеть, учитывая длину моего тестового файла.

Content-Length Заголовок будет автоматически вычислен, когда curl считывает и отправляет файл.

curl -i -H "Content-Type: application/xml" --data "@test.xml" -v -X POST https://<url>/<uri/

… < Длина содержимого: 479 …

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

Ответ №7:

В качестве альтернативы curl вы можете использовать HTTPie, it’a CLI, cURL-подобный инструмент для людей.

  1. Инструкции по установке: https://github.com/jakubroztocil/httpie#installation
  2. Затем запустите:
     http -f POST http://localhost:4040/api/users username=johnsnow photo@images/avatar.jpg
    
    HTTP/1.1 200 OK
    Access-Control-Expose-Headers: X-Frontend
    Cache-control: no-store
    Connection: keep-alive
    Content-Encoding: gzip
    Content-Length: 89
    Content-Type: text/html; charset=windows-1251
    Date: Tue, 26 Jun 2018 11:11:55 GMT
    Pragma: no-cache
    Server: Apache
    Vary: Accept-Encoding
    X-Frontend: front623311
    
    ...
     

Ответ №8:

Я понял, что это сработало с помощью этой команды curl -F 'filename=@/home/yourhomedirextory/file.txt' http://yourserver/upload

Ответ №9:

 cat test.txt 
 

файл test.txt содержание.

 curl -v -F "hello=word" -F "file=@test.txt" https://httpbin.org/post

> POST /post HTTP/2
> Host: httpbin.org
> user-agent: curl/7.68.0
> accept: */*
> content-length: 307
> content-type: multipart/form-data; boundary=------------------------78a9f655d8c87a53
> 
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
* We are completely uploaded and fine
< HTTP/2 200 
< date: Mon, 15 Nov 2021 06:18:47 GMT
< content-type: application/json
< content-length: 510
< server: gunicorn/19.9.0
< access-control-allow-origin: *
< access-control-allow-credentials: true
< 
{
  "args": {}, 
  "data": "", 
  "files": {
    "file": "file test.txt content.n"
  }, 
  "form": {
    "hello": "word"
  }, 
  "headers": {
    "Accept": "*/*", 
    "Content-Length": "307", 
    "Content-Type": "multipart/form-data; boundary=------------------------78a9f655d8c87a53", 
    "Host": "httpbin.org", 
    "User-Agent": "curl/7.68.0", 
    "X-Amzn-Trace-Id": "Root=1-6191fbc7-6c68fead194d943d07148860"
  }, 
  "json": null, 
  "origin": "43.129.xx.xxx", 
  "url": "https://httpbin.org/post"
}
 

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

1. Из всей страницы ответов это единственный ответ, который мне подходит. -F "file=@test.txt" . На серверной части FastAPI ожидает request.filename свойство в объекте запроса, которое мне все равно нужно использовать file=@... в curl запросе (потому что это обычно ожидается стандартной функцией endpoint FastAPI).

Ответ №10:

Вот как правильно экранировать произвольные имена файлов загруженных файлов с помощью bash :

 #!/bin/bash
set -eu

f="$1"
f=${f//\/\\}
f=${f//"/\"}
f=${f//;/\;}

curl --silent --form "uploaded=@"$f"" "$2"
 

Ответ №11:

сохраните все отправленные файлы в папку: файл php на хосте. u.php:

 <?php
$uploaddir = 'C:/VALID_DIR/';
 echo '<pre>';
foreach ($_FILES as $key => $file) {
    if(!isset($file) || !isset($file['name'])) continue;
    $uploadfile = $uploaddir . basename($file['name']);
   
    if (move_uploaded_file($file['tmp_name'], $uploadfile)) {
        echo "$key file > $uploadfile .n";
    } else {
        echo " Error $key  file.n";
    }
}
print_r($_FILES);
print "</pre>";?>
 

Использование от клиента:

 curl -v -F filename=ff.xml -F upload=@ff.xml https://myhost.com/u.php
 

Это сработало для меня.

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