$_SERVER

(PHP 4 >= 4.1.0, PHP 5, PHP 7, PHP 8)

$_SERVER服务器和执行环境信息

描述

$_SERVER 是一个包含诸如标头、路径和脚本位置等信息的 数组。此数组中的条目由 Web 服务器创建,因此不能保证每个 Web 服务器都会提供这些条目;服务器可能会省略一些条目,或者提供此处未列出的其他条目。但是,大多数这些变量在 » CGI/1.1 规范 中有说明,并且很可能被定义。

注意: 当在 命令行 上运行 PHP 时,大多数这些条目将不可用或没有任何意义。

除了下面列出的元素外,PHP 还将创建包含请求标头值的额外元素。这些条目的名称将为 HTTP_ 后跟标头名称,大写,并用下划线代替连字符。例如,Accept-Language 标头将作为 $_SERVER['HTTP_ACCEPT_LANGUAGE'] 提供。

索引

'PHP_SELF'
当前正在执行脚本的文件名,相对于文档根目录。例如,在地址 http://example.com/foo/bar.php 处的脚本中,$_SERVER['PHP_SELF'] 将为 /foo/bar.php__FILE__ 常量包含当前(即包含的)文件的完整路径和文件名。 如果 PHP 作为命令行处理器运行,此变量包含脚本名称。
'argv'
传递给脚本的参数数组。当脚本在命令行上运行时,这提供了对命令行参数的 C 样式访问。当通过 GET 方法调用时,这将包含查询字符串。
'argc'
包含传递给脚本的命令行参数的数量(如果在命令行上运行)。
'GATEWAY_INTERFACE'
服务器正在使用的 CGI 规范的版本;例如 'CGI/1.1'
'SERVER_ADDR'
当前脚本正在执行的服务器的 IP 地址。
'SERVER_NAME'
当前脚本正在执行的服务器主机名。如果脚本正在虚拟主机上运行,这将是为该虚拟主机定义的值。

注意: 在 Apache 2 中,必须设置 UseCanonicalName = OnServerName。否则,此值将反映客户端提供的 hostname,该 hostname 可以被欺骗。在安全相关的上下文中依赖此值是不安全的。

'SERVER_SOFTWARE'
服务器标识字符串,在响应请求时在标头中给出。
'SERVER_PROTOCOL'
请求页面所用信息协议的名称和版本;例如 'HTTP/1.0'
'REQUEST_METHOD'
用于访问页面的请求方法;例如 'GET''HEAD''POST''PUT'

注意:

如果请求方法为 HEAD,则 PHP 脚本在发送标头后(意味着在没有输出缓冲的情况下产生任何输出后)终止。

'REQUEST_TIME'
请求开始的时间戳。
'REQUEST_TIME_FLOAT'
请求开始的时间戳,具有微秒精度。
'QUERY_STRING'
用于访问页面的查询字符串(如果有)。
'DOCUMENT_ROOT'
当前脚本正在执行的文档根目录,如服务器配置文件中定义。
'HTTPS'
如果脚本是通过 HTTPS 协议查询的,则设置为非空值。
'REMOTE_ADDR'
用户正在查看当前页面的 IP 地址。
'REMOTE_HOST'
用户正在查看当前页面的主机名。反向 DNS 查询基于用户的 REMOTE_ADDR

注意: Web 服务器必须配置为创建此变量。例如,在 Apache 中,必须在 httpd.conf 中设置 HostnameLookups On 才能使它存在。另请参见 gethostbyaddr()

'REMOTE_PORT'
用户机器上用于与 Web 服务器通信的端口。
'REMOTE_USER'
经过身份验证的用户。
'REDIRECT_REMOTE_USER'
如果请求被内部重定向,则经过身份验证的用户。
'SCRIPT_FILENAME'

当前正在执行脚本的绝对路径名。

注意:

如果脚本使用 CLI 执行,作为相对路径,例如 file.php../file.php$_SERVER['SCRIPT_FILENAME'] 将包含用户指定的相对路径。

'SERVER_ADMIN'
在 Web 服务器配置文件中为 SERVER_ADMIN(对于 Apache)指令提供的值。如果脚本正在虚拟主机上运行,这将是为该虚拟主机定义的值。
'SERVER_PORT'
Web 服务器用于通信的服务器机器上的端口。对于默认设置,这将是 '80';例如,使用 SSL 将将其更改为您定义的安全 HTTP 端口。

注意: 在 Apache 2 中,必须在 httpd.conf 中设置 UseCanonicalName = On 以及 UseCanonicalPhysicalPort = On 才能获得物理(实际)端口,否则,此值可能会被欺骗,并且可能或可能不返回物理端口值。在安全相关的上下文中依赖此值是不安全的。

'SERVER_SIGNATURE'
包含服务器版本和虚拟主机名的字符串,如果已启用,这些字符串将添加到服务器生成的页面中。
'PATH_TRANSLATED'
当前脚本的基于文件系统(而不是文档根目录)的路径,在服务器执行任何虚拟到真实的映射后。

注意: Apache 2 用户可以在 httpd.conf 中使用 AcceptPathInfo = On 来定义 PATH_INFO

