11.5 header()函数的使用
PHP的header()函数将向浏览器传送一个HTTP响应头信息,该信息遵循 HTTP 的规范,浏览器接收到这些信息后会作出适当的反应。
header()函数的语法格式:int header(string message);
header()函数的功能:将message响应放入HTTP响应头信息中,随着响应发送到浏览器。
message的格式:"header_name: header_value"
message格式说明:message中header_name和“:”之间不能有空格,header_name大小写不敏感,如Location可以写成LOCATION。
下面列举header()函数的常用功能以及对应HTTP响应头信息。
11.5.1 页面重定向
页面重定向功能可以使用Location响应头信息和Refresh响应头信息实现。
1.Location响应头
格式:“Location:URL”
功能:向浏览器发送Location响应头信息,浏览器接收到该响应头后,将页面重定向到URL指定的页面。Location响应头经常和exit语句一起使用,避免了后续代码继续执行。
说明:HTTP/1.1 要求 URL 必须是一个绝对 URL(包括协议头、主机名和绝对路径),但大部分浏览器可以接受相对URL,这取决于浏览器。程序php_redirect.php演示了Location响应头的用法。
2.Refresh响应头
格式:“Refresh: N ; url=URL”
功能:将PHP页面延迟N秒后,重定向到指定的URL页面。
说明:N表示刷新时间,时间单位为秒。若刷新时间为0,则功能与header("Location:URL")等效。url用于指定重定向后的URL页面。如果省略URL,则表示刷新网页本身。
例如,程序refresh.php如下。
今日注意事项如下: <p/>
1. XXXXXXX <br/>
2. xxxxxxx <br/>
3. XXXXXXX <p/>
5秒后将自动进入百度首页!
<?php
header("refresh:5;url=http://www.baidu.com");
?>
程序refresh.php说明:程序refresh.php执行前请将php.ini的配置output_buffering选项设置为On,否则将出现如图11-19所示的错误。
11.5.2 创建Cookie
除了可以使用setcookie()函数创建Cookie外,还可以使用header()函数的Set-Cookie响应头实现。
响应头格式:"Set-Cookie:name=value"
功能:向浏览器发送Cookie响应头信息,浏览器接收到该响应头后,将Cookie信息保存到浏览器端内存中。例如,程序header_cookie.php如下。
<?php
header("Set-Cookie:name=victor");
var_dump($_COOKIE);
?>
浏览器第一次访问header_cookie.php页面时的运行结果如图11-20所示,刷新页面后再次访问header_cookie.php页面时的运行结果如图11-21所示。
11.5.3 服务器响应内容的控制
当浏览器用户请求WEB服务器某PHP页面时,服务器将该PHP页面的执行结果(包括正文信息和响应头信息)放入到响应中发送给浏览器,响应头可以控制正文信息在浏览器端的打开方式和字符编码,如图11-22所示。
1.Content-Type响应头
格式:"Content-Type: MIME类型"
功能:设置浏览器打开正文信息的方式,浏览器调用适当的应用程序来处理正文信息。
说明:使用MIME类型可以限定正文信息的打开方式。
例如程序content_type.php如下。
<?php
if(isset($_POST["contentType"])){
$contentType = $_POST["contentType"];
if($contentType=="html"){
header("content-type:text/html");
}else if($contentType=="xml"){
header("content-type:text/xml;charset=gb2312");
echo "<?xml version='1.0' encoding='gb2312'?>";
}else if($contentType=="text"){
header("content-type:text/plain");
}
}
?>
<form action="content_type.php" method="post">
<select name="contentType">
<option value="html">html</option>
<option value="xml">xml</option>
<option value="text">text</option>
text/plain
</select>
<input type="submit" value="测试"/>
</form>
程序 content_type.php 说明:“header("content-type:text/xml;charset=gb2312")”中的“charset=gb2312”用于指定浏览器打开正文信息的编码方式为 gb2312。打开IE浏览器并在地址栏中输入“http://localhost/11/content_type.php”,将会看到如图11-23所示的运行结果。
情形1 在下拉列表中选择“html”,然后单击“测试”按钮后,content_type.php程序的运行结果如图 11-23 所示,此时运行结果的源文件如图 11-24 所示。这是由于此时选择的响应头信息为“content-type:text/html”,告诉浏览器使用浏览器方式打开正文信息。
情形2 在下拉列表中选择“xml”,然后单击“测试”按钮后,content_type.php 程序的运行结果如图 11-25 所示,此时运行结果的源文件如图 11-26 所示。这是由于此时选择的响应头信息为“content-type:text/xml”,告诉浏览器使用xml方式打开正文信息。
情形3 在下拉列表中选择“text”,然后单击“测试”按钮后,content_type.php 程序的运行结果如图11-27所示。当单击“打开”按钮时,此时选择的响应头信息为“content-type:text/ plain”,即告诉浏览器调用记事本程序打开正文信息,如图11-28所示。
header()函数中常用的Content-type响应头中的MIME类型有以下几个。
text/html; charset=utf-8: 指定正文信息使用浏览器打开,打开的编码方式为UTF-8
application/octet-stream: 指定正文信息以二进制方式打开
image/gif: 指定正文信息以gif图片方式打开
application/pdf: 指定正文信息以pdf方式打开
text/plain: 指定正文信息以记事本方式打开
image/jpeg: 指定正文信息以JPG图片方式打开
application/zip: 指定正文信息以ZIP文件方式打开
audio/mpeg: 指定正文信息以音频文件方式打开
application/x-shockwave-flash:指定正文信息以Flash动画方式打开
2.Content-Length响应头
格式:"Content-Length:长度"
功能:设置响应中正文信息的长度,单位为字节。浏览器接收到它所指定的字节数的信息后就会认为正文信息已经被完整接收了。例如header('Content-Length: 1234')用于指定响应中正文信息的长度为1 234字节。
3.Content_Dispostion响应头
格式:"Content-Disposition: attachment;filename=文件名"
功能:强制浏览器显示保存对话框,提示浏览器用户下载相应的正文信息,并为正文信息提供文件名。例如将程序content_type.php程序修改为如下代码(粗体字部分为代码的改动部分,其他代码不变)。
<?php
if(isset($_POST["contentType"])){
$contentType = $_POST["contentType"];
if($contentType=="html"){
header("content-type:text/html");
header("Content-Disposition: attachment;filename=downloaded.html");
}else if($contentType=="xml"){
header("content-type:text/xml;charset=gb2312");
echo "<?xml version='1.0' encoding='gb2312'?>";
header("Content-Disposition: attachment;filename=downloaded.xml");
}else if($contentType=="text"){
header("content-type:text/plain");
header("Content-Disposition: attachment;filename=downloaded.txt");
}
}
?>
<form action="content_type.php" method="post">
……
</form>
若在下拉列表中选择“html”,然后单击“测试”按钮后,content_type.php程序运行结果如图11-29所示。若在下拉列表中选择“xml”,然后单击“测试”按钮后, content_type.php程序运行结果如图11-30所示。在下拉列表中选择“text”,然后单击“测试”按钮后,content_type.php程序运行结果如图11-31所示。
11.5.4 浏览器缓存的远程控制
所有的浏览器都有缓存策略,浏览器会暂时将浏览过的页面缓存在一个特殊的目录里,当用户重新访问该页面时,若页面的内容没有改变,则访问的是浏览器缓存中的页面。浏览器缓存是提高用户体验和提升系统性能的一个重要途径。通过浏览器的缓存控制,可以对实时性要求不高的数据进行缓存,减少甚至不需要再次对服务器的请求就可以显示数据,从而加快浏览器用户访问服务器页面的速度,并且可以减轻服务器的负担。
为了加快浏览器访问服务器页面的速度,默认情况下浏览器是开启缓存的,但有时并不希望浏览器使用缓存加快网页的显示,尤其是那些内容更新较为频繁的服务器页面(股票交易平台等)。PHP提供的header()函数可以覆盖浏览器默认的缓存设置,从而实现浏览器缓存的远程控制。
1.浏览器缓存设置
以IE浏览器为例,单击IE浏览器“工具”菜单栏,选择“Internet选项”,在“常规”选项卡中的“Internet临时文件”下单击“设置”按钮,如图11-32所示。在“设置”对话框中显示了Internet 临时文件夹的位置(笔者 Internet 临时文件夹为:D:\temp\Temporary Internet Files),如图 11-33 所示。单击“设置”对话框中的“查看文件”按钮可以查看临时文件夹下的所有缓存文件(笔者Internet当前临时文件夹内容为空),如图11-34所示。临时文件夹中的缓存文件包含名称、Internet地址、类型、大小、截止期、上次修改时间、上次访问时间和上次检查时间等文件属性。默认情况下,临时文件夹中的缓存文件随着浏览器的关闭而自动清除,可以通过设置缓存文件的过期时间等属性延长缓存文件的生存周期。
2.HTTP/1.0的浏览器缓存控制
HTTP/1.0定义了3个可以用来控制浏览器缓存的HTTP头:Last-Modified、Expires、Pragma:no-cache。这些HTTP头通常搭配使用实现浏览器的缓存控制功能。
(1)Last-Modified:用于设置浏览器缓存文件的上次修改时间。在HTTP/1.0中,Last-Modified是控制浏览器缓存非常重要的响应头,如果需要浏览器缓存,必须设置缓存文件的上次修改时间。当浏览器第一次访问PHP页面时,WEB服务器首先设置该页面在浏览器缓存中的上次修改时间;当浏览器第二次访问该PHP页面时,浏览器自动在请求中加入If-Modified-Since请求头信息,该请求头信息的格式为:If-Modified-Since= Last-Modified的值。该请求头发送给服务器,以便服务器判断是否有必要重新执行该PHP程序。
(2)Expires:用于设置浏览器缓存文件的截止期,该时间为绝对时间,其时间格式遵循格林威治标准时(GMT)时间格式。在HTTP/1.0中,Expires是控制浏览器缓存的另一个非常重要的响应头。Expires告诉浏览器在截止期之前不会对服务器发送请求,直接使用浏览器的缓存;截止期之后,浏览器对服务器发送新的请求得到一份最新的服务器数据。
(3)Pragma: no-cache:用于设置浏览器不使用缓存文件中的数据,每次浏览器请求服务器时获取的内容都是最新版本。
例如程序http10.php的代码如下。打开IE浏览器,在地址栏中输入“http://localhost/ 11/http10.php”按回车键,第一次访问http10.php页面的运行结果如图11-35所示。60s内打开新的浏览器页面后,在地址栏中输入“http://localhost/11/http10.php”后回车,第二次访问 http10.php 页面的运行结果如图11-35所示。过了1min后,再次访问http10.php页面时,运行结果如图11-36所示。
<?php
function http_10_cache($lifeTime=60){
$gmtime = time();
if ($lifeTime){
$gmtime += $lifeTime;
$gmtime = gmdate('D, d M Y H:i:s',$gmtime).' GMT';
header("Last-Modified: $gmtime");
header("Expires: $gmtime");
}else{
header("Pragma: no-cache");
}
}
http_10_cache(60);
echo date("Y-m-d H:i:s");
?>
读者可以将程序 http10.php 中的函数调用语句修改为“http_10_cache(0);”,然后观察程序http10.php的运行结果。
程序http10.php说明如下。
(1)程序中定义了http_10_cache()函数。
语法格式:void http_10_cache(int $lifeTime=60)
函数功能:http_10_cache()函数设置了$lifeTime 作为缓存文件的存活时间,单位为秒(默认值为60s)。在缓存文件存活时间内再次请求同一个PHP页面时,浏览器将访问缓存文件的正文内容。
(2)程序http10.php中使用gmdate()函数取得了某个时间戳的格林威治时间。
gmdate()函数的语法格式:string gmdate ( string format [, int timestamp] )
gmdate()函数的功能:使用gmdate()函数可以得到UNIX时间戳timestamp参数(从UNIX纪元到当前时间的秒数)的格林威治时间,该格林威治时间的格式由format参数定义。
HTTP/1.0实现浏览器缓存的缺点是服务器和浏览器端的时间有可能不同步,这样会造成缓存的实现达不到预期效果,HTTP/1.1解决了这个问题。
3.HTTP/1.1的浏览器缓存控制
HTTP/1.1 同样定义了 3 个可以用来控制浏览器缓存的 HTTP 头:Last-Modified、Expires、Cache-Control。其中Last-Modified和Expires的含义请参考HTTP/1.0。Cache-Control响应头格式为:Cache-Control:缓存响应指令列表,缓存响应指令列表中可以定义多个缓存响应指令,各缓存响应指令之间使用“,”隔开即可。以下是常见的缓存响应指令以及具体含义。
(1)public:设置WEB服务器返回的所有正文信息(包括图片、JavaScript文件、css文件等静态资源)可以被浏览器以及代理服务器缓存,并可以被多个浏览器用户共享。
(2)private:设置WEB服务器返回的所有正文信息(包括图片、JavaScript文件、css文件等静态资源)可以被某浏览器用户缓存到该用户的私有缓存中,但正文信息不能被代理服务器缓存。即缓存数据仅对当前浏览器用户有效,对其他用户无效。
(3)no-cache:设置WEB服务器返回的正文信息不能被浏览器缓存,图片、JavaScript文件、css文件等静态资源除外。
(4)no-store:设置WEB服务器返回的正文信息不能被浏览器缓存,图片、JavaScript文件、css文件等静态资源除外。一般用于敏感数据,以免数据被无意发布。
(5)must-revalidate:设置所有的缓存数据都必须重新验证。若浏览器中的缓存数据失效,则浏览器访问服务器数据;若浏览器的缓存数据有效,浏览器访问缓存数据。具体步骤为,浏览器的第二次请求中会包含If-Modified-Since请求头与ETag请求头,如果服务器验证得出当前的浏览器缓存数据为最新的数据,那么服务器返回一个304 Not Modified响应头给浏览器;否则WEB服务器给浏览器返回新的正文信息。
(6)proxy-revalidate:设置代理服务器的缓存,与must-revalidate功能相似。
(7)max-age:设置缓存数据的寿命,缓存数据超过max-age设置的秒数后就会失效。该时间是相对时间,以浏览器读取页面开始计时。
(8)s-maxage:设置代理服务器的缓存,与max-age功能相似。
HTTP/1.1的浏览器缓存控制如图11-37所示。
图11-37说明如下。
(1)浏览器第一次请求WEB服务器某PHP页面(例如page)时,请求头中将包含如下信息。
第1行:get请求(或post请求) 请求的是哪个服务器页面 使用的HTTP
第2行:浏览器可接受的MIME类型
第6行:浏览器默认的语言种类
第7行:浏览器能够进行解码的数据编码方式
第8行:浏览器类型、版本以及操作系统类型、版本
第10行:浏览器请求的WEB服务器主机IP和端口号
第11行:是否需要持久连接
(2)服务器接收到第一次请求后,运行page页面程序,将运行结果附带响应头信息返回浏览器,响应头中将包含如下信息。
第1行:使用的HTTP HTTP状态码(200表示操作成功) HTTP状态字符串
第2行:服务器当前的GMT时间
第3行:服务器种类(Apache)
第4行:缓存的设置(其中包括max-age、Last-Modified等缓存设置),ETag标记由WEB服务器产生。响应头中的Last-Modified信息以及ETag信息用于以后比较当前浏览器的缓存文件是否和服务器端文件一致,如果不一致则获取最新版本内容,如果一致则读取浏览器缓存文件
第7行:正文信息的长度
第8行:是否需要持久连接
第9行:正文信息属于何种MIME类型
(3)浏览器第二次请求WEB服务器该PHP页面(例如page),此次请求为带条件请求,请求头中将包含如下信息。
第1行:get请求(或post请求) 请求的是哪个服务器页面 使用的HTTP
第2行:浏览器可接受的MIME类型
第3行:浏览器默认的语言种类
第4行:浏览器能够进行解码的数据编码方式
第5行:由于第一次响应头中包含Last-Modified值,第二次请求中加入If-Modified-Since请求头,它所对应的值为Last-Modified的值
第7行:由于第一次响应头中包含ETag值,第二次请求中加入If-None-Match请求头,它所对应的值为ETag的值
第8行:浏览器类型、版本以及操作系统类型、版本
第10行:浏览器请求的WEB服务器主机IP和端口号
第11行:是否需要持久连接
(4)服务器接收到第二次请求后,将“有条件”运行page页面程序,并将运行结果附带响应头信息返回浏览器。若没有运行page页面程序,此时响应头中将包含如下信息。
第1行:使用的HTTP HTTP状态码(例如304表示未修改,403表示服务器拒绝请求,404表示服务器找不到请求的网页) HTTP状态字符串
第2行:服务器当前的GMT时间
第3行:服务器种类
第4行:是否需要持久连接
第5行:ETag标记(由于WEB服务器产生的ETag标记值与第二次请求头中的ETag标记值一致,因此没有运行page页面程序,浏览器将读取浏览器缓存文件中的信息)
第6行:缓存的设置(其中包括max-age、Last-Modified等缓存设置)
了解了缓存响应指令后就可以根据不同的需求来设置服务器内各页面的缓存期限,下面是一些常用的浏览器缓存控制函数。
11.5.5 常用的浏览器缓存控制函数
(1)如下程序cache_browser.php中定义了函数cache_browser()。
函数的语法格式:void cache_browser([int $interval])
函数的功能:cache_browser()函数设置了$interval作为缓存文件的存活时间,单位为秒(默认值为60s),该缓存文件不被所有浏览器用户共享,且该缓存文件不在代理服务器上缓存。
<?php
function cache_browser($interval = 60){
$now = time();
$pretty_lmtime = gmdate('D, d M Y H:i:s', $now) . ' GMT';
$pretty_extime = gmdate('D, d M Y H:i:s', $now + $interval) . ' GMT';
//向后兼容HTTP/1.0
header("Last Modified: $pretty_lmtime");
header("Expires: $pretty_extime");
//支持HTTP/1.1
header("Cache-Control: private,max-age=$interval,s-maxage=0");
}
cache_browser(60);
echo date("Y-m-d H:i:s");
?>
(2)如下程序cache_none.php中定义了函数cache_none()。
函数的语法格式:void cache_none(void)
函数的功能:cache_none()函数关闭了浏览器和代理服务器的缓存功能。
<?php
function cache_none(){
//向后兼容HTTP/1.0
header("Expires: 0");
header("Pragma: no-cache");
//支持HTTP/1.1
header("Cache-Control: no-cache,no-store,max-age=0,s-maxage=0,must-revalidate");
}
cache_none();
echo date("Y-m-d H:i:s");
?>
(3)如下程序cache_novalidate.php中定义了函数cache_novalidate()。
函数的语法格式:void cache_novalidate([int $interval])
函数的功能:cache_novalidate()函数设置了$interval作为缓存文件的存活时间,单位为秒(默认值为60s),该缓存文件可以保存在代理服务器上,并被所有浏览器用户共享。
<?php
function cache_novalidate($interval = 60){
$now = time();
$pretty_lmtime = gmdate('D, d M Y H:i:s', $now) . ' GMT';
$pretty_extime = gmdate('D, d M Y H:i:s', $now + $interval) . 'GMT';
//向后兼容HTTP/1.0
header("Last Modified: $pretty_lmtime");
header("Expires: $pretty_extime");
//支持HTTP/1.1
header("Cache-Control: public,max-age=$interval");
}
cache_novalidate(60);
echo date("Y-m-d H:i:s");
?>
11.5.6 完善新闻发布系统文件下载功能
修改新闻发布系统中“C:\wamp\www\news\functions”目录下file_system.php页面中文件下载函数download()的代码,完善文件下载功能。
(1)在file_system.php程序文件中添加用户自定义函数extension_name()。
函数的语法格式:string extension_name(string file_name)
函数的功能:返回文件名file_name的扩展名。
extension_name()函数代码如下。
function extension_name($file_name){
$extension = explode(".",$file_name);
$key = count($extension)-1;
return $extension[$key];
}
(2)在file_system.php程序文件中添加用户自定义函数content_type()。
content_type()函数的语法格式:string content_type(string extension_name)
函数的功能:返回文件扩展名extension_name对应的MIME类型。
content_type()函数代码如下。
function content_type($extension){
$mime_types = array(
'txt' => 'text/plain',
'htm' => 'text/html',
'html' => 'text/html',
'php' => 'text/html',
'css' => 'text/css',
'js' => 'application/javascript',
'xml' => 'application/xml',
'swf' => 'application/x-shockwave-flash',
'flv' => 'video/x-flv',
// images
'png' => 'image/png',
'jpe' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'jpg' => 'image/jpeg',
'gif' => 'image/gif',
'bmp' => 'image/bmp',
'ico' => 'image/vnd.microsoft.icon',
// archives
'zip' => 'application/zip',
'rar' => 'application/x-rar-compressed',
'exe' => 'application/x-msdownload',
// audio/video
'mp3' => 'audio/mpeg',
'qt' => 'video/quicktime',
'mov' => 'video/quicktime',
// adobe
'pdf' => 'application/pdf',
// ms office
'doc' => 'application/msword',
'rtf' => 'application/rtf',
'xls' => 'application/vnd.ms-excel',
'ppt' => 'application/vnd.ms-powerpoint'
);
if(array_key_exists($extension,$mime_types)){
return $mime_types["$extension"];
}else{
return "application/octet-stream";
}
}
(3)修改file_system.php程序中的文件下载函数download()的代码,修改后的download ()函数代码如下。
function download($file_dir,$file_name){
if (!file_exists($file_dir.$file_name)) { //检查文件是否存在
exit("文件不存在或已删除");
} else {
$file = fopen($file_dir.$file_name,"r"); // 打开文件
//取得文件的扩展名
$extension_name = extension_name($file_name);
//根据扩展名取得文件的MIME类型
$content_type = content_type($extension_name);
//设置浏览器打开正文信息的打开方式
header("Content-Type:$content_type");
//强迫浏览器显示保存对话框,并提供一个推荐的文件名
header("Content-Disposition: attachment; filename=".$file_name);
// 输出文件内容
echo fread($file,filesize($file_dir.$file_name));
fclose($file);
exit;
}
}
打开Firefox浏览器下载某个Excel工作表时,使用修改前的download()函数下载该工作表将弹出如图11-38所示的对话框,使用修改后的download()函数下载该工作表将弹出如图11-39所示的对话框。