没有URL编码的http_build_query()


69

有没有一种方法可以http_build_query()使URL根据某些RFC标准进行编码?

为什么我不想对所有内容进行URL编码:我正在查询Ebay API。.老实说,就括号中的逗号而言,他们坚持不对参数名称进行URL编码。例如,DomainName(0)是一个参数,如果对这些括号进行了编码,查询将失败。

Answers:


149

您可以urldecode()对从中获取的结果字符串使用functionhttp_build_query()


您可以为此创建自己的函数http_build_query_decoded()。不过,由于需要将参数传递给,因此您必须复制参数http_build_query
Thijs Riezebeek

此问题在PHP 5.4及更高版本中不再存在,“&”号不进行url编码。
罗勒·穆萨

1
@BasilMusa键和值仍通过url编码。此解决方案也对它们进行解码。
科多斯·约翰逊,

6

不,它似乎总是要进行编码(在为URL建立参数列表时应该对URL进行编码)。

你可以自己做...

$params = array('a' => 'A', 'b' => 'B');

$paramsJoined = array();

foreach($params as $param => $value) {
   $paramsJoined[] = "$param=$value";
}

$query = implode('&', $paramsJoined);

键盘


3
这将不处理嵌套数组。
Matsemann 2013年

6

PHP 5.3.1(Buggy行为) http_build_query确实转义了连接参数的'&'和符号。例:user_id=1&setting_id=2

PHP 5.4+ http_build_query不会转义连接参数的'&'和符号。例:user_id=1&setting_id=2

例:

$params = array(
    'user_id' => '1', 
    'setting_id' => '2'
);
echo http_build_query($params);

// Output for PHP 5.3.1:
user_id=1&setting_id=2   // NOTICE THAT: '&' character is escaped

// Output for PHP 5.4.0+:
user_id=1&setting_id=2       // NOTICE THAT: '&' character is NOT escaped

定位多个版本时的解决方案

选项#1:编写包装函数:

/** 
 * This will work consistently and will never escape the '&' character
 */
function buildQuery($params) {
    return http_build_query($params, '', '&');
}

选项2:放弃http_build_query函数并编写自己的函数。


php.ini核心设置arg_separator.output链接怎么样?我使用的是PHP 5.4.34,它的输出分隔符设置为& 而输入分隔符是&。对我来说似乎很奇怪。
sootsnoot

@sootsnoot有点晚,但是对于任何阅读您的问题的人:“ arg_separator:arg_separator.output用于分隔参数,但可以通过指定此参数来覆盖。”
nico gawenda

4

您可能想尝试使用他们的JSON API。我尝试获取一个有效的示例,但是我没有应用名称,因此无法验证结果。这是代码:

<?php
$appName = "Your App Name Here";

$post_data = array(
  'jsonns.xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
  'jsonns.xs' => 'http://www.w3.org/2001/XMLSchema',
  'jsonns.tns' => 'http://www.ebay.com/marketplace/search/v1/services',
  'tns.findItemsByKeywordsRequest' => array(
    'keywords' => 'harry potter pheonix'
  )
);

$headers = array(
  "X-EBAY-SOA-REQUEST-DATA-FORMAT: JSON", 
  "X-EBAY-SOA-RESPONSE-DATA-FORMAT: JSON",
  "X-EBAY-SOA-OPERATION-NAME: findItemsByKeywords",
  "X-EBAY-SOA-SECURITY-APPNAME: $appName"
);

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'http://svcs.ebay.com/services/search/FindingService/v1');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

$result = curl_exec($ch);
if($result) {
  $response = json_decode($result);
}

curl_close($ch);
?>

您需要填写$appName应用程序的名称。此外,X-EBAY-SOA-OPERATION-NAME将需要设置为实际调用,如果调用不同,则修改JSON。


4

没有urlencoding的http_build_query()是无效的。也许您不小心对它进行了双重编码?例如,尝试为此数组构建http查询:

$params = array('a' => 'a&b=b');

没有编码,您将得到

a=a&b=b

正确编码后,您将获得

a=a%26b%3Db

哪个是正确的。如果跳过编码,请确保避免URL注入攻击。


3

您可以使用urldecode()。或将http_build_query与$ arg_separator参数一起使用。

    $query_data= $data = array('bar', 'baz'=>'boom');
    $numeric_prefix= 'test_';
    $arg_separator = '&';
    $http_query = http_build_query ( $query_data, $numeric_prefix, $arg_separator );
    var_dump( $http_query );

上面的输出是

     string 'test_0=bar&baz=boom' (length=19)

numeric_prefix:如果数组索引是数字,则此字符串将作为前缀添加到每个索引中。在这种情况下,' test_0 = bar'

arg_separator:用于分隔参数。如果未指定php,请使用php.ini中定义的arg_separator.output

参见php http_build_query


0

我对alex的回答不一,但速度更快

$params = array('a' => 'A', 'b' => 'B');
$query = '';

foreach ($params as $param => $value) {
   $query .= $param.'='.$value .'&';
}

echo substr($query, 0, -1);

您也可以使用第二个参数trim()来指定要修剪的字符。例如,我会用trim($query, '&')代替substr($query, 0, -1)
Dzhuneyt


0

我最近尝试这样做https://gist.github.com/marcocesarato/4293986fe93139f04d8269aa3fbd47e9,不同之处在于此函数是数组递归的并且与PHP4兼容。您可以在此处管理urlencode

<?php
/**
 * Build URL query params
 * as http_build_query build a query url the difference is 
 * that this function is array recursive and compatible with PHP4
 *
 * @author Marco Cesarato <cesarato.developer@gmail.com>
 * @param $query
 * @param string $parent
 * @return string
 *
 * @example
 * $p = array('abbreviations' => array('google' => 'ggle', 'facebook' => array('abb_key' => 'fbook', 'fcbk')), 'key' => 'value');
 * echo url_build_query($p);
 */
function url_build_query($query, $parent = null){
    $query_array = array();
    foreach($query as $key => $value){
        $_key = empty($parent) ?  urlencode($key) : $parent . '[' . urlencode($key) . ']';
        if(is_array($value)) {
            $query_array[] = url_build_query($value, $_key);
        } else {
            $query_array[] = $_key . '=' . urlencode($value);
        }
    }
    return implode('&', $query_array);
}

0

我正在尝试创建一个GET字符串,将其附加到这样的url的末尾-

$get_params = array(
    'include' => array(
        'enrollments',
        'current_grading_period_scores'
    ),
    'enrollment_type' => array(
        'student',
    ),

);
$get_params = http_build_query($get_params);
$get_params = urldecode($get_params);
$url = $domain.$slug;
$url = $url.'?'.$get_params;
echo $url;

打印出来

include[0]=enrollments&include[1]=current_grading_period_scores&enrollment_type[0]=student

但是我的api不喜欢方括号中的数字,因此我找到了删除数字的正则表达式-

preg_replace('/[[0-9]+]/', '[]', $get_params);

最终代码和结果-

$get_params = array(
    'include' => array(
        'enrollments',
        'current_grading_period_scores'
    ),
    'enrollment_type' => array(
        'student',
    ),

);
$get_params = http_build_query($get_params);
$get_params = urldecode($get_params);
$get_params = preg_replace('/[[0-9]+]/', '[]', $get_params);
$url = $domain.$slug;
$url = $url.'?'.$get_params;
echo $url;

打印输出-

include[]=enrollments&include[]=current_grading_period_scores&enrollment_type[]=student

如果有人知道更好的正则表达式,请告诉我,我有点菜鸟。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.