'SCRIPT_NAME'
包含当前脚本的路径。这对需要指向自身的页面很有用。 __FILE__ 常量包含当前(即包含的)文件的完整路径和文件名。
'REQUEST_URI'
用于访问此页面的 URI;例如,“/index.html”。
'PHP_AUTH_DIGEST'
执行 Digest HTTP 身份验证时,此变量设置为客户端发送的“Authorization”标头(然后应使用它进行适当的验证)。
'PHP_AUTH_USER'
执行 HTTP 身份验证时,此变量设置为用户提供的用户名。
'PHP_AUTH_PW'
执行 HTTP 身份验证时,此变量设置为用户提供的密码。
'AUTH_TYPE'
执行 HTTP 身份验证时,此变量设置为身份验证类型。
'PATH_INFO'
包含任何客户端提供的路径名信息,这些信息跟随实际脚本文件名,但在查询字符串之前,如果有的话。例如,如果当前脚本通过 URI http://www.example.com/php/path_info.php/some/stuff?foo=bar 访问,则 $_SERVER['PATH_INFO'] 将包含 /some/stuff
'ORIG_PATH_INFO'
在 PHP 处理之前,“PATH_INFO”的原始版本。

示例

示例 #1 $_SERVER 示例

<?php
echo $_SERVER['SERVER_NAME'];
?>

上面的示例将输出类似于

www.example.com

备注

注意:

这是一个“超级全局”或自动全局变量。这仅仅意味着它在整个脚本的所有范围内都可用。无需执行 global $variable; 就可以在函数或方法中访问它。

另请参阅

添加说明

用户贡献的说明 40 条说明

Vladimir Kornea
15 年前
1. 所有键名以 'HTTP_' 开头的 $_SERVER 数组元素都来自 HTTP 请求头,并且不可信。

2. 所有发送到脚本的 HTTP 头都通过 $_SERVER 数组提供,其名称以 'HTTP_' 为前缀。

3. 如果使用不当,$_SERVER['PHP_SELF'] 是危险的。如果请求 login.php/nearly_arbitrary_string,$_SERVER['PHP_SELF'] 将不仅包含 login.php,还会包含整个 login.php/nearly_arbitrary_string。如果您在没有执行 HTML 编码的情况下将 $_SERVER['PHP_SELF'] 作为表单标签的 action 属性值打印出来,攻击者可以通过向用户提供以下链接到您网站的链接来执行 XSS 攻击:

<a href='http://www.example.com/login.php/"><script type="text/javascript">...</script><span a="'>Example.com</a>

javascript 块将定义一个事件处理程序函数并将其绑定到表单的提交事件。此事件处理程序将通过 <img> 标签加载一个外部文件,其中包含提交的用户名和密码作为参数。

使用 $_SERVER['SCRIPT_NAME'] 而不是 $_SERVER['PHP_SELF']。对发送到浏览器的每个不应该被解释为 HTML 的字符串进行 HTML 编码,除非您绝对确定它不包含任何浏览器可以解释为 HTML 的内容。
vcoletti at tiscali dot it
4 年前
要列出所有 $_SERVER 参数,只需执行

foreach ($_SERVER as $parm => $value) echo "$parm = '$value'\n";

无需列出数组的所有可能的键。
MarkAgius at markagius dot co dot uk
12 年前
您错过了 'REDIRECT_STATUS'

如果您将所有错误页面指向同一个文件,这非常有用。

文件;.htaccess
# .htaccess 文件。

ErrorDocument 404 /error-msg.php
ErrorDocument 500 /error-msg.php
ErrorDocument 400 /error-msg.php
ErrorDocument 401 /error-msg.php
ErrorDocument 403 /error-msg.php
# 文件结束。

文件;error-msg.php
<?php
$HttpStatus
= $_SERVER["REDIRECT_STATUS"] ;
if(
$HttpStatus==200) {print "文档已处理并发送给您。";}
if(
$HttpStatus==400) {print "错误的 HTTP 请求 ";}
if(
$HttpStatus==401) {print "未经授权 - 密码无效";}
if(
$HttpStatus==403) {print "禁止";}
if(
$HttpStatus==500) {print "内部服务器错误";}
if(
$HttpStatus==418) {print "我是一个茶壶! - 这是 1998 年定义的真实值";}

?>
jonbarnett at gmail dot com
15 年前
值得注意的是,$_SERVER 变量会为任何 HTTP 请求头创建,包括您可能发明的那些头。

如果浏览器发送以下 HTTP 请求头:
X-Debug-Custom: some string

那么

<?php
$_SERVER
['HTTP_X_DEBUG_CUSTOM']; // "some string"
?>

有更好的方法来识别浏览器发送的 HTTP 请求头,但这对于您知道从(例如)具有自定义头的 AJAX 脚本中预期什么来说很方便。

适用于使用 mod_php 的 Apache 上的 PHP5。不知道这在其他环境中是否适用。
Lord Mac
14 年前
一个更改进的版本...

