curlを使用してファイルを含むPOSTデータをアップロードする


414

cURLを使用して、HTTP POSTでデータパラメータを送信するだけでなく、特定のフォーム名でファイルをアップロードしたいと思います。どうすればいいですか?

HTTP Postパラメータ:

userid = 12345 filecomment =これは画像ファイルです

HTTPファイルのアップロード:ファイルの場所= /home/user1/Desktop/test.jpgファイルのフォーム名=画像(PHP側の$ _FILES ['image']に対応)

cURLコマンドの一部を次のように考えました。

curl -d "userid=1&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

問題は、PHPスクリプトでファイルを取得するために$ _FILES ['image']を使用していることです。

cURLコマンドをそれに応じて調整するにはどうすればよいですか?

回答:


656

-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ファイルを変更せずに問題なくアップロードしました。
Deanna Gelbart 2013年

1
@DavidGelbartそうですね。私の最初の答えは-d誤ってオプションを参照しましたが、これには入力URLエンコードが必要です。-Fオプションの回答を更新したときに、それを削除する必要がありました。それをキャッチしてくれてありがとう。
jimp 2013年

3
@ user956424例では、 "image"をフィールドの名前に設定します。また、PHPなどの一部の言語では、グループ化する必要のある入力に「image []」などを指定すると、配列が作成されます。
jimp

1
何である@ではimage=@/..
ティモ

2
@Timoこれは、名前付きフォームフィールドのコンテンツをファイルパスからロードする必要があることを意味します。それがなければ、文字列引数自体が渡されます。
jimp

93

ユーザーIDをパス変数としてキャッチする(推奨):

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

フォームの一部としてユーザーIDをキャッチする:

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/

16
-Fを設定する必要はありません"Content-Type: multipart/form-data"
William Hu

10
指定したセミコロン区切り文字で-Fを適切に機能させることができませんでした。代わりに、2つの冗長な-F引数を指定する必要がありました。例:-F "data=@test.mp3" -F "userid = 1234"
robbpriestley

22

これが私の解決策です。私はたくさんの投稿を読んでいますが、それらは本当に役に立ちました。最後に、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 = "\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

}

これで、次の変数が投稿された「api.endpoint.post」に到達するはずです。このスクリプトで簡単にテストできpostFile()、最後の行で関数のこのデバッグを受け取る必要があります。

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

それはうまくいくはずですが、より良い解決策かもしれませんが、これはうまくいき、Boundaryとmultipart / from-data mimeがPHPとcURLライブラリでどのように機能するかを理解するのに本当に役立ちます。


エンコードされていないファイルを送信する必要がある場合は、この行を変更します$ BODY。= 'Content-Transfer-Encoding:multipart / form-data'。$ eol。$ eol; //最後のコンテンツと2 $ eol、$ BODY。= file_get_contents($ file_url)を配置します。$ eol; //データを完成させるために、Base64ファイルコンテンツと$ eolを書き込みます
andreah

8

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'

4
バイナリのcsvファイルの例をご覧ください。
ポリス

4
@polisオプションは、フラグではなく、データの前処理を行わないように--data-binary指示curlします。コメントに直接対処するには、テキストもバイナリであることに注意してください。ただし、ASCII文字として解釈できます。明確な例が本当に必要な場合は、フィールドに絵文字が含まれているCSVについて考えてください。彼らのバイトはテキストに直接マッピングされません--data
CiprianTomoiagăMay

3

ここで私を導いた問題は、基本的なユーザーエラーであることがわかりました- @ファイルのパスに記号を含めなかったため、curlは内容ではなくファイルのパス/名前を投稿していました。Content-Lengthしたがって、この値は、テストファイルの長さを考慮して、予想される479ではなく8でした。

Content-Lengthカールは、ファイルを読み込み、投稿時にヘッダが自動的に計算されます。

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

... <コンテンツの長さ:479 ...

これをここに投稿して、将来他の初心者を支援します。


2

の代わりにcurlHTTPieを使用できます。HTTPieは、人間向けの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
    
    ...

2

多くの試行の後、このコマンドは私にとってうまくいきました:

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

1

アップロードされたファイルの任意のファイル名を正しくエスケープする方法はbash次のとおりです。

#!/bin/bash
set -eu

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.