题 获取PHP中的完整URL


我使用此代码获取完整的URL:

$actual_link = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'];

问题是我在我的身上使用了一些口罩 .htaccess,所以我们在URL中看到的并不总是文件的真实路径。

我需要的是获取URL,URL中写的内容,没有更多,也就是说完整的URL。

我需要了解它在Web浏览器的导航栏中的显示方式,而不是服务器上文件的真实路径。


979
2017-07-20 21:29


起源


@Brade URL栏位于用户浏览器上,那么为什么PHP会有相关的功能呢? PHP是服务器端。 - eis
@eis相信我,有很多理由想要这个。使用相同模板但需要单独跟踪的登陆页面等等。事实上,PHP(或任何服务器端lang)可以返回URL的所有各个部分,但似乎永远不会在一个字符串中提供整个内容。这看起来很愚蠢。 - Brade
整件事永远不会发送到服务器端,因为它无关紧要,这就是它无法在任何地方随时可用的原因。我认为任何依赖于破坏的功能。但那只是我的个人意见。 - eis
上面我需要一个自我URL的例子:“填充FORM动作URL”可能是错误的,因为PHP_SELF(仅限路径,无域等)应该足够了。但这并不一定意味着规范自我URL的所有其他需求都是无效的。如果他们确实如此,那么看到一个彻底的解释,为什么会很棒。 - Sz.
您不应在配置中对URL进行硬编码的原因之一是您有不同的平台,您的项目将安装在其上(开发,集成,生产)。其中每个都有自己的特定URL,您不希望根据项目安装的服务器更改代码。 - Guillaume Fache


答案:


看一下 $_SERVER['REQUEST_URI'],即

$actual_link = "http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";