<?php
phpinfo
(32);
?>
pierstoval at example dot com
7 年前
由于 PHP $_SERVER 变量被大量变量填充,我认为重要的是要说明它也填充了环境变量。

例如,使用 PHP 脚本,我们可以有以下内容

MY_ENV_VAR=Hello php -r 'echo $_SERVER["MY_ENV_VAR"];'

将显示“Hello”。

但是,在内部,PHP 确保 $_SERVER 中的“内部”键不会被覆盖,因此您无法执行以下操作

REQUEST_TIME=Hello php -r 'var_dump($_SERVER["REQUEST_TIME"]);'

将显示类似 1492897785 的内容

但是,许多变量仍然容易受到环境注入的影响。

我在这里创建了一个 gist(https://gist.github.com/Pierstoval/f287d3e61252e791a943dd73874ab5ee)以及我在 Windows 上使用 PHP7.0.15 在 WSL 上使用 bash 的 PHP 配置,结果表明,唯一“安全”的变量如下

PHP_SELF
SCRIPT_NAME
SCRIPT_FILENAME
PATH_TRANSLATED
DOCUMENT_ROOT
REQUEST_TIME_FLOAT
REQUEST_TIME
argv
argc

所有其他变量都可以被环境变量覆盖,这实际上并不好,因为有时它会导致 PHP 应用程序崩溃...

(我仅在 CLI 上测试过,没有耐心在 Apache mod_php 或 Nginx + PHP-FPM 上进行测试,但我可以想象,并非很多 $_SERVER 属性是“那么”安全...)
ywarnier at beeznest dot org
7 年前
请注意,$_SERVER['REQUEST_URI'] 在某些情况下可能包含方案和域。

例如,当使用 'request_fulluri' 设置为 1 的 HTTP 头调用 stream_context_create() 时,就会发生这种情况。

例如

$http = ['request_fulluri' => 1, /* 其他参数在此处 */];
$context = stream_context_create(array( 'http' => $http ));
$fp = fopen($some_url, 'rb', false, $context);

在 $some_url 处的服务器上输出 $_SERVER['REQUEST_URI'] 时,您将获得
https://some_url/some_script.php

删除 request_fulluri => 1 选项,$_SERVER['REQUEST_URI'] 将恢复到其“正常”状态
/some_script.php

显然,request_fulluri 在使用某些代理服务器时很有用。

在这种情况下,没有正确的方法来“检测”此选项是否已设置,您可能应该结合使用其他 $_SERVER[] 元素(如 REQUEST_SCHEME、SERVER_NAME 和 SERVER_PORT)来确定是否为这种情况。

一种快速(且可改进的)检测方法是将 REQUEST_URI 的开头与 REQUEST_SCHEME 进行比较

$scheme = $_SERVER['REQUEST_SCHEME'] . '://';
if (strcmp(substr($_SERVER['REQUEST_URI'], 0, strlen($scheme)), $scheme) === 0) {
// request_fulluri 已设置
}
chris at ocproducts dot com
7 年前
绝对路径指南...

数据:__FILE__
数据类型:字符串
目的:正在运行的 PHP 文件的绝对路径名,包括文件名。
警告:这不是由 PHP 处理器调用的文件,而是正在运行的文件。因此,如果您位于 include 中,则是 include。
警告:符号链接已预先解析,因此不要相信路径比较是准确的。
警告:不要假设所有操作系统都使用 '/' 作为目录分隔符。
适用于 Web 模式:是
适用于 CLI 模式:是

数据:__DIR__
数据类型:字符串
目的:正在运行的 PHP 文件的绝对路径名,不包括文件名
警告:这不是由 PHP 处理器调用的文件,而是正在运行的文件。因此,如果您位于 include 中,则是 include。
警告:符号链接已预先解析,因此不要相信路径比较是准确的。
警告:不要假设所有操作系统都使用 '/' 作为目录分隔符。
适用于 Web 模式:是
适用于 CLI 模式:是

数据:$_SERVER['SCRIPT_FILENAME']
数据类型:字符串
目的:原始 PHP 文件的绝对路径名,包括文件名
警告:并非所有 PHP 环境都设置,可能需要在包含其他文件之前从 __FILE__ 复制。
警告:符号链接不会预先解析,如果您需要解析,请使用 PHP 的 'realpath' 函数。
警告:不要假设所有操作系统都使用 '/' 作为目录分隔符。
警告:“文件名”让你觉得它只是一个文件名,但实际上它是完整的绝对路径名。将标识符读作“脚本的文件系统(路径)名”。
适用于 Web 模式:是
适用于 CLI 模式:是

数据:$_SERVER['PATH_TRANSLATED']
数据类型:字符串
目的:原始 PHP 文件的绝对路径名,包括文件名
警告:它可能没有设置,最好不要使用它。只需使用 realpath($_SERVER['SCRIPT_FILENAME'])(并意识到它本身可能需要被模拟)。
警告:符号链接已预先解析,因此不要相信路径比较是准确的。
警告:不要假设所有操作系统都使用 '/' 作为目录分隔符。
适用于 Web 模式:是
适用于 CLI 模式:否

数据:$_SERVER['DOCUMENT_ROOT']
数据类型:字符串
目的:获取 Web 服务器文档根目录的绝对路径。没有尾部斜杠。
警告:除非您控制服务器环境,否则不要相信它已设置,或设置正确。
警告:符号链接可能已预先解析,也可能未预先解析,如果您需要解析,请使用 PHP 的 'realpath' 函数。
警告:不要假设所有操作系统都使用 '/' 作为目录分隔符。
适用于 Web 模式:是
适用于 CLI 模式:否

请注意,如果某些内容未设置,它可能在 $_SERVER 中缺失,也可能为空,因此请使用 PHP 的 'empty' 函数进行测试。

请注意,如果您在命令行上调用“php --info”,那么自然,这些设置中的一些将为空,因为没有涉及 PHP 文件。
Richard York
15 年前
这里没有记录的是,$_SERVER 在通过 shell 访问 PHP 时填充了一些非常有用的信息。

["_SERVER"]=>
array(24) {
["MANPATH"]=>
string(48) "/usr/share/man:/usr/local/share/man:/usr/X11/man"
["TERM"]=>
string(11) "xterm-color"
["SHELL"]=>
string(9) "/bin/bash"
["SSH_CLIENT"]=>
string(20) "127.0.0.1 41242 22"
["OLDPWD"]=>
string(60) "/Library/WebServer/Domains/www.example.com/private"
["SSH_TTY"]=>
string(12) "/dev/ttys000"
["USER"]=>
string(5) "username"
["MAIL"]=>
string(15) "/var/mail/username"
["PATH"]=>
string(57) "/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin"
["PWD"]=>
string(56) "/Library/WebServer/Domains/www.example.com/www"
["SHLVL"]=>
string(1) "1"
["HOME"]=>
string(12) "/Users/username"
["LOGNAME"]=>
string(5) "username"
["SSH_CONNECTION"]=>
string(31) "127.0.0.1 41242 10.0.0.1 22"
["_"]=>
string(12) "/usr/bin/php"
["__CF_USER_TEXT_ENCODING"]=>
string(9) "0x1F5:0:0"
["PHP_SELF"]=>
string(10) "Shell.php"
["SCRIPT_NAME"]=>
string(10) "Shell.php"
["SCRIPT_FILENAME"]=>
string(10) "Shell.php"
["PATH_TRANSLATED"]=>
string(10) "Shell.php"
["DOCUMENT_ROOT"]=>
string(0) ""
["REQUEST_TIME"]=>
int(1247162183)
["argv"]=>
array(1) {
[0]=>
string(10) "Shell.php"
}
["argc"]=>
int(1)
}
chris at ocproducts dot com
7 年前
URL 路径指南...

数据:$_SERVER['PHP_SELF']
数据类型:字符串
目的:当前 PHP 文件的 URL 路径名,包括路径信息(参见 $_SERVER['PATH_INFO'])但不包括 URL 查询字符串。包含前导斜杠。
注意:这是在 URL 重写之后(即 PHP 所见,不一定与原始调用 URL 相同)。
适用于 Web 模式:是
在 CLI 模式下有效:不稳定(模拟只包含 CLI 脚本的精确调用路径,以及你可能用到的任何奇特的相对路径名,没有变为绝对路径,也没有规范化或预先解析)。

数据:$_SERVER['SCRIPT_NAME']
数据类型:字符串
用途:当前 PHP 文件的 URL 路径名,不包括路径信息,也不包括 URL 查询字符串。包含前导斜杠。
注意:这是在 URL 重写之后(即 PHP 所见,不一定与原始调用 URL 相同)。
注意:并非所有 PHP 环境都设置了此变量,可能需要通过 preg_replace('#\.php/.*#', '.php', $_SERVER['PHP_SELF']) 设置。
适用于 Web 模式:是
在 CLI 模式下有效:不稳定(模拟只包含 CLI 脚本的精确调用路径,以及你可能用到的任何奇特的相对路径名,没有变为绝对路径,也没有规范化或预先解析)。

数据:$_SERVER['REDIRECT_URL']
数据类型:字符串
用途:当前 PHP 文件的 URL 路径名,路径信息为 N/A,不包括 URL 查询字符串。包含前导斜杠。
注意:这是在 URL 重写之前(即与原始调用 URL 相同)。
注意:并非所有 PHP 环境都设置了此变量,并且肯定只有具有 URL 重写的环境才设置。
适用于 Web 模式:是
适用于 CLI 模式:否

数据:$_SERVER['REQUEST_URI']
数据类型:字符串
用途:当前 PHP 文件的 URL 路径名,包括路径信息和 URL 查询字符串。包含前导斜杠。
注意:这是在 URL 重写之前(即与原始调用 URL 相同)。*
*: 我见过至少一种情况,这种情况并非如此(存在另一个由 URL 重写器提供的 $_SERVER 变量可以使用),但 URL 重写器的作者后来修复了它,因此可能可以忽略此特定说明。
注意:并非所有 PHP 环境都设置了此变量,可能需要通过 $_SERVER['REDIRECT_URL'] . '?' . http_build_query($_GET) 设置 [如果设置了 $_SERVER['REDIRECT_URL'],并且不完美,因为我们不知道最初传递了哪些 GET 参数,以及哪些在 URL 重写中被注入] --否则-- $_SERVER['PHP_SELF'] . '?' . http_build_query($_GET)。
适用于 Web 模式:是
适用于 CLI 模式:否

数据:$_SERVER['PATH_INFO']
数据类型:字符串
用途:查找路径信息,即 URL 调用中 .php 文件名之后的数据。这是一个奇怪的概念。
注意:某些环境可能不支持它,最好避免使用它,除非你拥有完整的服务器控制权。
适用于 Web 模式:是
适用于 CLI 模式:否

请注意,如果某些内容未设置,它可能在 $_SERVER 中缺失,也可能为空,因此请使用 PHP 的 'empty' 函数进行测试。
krinklemail at gmail dot com
11 年前
如果对你的 PHP 脚本的请求发送了 "Content-Type" 或/ "Content-Length" 头部,它将不会像普通的 HTTP 头部那样出现在 $_SERVER 中,即 $_SERVER['HTTP_CONTENT_TYPE']。PHP 会根据 CGI/1.1 规范[1] 从 HTTP_ 匹配组中删除这些头部。

它们仍然可以访问,但前提是请求是 POST 请求。如果是这样,它将作为
$_SERVER['CONTENT_LENGTH']
$_SERVER['CONTENT_TYPE']

[1] https://www.ietf.org/rfc/rfc3875
Daniels118
2 年前
如果你需要知道客户端使用的协议(http 或 https),那么如果你的服务器位于代理或负载均衡器后面,$_SERVER['HTTPS'] 变量可能无法真正报告真实情况(实际上,客户端可以使用 https 连接到负载均衡器,然后负载均衡器使用 http 将请求转发到服务器)。
如果代理/负载均衡器配置正确,它可以在头部发送原始请求协议,你将在 $_SERVER[HTTP_X_FORWARDED_PROTO] 变量中找到它。
Tonin
15 年前
在使用 apache 虚拟主机设置并使用 ServerAlias 指令时使用 $_SERVER['SERVER_NAME'] 变量,请务必检查 UseCanonicalName apache 指令。如果它是 On,此变量将始终具有 apache ServerName 的值。如果它是 Off,它将具有浏览器发送的头部提供的值。

根据你想对此变量的内容做些什么,将其设置为 On 或 Off。
Stefano (info at sarchittu dot org)
13 年前
一种获取页面绝对路径的方法,与网站位置无关(因此在本地机器和服务器上都能工作,无需设置任何东西),与服务器操作系统无关(在 Unix 系统和 Windows 系统上都能工作)。

它唯一需要的参数是放置此脚本的文件夹。
因此,例如,我将把它放在我的 SCRIPT 文件夹中,并在 $conflen 中写入 SCRIPT 字词的长度。

<?php
$conflen
=strlen('SCRIPT');
$B=substr(__FILE__,0,strrpos(__FILE__,'/'));
$A=substr($_SERVER['DOCUMENT_ROOT'], strrpos($_SERVER['DOCUMENT_ROOT'], $_SERVER['PHP_SELF']));
$C=substr($B,strlen($A));
$posconf=strlen($C)-$conflen-1;
$D=substr($C,1,$posconf);
$host='http://'.$_SERVER['SERVER_NAME'].'/'.$D;
?>

$host 最终将包含绝对路径。
info at mtprod dot com
15 年前
在 Windows IIS 7 上,你必须使用 $_SERVER['LOCAL_ADDR'] 而不是 $_SERVER['SERVER_ADDR'] 来获取服务器的 IP 地址。
lemonostif at gmail dot com
5 年前
PHP_SELF 是程序员工作中的耻辱。从版本 4 开始,这是 PHP 最广泛传播的漏洞之一,手册中没有提到任何危险。至少要澄清它的值可以由用户提供,最好用大写字母,如果你想让互联网更加安全的话……
Mark Simon
5 年前
差一点,但还是差了……

$_SERVER 几乎包含你了解当前网页环境所需的一切。方便的是,可以轻松访问协议和实际的 Web 根目录。

对于协议,你可能拥有或可能不拥有 $_SERVER['HTTPS'],它也可能为空或不为空。对于 Web 根目录,$_SERVER['DOCUMENT_ROOT'] 依赖于服务器配置,并且不适用于虚拟主机。

出于实际目的,我通常在我的脚本中包含以下内容

<?php
// Web 根目录
// 用法:include("$root/includes/something.inc.php");
$root = $_SERVER['WEB_ROOT'] = str_replace($_SERVER['SCRIPT_NAME'],'',$_SERVER['SCRIPT_FILENAME']);

// 主机和协议
// 用法:$url = "$protocol://$host/images/something.jpg";
$host = $_SERVER['HTTP_HOST'];
$protocol=$_SERVER['PROTOCOL'] = isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) ? 'https' : 'http';
?>
steve at sc-fa dot com
14 年前
如果你从代理服务器后面提供服务,几乎可以肯定通过查看这些 $_SERVER 变量在代理后面的机器上的行为来节省时间。

