PHP Conference Japan 2024

http_build_query

(PHP 5, PHP 7, PHP 8)

http_build_query產生 URL 編碼的查詢字串

說明

http_build_query(
    陣列|物件 $data,
    字串 $numeric_prefix = "",
    ?字串 $arg_separator = null,
    整數 $encoding_type = PHP_QUERY_RFC1738
): 字串

從提供的關聯式(或索引式)陣列產生 URL 編碼的查詢字串。

參數

data

可以是一個陣列或包含屬性的物件。

如果 data 是一個陣列,它可以是一個簡單的一維結構,或者是一個陣列的陣列(而這些陣列又可能包含其他陣列)。

如果 data 是一個物件,則只有公開屬性會被併入結果中。

numeric_prefix

如果在基礎陣列中使用了數字索引,並且提供了此參數,則它將會被加在基礎陣列中元素的數字索引之前。

這是為了在資料稍後被 PHP 或其他 CGI 應用程式解碼時允許使用合法的變數名稱。

arg_separator

參數分隔符號。如果未設定或為 null,則會使用 arg_separator.output 來分隔參數。

encoding_type

預設為 PHP_QUERY_RFC1738

如果 encoding_typePHP_QUERY_RFC1738,則會根據 » RFC 1738application/x-www-form-urlencoded 媒體類型進行編碼,這表示空格會被編碼為加號 (+)。

如果 encoding_typePHP_QUERY_RFC3986,則會根據 » RFC 3986 進行編碼,空格會被百分比編碼 (%20)。

回傳值

回傳一個 URL 編碼的字串。

更新日誌

版本 說明
8.0.0 arg_separator 現在可以為 null。

範例

範例 #1 http_build_query() 的簡單用法

<?php
$data
= array(
'foo' => 'bar',
'baz' => 'boom',
'cow' => 'milk',
'null' => null,
'php' => 'hypertext processor'
);

echo
http_build_query($data) . "\n";
echo
http_build_query($data, '', '&amp;');

?>

上述範例將輸出

foo=bar&baz=boom&cow=milk&php=hypertext+processor
foo=bar&amp;baz=boom&amp;cow=milk&amp;php=hypertext+processor

範例 #2 使用帶有數字索引元素的 http_build_query()

<?php
$data
= array('foo', 'bar', 'baz', null, 'boom', 'cow' => 'milk', 'php' => 'hypertext processor');

echo
http_build_query($data) . "\n";
echo
http_build_query($data, 'myvar_');
?>

上述範例將輸出

0=foo&1=bar&2=baz&4=boom&cow=milk&php=hypertext+processor
myvar_0=foo&myvar_1=bar&myvar_2=baz&myvar_4=boom&cow=milk&php=hypertext+processor

範例 #3 使用含有複雜陣列的 http_build_query()

<?php
$data
= array(
'user' => array(
'name' => 'Bob Smith',
'age' => 47,
'sex' => 'M',
'dob' => '5/12/1956'
),
'pastimes' => array('golf', 'opera', 'poker', 'rap'),
'children' => array(
'bobby' => array('age'=>12, 'sex'=>'M'),
'sally' => array('age'=>8, 'sex'=>'F')
),
'CEO'
);

echo
http_build_query($data, 'flags_');
?>

以上範例將輸出:(為了方便閱讀而自動換行)

user%5Bname%5D=Bob+Smith&user%5Bage%5D=47&user%5Bsex%5D=M&
user%5Bdob%5D=5%2F12%2F1956&pastimes%5B0%5D=golf&pastimes%5B1%5D=opera&
pastimes%5B2%5D=poker&pastimes%5B3%5D=rap&children%5Bbobby%5D%5Bage%5D=12&
children%5Bbobby%5D%5Bsex%5D=M&children%5Bsally%5D%5Bage%5D=8&
children%5Bsally%5D%5Bsex%5D=F&flags_0=CEO

注意事項:

只有在基底陣列 "CEO" 中,以數字索引的元素會加上前綴。在 `pastimes` 底下找到的其他數字索引,不需要字串前綴即可成為合法的變數名稱。

範例 #4 使用物件搭配 http_build_query()

<?php
class parentClass {
public
$pub = 'publicParent';
protected
$prot = 'protectedParent';
private
$priv = 'privateParent';
public
$pub_bar = null;
protected
$prot_bar = null;
private
$priv_bar = null;

public function
__construct(){
$this->pub_bar = new childClass();
$this->prot_bar = new childClass();
$this->priv_bar = new childClass();
}
}

class
childClass {
public
$pub = 'publicChild';
protected
$prot = 'protectedChild';
private
$priv = 'privateChild';
}

$parent = new parentClass();

echo
http_build_query($parent);
?>

上述範例將輸出

pub=publicParent&pub_bar%5Bpub%5D=publicChild

另請參閱

新增註解

使用者貢獻的註解 18 則註解

