PHP 日本大会 2024

$_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 下,必须设置 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'
执行摘要式 HTTP 身份验证时,此变量设置为客户端发送的“授权”报头(然后应使用此报头进行相应的验证)。
'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'
'PATH_INFO' 在 PHP 处理之前的原始版本。

示例

示例 #1 $_SERVER 示例

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

上面的示例将输出类似于以下内容

www.example.com

备注

注意:

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

另请参阅

添加注释

用户贡献注释 38 条注释

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
13 年前
你错过了 '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年定义的真实值";}

?>
Lord Mac
15 年前
一个更改进的版本……

<?php
phpinfo
(32);
?>
jonbarnett at gmail dot com
16 年前
值得注意的是,对于任何 HTTP 请求头(包括你可能发明的那些头),都会创建 $_SERVER 变量。

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

那么

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

还有更好的方法来识别浏览器发送的 HTTP 请求头,但如果你知道例如带有自定义头的 AJAX 脚本的预期内容,这将很方便。

在带有 mod_php 的 Apache 上的 PHP5 中有效。不知道其他环境是否如此。
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 属性都那么“安全”……)
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 年前
此处未记录的是,通过 shell 访问 PHP 时,$_SERVER 会填充一些非常有用的信息。

["_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)
}
ywarnier at beeznest dot org
7 年前
请注意,在某些情况下,$_SERVER['REQUEST_URI'] 可能包含方案和域名。

例如,当通过调用 `stream_context_create()` 并设置 HTTP 头部 'request_fulluri' 为 1 来调用页面时,就会发生这种情况。

例如

$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 年前
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
12 年前
如果对您的 PHP 脚本的请求发送标题“Content-Type”或/“Content-Length”,则与常规 HTTP 标题相反,它不会出现在 $_SERVER 中作为 $_SERVER['HTTP_CONTENT_TYPE']。PHP 会根据 CGI/1.1 规范[1] 从 HTTP_ 匹配组中移除这些标题。

它们仍然可以访问,但只有在请求是 POST 请求时才可用。如果是 POST 请求,它将可用作
$_SERVER['CONTENT_LENGTH']
$_SERVER['CONTENT_TYPE']

[1] https://www.ietf.org/rfc/rfc3875
lemonostif at gmail dot com
5 年前
PHP_SELF 是程序员工作中的耻辱。自版本 4 以来,这是最广泛的 PHP 漏洞之一,并且手册中没有说明其危险性。如果您想让互联网更安全,至少要说明其值可以由用户提供,最好用大写字母……
Tonin
16 年前
在使用 ServerAlias 指令的 apache 虚拟主机设置中使用 $_SERVER['SERVER_NAME'] 变量时,请务必检查 UseCanonicalName apache 指令。如果它为 On,则此变量将始终具有 apache ServerName 值。如果它为 Off,则它将具有浏览器发送的标头给出的值。

根据您要对此变量的内容执行的操作,将其设置为 On 或 Off。
info at mtprod dot com
15 年前
在 Windows IIS 7 上,必须使用 $_SERVER['LOCAL_ADDR'] 而不是 $_SERVER['SERVER_ADDR'] 来获取服务器的 IP 地址。
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 一致性的好方法。这将节省您数小时的工作,无需准备您的应用程序即可从您的计算机部署到生产服务器(更不用说节省您因包含路径失败而造成的头痛了)。
Stefano (info at sarchittu dot org)
14 年前
一种获取页面绝对路径的方法,与站点位置无关(因此在本地机器和服务器上都能工作,无需设置任何内容),并且与服务器操作系统无关(在 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 最终将包含绝对路径。
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
15 年前
如果您通过代理服务器提供服务,查看这些 $_SERVER 变量在您代理服务器后的机器上的作用几乎肯定可以节省时间。

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

使用 $_SERVER['HTTP_X_FORWARDED_HOST'] 和
$_SERVER['HTTP_X_FORWARDED_SERVER'] 代替(至少在我们的案例中)$_SERVER['SERVER_NAME']
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);
?>
Daniels118
2 年前
如果您需要知道客户端使用的协议(http 或 https),那么如果您的服务器位于代理服务器或负载均衡器之后,$_SERVER['HTTPS'] 变量可能无法实际报告真实情况(实际上,客户端可以使用 https 连接到负载均衡器,然后负载均衡器使用 http 将请求转发到服务器)。
如果代理/负载均衡器配置正确,它可以在标头中发送原始请求协议,您将在 $_SERVER[HTTP_X_FORWARDED_PROTO] 变量中找到它。
pomat at live dot it
11 年前
在 Windows 系统上,$_SERVER['DOCUMENT_ROOT'] 可能包含反斜杠,当然它也可能包含或不包含尾部斜杠(反斜杠)。
我看到以下内容是关于我们应该如何处理此问题的正确方法的示例

<?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”)。
lilJoshu
6 年前
记住:

尽管 $_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;
}

?>
Tom
12 年前
请注意,服务器数组的大多数内容(甚至 $_SERVER['SERVER_NAME'])都是由客户端提供的,并且可以被操纵。它们也可以用于注入,因此必须像任何其他用户输入一样进行检查和处理。
chris
15 年前
$_SERVER 数组中的所有内容的表格可以在 phpinfo(); 输出的底部附近找到。
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
13 年前
一个简单的函数,用于检测当前页面地址是否由 mod_rewrite 重写

<?php
public function urlWasRewritten() {
$realScriptName=$_SERVER['SCRIPT_NAME'];
$virtualScriptName=reset(explode("?", $_SERVER['REQUEST_URI']));
return !(
$realScriptName==$virtualScriptName);
}
?>
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
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
15 年前
<?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
)
php at isnoop dot net
14 年前
使用 apache SetEnv 指令在您的虚拟主机或 apache 配置中设置任意 $_SERVER 变量。

SetEnv varname "variable value"
sammyhacker at gmail dot com
3 年前
简而言之,$_SERVER 包含所有环境变量。

CGI 的工作方式是 HTTP 应用程序服务器填写所有必需的环境变量并调用 PHP 进程。这些环境变量存储在 $_SERVER 中。
plugwash at p10link dot net
9 年前
注意,通过此数组访问 x-forwarded-for 和类似的 header 是个坏主意。填充数组时 header 名称会被篡改,这种篡改可能会引入欺骗漏洞。

有关此现实世界漏洞利用的详细信息,请参阅http://en.wikipedia.org/wiki/User:Brion_VIBBER/Cool_Cat_incident_report
jit_chavan at yahoo dot com
10年前
搜索了 $_SERVER["REDIRECT_URL"] 一段时间,并注意到 PHP 文档页面本身并没有提到它。看起来这只有 Apache 服务器(而不是其他服务器)生成,在我的某些情况下使用 $_SERVER["REQUEST_URI"] 会很有用。
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 模式下有效:是
wbeaumo1 at gmail dot com
14 年前
不要忘记 $_SERVER['HTTP_COOKIE']。它包含用户代理发送的 'Cookie' header 的原始值。
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
15 年前
技术说明
$_SERVER['argc'] 和 $_SERVER['argv'][] 有一些奇怪的行为,
从 Linux(bash)命令行使用,当像这样调用时
"php ./script_name.php 0x020B"
一切正常,但是
"./script_name.php 0x020B"
是不正确的 - "0" 传递给 $_SERVER['argv'][1] 而不是 "0x020B" - 请参见下面的脚本。
看起来参数没有从 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 失败
}
To Top