$_SERVER['HTTP_X_FORWARDED_FOR'] 代替 $_SERVER['REMOTE_ADDR']

$_SERVER['HTTP_X_FORWARDED_HOST'] 和
$_SERVER['HTTP_X_FORWARDED_SERVER'] 代替(至少在我们这里)$_SERVER['SERVER_NAME']
jarrod at squarecrow dot com
15 年前
$_SERVER['DOCUMENT_ROOT'] 非常有用,尤其是在开发环境中工作时。如果你正在处理大型项目,你可能需要将大量文件包含到你的页面中。例如

<?php
// 为 "include" URL 定义常量 - 有助于保持路径整洁

define("REGISTRY_CLASSES", $_SERVER['DOCUMENT_ROOT']."/SOAP/classes/");
define("REGISTRY_CONTROLS", $_SERVER['DOCUMENT_ROOT']."/SOAP/controls/");

define("STRING_BUILDER", REGISTRY_CLASSES. "stringbuilder.php");
define("SESSION_MANAGER", REGISTRY_CLASSES. "sessionmanager.php");
define("STANDARD_CONTROLS", REGISTRY_CONTROLS."standardcontrols.php");
?>

在开发环境中,你很少使用根文件夹,尤其是在本地机器上运行 PHP 时,使用 DOCUMENT_ROOT 是维护 URL 一致性的一种好方法。这将节省你数小时准备应用程序从你的机器部署到生产服务器的工作(更不用说节省你因包含路径失败而导致的头痛了)。
php at isnoop dot net
14 年前
使用 apache SetEnv 指令在你的 vhost 或 apache 配置中设置任意 $_SERVER 变量。

