关于shell:使用curl上传带有文件的POST数据

Using curl to upload POST data with files

我想使用curl不仅在HTTP Post中发送数据参数,而且上传具有特定表单名称的文件。我该怎么做呢?

HTTP POST参数:

用户ID=12345filecomment=这是图像文件

HTTP文件上载:文件位置=/home/user1/desktop/test.jpgfile=image的表单名称(对应于php端的$_files['image']

我计算了curl命令的一部分,如下所示:

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

我遇到的问题是:

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

问题是我正在使用$_files['image']来获取PHP脚本中的文件。

如何相应地调整卷曲命令?


您需要使用-F选项:江户十一〔一〕号

试试这个:

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


将用户ID捕获为路径变量(推荐):

1
2
curl -i -X POST -H"Content-Type: multipart/form-data"
-F"[email protected]" http://mysuperserver/media/1234/upload/

将用户ID作为表单的一部分捕获:

1
2
curl -i -X POST -H"Content-Type: multipart/form-data"
-F"[email protected];userid=1234" http://mysuperserver/media/upload/

或:

1
2
curl -i -X POST -H"Content-Type: multipart/form-data"
-F"[email protected]" -F"userid=1234" http://mysuperserver/media/upload/


这是我的解决方案,我已经读了很多帖子,它们真的很有用。最后,我为小文件编写了一些代码,使用curl和php,我认为这非常有用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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 ="

"; //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"上发布以下var。您可以很容易地使用这个脚本进行测试,并且应该在最后一行的函数postFile()上接收到这个调试。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
print_r($response); //print response

public function getPostFile()
{

    echo"

_SERVER
";
    echo"[cc]";
    print_r($_SERVER['HTTP_X_PARAM_TOKEN']);
    echo"/[cc]";
    echo"_POST
";
    echo"[cc]";
    print_r($_POST['sometext']);
    echo"/[cc]";
    echo"_FILES
";
    echo"[cc]";
    print_r($_FILEST['somefile']);
    echo"/[cc]";
}

它应该很好地工作,它们可能是更好的解决方案,但这确实有效,对于理解边界和multipart/from-data-mime如何在PHP和curl库上工作非常有帮助。


如果要上载二进制文件(如csv),请使用以下格式上载文件

1
2
3
4
5
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'


作为curl的替代品,你可以使用httpie,它是一个cli,一个人类的卷曲工具。

  • 安装说明:https://github.com/jakubroztocil/httpie安装

  • 然后,运行:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    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

    ...


  • 以下是如何正确转义bash上传文件的任意文件名:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #!/bin/bash
    set -eu

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

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