通过添加GET参数来操作url字符串


Manipulate a url string by adding GET parameters

我想为url添加GET参数,这些url可能包含GET参数,也可能不包含GET参数,而不重复?&

的例子:

如果我想添加category=action

$url="http://www.acme.com";
 // will add ?category=action at the end
$url="http://www.acme.com/movies?sort=popular";
 // will add &category=action at the end

如果你注意到我试图不重复这个问号,如果它被发现。

URL只是一个字符串。

附加特定GET参数的可靠方法是什么?

基本方法

$query = parse_url($url, PHP_URL_QUERY);
// Returns a string if the URL has parameters or NULL if not
if ($query) {
    $url .= '&category=1';
} else {
    $url .= '?category=1';
}
更高级

$url = 'http://example.com/search?keyword=test&category=1&tags[]=fun&tags[]=great';
$url_parts = parse_url($url);
// If URL doesn't have a query string.
if (isset($url_parts['query'])) { // Avoid 'Undefined index: query'
    parse_str($url_parts['query'], $params);
} else {
    $params = array();
}
$params['category'] = 2;     // Overwrite if exists
$params['tags'][] = 'cool';  // Allows multiple values
// Note that this will url_encode all values
$url_parts['query'] = http_build_query($params);
// If you have pecl_http
echo http_build_url($url_parts);
// If not
echo $url_parts['scheme'] . '://' . $url_parts['host'] . $url_parts['path'] . '?' . $url_parts['query'];

你至少应该把它放在一个函数中,如果不是一个类。

以下是接受答案的简短版本:

$url .= (parse_url($url, PHP_URL_QUERY) ? '&' : '?') . 'category=action';

编辑:正如在公认的答案中讨论的那样,这是有缺陷的,因为它没有检查category是否已经存在。更好的解决方案是将$_GET视为一个数组,并使用像in_array()这样的函数。

$data = array('foo'=>'bar',
              'baz'=>'boom',
              'cow'=>'milk',
              'php'=>'hypertext processor');
$queryString =  http_build_query($data);
//$queryString = foo=bar&baz=boom&cow=milk&php=hypertext+processor
echo 'http://domain.com?'.$queryString;
//output: http://domain.com?foo=bar&baz=boom&cow=milk&php=hypertext+processor

使用strpos来检测?自吗?只能出现在URL查询字符串的开头,你知道它是否存在,你需要使用&

添加参数
function addGetParamToUrl(&$url, $varName, $value)
{
    // is there already an ?
    if (strpos($url, "?"))
    {
        $url .= "&" . $varName . "=" . $value; 
    }
    else
    {
        $url .= "?" . $varName . "=" . $value;
    }
}

此函数覆盖现有参数

function addToURL( $key, $value, $url) {
    $info = parse_url( $url );
    parse_str( $info['query'], $query );
    return $info['scheme'] . '://' . $info['host'] . $info['path'] . '?' . http_build_query( $query ? array_merge( $query, array($key => $value ) ) : array( $key => $value ) );
}

更新已有参数的示例。

还使用了url_encode,并且可以不指定参数值

    <?
    /**
     * Add parameter to URL
     * @param string $url
     * @param string $key
     * @param string $value
     * @return string result URL
     */
    function addToUrl($url, $key, $value = null) {
        $query = parse_url($url, PHP_URL_QUERY);
        if ($query) {
            parse_str($query, $queryParams);
            $queryParams[$key] = $value;
            $url = str_replace("?$query", '?' . http_build_query($queryParams), $url);
        } else {
            $url .= '?' . urlencode($key) . '=' . urlencode($value);
        }
        return $url;
    }

一行:

$url .= (strpos($url, '?') ? '&' : '?') . http_build_query($additionalParams);

建议使用http_build_query,因为它编码特殊字符(例如空格或电子邮件地址中的@)


2022年改进版本