SetEnv varname "variable value"
pomat at live dot it
11 年前
$_SERVER['DOCUMENT_ROOT'] 在 Windows 系统上可能包含反斜杠,并且它可能包含或可能不包含尾部斜杠(反斜杠)。
我看到了以下内容,作为处理此问题的正确方法的示例

<?php
include(dirname($_SERVER['DOCUMENT_ROOT']) . DIRECTORY_SEPARATOR . 'file.php');
?>

好的,后者可能用于访问文档根目录的父目录中的文件,但实际上并没有正确解决这个问题。
最终,不要担心。在所有情况下使用正斜杠并附加尾部斜杠应该是安全的。
假设我们有以下内容

<?php
$path
= 'subdir/file.php';
$result = $_SERVER['DOCUMENT_ROOT'] . '/' . $path;
?>

在 Linux 上,$result 可能类似于
1) "/var/www/subdir/file.php"
2) "/var/www//subdir/file.php"
字符串 2 与字符串 1 的解析方式相同(尝试使用命令“cd”)。

在 Windows 上,$result 可能类似于
1) "C:/apache/htdocs/subdir/file.php"
2) "C:/apache/htdocs//subdir/file.php"
3) "C:\apache\htdocs/subdir/file.php"
4) "C:\apache\htdocs\/subdir/file.php"
所有这些字符串都将解析为 "C:\apache\htdocs\subdir\file.php"(尝试使用“cd”)。
chris
15 年前
可以在 phpinfo() 输出的底部找到 $_SERVER 数组中所有内容的表格;
Tom
11 年前
请注意,Server 数组中的大多数内容(即使是 $_SERVER['SERVER_NAME'])都是由客户端提供的,可以进行操作。它们也可以用于注入,因此必须像任何其他用户输入一样进行检查和处理。
centurianii at yahoo dot co dot uk
7 年前
如果使用 Apache 虚拟主机文件中的命令,在所有请求中应用重定向,例如
RewriteEngine On
RewriteCond "%{REQUEST_URI}" "!=/index.php"
RewriteRule "^/(.*)$" "index.php?$1" [NC,NE,L,QSA]
您应该预期 $_SERVER 全局变量会有一些偏差。

