PHP curl_setopt($ch, CURLOPT_POSTFIELDS, $data) 若傳入陣列,會自動編碼為 multipart/form-data 或 application/x-www-form-urlencoded。但多維陣列需轉換為「方括號語法」的一維陣列(如 user[name]=John&user[age]=25),cURL 才能正確發送巢狀結構。本文提供遞迴扁平化函式與使用範例。
<?php
/**
* 多維陣列轉換為 cURL 可用的一維陣列(方括號語法)
* @param array $params 來源陣列
* @param string $prefix 遞迴前綴(內部使用)
* @return array 扁平化後的陣列
*/
function toPostArray(array $params, string $prefix = ''): array {
$result = [];
foreach ($params as $key => $val) {
$newKey = $prefix ? "{$prefix}[{$key}]" : $key;
if (is_array($val)) {
// 遞迴處理子陣列
$result = array_merge($result, toPostArray($val, $newKey));
} else {
$result[$newKey] = $val;
}
}
return $result;
}
?>
<?php
$data = [
'user' => [
'name' => 'John',
'age' => 25,
'address' => [
'city' => 'Taipei',
'zip' => '100',
'tags' => ['vip', 'early-bird'], // 數值索引陣列
],
],
'action' => 'register',
'source' => ['web', 'mobile'], // 根層數值索引
];
$postData = toPostArray($data);
print_r($postData);
/*
Array
(
[user[name]] => John
[user[age]] => 25
[user[address][city]] => Taipei
[user[address][zip]] => 100
[user[address][tags][0]] => vip
[user[address][tags][1]] => early-bird
[action] => register
[source[0]] => web
[source[1]] => mobile
)
*/
// 直接傳給 cURL
$ch = curl_init('https://api.example.com/endpoint');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); // 自動編碼為 application/x-www-form-urlencoded
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
?>
POST /endpoint HTTP/1.1 Host: api.example.com Content-Type: application/x-www-form-urlencoded Content-Length: 156 user[name]=John&user[age]=25&user[address][city]=Taipei&user[address][zip]=100&user[address][tags][0]=vip&user[address][tags][1]=early-bird&action=register&source[0]=web&source[1]=mobile
<?php
function toPostArrayWithFiles(array $params, string $prefix = ''): array {
$result = [];
foreach ($params as $key => $val) {
$newKey = $prefix ? "{$prefix}[{$key}]" : $key;
if (is_array($val)) {
// 檢查是否為 CURLFile 物件陣列(檔案上傳)
if (count($val) > 0 && $val[0] instanceof \CURLFile) {
$result[$newKey] = $val; // 保持陣列結構,cURL 會正確處理多檔案
} else {
$result = array_merge($result, toPostArrayWithFiles($val, $newKey));
}
} elseif ($val instanceof \CURLFile) {
$result[$newKey] = $val;
} else {
$result[$newKey] = $val;
}
}
return $result;
}
// 使用
$postData = [
'user' => [
'avatar' => new \CURLFile('/path/to/avatar.jpg', 'image/jpeg', 'avatar.jpg'),
'docs' => [
new \CURLFile('/path/to/doc1.pdf', 'application/pdf', 'doc1.pdf'),
new \CURLFile('/path/to/doc2.pdf', 'application/pdf', 'doc2.pdf'),
],
],
];
$flat = toPostArrayWithFiles($postData);
// 此時傳給 CURLOPT_POSTFIELDS 會自動使用 multipart/form-data
?>
PHP 內建 http_build_query() 同樣支援多維陣列方括號語法:
<?php $data = ['user' => ['name' => 'John', 'tags' => ['a', 'b']]]; $query = http_build_query($data); // user[name]=John&user[tags][0]=a&user[tags][1]=b // 直接用於 CURLOPT_POSTFIELDS(字串模式) curl_setopt($ch, CURLOPT_POSTFIELDS, $query); // 或 GET 請求 $url = 'https://api.example.com/endpoint?' . $query; ?>
差異: http_build_query 回傳字串,toPostArray 回傳陣列。傳陣列給 CURLOPT_POSTFIELDS 會強制 multipart/form-data(含邊界字串開銷),傳字串則用 application/x-www-form-urlencoded(較輕量)。API 文檔要求 form-data 時用陣列,要求 urlencoded 時用字串。
[0]、[1] 會出現在鍵名中,後端需對應解析true → '1'、false → '',後端解析需注意http_build_query 忽略,陣列模式保留鍵但值為空字串掌握多維陣列扁平化技巧,能讓 PHP 與各類 REST API、第三方服務(支付、簡訊、雲存儲)無縫對接,避免手動拼接字串的錯誤與維護負擔。