冷知识 - HTTP请求头与SERVER数组 ¶
作者:KK
发表日期:2016.12.11
要点速读 ¶
一句话笼统的话囊括:请求头有什么报头,SERVER数组就有什么;请求头没有的,SERVER数组也不会有。所以你想要的SERVER元素可能不存在,取值前先isset判断
除了一些特殊的http请求头,通常情况下,其它所有请求头的名称和值都会默认在$_SERVER
数组里对应产生HTTP_请求头大写名称
的key
比如请求头中有个user-agent
的话,则$_SERVER['HTTP_USER_AGENT']
就与之对应
如果再添加个abc
的请求头,则PHP底层也会预定义$_SERVER['HTTP_ABC']
来让服务端取值
测试代码 ¶
用jQuery添加http报头测试:
$.ajax({
url : '/test.php',
dataType : 'text',
beforeSend : function(xhr){
xhr.setRequestHeader('abc-def', 123);
},
success : function(result){
alert(result);
}
});
PHP响应代码:
echo $_SERVER['HTTP_ABC_DEF'];
结果提示的值就是123
提示 ¶
所以你可以认为大部分HTTP_
开头的$_SERVER数组的key都是从请求头里面采集信息得来的
如果请求信息中没有这些请求头字段的话,则PHP无法获取相关的key,这也是为什么$_SERVER['HTTP_REFERER']
有时候会不存在的原因,反正请求过来的报头没有的话就没有咯,你叫人家去哪里给你值呢
吓你一跳的真相 ¶
你千万别只想着“哦,我知道了,反正获取HTTP_REFERER的时候isset一下就是了”
其实你基本上获取一切HTTP_****
的相关下标值都要isset一下,你先在测试web下建立a.php
和b.php
,在a.php里粘贴以下基本的curl代码:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://test/b.php');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
$output = curl_exec($ch);
curl_close($ch);
print_r($output);
然后b.php的代码就是print_r($_SERVER);
这样输出整个SERVER数组
好了跑一下a.php,看看b.php响应过来的结果(跟我的差不多吧):
Array
(
[PATH] => C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;D:\app\Python27\;D:\app\Python27\Scripts;C:\ProgramData\Oracle\Java\javapath;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;D:\Program Files\TortoiseSVN\bin;D:\Program Files (x86)\Git\cmd;D:\phpStudy\php\php-7.0.12-nts;C:\ProgramData\ComposerSetup\bin;C:\Users\Administrator\AppData\Local\Google\Chrome\Application;D:\Program Files\nodejs\;C:\sqlite;D:\Program Files\scrt\
[SYSTEMROOT] => C:\WINDOWS
[COMSPEC] => C:\WINDOWS\system32\cmd.exe
[PATHEXT] => .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
[WINDIR] => C:\WINDOWS
[PHP_FCGI_MAX_REQUESTS] => 1000
[PHPRC] => D:/phpStudy2/php/php-7.0.12-nts/
[_FCGI_SHUTDOWN_EVENT_] => 2256
[HTTP_CONNECTION] => close
[SCRIPT_NAME] => /b.php
[REQUEST_URI] => /b.php
[QUERY_STRING] =>
[REQUEST_METHOD] => GET
[SERVER_PROTOCOL] => HTTP/1.1
[GATEWAY_INTERFACE] => CGI/1.1
[REMOTE_PORT] => 47514
[SCRIPT_FILENAME] => E:/projects/test/b.php
[SERVER_ADMIN] => admin@phpStudy.net
[CONTEXT_DOCUMENT_ROOT] => E:/projects/test
[CONTEXT_PREFIX] =>
[REQUEST_SCHEME] => http
[DOCUMENT_ROOT] => E:/projects/test
[REMOTE_ADDR] => 127.0.0.1
[SERVER_PORT] => 80
[SERVER_ADDR] => 127.0.0.1
[SERVER_NAME] => test
[SERVER_SOFTWARE] => Apache/2.4.23 (Win32) OpenSSL/1.0.2j mod_fcgid/2.3.9
[SERVER_SIGNATURE] =>
[SystemRoot] => C:\WINDOWS
[HTTP_ACCEPT] => */*
[HTTP_HOST] => test
[FCGI_ROLE] => RESPONDER
[PHP_SELF] => /b.php
[REQUEST_TIME_FLOAT] => 1481472847.2315
[REQUEST_TIME] => 1481472847
)
亲,你能在这里发现HTTP_USER_AGENT
吗
给你清点一下,比平时浏览器请求过来的一共是少了这些:
HTTP_REFERER
、HTTP_USER_AGENT
、HTTP_X_REQUESTED_WITH
、HTTP_ACCEPT_LANGUAGE
、HTTP_ACCEPT_ENCODING
、HTTP_CONNECTION
因为curl请求只填写了很基本的必须的http请求头,所以服务端并没有收到更多
而在浏览器里面用ajax或a标签跳转产生的请求,被浏览器底层包装一翻后就有了很多相关的报头,在我们“年少”的时候,一直被迷惑,如果你玩PHP有一两个年头,是时候要认清一下HTTP请求信息与PHP的$_SERVER数组的关系了