例如,您发送一个 URL:[此处的主机名]/a/b?x=1&y=2
这会导致 Apache 修改为:/index.php?/a/b?x=1&y=2

现在您的 $_SERVER 全局变量包含以下内容
'REQUEST_URI' => '/a/b?x=1&y=2',它保留了主机后的初始 URL
'QUERY_STRING' => 'a/b&x=1&y=2',请注意 php 如何将 '?' 替换为 '&'
'SCRIPT_NAME' => '/index.php',因为它本来应该这样。

要测试您的 $_SERVER 全局变量
function serverArray(){
$arr = array();
foreach($_SERVER as $key=>$value)
$arr[] = '&nbsp;&nbsp;&nbsp;\'' . $key . '\' => \'' . (isset($value)? $value : '-') . '\'';
return @\sort($arr)? '$_SERVER = array(<br />' . implode($arr, ',<br />') . '<br />);' : false;
}
echo serverArray();
mirko dot steiner at slashdevslashnull dot de
14 年前
<?php

// RFC 2616 兼容的 Accept Language 解析器
// http://www.ietf.org/rfc/rfc2616.txt, 14.4 Accept-Language, 第 104 页
// 超文本传输协议 -- HTTP/1.1

foreach (explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']) as $lang) {
$pattern = '/^(?P<primarytag>[a-zA-Z]{2,8})'.
'(?:-(?P<subtag>[a-zA-Z]{2,8}))?(?:(?:;q=)'.
'(?P<quantifier>\d\.\d))?$/';

$splits = array();

printf("Lang:,,%s''\n", $lang);
if (
preg_match($pattern, $lang, $splits)) {
print_r($splits);
} else {
echo
"\nno match\n";
}
}

