http_build_query

(PHP 5)

http_build_query -- 生成 url-encoded 之后的请求字符串

描述

string http_build_query ( array formdata [, string numeric_prefix] )

使用给出的关联(或下标)数组生成一个 url-encoded 请求字符串。参数 formdata 可以是数组或包含属性的对象。一个 formdata 数组可以是简单的一维结构,也可以是由数组组成的数组(其依次可以包含其它数组)。如果在基础数组中使用了数字下标同时给出了 numeric_prefix 参数,此参数值将会作为基础数组中的数字下标元素的前缀。这是为了让 PHP 或其它 CGI 程序在稍后对数据进行解码时获取合法的变量名。

例子 1. http_build_query() 使用示例

<?php
$data
= array('foo'=>'bar',
              
'baz'=>'boom',
              
'cow'=>'milk',
              
'php'=>'hypertext processor');
              
echo
http_build_query($data);
/* 输出:
      foo=bar&baz=boom&cow=milk&php=hypertext+processor
*/
?>

例子 2. http_build_query() 使用数字下标的元素

<?php
$data
= array('foo', 'bar', 'baz', 'boom', 'cow' => 'milk', 'php' =>'hypertext processor');
              
echo
http_build_query($data);
/* 输出:
      0=foo&1=bar&2=baz&3=boom&cow=milk&php=hypertext+processor
*/

echo http_build_query($data, 'myvar_');
/* 输出:
      myvar_0=foo&myvar_1=bar&myvar_2=baz&myvar_3=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[name]=Bob+Smith&user[age]=47&user[sex]=M&user[dob]=5%1F12%1F1956&
      pastimes[0]=golf&pastimes[1]=opera&pastimes[2]=poker&pastimes[3]=rap&
      children[bobby][age]=12&children[bobby][sex]=M&children[sally][age]=8&
      children[sally][sex]=F&flags_0=CEO

   注意:只有基础数组中的数字下标元素“CEO”才获取了前缀,其它数字下标元素(如
   pastimes 下的元素)则不需要为了合法的变量名而加上前缀。
*/
?>

例子 4. http_build_query() 使用对象

<?php
class myClass {
  var
$foo;
  var
$baz;
  
  function
myClass() {
    
$this->foo = 'bar';
    
$this->baz = 'boom';
  }
}

$data = new myClass();

echo
http_build_query($data);
/* 输出:
      foo=bar&baz=boom
*/
?>

参见:parse_str()parse_url()urlencode()array_walk()


add a note add a note User Contributed Notes
paulschneider at free dot fr
05-Apr-2006 02:14
using & as argument values separator produces invalid html; use &amp; instead
Colin Guthrie
08-Mar-2006 11:11
I am concerned about this function's generation of [ and ] in the variable names.

From what I can gather from http://www.faqs.org/rfcs/rfc3986.html (which I believe to be the most recent RFC on the matter), the use of square brackets is illegal here.

To be sure, always use the following:
str_replace(array('[',']'), array('%5B','%5D'), http_build_query($data));

I will also submit a bug, but thought it important to inform users.
Colin Guthrie
08-Mar-2006 10:25
@ xangelusx
You said that "It is actually illegal to set arg_separator.output to &amp; ("and amp ;") as every character is considered a seperator according to the documentation."

I don't think this is correct. arg_separator.input maybe, but not the output. How can PHP encode my URLs (that is what this setting is used for, e.g. on URL rewriting etc.) with more than one separator?  It doesn't make sence for that variable.

I have personally used &amp; as a separate for output for years in order to create valid XHTML output via PHP.

I long ago wrote a function to do this for me, but depending on where I use the output, I sometimes want &amp; and sometimes just a plain old & (think putting the value in a href="" versus using it in a Location: header). Unfortunatly, I can see no way to deprecate my function just yet, as this built in function is lacking that distinction (an optional argument would be perfect IMO)
xangelusx at hotmail dot com
26-Jan-2006 10:53
@ arjini:
  It is actually illegal to set arg_separator.output to &amp; ("and amp ;") as every character is considered a seperator according to the documentation. Hosts should only be using the single "&" (andpersand) character.

