Utilizzo dell'arricciatura per caricare i dati POST con i file


415

Vorrei utilizzare cURL non solo per inviare i parametri di dati in HTTP POST ma anche per caricare file con un nome di modulo specifico. Come dovrei farlo?

Parametri HTTP Post:

userid = 12345 filecomment = Questo è un file di immagine

Caricamento file HTTP: Posizione file = /home/user1/Desktop/test.jpg Nome modulo per file = immagine (corrisponde a $ _FILES ['immagine'] sul lato PHP)

Ho calcolato parte del comando cURL come segue:

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

Il problema che sto riscontrando è il seguente:

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

Il problema è che sto usando $ _FILES ['image'] per raccogliere i file nello script PHP.

Come posso adattare i miei comandi cURL di conseguenza?

Risposte:


657

Devi usare l' -Fopzione:
-F/--form <name=content> Specify HTTP multipart POST data (H)

Prova questo:

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

1
Sono confuso dalla parte sulla codifica dell'URL del file. Ho caricato file JPG e PNG come questo senza modificarli, senza problemi.
Deanna Gelbart,

1
@DavidGelbart Hai ragione. La mia risposta iniziale ha fatto riferimento -dall'opzione per errore, che richiede la codifica dell'URL di input. Avrei dovuto rimuoverlo quando ho aggiornato la risposta -Fall'opzione. Grazie per averlo colto.
jimp

3
@ user956424 Nell'esempio, imposta "immagine" sul nome del tuo campo. E alcune lingue, come PHP, costruiranno un array se specifichi qualcosa come "image []" per gli input che devono essere raggruppati insieme.
jimp

1
Qual è il @in image=@/..?
Timo,

2
@Timo Significa che il contenuto del campo modulo denominato deve essere caricato da un percorso di file. Senza di essa viene passato l'argomento stringa stesso.
jimp

94

Cattura dell'ID utente come variabile di percorso (consigliata):

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

Cattura dell'ID utente come parte del modulo:

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

o:

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

16
uso -F non è necessario impostare"Content-Type: multipart/form-data"
William Hu

10
Non riesco a far funzionare correttamente -F con quel separatore punto e virgola che hai indicato. Invece, ho dovuto fornire due argomenti -F ridondanti. Come: -F "data=@test.mp3" -F "userid = 1234"
robbpriestley

22

Ecco la mia soluzione, ho letto molti post e sono stati davvero utili. Alla fine ho scritto del codice per piccoli file, con cURL e PHP che ritengo davvero utili.

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

}

Con questo dovremmo essere sul "api.endpoint.post" postati i seguenti parametri. Puoi facilmente provare con questo script e dovresti ricevere questi debug sulla funzione postFile()nell'ultima riga.

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>";
}

Dovrebbe funzionare bene, potrebbero essere soluzioni migliori ma questo funziona ed è davvero utile per capire come funziona il confine e il mime multipart / from-data sulla libreria PHP e cURL.


se devi inviare file non codificati, modifica questa riga $ BODY. = 'Codifica trasferimento contenuto: multipart / form-data'. $ eol. $ EOL; // mettiamo l'ultimo contenuto e 2 $ eol, $ BODY. = file_get_contents ($ file_url). $ EOL; // scriviamo il contenuto del file Base64 e $ eol per completare i dati,
andreah

8

se stai caricando un file binario come csv, usa il formato seguente per caricare il file

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
Vorrei vedere un esempio di un file csv binario.
polis

4
@polis l'opzione --data-binaryindica curldi non eseguire alcuna pre-elaborazione dei dati, al contrario di --dataflag. per rispondere direttamente al tuo commento, nota che anche il testo è binario, ma possiamo interpretarlo come caratteri ASCII. Se vuoi davvero un esempio distinto, pensa a un CSV i cui campi contengono emoji. I loro byte non si
associano

3

Il problema che mi ha portato qui si è rivelato un errore di base dell'utente: non includevo il @segno nel percorso del file e quindi curl stava pubblicando il percorso / nome del file anziché il contenuto. Il Content-Lengthvalore era quindi 8 anziché il 479 che mi aspettavo di vedere dato il legnth del mio file di test.

L' Content-Lengthintestazione verrà calcolata automaticamente quando l'arricciatura legge e pubblica il file.

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

... <Lunghezza contenuto: 479 ...

Pubblicando questo qui per aiutare altri neofiti in futuro.


2

In alternativa a curl, puoi usare HTTPie , è un CLI, uno strumento simile a cURL per l'uomo.

  1. Istruzioni per l'installazione: https://github.com/jakubroztocil/httpie#installation

  2. Quindi, esegui:

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

2

Dopo molti tentativi questo comando ha funzionato per me:

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

1

Ecco come sfuggire correttamente ai nomi di file arbitrari dei file caricati con bash:

#!/bin/bash
set -eu

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

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

0

Ho funzionato con questo comando curl -F 'filename=@/home/yourhomedirextory/file.txt' http://yourserver/upload

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.