?>

示例输出

Google Chrome 3.0.195.27 Windows xp

Lang:,,de-DE''
数组
(
[0] => de-DE
[primarytag] => de
[1] => de
[subtag] => DE
[2] => DE
)
Lang:,,de;q=0.8''
数组
(
[0] => de;q=0.8
[primarytag] => de
[1] => de
[subtag] =>
[2] =>
[quantifier] => 0.8
[3] => 0.8
)
Lang:,,en-US;q=0.6''
数组
(
[0] => en-US;q=0.6
[primarytag] => en
[1] => en
[subtag] => US
[2] => US
[quantifier] => 0.6
[3] => 0.6
)
Lang:,,en;q=0.4''
数组
(
[0] => en;q=0.4
[primarytag] => en
[1] => en
[subtag] =>
[2] =>
[quantifier] => 0.4
[3] => 0.4
)
kamil00110
1 年前
此代码可用于帮助查找试图深入服务器文件以查找某些内容的人员。

.htaccess

ErrorDocument 404 /your.php
ErrorDocument 403 /your.php

<?php
// 获取时间
$time = date("H:i:s d.m.y");
// 获取用户地址
$usr = $_SERVER['REMOTE_ADDR'];
// 获取“访问者”输入的 URL
$url = $_SERVER['REQUEST_URI'];
// 获取服务器地址
$ip = $_SERVER['SERVER_ADDR'];
// 合并在一起
$sus = "[".$time."] ".$usr." ".$ip.$url.PHP_EOL;
// 写入日志文件
file_put_contents("susip.txt", $sus, FILE_APPEND);
?>
chris at ocproducts dot com
7 年前
脚本参数指南...

数据:$_GET
数据类型:数组(映射)
用途:包含所有 GET 参数(即解析的 URL 查询字符串)。
注意事项:GET 参数名称必须符合 PHP 变量命名规则,例如不允许使用点,并且会进行替换。
适用于 Web 模式:是
适用于 CLI 模式:否

数据:$_SERVER['QUERY_STRING']
数据类型:字符串
用途:获取未解析的 URL 查询字符串。
注意事项:并非所有 PHP 环境都设置了此值,可能需要通过 http_build_query($_GET) 设置。
适用于 Web 模式:是
适用于 CLI 模式:否

数据:$_SERVER['argv']
数据类型:数组(列表)
用途:获取 CLI 调用参数。
在 Web 模式下有效:不稳定(只包含一个参数,即查询字符串)
适用于 CLI 模式:是
sammyhacker at gmail dot com
3 年前
简而言之,$_SERVER 包含所有环境变量。

CGI 的工作原理是 HTTP 应用程序服务器填充所有必需的环境变量并调用 PHP 进程。这些环境变量存储在 $_SERVER 中。
lilJoshu
5 年前
请记住,

尽管 $_SERVER["REQUEST_METHOD"] 最初是为 GET、POST、PUT、HEAD 而设计的,但服务器可以允许更多方法。

如果您正在构建也使用 PATCH 和 DELETE 等方法的 RESTful 接口,这一点很重要。

作为安全风险,它也是一个可能的注入点。如果您正在构建基于 REQUEST_METHOD 的内容,建议将其放在 switch 语句中。

<?php
switch ($_SERVER["REQUEST_METHOD"]){
case
"PUT":
foo_replace_data();
break;
case
"POST":
foo_add_data();
break;
case
"HEAD";
foo_set_that_cookie();
break;
case
"GET":
default:
foo_fetch_stuff()
break;
}

?>
silverquick at gmail dot com
16 年前
我认为 HTTPS 元素只会出现在 Apache 2.x 中。它不在此处的“特殊”变量列表中
https://httpd.apache.org/docs/1.3/mod/mod_rewrite.html#RewriteCond
但它在这里
https://httpd.apache.org/docs/2.0/mod/mod_rewrite.html#rewritecond
pudding06 at gmail dot com
15 年前
以下是一个简单、快速但有效的方法,可以阻止不需要的外部访问者访问您的本地服务器

<?php
// 只允许本地请求
if ($_SERVER['REMOTE_ADDR'] !== '127.0.0.1') die(header("Location: /"));
?>

这将把所有外部流量重定向到您的主页。当然,您可以发送 404 或其他自定义错误。最佳做法是不在带有自定义错误消息的页面上停留,因为您承认该页面确实存在。因此,我将不需要的调用重定向到(例如)phpmyadmin。
picov at e-link dot it
12 年前
一个简单函数,用于检测当前页面地址是否被 mod_rewrite 重写