(注意双引号字符串语法是 完全正确

如果要同时支持HTTP和HTTPS,则可以使用

$actual_link = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";

编者注: 使用此代码了 安全隐患。客户端可以将HTTP_HOST和REQUEST_URI设置为它想要的任意值。


1627
2017-07-20 21:33



如果您使用的是https链接怎么办?如果HTTP_HOST不可用或被客户端篡改怎么办?这个答案似乎不完整且不可靠。 - Manachi
你可以做的不多,这是问题的正确方法。 - Mfoo
这个答案并不完全正确 - 架构可能是https - Nigel Angel
您只需添加HTTPS检查: 'http' . (isset($_SERVER['HTTPS']) ? 's' : '') . '://' . "{$_SERVER['HTTP_HOST']}/{$_SERVER['REQUEST_URI']}" - ivkremer
如果您将URL作为链接输出到浏览器,只需将http:关闭即可。看到: stackoverflow.com/questions/4978235 - GameCharmer


短版本输出网页上的链接

$url =  "//{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}";

$escaped_url = htmlspecialchars( $url, ENT_QUOTES, 'UTF-8' );
echo '<a href="' . $escaped_url . '">' . $escaped_url . '</a>';

以下是有关问题和边缘情况的更多细节 //example.com/path/格式

完整版

function url_origin( $s, $use_forwarded_host = false )
{
    $ssl      = ( ! empty( $s['HTTPS'] ) && $s['HTTPS'] == 'on' );
    $sp       = strtolower( $s['SERVER_PROTOCOL'] );
    $protocol = substr( $sp, 0, strpos( $sp, '/' ) ) . ( ( $ssl ) ? 's' : '' );
    $port     = $s['SERVER_PORT'];
    $port     = ( ( ! $ssl && $port=='80' ) || ( $ssl && $port=='443' ) ) ? '' : ':'.$port;
    $host     = ( $use_forwarded_host && isset( $s['HTTP_X_FORWARDED_HOST'] ) ) ? $s['HTTP_X_FORWARDED_HOST'] : ( isset( $s['HTTP_HOST'] ) ? $s['HTTP_HOST'] : null );
    $host     = isset( $host ) ? $host : $s['SERVER_NAME'] . $port;
    return $protocol . '://' . $host;
}

function full_url( $s, $use_forwarded_host = false )
{
    return url_origin( $s, $use_forwarded_host ) . $s['REQUEST_URI'];
}

$absolute_url = full_url( $_SERVER );
echo $absolute_url;

这是一个经过大量修改的版本 http://snipplr.com/view.php?codeview&id=2734

网址结构:

方案://用户名密码@domain:端口/路径QUERY_STRING#fragment_id

功能不包括粗体部分

笔记:

  • 此功能不包括 username:password 从完整的URL或片段(哈希)。
  • 它不会显示HTTP的默认端口80和HTTPS的端口443。
  • 仅使用http和https方案进行测试。
  • #fragment_id 客户端(浏览器)不会将其发送到服务器,也不会添加到完整的URL。
  • $_GET 只会包含 foo=bar2 对于像这样的URL /example?foo=bar1&foo=bar2
  • 一些CMS和环境将重写 $_SERVER['REQUEST_URI'] 并返回 /example?foo=bar2 对于像这样的URL /example?foo=bar1&foo=bar2, 使用 $_SERVER['QUERY_STRING'] 在这种情况下。
  • 请记住 URI = URL + URN,但由于流行使用,URL现在意味着URI和URL。
  • 你应该删除 HTTP_X_FORWARDED_HOST 如果您不打算使用代理或平衡器。
  • 规范 说那个 Host header必须包含端口号,除非它是默认号码。

客户端(浏览器)控制变量:

  • $_SERVER['REQUEST_URI']。在发送之前,浏览器会对任何不受支持的字符进行编码。
  • $_SERVER['HTTP_HOST'] 并且根据PHP手册中的注释并不总是可用: http://php.net/manual/en/reserved.variables.php
  • $_SERVER['HTTP_X_FORWARDED_HOST'] 由平衡器设置,并没有在列表中提到 $_SERVER PHP手册中的变量。

服务器控制变量:

  • $_SERVER['HTTPS']。客户端选择使用它,但服务器返回空或“开”的实际值。
  • $_SERVER['SERVER_PORT']。服务器仅接受允许的号码作为端口。
  • $_SERVER['SERVER_PROTOCOL']。服务器只接受某些协议。
  • $_SERVER['SERVER_NAME'] 。它是在服务器配置中手动设置的,根据不适用于IPv6 kralyk

有关:

HTTP_HOST与SERVER_NAME
HTTP“主机”标头参数中是否需要端口号?
https://stackoverflow.com/a/28049503/175071


357
2018-01-17 08:57



如果服务器由IPv6 IP地址给出,则此代码将失败。要解决此问题,请使用HTTP_HOST替换SERVER_NAME。 - kralyk
注意: $_SERVER['REQUEST_URI'] 将会呈现 /example?foo=bar2 为url喜欢 /example?foo=bar1&foo=bar2 - Timo Huovinen
这不会包含#之后定义的任何内容,这些内容不会传递给服务器 - William King
我不确定这是否没有安全风险。在您的示例中,您可以发送Host标头以访问正确的页面,但可能会让页面认为它是使用HTTP_X_FORWARDED_HOST标头通过其他主机调用的。当应用程序使用此信息(无论如何)时,它确实是一个安全问题,因为它允许您承诺不是这种情况的事情。 - hek2mgl
@ Matt3o12端口的值直接取自 Host 标题,没有看到它设置那样,谢谢你提到它,将添加为一个调整 - Timo Huovinen


就此而言,只需查看整个数组即可 print_r($_SERVER),你会看到你需要的一切:)


190
2017-07-20 21:35



@ChenAsraf除了你不会在$ _SERVER中看到任何内容,例如任何HTTP_X变量。 请参阅此处的评论 如何从中获取更大的列表 搜索 phpinfo() 在dogpile上 - Timo Huovinen
不幸的是,获取当前URL实际上并不那么简单。所以这个答案没有帮助。 - mermshaus


URL的示例: https://example.com/subFolder/yourfile.php?var=blabla#12345

