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 现在可以为空。

示例

示例 #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

另请参阅

添加注释

用户贡献的注释 24 注释

Ilya Rudenko
18 年前
具有 null 值的参数不会出现在结果字符串中。

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

将生成

test2=1
itsadok at gmail dot com
8 年前
将 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);
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 注意逗号
?>
flavio at agenciaeme dot com dot br
6 年前
如果你发送布尔值,它会转换为整数

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

// 结果将为 teste1=1&teste2=0
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);
匿名
13 年前
如前所述,在 php5.3 中,分隔符是 &amp;,它似乎存在于某些服务器上。通常,如果发布到另一台 php5.3 机器,这不会出现问题。

但如果你发布到 Tomcat Java 服务器或其他服务器,&amp; 可能无法正确处理。

要克服这个问题,请指定

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

而不是

http_build_query($array); // 对某些服务器提供 &amp;
匿名
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
chat dot noir at arcor dot de
6 年前
如果你需要逆向功能,并且(像我一样)无法使用 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;

}
?>
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 年前
如前所述,此函数省略了具有空值的键。这可能会破坏一些将键视为布尔值的代码,因此没有值,或其他期望数组无论值如何都已填充的代码。

对此的解决方法是将空值替换为空字符串

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

// 补偿 http_build_query 省略空值的事实
foreach($data as &$datum) if($datum===null) $datum='';

如果它应该是一个真正的查询字符串,那么丢失原始数据的空值并不是真正的损失。如果空值很重要,您可以使用虚拟值来代替。

马克
rishad at kaluma dot com
5 年前
在使用 http_build_query($args) 时,其中 $args 是一个数组;请注意,数组的大小有限制。请参阅 php.ini 中的 max_input_vars 以增加此大小。
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;
}

if (is_array($v)||is_object($v))
{
$r[]=cr_post($v,$k,1);
continue;
}
$r[]=urlencode($k)."=".urlencode($v);
}
return implode("&",$r);
}
</code>
netrox at aol dot com
14 年前
我注意到,即使禁用了 magic quotes,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
valdikss at gmail dot com
16 年前
此函数不适用于 http!
http 中的数组是这样的

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

但函数是这样的

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

这是一个正常函数

<?php
function cr_post($a,$b=\'\',$c=0){
if (!is_array($a)) return false;
foreach ((array)$a as $k=>$v){
if ($c) $k=$b.\"[]\"; elseif (is_int($k)) $k=$b.$k;
if (is_array($v)||is_object($v)) {$r[]=cr_post($v,$k,1);continue;}
$r[]=urlencode($k).\"=\".urlencode($v);}return implode(\"&\",$r);}
?>
drewdeveloperthomas at gmail dot com
4 年前
文档中没有提到,但是当对对象调用 http_build_query 时,公共空字段将被忽略。

<?php

class A {
public
int $publicNotNull;
public ?
int $publicNull;
private
string $privateNotNull;

public function
__construct()
{
$this->publicNotNull = 2;
$this->privateNotNull = "Test";
}
}

$a = new A();
echo
http_build_query($a); // publicNotNull=2
?>
joey dot qiang at innomative dot com
9 年前
不建议消除数字索引,例如
'arg[0]' --> 'arg[]'

原因是此函数不会在结果字符串中包含空值

$data = array(
'arg' => array(
null,
2,
3
)
);
echo http_build_query($data);

输出类似于 "arg[1]=2&arg[2]=3";
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 ) );
/* Outputs:
object(SimpleXMLElement)#1 (2) {
["key"]=>
object(SimpleXMLElement)#2 (0) {
}
["key2"]=>
string(6) "value2"
}
string(11) "key2=value2"
*/
?>
Kirils Solovjovs
11 年前
我发现,与其他对我不起作用的建议相比,构建 POST 内容(例如用于 stream_context_create)的最佳方法是 urldecode(http_build_query($query))
joelhy
8 年前
具有 false 值的参数将在结果字符串中更改为零。

<?php
$arr
= ['foo' => false];
echo
http_build_query($arr);
?>

将生成

foo=0
stocki dot r at gmail dot com
11 年前
如果您只需要键值对,可以使用此方法

<?php
$array
= array(
"type" => "welcome",
"message" => "Hello World!"
);
echo
urldecode(http_build_query($array, '', ';'));
?>

结果:type=welcome;message=Hello World!
jakub dot lopuszanski at nasza-klasa dot pl
10 年前
虽然没有记录,但此 http_build_query 在某些输入上可能会返回 FALSE
<?php
//gives bool(false)
var_dump(http_build_query('whatever'));
?>
To Top