ใช้ curl เพื่ออัพโหลดข้อมูล POST พร้อมไฟล์


414

ฉันต้องการใช้ cURL เพื่อส่งพารามิเตอร์ข้อมูลใน HTTP POST ไม่เพียง แต่จะอัปโหลดไฟล์ที่มีชื่อฟอร์มเฉพาะ ฉันควรจะทำอย่างไร

พารามิเตอร์ HTTP Post:

userid = 12345 filecomment = นี่คือไฟล์รูปภาพ

HTTP อัพโหลดไฟล์: ตำแหน่งไฟล์ = /home/user1/Desktop/test.jpg ชื่อแบบฟอร์มสำหรับไฟล์ = ภาพ (ตรงกับ $ _FILES ['image'] ที่ด้าน PHP)

ฉันคิดว่าเป็นส่วนหนึ่งของคำสั่ง 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 ได้อย่างไร

คำตอบ:


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

1
@DavidGelbart คุณพูดถูก คำตอบเริ่มต้นของฉันอ้างถึง-dตัวเลือกโดยไม่ตั้งใจซึ่งจำเป็นต้องใส่ URL ที่เข้ารหัส ฉันควรลบสิ่งนั้นเมื่อฉันอัพเดตคำตอบของ-Fตัวเลือก ขอบคุณสำหรับการจับที่
jimp

3
@ user956424 ในตัวอย่างตั้งค่า "รูปภาพ" เป็นชื่อของฟิลด์ของคุณ และบางภาษาเช่น PHP จะสร้างอาร์เรย์หากคุณระบุบางสิ่งเช่น "image []" สำหรับอินพุตที่จำเป็นต้องจัดกลุ่มเข้าด้วยกัน
jimp

1
คืออะไร@ในimage=@/..?
Timo

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"
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" vars ต่อไปโพสต์ คุณสามารถทดสอบกับสคริปต์นี้ได้อย่างง่ายดายและคุณควรได้รับ debugs นี้ในฟังก์ชัน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>";
}

มันควรจะทำงานได้ดีพวกเขาอาจเป็นทางออกที่ดีกว่า แต่มันใช้งานได้และเป็นประโยชน์อย่างมากในการทำความเข้าใจว่า Mime ของ Boundary และ Multipart / from-data ทำงานบน PHP และไลบรารี่ cURL ได้อย่างไร


ถ้าคุณต้องการส่งไฟล์ที่ไม่ได้เข้ารหัสเปลี่ยนบรรทัดนี้ $ BODY. = 'การเข้ารหัสการถ่ายโอนเนื้อหา: หลายส่วน / แบบฟอร์มข้อมูล' $ 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 แบบไบนารี
polis

4
@polis ตัวเลือก--data-binaryแนะนำcurlให้ไม่ทำการประมวลผลข้อมูลล่วงหน้าใด ๆ เมื่อเทียบกับการ--dataตั้งค่าสถานะ เพื่อระบุความคิดเห็นของคุณโดยตรงโปรดทราบว่าข้อความนั้นเป็นเลขฐานสอง แต่เราสามารถตีความมันเป็นอักขระ ASCII ได้ หากคุณต้องการตัวอย่างที่ชัดเจนลองนึกถึง CSV ที่มีฟิลด์ที่มีอิโมจิ ไบต์ของพวกเขาไม่ตรงกับข้อความ
Ciprian Tomoiagă

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 , it'a CLI ขดเหมือนเครื่องมือสำหรับมนุษย์

  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


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.