//built-in function 
$x = parse_url($url);
$x['scheme']               🡺 https
$x['host']                 🡺         example.com (or with WWW)
$x['path']                 🡺                    /subFolder/yourfile.php
$x['query']                🡺                                          var=blabla
$x['fragment']             🡺                                                     12345 // hashtag outputed only in case, when hashtag-containing string was manually passed to function, otherwise PHP is unable to recognise hashtags in $_SERVER

//built-in function  (with this function, I only recommend to pass `parse_url`s output as argument)
$A = pathinfo($url);
$B = pathinfo(parse_url($url)['path']);
$A['dirname']              🡺 https://example.com/subFolder
$B['dirname']              🡺                    /subFolder
$A['basename']             🡺                               yourfile.php?var=blabla#12345
$B['basename']             🡺                               yourfile.php
$A['extension']            🡺                                        php?var=blabla#12345
$B['extension']            🡺                                        php
$A['filename']             🡺                               yourfile
$B['filename']             🡺                               yourfile


//=================================================== //
//========== self-defined SERVER variables ========== //
//=================================================== //
$_SERVER["DOCUMENT_ROOT"]  🡺 /home/user/public_html
$_SERVER["SERVER_ADDR"]    🡺 143.34.112.23
$_SERVER["SERVER_PORT"]    🡺 80(or 443 etc..)
$_SERVER["REQUEST_SCHEME"] 🡺 https                                         //similar: $_SERVER["SERVER_PROTOCOL"] 
$_SERVER['HTTP_HOST']      🡺         example.com (or with WWW)             //similar: $_SERVER["ERVER_NAME"]
$_SERVER["REQUEST_URI"]    🡺                       /subFolder/yourfile.php?var=blabla
$_SERVER["QUERY_STRING"]   🡺                                               var=blabla
__FILE__                   🡺 /home/user/public_html/subFolder/yourfile.php
__DIR__                    🡺 /home/user/public_html/subFolder              //same: dirname(__FILE__)
$_SERVER["REQUEST_URI"]    🡺                       /subFolder/yourfile.php?var=blabla
parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH)🡺  /subFolder/yourfile.php 
$_SERVER["PHP_SELF"]       🡺                       /subFolder/yourfile.php

// ==================================================================//
//if "YOURFILE.php" is included in "PARENTFILE.php" , and you visit  "PARENTFILE.PHP?abc":
$_SERVER["SCRIPT_FILENAME"]🡺 /home/user/public_html/parentfile.php
$_SERVER["PHP_SELF"]       🡺                       /parentfile.php
$_SERVER["REQUEST_URI"]    🡺                       /parentfile.php?abc
__FILE__                   🡺 /home/user/public_html/subFolder/yourfile.php

// =================================================== //
// ================= handy variables ================= //
// =================================================== //
//If site uses HTTPS:
$HTTP_or_HTTPS = ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS']!=='off') || $_SERVER['SERVER_PORT']==443) ? 'https://':'http://' );            //in some cases, you need to add this condition too: if ('https'==$_SERVER['HTTP_X_FORWARDED_PROTO'])  ...

//To trim values to filename, i.e. 
basename($url)             🡺 yourfile.php

//excellent solution to find origin
$debug_files = debug_backtrace();       $initial_called_file = count($debug_files) ? $debug_files[count($debug_files) - 1]['file'] : __FILE__;

