2010-08-10 32 views
6

Tôi đang gặp sự cố khi đăng một mảng đa chiều với các tệp tải lên bằng PHP và CURL.Cách tải lên tệp (multipart/form-data) với POSTFIELDS đa chiều bằng cách sử dụng PHP và CURL?

Mảng đa chiều là ví dụ:

$post['question'] = 'Are you human?'; 
$post['answers'] = array('yes', 'no', 'maybe'); 
$post['file'] = '@/path/to/file'; 

// Output: 

Array(
    'question' => Are you human?, 
    'answers' => Array(
     '0' => yes, 
     '1' => no, 
     '2' => maybe 
     ), 
    'file' => @/path/to/file 
) 

Có một vài điều tại sao điều này sẽ không hoạt động nếu bạn chỉ đơn giản là cố gắng đăng bài này với CURLOPT_POSTFIELDS trong CURL như thế này:

$ch = curl_init(); 

curl_setopt($ch, CURLOPT_URL, 'http://example.com'); 
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 
curl_setopt($ch, CURLOPT_POST, true); 
curl_setopt($ch, CURLOPT_POSTFIELDS, $post); 

$response = curl_exec($ch); 

Đầu tiên của tất cả các chính thức PHP description của CURLOPT_POSTFIELDS nói:

Dữ liệu đầy đủ để đăng trong hoạt động HTTP "POST" . Để đăng tệp, hãy thêm một tên tệp bằng @ và sử dụng đường dẫn đầy đủ. này có thể được thông qua như là một chuỗi urlencoded như 'para1 = VAL1 & para2 = VAL2 & ...' hoặc như một mảng với tên trường như dữ liệu quan trọng và lĩnh vực như giá trị. Nếu giá trị là một mảng , tiêu đề Loại nội dung sẽ là được đặt thành nhiều phần/biểu mẫu dữ liệu.

Có vẻ như bạn có thể chuyển bất kỳ loại mảng nào cho POSTFIELDS phải không? Sai rồi. POSTFIELDS chỉ chấp nhận các giá trị không vô hướng và sẽ bị nghẹt thở với lỗi Array to string conversion khi truyền các mảng đa chiều. Vì vậy, lựa chọn duy nhất khác bạn có là để http_build_query() mảng của bạn để có thể vượt qua mảng đa chiều mà không bị nghẹt thở.

Nhưng .. như bạn có thể đọc trong ghi chú trên trang PHP:

Lưu ý: Đi qua một mảng để CURLOPT_POSTFIELDS sẽ mã hóa các dữ liệu như multipart/form-data, trong khi đi qua một URL chuỗi được mã hóa sẽ mã hóa dữ liệu là ứng dụng/x-www-form-urlencoded.

Bài đăng sẽ không được mã hóa đa dạng/biểu mẫu nếu bạn chuyển chuỗi được mã hóa url đến POSTFIELDS, khiến tệp của bạn tải lên không thành công.

Vì vậy, có vẻ như gần như không thể kết hợp hai với CURL, trong khi nó sẽ không là vấn đề nếu bạn đã sử dụng biểu mẫu HTML thông thường.

Câu hỏi của tôi là: có thể bỏ qua quirk lạ này của CURL để có thể đăng mảng đa chiều và tải lên tệp không?

Trả lời

6

multipart/form-data không hỗ trợ giá trị lồng nhau. Và tôi không tin CURL cũng có thể làm được.

Tôi nghi ngờ kết thúc yêu cầu của bạn cũng là một tập lệnh PHP. Nếu, sau đó bạn có thể gửi một mảng lồng nhau là một trong những giá trị, nếu bạn chỉ cần chuẩn bị cho mình:

$post['answers[0]'] = "yes"; 
$post['answers[1]'] = "no"; 
$post['answers[2]'] = "maybe"; 

Về mặt lý thuyết bạn muốn chỉ cần 'answers[]' mà không cần chỉ mục, nhưng điều đó sẽ ghi đè lên giá trị preceeding - và do đó chỉ hoạt động với http_build_query.

Tôi không chắc liệu có bất kỳ thư viện HTTP nào trong PHP có thể tự động thực hiện việc này hay không.

+0

Tôi thích cách giải quyết này, cảm ơn. – Melvin

+0

Bí quyết tuyệt vời, nó hoạt động như một sự quyến rũ! – aknatn

2

Một cách khác để hoàn thành câu trả lời đầu tiên:

foreach(array("yes","no","maybe") as $key=>$value) 
    $post["answers[$key]"] = $value;
+0

Điều này sẽ không hoạt động đối với các mảng đa chiều –

1

Hãy thử chức năng đệ quy này.

https://gist.github.com/yisraeldov/ec29d520062575c204be7ab71d3ecd2f

<?php 
function build_post_fields($data,$existingKeys='',&$returnArray=[]){ 
    if(($data instanceof CURLFile) or !(is_array($data) or is_object($data))){ 
     $returnArray[$existingKeys]=$data; 
     return $returnArray; 
    } 
    else{ 
     foreach ($data as $key => $item) { 
      build_post_fields($item,$existingKeys?$existingKeys."[$key]":$key,$returnArray); 
     } 
     return $returnArray; 
    } 
} 

Và bạn có thể sử dụng nó như thế này.

curl_setopt($ch, CURLOPT_POSTFIELDS, build_post_fields($postfields)); 
Các vấn đề liên quan