【问题标题】:Using cURL to upload POST data with files使用 cURL 上传带有文件的 POST 数据
【发布时间】:2012-09-21 23:29:33
【问题描述】:

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

HTTP Post 参数:

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

HTTP 文件上传: 文件位置 = /home/user1/Desktop/test.jpg file = 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 命令?

【问题讨论】:

    标签: shell file curl post file-upload


    【解决方案1】:

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

    【讨论】:

    • 我对文件的 url 编码部分感到困惑。我已经上传了这样的JPG和PNG文件,没有修改它们,没有任何问题。
    • @DavidGelbart 你是对的。我最初的答案错误地引用了-d 选项,它需要输入 URL 编码。当我更新-F 选项的答案时,我应该删除它。感谢您了解这一点。
    • @user956424 在示例中,将“image”设置为您的字段名称。如果您为需要组合在一起的输入指定类似“image[]”之类的内容,某些语言(例如 PHP)将构建一个数组。
    • image=@/.. 中的@ 是什么?
    • @Timo 这意味着命名表单字段的内容应该从文件路径加载。没有它,字符串参数本身就会被传递。
    【解决方案2】:

    将用户 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/
    

    【讨论】:

    • 使用 -F 不需要设置"Content-Type: multipart/form-data"
    • 我无法让 -F 与您指定的分号分隔符一起正常工作。相反,我必须提供两个冗余的 -F 参数。比如:-F "data=@test.mp3" -F "userid=1234"
    【解决方案3】:

    这是我的解决方案,我已经阅读了很多帖子,它们真的很有帮助。最后我为小文件写了一些代码,用 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>";
    }
    

    它应该很好用,它们可能是更好的解决方案,但它确实有效,并且对于理解边界和 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 来完成数据,
    【解决方案4】:

    如果您要上传 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'
    

    【讨论】:

    • 我想看一个二进制 csv 文件的例子。
    • @polis 选项--data-binary 指示curl 对数据进行任何预处理,而不是--data 标志。要直接解决您的评论,请注意文本也是二进制的,但我们可以将其解释为 ASCII 字符。如果您真的想要一个独特的示例,请考虑一个字段包含表情符号的 CSV。它们的字节不直接映射到文本
    • 如果有人在谷歌搜索:--data-binary 适用于 AzureBlob 直接上传 url docs.microsoft.com/en-us/rest/api/storageservices/…
    【解决方案5】:

    经过多次尝试,这个命令对我有用:

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

    【讨论】:

      【解决方案6】:

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

      Content-Length 标头会在 curl 读取和发布文件时自动计算出来。

      curl -i -H "Content-Type: application/xml" --data "@test.xml" -v -X POST https://&lt;url&gt;/&lt;uri/

      ...

      在此发布以帮助其他新手。

      【讨论】:

        【解决方案7】:

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

        【讨论】:

          【解决方案8】:

          这里是如何正确转义上传文件的任意文件名bash

          #!/bin/bash
          set -eu
          
          f="$1"
          f=${f//\\/\\\\}
          f=${f//\"/\\\"}
          f=${f//;/\\;}
          
          curl --silent --form "uploaded=@\"$f\"" "$2"
          

          【讨论】:

            【解决方案9】:

            我已经用这个命令curl -F 'filename=@/home/yourhomedirextory/file.txt' http://yourserver/upload

            【讨论】:

              【解决方案10】:
              cat test.txt 
              

              文件 test.txt 内容。

              curl -v -F "hello=word" -F "file=@test.txt" https://httpbin.org/post
              
              > POST /post HTTP/2
              > Host: httpbin.org
              > user-agent: curl/7.68.0
              > accept: */*
              > content-length: 307
              > content-type: multipart/form-data; boundary=------------------------78a9f655d8c87a53
              > 
              * Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
              * We are completely uploaded and fine
              < HTTP/2 200 
              < date: Mon, 15 Nov 2021 06:18:47 GMT
              < content-type: application/json
              < content-length: 510
              < server: gunicorn/19.9.0
              < access-control-allow-origin: *
              < access-control-allow-credentials: true
              < 
              {
                "args": {}, 
                "data": "", 
                "files": {
                  "file": "file test.txt content.\n"
                }, 
                "form": {
                  "hello": "word"
                }, 
                "headers": {
                  "Accept": "*/*", 
                  "Content-Length": "307", 
                  "Content-Type": "multipart/form-data; boundary=------------------------78a9f655d8c87a53", 
                  "Host": "httpbin.org", 
                  "User-Agent": "curl/7.68.0", 
                  "X-Amzn-Trace-Id": "Root=1-6191fbc7-6c68fead194d943d07148860"
                }, 
                "json": null, 
                "origin": "43.129.xx.xxx", 
                "url": "https://httpbin.org/post"
              }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2018-07-19
                • 1970-01-01
                • 2021-05-08
                • 2019-10-16
                • 2015-01-02
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多