使用curl上传带有文件的POST数据


413

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

HTTP Post参数:

userid = 12345 filecomment =这是一个图像文件

HTTP文件上传:文件位置= /home/user1/Desktop/test.jpg文件的表单名称= image(对应于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

问题是我正在使用$ _FILES ['image']在PHP脚本中拾取文件。

如何相应地调整cURL命令?

Answers:


654

您需要使用以下-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

1
@DavidGelbart你是对的。我的最初答案-d错误地引用了该选项,该选项需要输入的URL编码。我在更新-F选项答案时应该已经删除了它。感谢您抓住这一点。
2013年

3
@ user956424在示例中,将“ image”设置为您的字段名称。如果您为需要分组的输入指定诸如“ image []”之类的内容,则某些语言(例如PHP)将构建一个数组。
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与您指定的分号分隔符一起正常工作。相反,我必须提供两个冗余的-F参数。就像:-F“ data=@test.mp3” -F“ userid = 1234”
robbpriestley16年

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; //我们放入最后一个Content和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文件的例子。
polis

4
@polis选项--data-binary指示curl进行数据的任何预处理,而不是--data标志。为了直接处理您的评论,请注意文本也是二进制的,但是我们可以将其解释为ASCII字符。如果您确实想要一个不同的示例,请考虑一个其字段包含表情符号的CSV。他们的字节不直接映射到文本
CiprianTomoiagă19年

3

导致我在这里出现的问题是一个基本的用户错误-我没有@在文件的路径中包括符号,因此curl在发布文件的路径/名称而不是内容。的Content-Length因此,值是8,而不是给定测试文件的预期长度时应该看到的479。

Content-Length头将卷曲时读取和职位的文件自动计算。

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

... <内容长度:479 ...

在此处发布此信息以帮助将来的其他新手。


2

作为替代curl,您可以使用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"

0

我明白了这个命令 curl -F 'filename=@/home/yourhomedirextory/file.txt' http://yourserver/upload

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.