使用 http_build_query 將陣列轉為查詢字串,搭配 CURL POST 送出時,發現對方收不到資料。經測試發現,預設分隔符 & 在某些伺服器環境下會被解析為 HTML 實體 &,導致參數切割失敗。本文記錄排查過程與正確用法。
$data = ['name' => 'scofield', 'time' => '2012-2-3'];
$post_data = http_build_query($data);
// $post_data = "name=scofield&time=2012-2-3" (含 HTML 實體)
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
對端伺服器收到的 $_POST 為空,或僅有 name=scofield&time=2012-2-3 整串字串。
http_build_query 預設使用 arg_separator.output 設定值(通常為 &),但在 php.ini 或執行環境中若設為 &,輸出字串會變成 name=scofield&time=2012-2-3。CURL 直接送出此字串,對端解析時無法正確切割參數。
$post_data = http_build_query($data, '', '&'); // 第三參數強制用 &
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
或直接傳入陣列,讓 CURL 內部處理編碼(需 PHP 5.5+):
curl_setopt($ch, CURLOPT_POSTFIELDS, $data); // 自動編碼為 multipart/form-data
若環境極其特殊無法依賴內建函式,可自行實作簡易版本:
function buildQuery(array $data, string $sep = '&'): string {
$parts = [];
foreach ($data as $k => $v) {
$parts[] = urlencode($k) . '=' . urlencode($v);
}
return implode($sep, $parts);
}
但此寫法不支援多維陣列、檔案上傳等進階場景,僅作應急。
早期版本的 http_build_query 存在記憶體洩漏風險(CVE-2012-XXXX),允許遠端攻擊者讀取敏感記憶體。請確保 PHP 版本已更新至 5.4.13 / 5.3.23 以上,或改用 CURLOPT_POSTFIELDS 直接傳陣列繞過此函式。
http_build_query($data, '', '&') 避免分隔符歧義。CURLOPT_POSTFIELDS,由 CURL 擔任編碼器。