不带GET参数的请求字符串

70

有没有一种简单的方法可以获取请求的文件或目录而不带GET参数?例如,如果URL是http://example.com/directory/file.php?paramater=value,我想返回http://example.com/directory/file.php。我很惊讶在$_SERVER[]中没有一个简单的索引。我错过了吗?


使用POST代替GET?这样做可行吗? - Pluckerpluck
不,这是一个更大的Web应用程序的一部分。无法确定将使用GET还是POST。 - Nathan
12个回答

126

编辑:@T.Todua提供了一个使用parse_url的更新这个问题的答案

(请点赞该答案以使其更加可见)。

编辑2:有人在垃圾邮件和编辑有关提取方案的内容,因此我已将其添加在底部。

parse_url解决方案

The simplest solution would be:

echo parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH);

parse_url是一个内置的php函数,其唯一目的是从url中提取特定的组件,包括路径(第一个“?”之前的所有内容)。因此,它是我解决这个问题的新“最佳”解决方案。

strtok解决方案

Stackoverflow:如何删除查询字符串并仅获取url?

You can use strtok to get string before first occurence of ?

$url=strtok($_SERVER["REQUEST_URI"],'?');

性能注意事项: 这个问题也可以使用explode来解决。

  • 对于仅在单个分隔符上拆分字符串的情况,explode倾向于表现更好。
  • 对于利用多个分隔符的情况,strtok倾向于表现更好。

将strtok应用于返回字符串中第一个字符实例之前的所有内容将比PHP中的任何其他方法都表现更好,但会在内存中保留查询字符串。

关于方案(http/https)和$_SERVER变量的一些说明

虽然OP没有询问,但我认为值得一提的是: 应该使用parse_url从url中提取任何特定组件,请参阅该函数的文档:

parse_url($actual_link, PHP_URL_SCHEME); 

需要注意的是,从请求中获取完整的URL并不是一项微不足道的任务,并且有许多安全方面的考虑。在这里,$_SERVER变量是你的朋友,但它们是一个善变的朋友,因为apache/nginx配置、php环境甚至客户端都可能省略或更改这些变量。所有这些都超出了本问题的范围,但已经进行了深入讨论:

https://dev59.com/imw15IYBdhLWcg3wMY6L#6768831

重要的是要注意这些 $_SERVER 变量在运行时由执行引擎(/var/run/php//etc/php/[version]/fpm/)填充。这些变量从操作系统传递到web服务器(apache/nginx),再到php引擎,并在每个步骤中进行修改和修正。可以依靠的仅有的这些变量是 REQUEST_URI (因为它是php所需的)和RFC 3875中列出的变量(请参见: PHP: $_SERVER),因为它们是web服务器所必需的。请注意: 在其他问题中垃圾邮件链接到您的答案是不好的方式。

73

您可以使用$_SERVER['REQUEST_URI']来获取请求的路径。然后,您需要删除参数...

$uri_parts = explode('?', $_SERVER['REQUEST_URI'], 2);

然后,加入主机名和协议。

echo 'http://' . $_SERVER['HTTP_HOST'] . $uri_parts[0];

如果你同时使用了http:https://,你还需要检测协议。可以使用$_SERVER['REQUEST_SCHEME']获取协议。至于如何实现,就留给你自己去练习吧。


将所有内容组合在一起:

echo $_SERVER['REQUEST_SCHEME'] .'://'. $_SERVER['HTTP_HOST'] 
     . explode('?', $_SERVER['REQUEST_URI'], 2)[0];

返回值,例如:

http://example.com/directory/file.php


php.com文档:

  • $_SERVER — 服务器和执行环境信息
  • explode — 用字符串分割另一个字符串
  • parse_url — 解析URL,返回其组成部分(可能是更好的解决方案)

太棒了。我就知道一定是什么简单的问题。我把explode函数的最后一个参数删掉了,现在它完美地工作了。谢谢! - Nathan
@BrNathanH,我已编辑限制,现在是2。这对您来说不重要,但如果您想要查询字符串部分(在“?”后面),并且有人在那里插入了第二个“?” ,那么将explode()限制为2个元素即可。 - Brad
isset( $_SERVER[ 'HTTPS' ] ) ? "https" : "http" - GDY

56

echo parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH);


2
尽管这可能是一个不错的答案,但最好解释一下你的答案背后的原因。http://stackoverflow.com/help/how-to-answer - Daniel Casserly
1
谢谢,这个方法可行且是最佳实践。 - Bo Pennings
4
我认为这是最好的答案,不需要解释,在我看来,如果我们需要解释,我们会去问医生。 - pythonian29033
2
@pythonian29033,但正如你所提到的,“去看文档”- 那么至少应该有指向文档的链接。 - user5147563
2
让我们不要懒惰。 - pythonian29033
1
漂亮而优雅 - Eduardo de Souza

2

下面是一种考虑到不同端口和https的解决方案:

