当不存在参数时,如何摆脱 URL 中的“?”


How to get rid of `?` in URL when no parameters exist?

我有以下规则来检查 url 是否包含任何以 p2 开头的参数:

function unparse_url($parsed_url) {
  $scheme   = isset($parsed_url['scheme']) ? $parsed_url['scheme'] . '://' : '';
  $host     = isset($parsed_url['host']) ? $parsed_url['host'] : '';
  $port     = isset($parsed_url['port']) ? ':' . $parsed_url['port'] : '';
  $user     = isset($parsed_url['user']) ? $parsed_url['user'] : '';
  $pass     = isset($parsed_url['pass']) ? ':' . $parsed_url['pass']  : '';
  $pass     = ($user || $pass) ? "$pass@" : '';
  $path     = isset($parsed_url['path']) ? $parsed_url['path'] : '';
  $query    = isset($parsed_url['query']) ? '?' . trim($parsed_url['query'], '&') : '';
  $fragment = isset($parsed_url['fragment']) ? '#' . $parsed_url['fragment'] : '';
  return "$scheme$user$pass$host$port$path$query$fragment";
}
function strip_query($url, $query_to_strip) {
  $parsed = parse_url($url);
  $parsed['query'] = preg_replace('/(^|&)'.$query_to_strip.'[^&]*/', '', $parsed['query']);
  return unparse_url($parsed);
}
$url = "http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
$new_url = (strip_query($url, 'p2'));
# redirect  if url contains anything that starts with p2 
$filtered = array_filter(array_keys($_GET), function($k) {
    return strpos($k, 'p2') === 0;
});
if ( !empty($filtered) ) {
    header ("Location: $new_url");
}
else {
}

如果 url 包含任何p2*参数,则会重定向到没有这些参数的同一页面。

例:

domain.com/?a=3&p2=1

将重定向至

domain.com/?a=3

但是,使用当前规则,如果原始 URL 是:

domain.com/?p2=1

然后它将重定向到:

domain.com/?

但由于它毫无意义,我希望在这种情况下它将重定向到:

domain.com/

怎么能做到呢?

像@dontfight一样,我建议使用mod_rewrite但是如果您更喜欢PHP,则可以在执行重定向之前使用rtrim

rtrim($url, '?');
使用

您的代码,您可以像这样使用

$filtered = array_filter(array_keys($_GET), function($k) {
    return strpos($k, 'p2') === 0;
});
$new_url_trim = rtrim($new_url, '?');
if ( !empty($filtered) ) {
    header ("Location: $new_url_trim");
}
else {
}

下面是删除查询参数的另一种方法:

  1. 分析 URL 以将其分为方案、路径和查询
  2. 将查询字符串解析为数组
  3. 取消设置数组中的参数
  4. 重新创建网址

例:

<?php
function removeQuery($url, $param) {
    $parsed = parse_url($url);
    parse_str($parsed['query'], $query);
    unset($query[$param]);
    $parsed['scheme'] .= '://';
    $parsed['query'] = http_build_query($query);
    if (!empty($parsed['query']))
        $parsed['path'] .= '?';
    return implode($parsed);
}
echo removeQuery('http://domain.com/?a=3&p2=1', 'a') . "'n";
echo removeQuery('http://domain.com/?a=3&p2=1', 'p2') . "'n";
echo removeQuery('http://domain.com/?p2=1', 'p2');

输出:

http://domain.com/?p2=1
http://domain.com/?a=3
http://domain.com/

我还注意到,如果p2出现在字符串中的任何位置,您想删除它,因此这是另一个旨在执行此操作的版本:

<?php
function removeP2($url) {
    $parsed = parse_url($url);
    parse_str($parsed['query'], $query);
    foreach ($query as $key => $value)
        if (strpos($key, 'p2') === 0)
            unset($query[$key]);
    $parsed['scheme'] .= '://';
    $parsed['query'] = http_build_query($query);
    if (!empty($parsed['query']))
        $parsed['path'] .= '?';
    return implode($parsed);
}
echo removeP2('http://domain.com/?a=3&p2=1') . "'n";
echo removeP2('http://domain.com/?a=3&p2sks=1') . "'n";
echo removeP2('http://domain.com/?p2=1');

输出:

http://domain.com/?a=3
http://domain.com/?a=3
http://domain.com/

现在要让它重定向,您已经知道如何重定向:

header("Location: " . removeP2('http://' . $_SERVER[HTTP_HOST] . $_SERVER[REQUEST_URI]));

既然没有人费心告诉你出了什么问题......

您的

问题是您的 strip_query() 函数总是将$url["query"]设置为一个值,即使该值是空字符串:

$parsed['query'] = preg_replace('/(^|&)'.$query_to_strip.'[^&]*/', '', $parsed['query']);

当您的unparse_url()函数获取 URL 时,它会使用 isset() 检查该数组索引,该索引始终传递:

$query    = isset($parsed_url['query']) ? '?' . trim($parsed_url['query'], '&') : '';

您可以使用 empty() 代替检查isset(),如果值未设置为空字符串,它将返回 false:

$query    = !empty($parsed_url['query']) ? '?' . trim($parsed_url['query'], '&') : '';

如果mod_rewrite可用,这可以在没有PHP代码的情况下完成。

这不是答案,而是评论,但有点长。

为什么你如此热衷于从URL中删除这个变量?它对你有什么伤害,你必须不遗余力地根除它的存在?为什么不只是...

unset($_GET['p2']);

但既然毫无意义,

以什么方式?

我可以看到unparse_url($parsed_url)函数的一些优点,如果您修复错误(提示:尝试一些带有用户名和/或密码的测试用例(,那么它的结构相当良好 - 但随后用于操作数据的代码是正则表达式字符串拼接的混乱混合 - 这不是处理此类结构化数据的正确方法 - PHP 具有此功能。

但最糟糕的一点是注入另一个完整的 RTT 来解析 URL。

你比这个洛基罗比!