Hochladen von POST-Daten mit Dateien mithilfe von Curl


413

Ich möchte cURL verwenden, um nicht nur Datenparameter in HTTP POST zu senden, sondern auch Dateien mit einem bestimmten Formularnamen hochzuladen. Wie soll ich das machen?

HTTP-Post-Parameter:

userid = 12345 filecomment = Dies ist eine Bilddatei

Hochladen der HTTP-Datei: Dateispeicherort = /home/user1/Desktop/test.jpg Formularname für Datei = Bild (entspricht $ _FILES ['Bild'] auf der PHP-Seite)

Ich habe einen Teil des Befehls cURL wie folgt dargestellt:

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

Das Problem, das ich bekomme, ist wie folgt:

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

Das Problem ist, dass ich $ _FILES ['image'] verwende, um Dateien im PHP-Skript abzurufen.

Wie passe ich meine cURL-Befehle entsprechend an?

Antworten:


654

Sie müssen die -FOption verwenden:
-F/--form <name=content> Specify HTTP multipart POST data (H)

Versuche dies:

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

1
Ich bin verwirrt von dem Teil über die URL-Codierung der Datei. Ich habe JPG- und PNG-Dateien wie diese hochgeladen, ohne sie zu ändern, ohne Probleme.
Deanna Gelbart

1
@ DavidGelbart Du hast recht. Meine erste Antwort bezog sich versehentlich auf die -dOption, für die die Eingabe-URL codiert werden muss. Ich hätte das entfernen sollen, als ich die Antwort auf die -FOption aktualisiert habe . Danke, dass du das verstanden hast.
Jimp

3
@ user956424 Setzen Sie im Beispiel "image" auf den Namen Ihres Feldes. Einige Sprachen, wie z. B. PHP, erstellen ein Array, wenn Sie für die Eingaben, die zusammen gruppiert werden müssen, "image []" angeben.
Jimp

1
Was ist das @in image=@/..?
Timo

2
@Timo Dies bedeutet, dass der Inhalt für das benannte Formularfeld aus einem Dateipfad geladen werden sollte. Ohne sie wird das String-Argument selbst durchlaufen.
Jimim

93

Abrufen der Benutzer-ID als Pfadvariable (empfohlen):

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

Abrufen der Benutzer-ID als Teil des Formulars:

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

oder:

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

16
benutze -F muss nicht gesetzt werden"Content-Type: multipart/form-data"
William Hu

10
Ich konnte -F nicht dazu bringen, mit dem von Ihnen angegebenen Semikolon-Trennzeichen richtig zu funktionieren. Stattdessen musste ich zwei redundante -F-Argumente angeben. Wie: -F "data=@test.mp3" -F "userid = 1234"
robbpriestley

22

Hier ist meine Lösung, ich habe viele Beiträge gelesen und sie waren wirklich hilfreich. Schließlich habe ich Code für kleine Dateien mit cURL und PHP geschrieben, die ich für sehr nützlich halte.

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 = "\r\n"; //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

}

Damit sollten wir auf der "api.endpoint.post" die folgenden vars posten. Sie können mit diesem Skript problemlos testen, und Sie sollten diese Debugs für die Funktion postFile()in der letzten Zeile erhalten.

print_r($response); //print response

public function getPostFile()
{

    echo "\n\n_SERVER\n";
    echo "<pre>";
    print_r($_SERVER['HTTP_X_PARAM_TOKEN']);
    echo "/<pre>";
    echo "_POST\n";
    echo "<pre>";
    print_r($_POST['sometext']);
    echo "/<pre>";
    echo "_FILES\n";
    echo "<pre>";
    print_r($_FILEST['somefile']);
    echo "/<pre>";
}

Es sollte gut funktionieren, es sind vielleicht bessere Lösungen, aber dies funktioniert und ist wirklich hilfreich, um zu verstehen, wie die MIME Boundary und Multipart / From-Data in PHP- und cURL-Bibliotheken funktioniert.


Wenn Sie eine nicht codierte Datei senden müssen, ändern Sie diese Zeilen $ BODY. = 'Content-Transfer-Encoding: Multipart / Formulardaten'. $ eol. $ eol; // Wir setzen den letzten Inhalt und 2 $ eol, $ BODY. = file_get_contents ($ file_url). $ eol; // Wir schreiben den Base64-Dateiinhalt und das $ eol, um die Daten
fertigzustellen.

8

Wenn Sie eine Binärdatei wie CSV hochladen, verwenden Sie das folgende Format, um die Datei hochzuladen

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'

4
Ich würde gerne ein Beispiel für eine binäre CSV-Datei sehen.
Polis

4
@polis die Option --data-binaryinstruiert , curlum nicht irgendeine Vorverarbeitung der Daten zu tun, im Gegensatz zu --dataFlagge. Um Ihren Kommentar direkt anzusprechen, beachten Sie, dass der Text ebenfalls binär ist, wir ihn jedoch als ASCII-Zeichen interpretieren können. Wenn Sie wirklich ein eindeutiges Beispiel wünschen, denken Sie an eine CSV, deren Felder Emoji enthalten. Ihre Bytes werden nicht direkt dem Text zugeordnet
Ciprian Tomoiagă

3

Das Problem, das mich hierher führte, stellte sich als grundlegender Benutzerfehler heraus - ich habe das nicht berücksichtigt @ Zeichen nicht in den Pfad der Datei aufgenommen, und so hat curl den Pfad / Namen der Datei und nicht den Inhalt veröffentlicht. Der Content-LengthWert war daher eher 8 als der Wert 479, den ich angesichts des Legten meiner Testdatei erwartet hatte.

Der Content-LengthHeader wird automatisch berechnet, wenn Curl die Datei liest und veröffentlicht.

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

... <Inhaltslänge: 479 ...

Veröffentlichen Sie dies hier, um anderen Neulingen in Zukunft zu helfen.


2

Alternativ dazu curlkönnen Sie HTTPie verwenden , ein CLI-ähnliches cURL-ähnliches Tool für Menschen.

  1. Installationsanweisungen: https://github.com/jakubroztocil/httpie#installation

  2. Dann renne:

    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
    
    ...

1

So können Sie beliebige Dateinamen hochgeladener Dateien korrekt umgehen mit bash:

#!/bin/bash
set -eu

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

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

1

Nach vielen Versuchen funktionierte dieser Befehl für mich:

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

0

Ich habe es mit diesem Befehl funktioniert curl -F 'filename=@/home/yourhomedirextory/file.txt' http://yourserver/upload

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.