Sử dụng curl để tải lên dữ liệu POST với các tệp


414

Tôi muốn sử dụng cURL để không chỉ gửi các tham số dữ liệu trong HTTP POST mà còn tải lên các tệp có tên biểu mẫu cụ thể. Làm thế nào tôi nên đi về làm điều đó?

Thông số bài viết HTTP:

userid = 12345 filecomment = Đây là một tệp hình ảnh

Tải lên tệp HTTP: Vị trí tệp = /home/user1/Desktop/test.jpg Tên biểu mẫu cho tệp = hình ảnh (tương ứng với $ _FILES ['image'] ở phía PHP)

Tôi đã tìm ra một phần của lệnh cURL như sau:

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

Vấn đề tôi nhận được là như sau:

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

Vấn đề là tôi đang sử dụng $ _FILES ['image'] để chọn các tệp trong tập lệnh PHP.

Làm cách nào để điều chỉnh các lệnh cURL của tôi cho phù hợp?

Câu trả lời:


656

Bạn cần sử dụng -Ftùy chọn:
-F/--form <name=content> Specify HTTP multipart POST data (H)

Thử cái này:

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

1
Tôi bối rối bởi một phần về mã hóa url tệp. Tôi đã tải lên các tệp JPG và PNG như thế này mà không sửa đổi chúng, mà không gặp vấn đề gì.
Deanna Gelbart

1
@DavidGelbart Bạn nói đúng. Câu trả lời ban đầu của tôi đã tham chiếu -dtùy chọn do nhầm lẫn, cần mã hóa URL đầu vào. Tôi nên xóa nó khi tôi cập nhật câu trả lời cho -Ftùy chọn. Cảm ơn đã nắm bắt điều đó.
dong dỏng

3
@ user956424 Trong ví dụ, đặt "hình ảnh" thành tên của trường của bạn. Và một số ngôn ngữ, chẳng hạn như PHP, sẽ xây dựng một mảng nếu bạn chỉ định một cái gì đó như "hình ảnh []" cho các đầu vào cần được nhóm lại với nhau.
dong dỏng

1
Là gì @trong image=@/..?
Timo

2
@Timo Có nghĩa là nội dung cho trường biểu mẫu được đặt tên sẽ được tải từ đường dẫn tệp. Không có nó, chính đối số chuỗi được truyền qua.
dong dỏng

93

Bắt id người dùng làm biến đường dẫn (được khuyến nghị):

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

Bắt id người dùng như một phần của biểu mẫu:

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

hoặc là:

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

16
sử dụng -F không cần thiết lập"Content-Type: multipart/form-data"
William Hu

10
Tôi không thể có được -F để hoạt động đúng với dấu phân cách dấu chấm phẩy mà bạn đã chỉ định. Thay vào đó, tôi đã phải cung cấp hai đối số -F dự phòng. Giống như: -F "data=@test.mp3" -F "userid = 1234"
robbpriestley

22

Đây là giải pháp của tôi, tôi đã đọc rất nhiều bài viết và chúng thực sự hữu ích. Cuối cùng tôi đã viết một số mã cho các tệp nhỏ, với cURL và PHP mà tôi nghĩ rằng nó thực sự hữu ích.

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

}

Với điều này, chúng ta sẽ nhận được trên "api.endpoint.post" các vars sau đây được đăng. Bạn có thể dễ dàng kiểm tra với tập lệnh này và bạn sẽ nhận được các lỗi này trên hàmpostFile() ở hàng cuối cùng.

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

Nó nên hoạt động tốt, chúng có thể là giải pháp tốt hơn nhưng điều này hoạt động và thực sự hữu ích để hiểu cách Mime ranh giới và đa dữ liệu / từ dữ liệu hoạt động trên thư viện PHP và cURL.


nếu bạn cần gửi tệp không được mã hóa, hãy thay đổi dòng này $ BODY. = 'Content-Transfer-Encoding: Multipart / form-data'. $ eol. $ eol; // chúng tôi đặt Nội dung cuối cùng và 2 $ eol, $ BODY. = file_get_contents ($ file_url). $ eol; // chúng tôi viết Nội dung tệp Base64 và $ eol để hoàn tất dữ liệu,
andreah

8

nếu bạn đang tải lên tệp nhị phân như csv, hãy sử dụng định dạng bên dưới để tải lên tệp

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
Tôi muốn xem một ví dụ về tệp csv nhị phân.
Polis

4
@polis tùy chọn --data-binarychỉ thị curlđể không làm bất cứ pre-chế biến của dữ liệu, như trái ngược với --datacờ. để giải quyết trực tiếp bình luận của bạn, lưu ý rằng văn bản cũng là nhị phân, nhưng chúng ta có thể hiểu nó là các ký tự ASCII. Nếu bạn thực sự muốn một ví dụ riêng biệt, hãy nghĩ về một CSV có các trường chứa biểu tượng cảm xúc. Các byte của họ không trực tiếp ánh xạ tới văn bản
Ciprian Tomoiagă

3

Vấn đề dẫn đến tôi ở đây hóa ra là lỗi người dùng cơ bản - Tôi đã không bao gồm @dấu hiệu trong đường dẫn của tệp và vì vậy curl đã đăng đường dẫn / tên của tệp chứ không phải nội dung. CácContent-Length do đó giá trị là 8 chứ không phải là 479 tôi mong đợi để xem trao legnth của tập tin thử nghiệm của tôi.

Các Content-Lengthtiêu đề sẽ được tự động tính toán khi curl đọc và viết các tập tin.

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

... <Độ dài nội dung: 479 ...

Đăng bài này ở đây để hỗ trợ những người mới khác trong tương lai.


2

Thay thế cho curl, bạn có thể sử dụng HTTPie , đó là CLI, công cụ giống như cURL cho con người.

  1. Hướng dẫn cài đặt: https://github.com/jakubroztocil/httpie#installation

  2. Sau đó chạy:

    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

Sau rất nhiều lần thử, lệnh này đã có hiệu quả với tôi:

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

1

Dưới đây là cách thoát chính xác tên tệp tùy ý của các tệp được tải lên bằng bash:

#!/bin/bash
set -eu

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

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

0

Tôi đã làm cho nó hoạt động với lệnh này curl -F 'filename=@/home/yourhomedirextory/file.txt' http://yourserver/upload

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.