这允许替换现有的参数,并保留现有的URL片段(URL末尾#之后的部分)

function addParametersToUrl(string $url, array $newParams): string
{
    $url = parse_url($url);
    parse_str($url['query'] ?? '', $existingParams);
    $newQuery = array_merge($existingParams, $newParams);
    $newUrl = $url['scheme'] . '://' . $url['host'] . ($url['path'] ?? '');
    if ($newQuery) {
        $newUrl .= '?' . http_build_query($newQuery);
    }
    if (isset($url['fragment'])) {
        $newUrl .= '#' . $url['fragment'];
    }
    return $newUrl;
}

测试:

$newParams = [
    'newKey' => 'newValue',
    'existingKey' => 'new',
];
echo addParametersToUrl('https://www.example.com', $newParams);
// https://www.example.com?newKey=newValue&existingKey=new
echo addParametersToUrl('https://www.example.com/', $newParams);
// https://www.example.com/dir/?newKey=newValue&existingKey=new
echo addParametersToUrl('https://www.example.com/dir/', $newParams);
// https://www.example.com/dir/?newKey=newValue&existingKey=new
echo addParametersToUrl('https://www.example.com/dir/file?foo=bar', $newParams);
// https://www.example.com/dir/file?foo=bar&newKey=newValue&existingKey=new
echo addParametersToUrl('https://www.example.com/dir/file?foo=bar&existingKey=old', $newParams);
// https://www.example.com/dir/file?foo=bar&existingKey=new&newKey=newValue
echo addParametersToUrl('https://www.example.com/dir/file?foo=bar&existingKey=old#hash', $newParams);
// https://www.example.com/dir/file?foo=bar&existingKey=new&newKey=newValue#hash
echo addParametersToUrl('https://www.example.com/dir/file#hash', $newParams);
// https://www.example.com/dir/file?newKey=newValue&existingKey=new#hash
echo addParametersToUrl('https://www.example.com/dir/file?foo=bar#hash', $newParams);
// https://www.example.com/dir/file?foo=bar&newKey=newValue&existingKey=new#hash

<?php
$url1 = '/test?a=4&b=3';
$url2 = 'www.baidu.com/test?a=4&b=3&try_count=1';
$url3 = 'http://www.baidu.com/test?a=4&b=3&try_count=2';
$url4 = '/test';
function add_or_update_params($url,$key,$value){
    $a = parse_url($url);
    $query = $a['query'] ? $a['query'] : '';
    parse_str($query,$params);
    $params[$key] = $value;
    $query = http_build_query($params);
    $result = '';
    if($a['scheme']){
        $result .= $a['scheme'] . ':';
    }
    if($a['host']){
        $result .= '//' . $a['host'];
    }
    if($a['path']){
        $result .=  $a['path'];
    }
    if($query){
        $result .=  '?' . $query;
    }
    return $result;
}
echo add_or_update_params($url1,'try_count',1);
echo "'n";
echo add_or_update_params($url2,'try_count',2);
echo "'n";
echo add_or_update_params($url3,'try_count',3);
echo "'n";
echo add_or_update_params($url4,'try_count',4);
echo "'n";
 /**
 * @example addParamToUrl('/path/to/?find=1', array('find' => array('search', 2), 'FILTER' => 'STATUS'))
 * @example addParamToUrl('//example.com/path/to/?find=1', array('find' => array('search', 2), 'FILTER' => 'STATUS'))
 * @example addParamToUrl('https://example.com/path/to/?find=1&FILTER=Y', array('find' => array('search', 2), 'FILTER' => 'STATUS'))
 *
 * @param       $url string url
 * @param array $addParams
 *
 * @return string
 */
function addParamToUrl($url, array $addParams) {
  if (!is_array($addParams)) {
    return $url;
  }
  $info = parse_url($url);
  $query = array();
  if ($info['query']) {
    parse_str($info['query'], $query);
  }
  if (!is_array($query)) {
    $query = array();
  }
  $params = array_merge($query, $addParams);
  $result = '';
  if ($info['scheme']) {
    $result .= $info['scheme'] . ':';
  }
  if ($info['host']) {
    $result .= '//' . $info['host'];
  }
  if ($info['path']) {
    $result .= $info['path'];
  }
  if ($params) {
    $result .= '?' . http_build_query($params);
  }
  return $result;
}
$parameters = array();
foreach ($get as $key => $value)
{
     $parameters[] = $key.'='.$value;
}
$url = 'http://example.com/movies?'.implode('&', $parameters);

我认为你应该这样做。

class myURL {
    protected $baseURL, $requestParameters;
    public function __construct ($newURL) {
        $this->baseurl = $newURL;
        $this->requestParameters = array();
    }
    public function addParameter ($parameter) {
        $this->requestParameters[] = $parameter;
    }
    public function __toString () {
        return $this->baseurl.
               ( count($this->requestParameters) ?
                 '?'.implode('&', $this->requestParameters) :
                 ''
                 );
    }
}
$url1 = new myURL ('http://www.acme.com');
$url2 = new myURL ('http://www.acme.com');
$url2->addParameter('sort=popular');
$url2->addParameter('category=action');
$url1->addParameter('category=action');
echo $url1."'n".$url2;

在搜索了许多关于这个主题的资源/答案后,我决定编写自己的代码。根据@TaylorOtwell的回答,这就是我如何处理传入的$_GET请求并修改/操作每个元素。

假设url为:http://domain.com/category/page.php?a=b&x=y我只需要一个排序参数:?desc=column_name或?asc=column_name。这样,单个url参数就足以同时进行排序和排序。因此,在第一次单击相关表标题行时,URL将是http://domain.com/category/page.php?a=b&x=y&desc=column_name。

然后我有表行标题,我想在第一次单击时排序DESC,在第二次单击同一标题时排序ASC。(每次第一次点击应该先"ORDER BY column DESC")如果没有排序,默认按"date then id"排序。

您可以进一步改进它,例如您可以向每个$_GET组件添加清理/过滤函数,但下面的结构奠定了基础。

foreach ($_GET AS $KEY => $VALUE){
    if ($KEY == 'desc'){
        $SORT = $VALUE;
        $ORDER = "ORDER BY $VALUE DESC";
        $URL_ORDER = $URL_ORDER . "&asc=$VALUE";
    } elseif ($KEY == 'asc'){
        $SORT = $VALUE;
        $ORDER = "ORDER BY $VALUE ASC";
        $URL_ORDER = $URL_ORDER . "&desc=$VALUE";
    } else {
        $URL_ORDER .= "&$KEY=$VALUE";
        $URL .= "&$KEY=$VALUE";
    }
}
if (!$ORDER){$ORDER = 'ORDER BY date DESC, id DESC';}
if ($URL_ORDER){$URL_ORDER = $_SERVER[SCRIPT_URL] . '?' . trim($URL_ORDER, '&');}
if ($URL){$URL = $_SERVER[SCRIPT_URL] . '?' . trim($URL, '&');}

(您可以使用$_SERVER[SCRIPT_URI]作为以http://domain.com开头的完整URL)

然后我在MySQL查询中使用上面得到的结果$ORDER:

"SELECT * FROM table WHERE limiter = 'any' $ORDER";

现在是查看URL是否有先前排序的函数,并根据顺序向URL添加带有"?"或"&"的排序(和排序)参数:

        function sort_order ($_SORT){
            global $SORT, $URL_ORDER, $URL;
            if ($SORT == $_SORT){
                return $URL_ORDER;
            } else {
                if (strpos($URL, '?') !== false){
                    return "$URL&desc=$_SORT";
                } else {                        
                    return "$URL?desc=$_SORT";
                }
            }
        }

最后,对表行头使用函数:

        echo "<th><a href='".sort_order('id')."'>ID</a></th>";

Summary:这将读取URL,修改每个$_GET组件,并使用你选择的参数生成最终URL,使用正确的"?"answers"&"

 public function addGetParamToUrl($url, $params)
{
    foreach ($params as $param) {
         if (strpos($url, "?"))
        {
            $url .= "&" .http_build_query($param); 
        }
        else
        {
            $url .= "?" .http_build_query($param); 
        }
    }
    return $url;
}

另一个改进的函数版本。将现有答案与小改进(端口支持)和错误修复(正确检查密钥)混合在一起。

/**
 * @param string $url original url to modify - can be relative, partial etc
 * @param array $paramsOverride associative array, can be empty
 * @return string modified url
 */
protected function overrideUrlQueryParams($url, $paramsOverride){
    if (!is_array($paramsOverride)){
        return $url;
    }
    $url_parts = parse_url($url);
    if (isset($url_parts['query'])) {
        parse_str($url_parts['query'], $params);
    } else {
        $params = [];
    }
    $params = array_merge($params, $paramsOverride);
    $res = '';
    if(isset($url_parts['scheme'])) {
        $res .= $url_parts['scheme'] . ':';
    }
    if(isset($url_parts['host'])) {
        $res .= '//' . $url_parts['host'];
    }
    if(isset($url_parts['port'])) {
        $res .= ':' . $url_parts['port'];
    }
    if (isset($url_parts['path'])) {
        $res .= $url_parts['path'];
    }
    if (count($params) > 0) {
        $res .= '?' . http_build_query($params);
    }
    return $res;
}

尝试此函数添加URL参数

当参数设置时,你可以禁用链接,这样就不会有重复的url参数。

<?php
  function addQueryString($a)
                {
             if (empty($_SERVER['QUERY_STRING']))
               return '?' . $a;
             else if (!empty($_SERVER['QUERY_STRING']))
              return '?' . $_SERVER['QUERY_STRING'] . '&' . $a;
                }
?>
 <a href="<?php echo addQueryString('lang=en'); ?>">test</a>
 <a href="<?php echo addQueryString('category=5'); ?>">sat</a>

如果你正在使用WordPress,你可以简单地使用

    add_query_args(['sort' => 'asc'], 'http:/example.com/?search=news')

文档https://developer.wordpress.org/reference/functions/add_query_arg/

Laravel的解

如果你正在使用Laravel,你可以使用Request对象的函数。

// In a controller function
function foo(Request $request) {
    // will be www.laravel.test?hi=there
    $urlWithNewQueryParam = $request->fullUrlWithQuery(['hi' => 'there']);
}
// Outside of a controller function (like in a blade)
request()->fullUrlWithQuery(['hi' => 'there']); // will be www.laravel.test?hi=there

这也将正确地添加&,并覆盖具有相同名称的查询参数,如果它们已经存在。

您可以在这里的文档中阅读更多内容https://laravel.com/docs/10.x/requests#retrieving-the-request-url.