Ilya Rudenko
18 年前
值為 null 的參數不會出現在結果字串中。

<?php
$arr
= array('test' => null, 'test2' => 1);
echo
http_build_query($arr);
?>

將會產生

test2=1
itsadok at gmail dot com
9 年前
將 null 傳遞給 $arg_separator 與傳遞空字串的效果相同,這可能不是您想要的。

如果您需要更改 enc_type,請使用以下程式碼:

http_build_query($query, null, '&', PHP_QUERY_RFC3986);

或者可能使用這個:

http_build_query($query, null, ini_get('arg_separator.output'), PHP_QUERY_RFC3986);

但不要使用這個:

// 不良程式碼!
http_build_query($query, null, null, PHP_QUERY_RFC3986);
eric dot muyser at gmail dot com
11 年前
這個函式會產生像這樣的結果:

files[0]=1&files[1]=2&...

要讓它變成像這樣:

files[]=1&files[]=2&...

請這樣做:

$query = http_build_query($query);
$query = preg_replace('/%5B[0-9]+%5D/simU', '%5B%5D', $query);
flavio at agenciaeme dot com dot br
6 年前
如果您傳送布林值,它會轉換成整數

$a = [teste1= true,teste2=false];
echo http_build_query($a)

//結果會是 teste1=1&teste2=0
Sergei S.
5 年前
在 <?php http_build_query() ?> 中發生的數字轉字串會受到地區設定的影響,這點可能不太明顯。

<?php
$params = ["v" => 5.63];

setlocale(LC_ALL, 'us_En');
http_build_query($params) // v=5.63

setlocale(LC_ALL, 'ru_RU');
http_build_query($params) // v=5,63 注意逗號
?>
匿名
13 年前
如前所述,在某些伺服器上,php5.3 的分隔符號似乎是 &amp;。通常,如果發佈到另一台 php5.3 機器,這不會造成問題。

但是,如果您發佈到 Tomcat Java 伺服器或其他伺服器,&amp; 可能無法正確處理。

要解決此問題,請指定

http_build_query($array, '', '&');

而不是

http_build_query($array); //某些伺服器會產生 &amp;
chat dot noir at arcor dot de
7 年前
如果您需要反向功能,而且(像我一樣)您無法使用 pecl_http,您可能需要使用類似以下的程式碼。

<?php function http_parse_query($Query) {

// 模擬 $_GET 的行為,另請參見 RFC 1738 和 3986。
$Delimiter = ini_get('arg_separator.input');
$Params = array();

foreach (
explode($Delimiter, $Query) as $NameValue) {
preg_match(
'/^(?P<name>[^=\[]*)(?P<indices_present>\[(?P<indices>[^\]]*(\]\[[^\]]*)*)\]?)?(?P<value_present>=(?P<value>.*))?$/',
$NameValue,
$NameValueParts
);

if (!empty(
$NameValueParts)) {
$Param =& $Params[$NameValueParts['name']];

if (!empty(
$NameValueParts['indices_present'])) {
$Indices = explode('][', $NameValueParts['indices']);

foreach (
$Indices as $Index) {
if (!
is_array($Param)) {
$Param = array();
}

if (
$Index === '') {
$Param[] = array();
end($Param);
$Param =& $Param[key($Param)];
} else {
if (
ctype_digit($Index)) { $Index = (int) $Index; }

if (!
array_key_exists($Index, $Param)) {
$Param[$Index] = array();
}
$Param =& $Param[$Index];
}
}
}

if (!empty(
$NameValueParts['value_present'])) {
$Param = urldecode($NameValueParts['value']);
} else {
$Param = '';
}
}
}

return
$Params;

}
?>
匿名
12 年前
如果 `query_data` 是一個關聯陣列,並且其中一個值本身是一個空陣列,或者是一個僅包含空陣列(或僅包含空陣列的陣列等等)的陣列,則對應的鍵將不會出現在結果查詢字串中,這點值得注意嗎?
例如:

$post_data = array('name'=>'miller', 'address'=>array('address_lines'=>array()), 'age'=>23);
echo http_build_query($post_data);

將會印出
name=miller&age=23
james at dimensionengineering dot com
9 年前
範例 1 要小心 -- 它正是 *不該* 如何實作的方式。

& 作為分隔符號是 URL 編碼。
&amp; 是 HTML 編碼。

如果您將 URL 嵌入網頁中,則應該對其進行 HTML 編碼。這比僅將 & 替換為 &amp; 更加複雜。按照此範例的建議操作會產生安全漏洞。
irish [-@-] ytdj [-dot-] ca
14 年前
當使用 http_build_query 函數從陣列創建 URL 查詢字串,以用於 curl_setopt($ch, CURLOPT_POSTFIELDS, $post_url) 之類的函數時,請注意 URL 編碼。

