具有 null 值的参数不会出现在结果字符串中。
<?php
$arr = array('test' => null, 'test2' => 1);
echo http_build_query($arr);
?>
将生成
test2=1
(PHP 5, PHP 7, PHP 8)
http_build_query — 生成 URL 编码的查询字符串
$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_type
为 PHP_QUERY_RFC1738
,则编码将根据 » RFC 1738 和 application/x-www-form-urlencoded
媒体类型执行,这意味着空格将被编码为加号 (+
) 符号。
如果 encoding_type
为 PHP_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, '', '&');
?>
上面的示例将输出
foo=bar&baz=boom&cow=milk&php=hypertext+processor foo=bar&baz=boom&cow=milk&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
具有 null 值的参数不会出现在结果字符串中。
<?php
$arr = array('test' => null, 'test2' => 1);
echo http_build_query($arr);
?>
将生成
test2=1
将 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);
在 <?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 注意逗号
?>
如果你发送布尔值,它会转换为整数
$a = [teste1= true,teste2=false];
echo http_build_query($a)
// 结果将为 teste1=1&teste2=0
此函数的执行方式如下
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);
如前所述,在 php5.3 中,分隔符是 &,它似乎存在于某些服务器上。通常,如果发布到另一台 php5.3 机器,这不会出现问题。
但如果你发布到 Tomcat Java 服务器或其他服务器,& 可能无法正确处理。
要克服这个问题,请指定
http_build_query($array, '', '&');
而不是
http_build_query($array); // 对某些服务器提供 &
值得注意的是,如果 query_data 是关联数组,并且值本身是空数组,或者仅包含空数组的数组(或仅包含空数组的数组等),则相应的键将不会出现在结果查询字符串中?
例如
$post_data = array('name'=>'miller', 'address'=>array('address_lines'=>array()), 'age'=>23);
echo http_build_query($post_data);
将打印
name=miller&age=23
如果你需要逆向功能,并且(像我一样)无法使用 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;
}?>
注意示例 1 - 它正是 *不* 应该实现的方式。
& 作为分隔符是 URL 编码。
& 是 HTML 编码。
如果你将 URL 嵌入网页中,则应该对其进行 HTML 编码。这比仅仅将 & 替换为 & 更复杂。按照本示例建议执行操作会存在安全漏洞。
当使用 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 数据的最终页面上,您应该适当地过滤/转义它。
如前所述,此函数省略了具有空值的键。这可能会破坏一些将键视为布尔值的代码,因此没有值,或其他期望数组无论值如何都已填充的代码。
对此的解决方法是将空值替换为空字符串
$data=array(
'a'=>'apple',
'b'=>2,
'c'=>null,
'd'=>'…',
);
// 补偿 http_build_query 省略空值的事实
foreach($data as &$datum) if($datum===null) $datum='';
如果它应该是一个真正的查询字符串,那么丢失原始数据的空值并不是真正的损失。如果空值很重要,您可以使用虚拟值来代替。
马克
在使用 http_build_query($args) 时,其中 $args 是一个数组;请注意,数组的大小有限制。请参阅 php.ini 中的 max_input_vars 以增加此大小。
对不带索引的参数数组进行编码的正确实现(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>
我注意到,即使禁用了 magic quotes,http_build_query() 也会自动为字符串添加斜杠。
因此,我不得不为每个字符串变量添加“stripslashes”。
在我的 PHP 5.3 安装中,http_build_query() 似乎使用 & 作为默认分隔符。与 stream_context_create() 结合用于 POST 请求,并在接收端获取 $_POST['amp;fieldName'] 时,这很有趣。
警告:不同的数组可能返回相同的结果
<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
此函数不适用于 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);}
?>
文档中没有提到,但是当对对象调用 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
?>
不建议消除数字索引,例如
'arg[0]' --> 'arg[]'
原因是此函数不会在结果字符串中包含空值
$data = array(
'arg' => array(
null,
2,
3
)
);
echo http_build_query($data);
输出类似于 "arg[1]=2&arg[2]=3";
虽然 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"
*/
?>
我发现,与其他对我不起作用的建议相比,构建 POST 内容(例如用于 stream_context_create)的最佳方法是 urldecode(http_build_query($query))
具有 false 值的参数将在结果字符串中更改为零。
<?php
$arr = ['foo' => false];
echo http_build_query($arr);
?>
将生成
foo=0
如果您只需要键值对,可以使用此方法
<?php
$array = array(
"type" => "welcome",
"message" => "Hello World!"
);
echo urldecode(http_build_query($array, '', ';'));
?>
结果:type=welcome;message=Hello World!
虽然没有记录,但此 http_build_query 在某些输入上可能会返回 FALSE
<?php
//gives bool(false)
var_dump(http_build_query('whatever'));
?>