@ vlad:
  Good call checking the servers arg_separator.output setting, but note that it can contain several characters (see the default setting in php.ini). Instead, try this:

<?php
//Discover the servers preferred parameter delimiters. If empty, assume "&"
$Delims = ((ini_get("arg_separator.input") == "") ? "&" : ini_get("arg_separator.input"));
if (
strlen($Delims) > 1) {
  
$Delims = preg_split('//', $Delims, -1, PREG_SPLIT_NO_EMPTY);
} else {
  
$Delims = array($Delims);
}
$separator = $Delims[0];
?>
Ilya Rudenko
10-Jan-2006 03:57
Params with null value do not present in result string.

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

will produce:

test2=1
arjini
10-Oct-2005 11:35
Note that some hosts have the ini setting "arg_separator.output" set to &amp; ("and amp ;" in case this form encoded that) and some have it set to just a plain old ampersand. When running unit tests on a number of different hosts I kept getting inconsistent results and in some cases double encoded html entitiy errors inside my url class. I changed

$queryString = http_build_query($args);

to

$queryString = html_entity_decode(http_build_query($args));

(one could change the ini setting instead but some hosts don't allow that, so this is the only catch I all solution I found).
vlad_mustafin at ukr dot net
05-Oct-2005 08:03
Dear anonymous, i think that your example is incorrect in some places (or at least is not flexible) and shortly only in names of variables (as $c, $k, etc.) and some spaces and line foldings  :), i can explain:
1. I think that next part of code is not wanted here:
<?if (!is_array($a)) return false;?>
because you have (array)$a in foreach! It is possible but not obligatory. Or maybe better to use trigger_error for this situation.
2. You don't use urlencode on key! It's wrong because it can have also unsafe value!
<?if ($c) $k=$b."[".$k."]"; elseif (is_int($k)) $k=$b.$k;?>
this part is wrong because $k can be integer even if $c is not empty. I can want to add numeric_prefix to all indexes in array, but your example will not allow to make it. Here using of elseif is excluded, these both conditions should exist simultaneously.
3. <?http_build_query($v,$k,1);?> - In my opinion it's a very rough error. You use second parameter (as "numeric_prefix" in my example and php manual for this function) for transfer of the current key into next iteration step of recursion. Certainly it's possible and is not of principle, but very not professionally, in my opinion. I use implicit rule: one ought not to violate function logic even inside of the same function one may only expand logic. And my <?http_build_query($v, null, $tmp_key);?> allows to add numeric_prefix to all indexes in array (see point 2), i need just to put $numeric_prefix instead of null into second parameter.

Also i want to extend my previous example because we must use ini_get('arg_separator.output') instead of '&' separator!

<?
if(!function_exists('http_build_query')) {
   function
http_build_query( $formdata, $numeric_prefix = null, $key = null ) {
      
$res = array();
       foreach ((array)
$formdata as $k=>$v) {
          
$tmp_key = urlencode(is_int($k) ? $numeric_prefix.$k : $k);
           if (
$key) $tmp_key = $key.'['.$tmp_key.']';
           if (
is_array($v) || is_object($v) ) {
              
$res[] = http_build_query($v, null /* or $numeric_prefix if you want to add numeric_prefix to all indexes in array*/, $tmp_key);
           } else {
              
$res[] = $tmp_key."=".urlencode($v);
           }
          
/*
           If you want, you can write this as one string:
           $res[] = ( ( is_array($v) || is_object($v) ) ? http_build_query($v, null, $tmp_key) : $tmp_key."=".urlencode($v) );
           */
      
}
      
$separator = ini_get('arg_separator.output');
       return
implode($separator, $res);
   }
}
?>