注意!:

  • hastag(#...)url部分无法从PHP(服务器端)检测到。为此,使用Javascript。
  • DIRECTORY_SEPARATOR 回报 \ 对于Windows类型的托管,而不是 /



对于WordPress

//(let's say, if wordpress is installed in subdirectory:  http://example.com/wpdir/)
home_url()                      🡺 http://example.com/wpdir/        //if is_ssl() is true, then it will be "https"
get_stylesheet_directory_uri()  🡺 http://example.com/wpdir/wp-content/themes/THEME_NAME  [same: get_bloginfo('template_url') ]
get_stylesheet_directory()      🡺 /home/user/public_html/wpdir/wp-content/themes/THEME_NAME
plugin_dir_url(__FILE__)        🡺 http://example.com/wpdir/wp-content/themes/PLUGIN_NAME
plugin_dir_path(__FILE__)       🡺 /home/user/public_html/wpdir/wp-content/plugins/PLUGIN_NAME/  

171
2017-11-15 09:59



#部分在哪里,我们是否无法在服务器端#之后访问部分? - Rohit Khatri
不幸的是,SERVER没有认识到..它可以在客户端浏览器中检测到(即javascript) - T.Todua
你能在Zend Framework中展示它吗? - YumYumYum


这是一个使用a的解决方案 三元声明,保持代码最小:

$url = "http" . (($_SERVER['SERVER_PORT'] == 443) ? "s" : "") . "://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];

假设一个人的Web服务器正在使用标准端口443,这是最小和最简单的方法 HTTPS


54
2018-04-24 13:30



或者使用 $_SERVER["HTTPS"] == "on" 检查SSL是否已启用。 - hasMobi - Android Apps
您应该使用$ _SERVER [“HTTPS”],因为端口443只是默认的SSL端口,而不是SSL指示器。 - Alex Barker
@AlexBarker - 这就是为什么我说“假设一个人的Web服务器使用标准的端口443进行HTTPS”。 - honyovk


我最喜欢的跨平台查找当前URL的方法是:

$url = (isset($_SERVER['HTTPS']) ? "https" : "http") . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";

40
2018-05-18 01:54



关闭,但我需要将其更改为:$ url =((isset($ _ SERVER ['HTTPS'])&& $ _SERVER ['HTTPS']!=='off')?“https”:“http”) 。 “:// $ _ SERVER [HTTP_HOST] $ _SERVER [REQUEST_URI]”; - Erik Allen


只需使用:

$uri = $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']

22
2017-12-09 09:07



尽管我想使用它,但它在IIS中不起作用。 stackoverflow.com/questions/18008135/... - Erik Allen
它输出了什么? - HappyCoder
PHP注意:未定义的索引:REQUEST_SCHEME - Erik Allen
我喜欢这个解决方案!但是你也可以让它适用于nginx吗? - cowboysaif
http://example.com  :8080  /request.php 并失败。这些答案很复杂是有原因的。 - DRS David Soft


function full_path()
{
    $s = &$_SERVER;
    $ssl = (!empty($s['HTTPS']) && $s['HTTPS'] == 'on') ? true:false;
    $sp = strtolower($s['SERVER_PROTOCOL']);
    $protocol = substr($sp, 0, strpos($sp, '/')) . (($ssl) ? 's' : '');
    $port = $s['SERVER_PORT'];
    $port = ((!$ssl && $port=='80') || ($ssl && $port=='443')) ? '' : ':'.$port;
    $host = isset($s['HTTP_X_FORWARDED_HOST']) ? $s['HTTP_X_FORWARDED_HOST'] : (isset($s['HTTP_HOST']) ? $s['HTTP_HOST'] : null);
    $host = isset($host) ? $host : $s['SERVER_NAME'] . $port;
    $uri = $protocol . '://' . $host . $s['REQUEST_URI'];
    $segments = explode('?', $uri, 2);
    $url = $segments[0];
    return $url;
}

注意:我刚刚对“Timo Huovinen”代码进行了更新,因此您不会在URL中获得任何内容。这个网址很简单,删除了“?hi = i&am = a&get”之类的内容。

例:

http://www.website.com/index?get=information

将显示为:

http://www.website.com/index

除非您使用Get来定义某些特定内容,否则请使用他的代码! :-)


16
2017-10-26 13:15



嘿那,非常酷:)你也可以删除散列“#”(url片段)之后的任何东西,以防它以某种方式滑入 - Timo Huovinen
不是真的,因为如果你设置为“explode('#',$ segment [0])”,它将被视为错误,因为“#”符号会破坏URL,并且只能通过Javascript读取。但是,你可以做的是,你可以做的是你可以用“返回修剪($ url,'#');”来重新制作“return $ url;”,因为那样你就会删除它,以防它会在那里。但它不会删除以下内容。如果您愿意,可以阅读“Parse_url”。 :-) - Alex Westergaard