$pageURL = (@$_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://';

if ($_SERVER['SERVER_PORT'] != '80')
  $pageURL .= $_SERVER['SERVER_NAME'].':'.$_SERVER['SERVER_PORT'].$_SERVER['PHP_SELF'];
else 
  $pageURL .= $_SERVER['SERVER_NAME'].$_SERVER['PHP_SELF'];  

或者一个更基础的解决方案,不考虑其他端口:

$pageURL = (@$_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://';
$pageURL .= $_SERVER['SERVER_NAME'].$_SERVER['PHP_SELF']; 

1

我认为这不是解析它的好方法。它不够干净,或者有点离题...

  • Explode很重
  • Session很重
  • PHP_SELF不能处理URL重写

我会做一些像这样的事情...

if ($pos_get = strpos($app_uri, '?')) $app_uri = substr($app_uri, 0, $pos_get);
  • 这个代码片段用于检测是否存在实际的“?”(GET标准格式)。
  • 如果没有问题,它会在保留用于获取数据的“?”之前截取我们的变量。

假设$app_uri是我的网站的URI / URL。


1
$uri_parts = explode('?', $_SERVER['REQUEST_URI'], 2);
$request_uri = $uri_parts[0];
echo $request_uri;

好的复制粘贴内容。 - j4k3
@j4k3,看起来可能像是复制粘贴,但实际上我正在我的项目中使用相同的代码。 - mahfuz

0

我知道这是一个旧帖子,但我遇到了同样的问题,并且我是这样解决的

$current_request = preg_replace("/\?.*$/","",$_SERVER["REQUEST_URI"]);

或者等价地

$current_request = preg_replace("/\?.*/D","",$_SERVER["REQUEST_URI"]);

0

并不是每个人都会觉得它简单,但我认为这是最好的解决方法:

preg_match('/^[^\?]+/', $_SERVER['REQUEST_URI'], $return);
$url = 'http' . ('on' === $_SERVER['HTTPS'] ? 's' : '') . '://' . $_SERVER['HTTP_HOST'] . $return[0]

它的作用很简单,就是从字符串的开头开始遍历REQUEST_URI,当遇到"?"时停止(实际上,只有在遇到参数时才会出现"?")。
然后你创建URL并将其保存到$url中:
在创建$url时...我们只是写入"http",然后检查是否使用了https,如果是,则再写入"s",然后连接"://",连接HTTP_HOST(服务器,例如:"stackoverflow.com"),并将之前找到的$return连接到其中(它是一个数组,但我们只想要其中的第一个索引...因为我们是从正则表达式的开头进行检查的,所以只能有一个索引)。
希望有人能用得上这个...
附注:已经确认在使用SLIM重新路由URL时可以正常工作。

1
你能解释一下相对于 parse_url 和/或 strtok 的优势吗? - Tony Chiboucas
我猜你现在关注的是 preg_match... 使用 strtok() 也可以得到与 preg_match() 相同的行为,但我不知道是否会有性能差异。 我只是更喜欢 preg_match,并认为它更常见和文档更好,因此其他开发人员将更容易使用它。 你可能可以使用 parse_url 并从中获取所需的所有内容。这可能是一种更轻量级的方法,但我没有找到测试的理由。 但是人们显然不知道它,因此从创建的数组中获取东西会更不可访问,以我看来。 - RasmusLD
1
我是一个正则表达式迷,所以我理解使用它作为所有解析需求的魔法药丸的愿望。然而,parse_url已经清楚地记录在案,对于那些不熟悉正则表达式的人来说,在代码中更容易理解。explode的性能更好,strtok的性能最佳,而正则表达式是基准测试php文档中最慢的选项。因此,我很好奇这个答案相比其他答案有什么优势? - Tony Chiboucas
我并不是要暗示你的回答是错误的,它仍然是一个好的答案。 - Tony Chiboucas
1
你当然是正确的,如果人们不熟悉正则表达式,那么遇到它就会很麻烦。但问题在于,在我工作的公司里,每个开发者都知道正则表达式(只有一个人对此不太熟悉),但是从彼此交流中,我发现这里的人们更理解正则表达式而不是parse_url和strtok。由于这是一个不需要迭代的简单操作,对我们来说,性能并不像可读性那样重要。总之,基于我们衡量的标准,这种方法对我们最好。但是说它是普遍最佳的方法是不科学的。 - RasmusLD

0

你可以使用$_GET来获取URL参数,或者使用$_POST来获取POST参数,但是$_REQUEST包含了$_GET$_POST$_COOKIE的所有参数。如果你想要隐藏URI参数,你可以将它转换为会话变量,像这样:

<?php

session_start();
if (isset($_REQUEST['param']) && !isset($_SESSION['param'])) {

    // Store all parameters received
    $_SESSION['param'] = $_REQUEST['param'];

    // Redirect without URI parameters
    header('Location: /file.php');
    exit;
}
?>
<html>
<body>
<?php
  echo $_SESSION['param'];
?>
</body>
</html>

编辑

使用$_SERVER['PHP_SELF']获取当前文件名或者$_SERVER['REQUEST_URI']获取请求的URI。


谢谢,但我想知道他们请求的页面是什么,不包括GET参数。 - Nathan
这与OP所问的相反。 - ashleedawg
@ashleedawg,那就给它点个踩吧(或者只需阅读“编辑”以获取正确答案),不确定为什么我需要被提醒我犯了7年前的错误-你也在审查其他答案吗? - JKirchartz

0

令人震惊的是,这些被投票/接受的答案中有多少是不完整的,因此它们没有回答问题,经过了7年!

  • 如果您在一个URL为:http://example.com/directory/file.php?paramater=value 的页面上

  • ...并且您想要返回:http://example.com/directory/file.php

  • 那么使用:

    echo $_SERVER['REQUEST_SCHEME'].'://'.$_SERVER['SERVER_NAME'].$_SERVER['PHP_SELF'];


为什么你在评论和问题中到处发垃圾信息?撇开OP并未询问scheme的事实不谈,$_SERVER['PHP_SELF'] 不可靠,不能像那样使用,因为在CGI/FCGI实施中它经常为空。 - Tony Chiboucas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接