All best!
04-Oct-2005 04:33
I made my very own http_build_query function quite some time ago for php 4 and below. Works exactly like the function below; but its just a bit shorter. :P

<?
function http_build_query($a,$b='',$c=0){
if (!
is_array($a)) return false;
foreach ((array)
$a as $k=>$v){
if (
$c) $k=$b."[".$k."]"; elseif (is_int($k)) $k=$b.$k;
if (
is_array($v)||is_object($v)) {$r[]=http_build_query($v,$k,1);continue;}
$r[]=$k."=".urlencode($v);
}
return
implode("&",$r);
}
?>
vlad_mustafin at ukr dot net
29-Sep-2005 07:31
My example of this function for PHP versions < PHP5 without any regular expressions, just cycles, recursion and standard functions. It can work with complex arrays or objects or both combined.
<?php
if(!function_exists('http_build_query')) {
   function
http_build_query( $formdata, $numeric_prefix = null, $key = null ) {
      
$res = array();
       foreach ((array)
$formdata as $k=>$v) {
          
$tmp_key = urlencode(is_int($k) ? $numeric_prefix.$k : $k);
           if (
$key) {
              
$tmp_key = $key.'['.$tmp_key.']';
           }
           if (
is_array($v) || is_object($v) ) {
              
$res[] = http_build_query($v, null, $tmp_key);
           } else {
              
$res[] = $tmp_key."=".urlencode($v);
           }
       }
       return
implode("&", $res);
   }
}
?>
mauricio at elmaster dot com
27-Sep-2005 10:31
Regarding the last comment, you should use:

if(!function_exists('http_build_query'))

instead of:

if(!defined('http_build_query'))
mwwaygoo AT hotmail DOT com
08-Aug-2005 04:25
The example given below works great but not for complex arrays. So I wrote one that did :)

The 3rd and 4th parameters are used to contruct the query from the complex array, so dont use them yourself, just stick to the defined variables as defined above.

<?php
if(!defined('http_build_query'))
{
   function
http_build_query($array, $flags='', $flags_unchecked=TRUE, $index="")
   {
       if(
$flags_unchecked)
       {
           if(
is_string($flags))
           {
              
$flags = ereg_replace("[^a-z0-9_]", "", $flags);
           }
           else
           {
              
$flags = '';
           }
       }
  
      
$string = "";
       if(
is_array($array))
       {
           foreach(
$array as $name => $value)
           {
               if(
is_array($value))
               {
                   if(
$index=="")
                   {
                      
$string.=http_build_query($value, $flags, FALSE, $name);
                   }
                   else
                   {
                      
$string.=http_build_query($value, $flags, FALSE, $index."[".$name."]");
                   }
               }
               else
               {
                   if(
$index=="")
                   {
                       if(
is_int($name))
                       {
                          
$name=$flags.$name;
                       }
                      
$string .= $name . "=" . urlencode($value) . "&";
                   }
                   else
                   {
                      
$string .= $index . "[" . $name . "]=" . urlencode($value) . "&";
                   }
               }
           }
           if(
$index=="")
           {
              
$string=ereg_replace("&$","",$string);
           }
       }
       return
$string;
   }
}
?>
php dot net at hiddemann dot org
12-May-2005 09:22
This is a workaround for PHP versions < PHP5. It does not work with complex arrays, however.

<?

if (!function_exists('http_build_query')) {
   function
http_build_query($formdata, $numeric_prefix = "")
   {
      
$arr = array();
       foreach (
$formdata as $key => $val)
        
$arr[] = urlencode($numeric_prefix.$key)."=".urlencode($val);
       return
implode($arr, "&");
   }
}

?>
aidan at php dot net
28-May-2004 11:25
This functionality is now implemented in the PEAR package PHP_Compat.

More information about using this function without upgrading your version of PHP can be found on the below link:

http://pear.php.net/package/PHP_Compat