PHP 设置响应头

本文最后更新于:2024年3月18日 凌晨

PHP 设置响应头

  • 正如我们前面所讨论的,服务器发送回来的HTTP响应包含以下信息:用于识别响应主体内容的头(header),发送响应的服务器,响应消息有多少字节和响应何时发出等等,PHP和Apache通常已经为你处理好了头信息,将文档识别为HTML和计算HTML页面的长度等等,绝大多数WEB程序不需要自己设置头,然而,如果你想让服务器返回的不是HTML,或者想设置页面的过期时间,重定向客户端浏览器到另一个地址,或是产生一个特定的HTTP错误,就需要使用header()函数来设置头部。
  • 设置header一定要在生成主体内容之前完成,这意味着所有header()(或setcookie(),如果你想设置 cookie)要在文件的最前面,甚至在<html>标签之前,例如:
1
2
3
4
5
6
7
8
9
10
<?php
header('Content-Type: text/plain');
?>

Date:today
From:fred
To:barney
Subject:hands off!
My lunchbox is mine and mine alone.Get your own,
you filthy scrounger!
  • 在文档主体内容已经开始后设置头部会引起一个警告:
1
Warning: Cannot add header information - headers already sent

不同的内容类型

  • Content-Type头指出了被返回的文档的类型,它通常是"text/html",指明了它是一个HTML文档,但还有其他一些有用的文档类型,例如"text/plain"让浏览器强制性地将内容当作纯文本来处理,这个类型就类似于自动的"查看源代码",它在调试时很有用。

重定向

  • 你可以向浏览器发送一个新的URL,并让浏览器转向到这个地址,这样的重定向(redirection)操作,只需要通过设置Location头即可:
1
2
3
4
<?php
header('Location: http://www,example.com/elsewhere.html');
exit();
?>
  • 如果你只提供相对的URL(如"/elsewhere.hmtl").重定向会在服务器内部进行,这种方法很少用,因为浏览器并不知道它得到的页面是否是所请求的,如果在新的文档中存在相对URL,浏览器会将它们解释成相对于所请求的文档,而不是被发送的文档,一般来说,我们习惯于重定向到绝对URL

过期

  • 服务器可以显式地通知浏览器(或者那些存在于服务器和浏览器发之间的代理服务器缓存)文档的过期时间,代理服务器和浏览器缓存在过期之前可保持文件,或提前结束它,重新载入一个被缓存的页面不需要和服务器进行通讯,但是尝试获取一个已经过期的文档就需要和服务器联系了。
  • 为一个文档设置过期时间,可使用Expires头:
1
header('Expires: Fri, 18 Jan 2006 05:30:00 GMT');
  • 要使文档在页面生成后的3小时后过期,我们使用time()gmstrftime()函数生成过期日期字符串:
1
2
3
$now = time();
$then = gmstrftime("%a, %d %b %Y %H:%M:%S GMT",$now+60*60*3);
header("Expires:$then");
  • 为了使一个文档永不过期,可使用一年为时间期限:
1
2
3
$now = time();
$then = gmstrftime("%a, %d %b %Y %H:%M:%S GMT",$now+365*86440);
header("Expires:$then");
  • 为了把文档标记为过期,可用当前时间或以前的时间:
1
2
$then = gmstrftime("%a, %d %b %Y %H:%M:%S GMT");
header("Expires:$then");
  • 以下是不使浏览器或代理缓存保存你的文档的最好方法;
1
2
3
4
5
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified:" . gmdate("D,d M Y H:i:s") . " GMT");
header("Cache-Control: no-store,no-cache,must-revalidate");
header("Cache-Control: post-check=0,pre-check=0",false);
header("Pragma: no-cache");
  • 你可以在Duane Wessels所著的$Web Caching$一书(由O’Reilly出版)的第6章中找到有关控制浏览器和Web缓存行为的更多信息。

HTTP认证

  • HTTP认证(HTTP authentication)通过请求的header和响应状态来工作,浏览器可以将用户名和密码放在请求的头里发送,如果认证凭证(credential,即指用户名和密码)未发送或者不匹配,服务器将发送一个"401 Unauthorized"响应并通过WWW认证头来确定当前认证的区域(realm)(一个字符串,诸如"Mary’s Pictures”或"Your Shopping Cart"),这通常会导致浏览器弹出一个"Enter username and password for …"对话框,且该页面会重新请求更新头中的认证凭证。
  • 为了用PHP来处理认证,可检查用户名和密码($_SERVER数组中的PHP_AUTH_USER和PHP_AUTH_PW两个元素)并调用header()函数来设置区域,然后发送一个"401 Unauthorized"响应:
1
2
header('WWW-Authenticate: Basic realm="Top Secret Files"');
header("HTTP/1.0 401 Unauthorized");
  • 可以使用各种方法来验证用户名和密码,例如:查询数据库,或读一个保存着合法用户名的文件,或者查询一个Microsoft域服务器。
  • 下例检查密码是否为翻转的用户名:
1
2
3
4
5
6
7
8
9
10
$auth_ok = 0;
$user = $_SERVER['PHP_AUTH_USER'];
$pass = $_SERVER['PHP_AUTH_PW'];
if(isset($user) && isset($pass) && $user === strrev($pass)){
$auth_ok = 1;
}
if(!$auth_ok){
header('WWW-Authenticate: Basic realm="Top Secret Files"');
header('HTTP/1.0 401 Unauthorized');
}
  • 将其放入一个文档:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
$auth_ok = 0;
$user = $_SERVER['PHP_AUTH_USER'];
$pass = $_SERVER['PHP_AUTH_PW'];
if(isset($user) && isset($pass) && $user === strrev($pass)){
$auth_ok = 1;
}
if(!$auth_ok){
header('WWW-Authenticate: Basic realm="Top Secret Files"');
header('HTTP/1.0 401 Unauthorized');
// 如果用户点击"Cancel"按钮,就只能看到在此输出的信息。
exit;
}
?>
}<!-- your password-protected document goes here -->
  • 如果你要保护的页面不只一个,把以上代码放到一个独立的文件中,然后再每个需要的页面include进来。
  • 如果你的服务器使用CGI版本的PHP,而不是Apache模块方式,以上这些变量无法使用,你需要采用其他形式的认证,例如通过HTML表单来获得用户名和密码。

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!