PHP http_build_query,两个数组键相同

ylamdve6  于 2023-11-16  发布在  PHP
关注(0)|答案(5)|浏览(119)

我想使用http_build_query构造这个URL:

https://www.googleapis.com/freebase/v1/topic/m/0d6lp?filter=/common/topic/notable_for&filter=/common/topic/alias

字符串
请注意,“filter=”参数在url中出现两次,以指定两个过滤器。
我试着这样做,但有一个问题:

$service_url = 'https://www.googleapis.com/freebase/v1/topic';
$mid = '/m/0d6lp';
$params = array('filter' => '/common/topic/notable_for', 'filter' =>   '/common/topic/alias');
$url = $service_url . $mid . '?' . http_build_query($params);


问题是因为“filter”数组键重复了两次,只有最后一个参数出现在http_build_query中。我如何用两个过滤器构造原始url?

whhtz7ly

whhtz7ly1#

这不是最好的解决方案,但我有一个解决方案:

$item = [
   'key1' => array('value1','value2'),
   'key2' => array('value3','value4')
];

$array=[
    'aaa' => 'aaa',
    'null' => 'null&'.preg_replace('/%5B(?:[0-9]|[1-9][0-9]+)%5D=/', '=', http_build_query($item,null,'&')),
    'zzz' => 'zzz'
];

echo urldecode(http_build_query($array));

字符串
输出量:

**错误:**可能这不会工作,因为url将是:

=

  • EDIT:* 其他选项将在将结果分配给url之前进行preg:
preg_replace('/%5B(?:[0-9]|[1-9][0-9]+)%5D=/', '=', http_build_query($item))


产出:
key1=value1&key1=value2&key2=value3&key2=value4

eagi6jfj

eagi6jfj2#

这里的问题当然是PHP数组(哈希)中的每个键只能有一个值。本质上,PHP哈希不是查询字符串的良好表示,因为查询字符串有顺序,并且没有关于键的唯一性的约束。
为了解决这个问题,你需要一个特殊的查询字符串构建器来处理重复的键:

class QueryString {
    private $parts = array();

    public function add($key, $value) {
        $this->parts[] = array(
            'key'   => $key,
            'value' => $value
        );
    }

    public function build($separator = '&', $equals = '=') {
        $queryString = array();

        foreach($this->parts as $part) {
            $queryString[] = urlencode($part['key']) . $equals . urlencode($part['value']);
        }

        return implode($separator, $queryString);
    }

    public function __toString() {
        return $this->build();
    }
}

字符串
示例用法(Codepad Demo):

$qs = new QueryString();
$qs->add('filter', '1');
$qs->add('filter', '2');
var_dump($qs->build()); // filter=1&filter=2

lnlaulya

lnlaulya3#

我已经扩展了@Bailey帕克的回答,以处理第一条评论中提出的问题。

class QueryString
{
        private $parts = array();

        public function add($key, $value) {
                if(empty($value))return;
                if(is_array($value))
                {
                        foreach ($value as $v)
                                $this->add($key,$v);
                }
                else
                {
                        $this->parts[$key][] = $value;
                }

        }

        public function build($separator = '&', $equals = '=') {
                $queryString = array();

                $parts = array();
                foreach($this->parts as $key=>$value)
                {
                        if(count($value) > 1)
                                $parts[$key] = $value;
                        else
                                $parts[$key] = $value[0];
                }
                $query = http_build_query($parts);
                return preg_replace('/%5B(?:[0-9]|[1-9][0-9]+)%5D=/', '[]=', $query);;

        }

        public function __toString() {
                return $this->build();
        }

}

字符串
此代码还可以接受特定键的值数组

$qs = new QueryString();
$qs->add('trialId', array('1','2'));
$qs->add('packageId', '12');
$qs->add('frequencyId', '4');
var_dump($qs->build());


这个类将生成普通的查询字符串,键有多个值,加上[]符号,输出如下所示

?frequencyId=4&packageId=12&trialId[]=1&trialId[]=2

flmtquvp

flmtquvp4#

PHP关联数组将在以后的赋值中覆盖键。
因此,你应该调整你的数组,

$service_url = 'https://www.googleapis.com/freebase/v1/topic';
$mid = '/m/0d6lp';
$params = array('filter' => '/common/topic/notable_for', 'filter' =>   '/common/topic/alias');
$url = $service_url . $mid . '?' . http_build_query($params);

字符串

$service_url = 'https://www.googleapis.com/freebase/v1/topic';
$mid = '/m/0d6lp';
$params = array('filter' => ['/common/topic/notable_for', '/common/topic/alias']);
$url = $service_url . $mid . '?' . http_build_query_duplicate_key($params);
// https://www.googleapis.com/freebase/v1/topic/m/0d6lp?filter=/common/topic/notable_for&filter=/common/topic/alias


http_build_query_duplicate_key定义如下:

function http_build_query_duplicate_key( array $array ) {
  $special_keys = [];
  foreach($array as $key => $value) {
    if (is_array($value) AND count($value) > 0) {
      if (array_is_list($value)) {
        foreach($value as $value_b) {
          /** Check if nested array that requires further breakdown */
          if (is_array($value_b) AND !array_is_list($value_b)) {
            foreach($value_b as $key2 => $value2) {
              /** Adding a $key2 in the bracket is needed for nested array */
              $special_keys[] = http_build_query_duplicate_key([$key.'['.$key2.']' => $value2]);
            }
          } else {
          /** Else, just build http query as usual. */
            $special_keys[] = http_build_query([$key => $value_b]);
          }
        }
      } else {
        /** PHP http_build_query will add array index number which are not accepted. Hence, we need to break it down manually. */
        $special_keys[] =  http_build_query_duplicate_key([$key => [$value]]);
      }
      unset($array[ $key ]);
    }
  }

  $and_symbol = '';
  if (count($array) > 0) {
    $and_symbol = '&';
  }

  return implode('&', $special_keys) . $and_symbol . http_build_query($array);
}


即使有嵌套数组,这段代码也可以工作,因为它将递归调用该方法,直到所有嵌套数组都被解决。
希望这有帮助

bq9c1y66

bq9c1y665#

1.不能在accoc数组中用一个索引存储两个或多个值。

  1. API不接受像filter[]这样的值
    因此,我建议您创建自己的函数来构建该查询。

相关问题