在我的情況下,我只是想將接收到的 $_POST 資料傳遞給 CURL 的 POST 資料,這需要它採用 URL 格式。如果像空格 [ ] 之類的內容進入 http_build_query,它會以 + 的形式輸出。如果您再次將其發送出去進行 POST,您將不會獲得預期的結果。這適用於 GET 但不適用於 POST。

如果您只是想傳遞資料,則可以自行編寫一個簡單的函數

<?php
$post_url
= '';
foreach (
$_POST AS $key=>$value)
$post_url .= $key.'='.$value.'&';
$post_url = rtrim($post_url, '&');
?>

然後,您可以使用它在 CURL 中傳遞 POST 資料。

<?php
$ch
= curl_init($some_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_url);
curl_exec($ch);
?>

請注意,在處理 POST 資料的最終頁面上,您應該正確地過濾/跳脫它。
Mark Simon
9 年前
如前所述,此函數會忽略值為 null 的鍵。這可能會破壞某些將鍵視為布林值,因此沒有值的程式碼,或者其他期望陣列無論值為何都被填入的程式碼。

解決此問題的方法是用空字串替換 null 值

$data=array(
'a'=>'apple',
'b'=>2,
'c'=>null,
'd'=>'…',
);

// 補償 http_build_query 忽略 null 值的事實
foreach($data as &$datum) if($datum===null) $datum='';

如果它應該是一個真正的查詢字串,那麼失去原始的 null 值並不是真正的損失。如果 null 值很重要,您可以改用虛擬值。

Mark
Vitaly Dyatlov
11 年前
在沒有索引的情況下編碼參數陣列的正確實作 (valdikks 修正的程式碼 - 不適用於內部陣列)

<code>
function cr_post($a,$b='',$c=0)
{
if (!is_array($a)) return false;
foreach ((array)$a as $k=>$v)
{
if ($c)
{
if( is_numeric($k) )
$k=$b."[]";
else
$k=$b."[$k]";
}
else
{ if (is_int($k))
$k=$b.$k;
}

如果 (is_array($v) || is_object($v))
{
$r[]=cr_post($v,$k,1);
繼續;
}
$r[]=urlencode($k)."=".urlencode($v);
}
返回 implode("&",$r);
}
</code>
rishad at kaluma dot com
6 年前
當使用 http_build_query($args) 且 $args 是一個陣列時;請注意陣列的大小有限制。請查看 php.ini 中的 max_input_vars 以增加此大小。
netrox at aol dot com
15 年前
我注意到即使關閉了魔術引號,http_build_query() 還是會自動在字串中加入反斜線。

因此,我必須在每個字串變數中加入 "stripslashes"。
v0idnull[try_to_spam_me_now] at gee-mail dot co
14 年前
在我的 PHP 5.3 安裝版本中,http_build_query() 似乎使用 &amp; 作為預設分隔符號。當與 stream_context_create() 結合用於 POST 請求,並在接收端取得 $_POST['amp;fieldName'] 時,這就變得很有趣。
rmaslo at archa dot cz
7 年前
警告:不同的陣列可能會返回相同的結果

<CODE>
$a1 = array('x[y]' => array('a'=>1));
$a2 = array('x' => array('y' => array('a'=>1)));
$q1 = http_build_query($a1);
$q2 = http_build_query($a2);
var_dump($a1);
echo '<BR>';
var_dump($a2);
echo '<BR>';
echo $q1;
echo '<BR>';
echo $q2;
echo '<BR>';
</CODE>

結果
array(1) { ["x[y]"]=> array(1) { ["a"]=> int(1) } }
array(1) { ["x"]=> array(1) { ["y"]=> array(1) { ["a"]=> int(1) } } }
x%5By%5D%5Ba%5D=1
x%5By%5D%5Ba%5D=1
drewdeveloperthomas at gmail dot com
4 年前
文件中沒有提到,但在物件上呼叫 http_build_query 時,公開的 null 欄位會被忽略。

<?php

類別 A {
公開
int $publicNotNull;
公開 ?
int $publicNull;
私有
string $privateNotNull;

公開 函式
__construct()
{
$this->publicNotNull = 2;
$this->privateNotNull = "Test";
}
}

$a = new A();
echo
http_build_query($a); // publicNotNull=2
?>
shaun at slickdesign dot com dot au
6 年前
雖然 http_build_query 也可用於將大多數類別編碼成查詢字串,但包含 <![CDATA[]]> 值的 SimpleXML 元素會被視為空陣列,因此不會被自然包含在內。

<?php
$xml
= simplexml_load_string( '<wrapper><key><![CDATA[value]]></key><key2>value2</key2></wrapper>' );
var_dump( $xml, http_build_query( $xml ) );
/* 輸出:
object(SimpleXMLElement)#1 (2) {
["key"]=>
object(SimpleXMLElement)#2 (0) {
}
["key2"]=>
string(6) "value2"
}
string(11) "key2=value2"
*/
?>
To Top