<?php
public function urlWasRewritten() {
$realScriptName=$_SERVER['SCRIPT_NAME'];
$virtualScriptName=reset(explode("?", $_SERVER['REQUEST_URI']));
return !(
$realScriptName==$virtualScriptName);
}
?>
jit_chavan at yahoo dot com
10 年前
搜索了 $_SERVER["REDIRECT_URL"] 一段时间,并注意到它在 php 文档页面本身中没有提到。看起来这只是由 apache 服务器(而不是其他服务器)生成的,在某些情况下使用 $_SERVER["REQUEST_URI"] 会很有用,就像我一样。
wbeaumo1 at gmail dot com
14 年前
不要忘记 $_SERVER['HTTP_COOKIE']。它包含用户代理发送的 'Cookie' 标头的原始值。
plugwash at p10link dot net
9 年前
请注意,通过此数组访问 x-forwarded-for 和类似标头是一个坏主意。填充数组时,标头名称会发生混淆,这种混淆会导致欺骗漏洞。

请参阅 http://en.wikipedia.org/wiki/User:Brion_VIBBER/Cool_Cat_incident_report 以了解对此的现实世界攻击的详细信息。
2962051004 at qq dot com
6 年前
<?php
/*
有时您会发现您的网站在添加 CDN 后无法获取正确的用户 IP,那么此函数将帮助您
*/
function real_ip()
{
$ip = $_SERVER['REMOTE_ADDR'];
if (isset(
$_SERVER['HTTP_X_FORWARDED_FOR']) && preg_match_all('#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#s', $_SERVER['HTTP_X_FORWARDED_FOR'], $matches)) {
foreach (
$matches[0] AS $xip) {
if (!
preg_match('#^(10|172\.16|192\.168)\.#', $xip)) {
$ip = $xip;
break;
}
}
} elseif (isset(
$_SERVER['HTTP_CLIENT_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif (isset(
$_SERVER['HTTP_CF_CONNECTING_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CF_CONNECTING_IP'])) {
$ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
} elseif (isset(
$_SERVER['HTTP_X_REAL_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_X_REAL_IP'])) {
$ip = $_SERVER['HTTP_X_REAL_IP'];
}
return
$ip;

}
echo
real_ip();

?>
Johan Winge
4 年前
应该注意的是,$_SERVER['SERVER_PROTOCOL'] 的值将永远不包含子字符串“HTTPS”。 假设这是一个常见的错误和混淆来源。 相反,请查看 $_SERVER['HTTPS']。
cupy at email dot cz
14 年前
技术说明
$_SERVER['argc'] 和 $_SERVER['argv'][] 有一些奇怪的行为,
从 Linux(bash)命令行使用,当像这样调用时
"php ./script_name.php 0x020B"
一切都正确,但是
"./script_name.php 0x020B"
不正确 - “0” 而不是 “0x020B” 被传递为 $_SERVER['argv'][1] - 请参阅下面的脚本。
看起来参数没有从 bash 传递到 PHP。
(但是,在 bash 的级别上检查,0x020B 被很好地理解为 $1)

尝试此示例

------------->8------------------
cat ./script_name.php
#! /usr/bin/php

if( $_SERVER['argc'] == 2)
{
// 有趣的是...... 我们必须使用此技巧来从参数传递例如 0x020B
// 忽略此内容:“PHP Notice: Undefined offset: 2 in ...”
$EID = $_SERVER['argv'][1] + $_SERVER['argv'][2] + $_SERVER['argv'][3];
}
else
{ // 默认
$EID = 0x0210; // PPS 失败
}
DanielTahar
4 年前
为了更详细地说明依赖“HTTP_REFERER”可能付出的代价:我经常阅读的几个大型新闻网站都有付费墙,并设置了 cookie,因此您只能阅读 X 篇文章才能订阅;如果您使用隐身模式,它们会计算您通过相同 IP 访问的次数;所有这些都是为了让您订阅。 但是,为了吸引人,任何来自 Google 新闻的“HTTP_REFERER”访问都会让您阅读整篇文章。 我确信他们的网站管理员面临着两难境地,但现在只要有人给您发送其中一个网站上的故事,您只需要搜索标题并点击 Google 新闻的结果。 底线:永远不要依赖它。

PS (1):当然,我说的是一个朋友。 我为内容付费。
PS (2):经过一些争论,RFC 决定保留“HTTP_REFERER”,尽管拼写错误。
Florin C
1 年前
<?php
// 使用 Debian Linux 和 Apache 2.4 成功测试的工作示例

$protocol=$_SERVER['PROTOCOL'] = isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) ? 'https' : 'http'; // 感谢 Mark Simon @ https://php.net/manual/en/reserved.variables.server.php
$doc_root = $_SERVER['DOCUMENT_ROOT']; // 例如 /var/www/webabc/web/
$module_path = dirname(__FILE__); // 例如 /var/www/webabc/web/modules/verstion152/
$host = $_SERVER['HTTP_HOST']; // 例如 192.168.1.4

$online_path = $protocol .'://'. $host . '/' . str_replace($doc_root, '', $module_path);

echo
"The online path is: " . $online_path;
To Top