本文目录导读:

在 PHP 中处理 Last-Modified 头主要用于HTTP 缓存,让浏览器和服务器之间进行条件请求验证,从而减少数据传输。
以下是完整的使用方法和示例:
基础用法:设置 Last-Modified 头
<?php
// 设置最后修改时间(必须使用 GMT 格式)
$lastModified = gmdate('D, d M Y H:i:s', time()) . ' GMT';
header('Last-Modified: ' . $lastModified);
?>
完整示例:带缓存验证的动态页面
<?php
// 假设你的内容最后修改时间(例如数据库中记录的)
$lastModifiedTime = strtotime('2024-01-15 10:30:00');
// 转换为 HTTP 格式
$lastModified = gmdate('D, d M Y H:i:s', $lastModifiedTime) . ' GMT';
// 设置 Last-Modified 头
header('Last-Modified: ' . $lastModified);
// 检查客户端是否发送了 If-Modified-Since 头
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
// 解析客户端的时间
$clientModified = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']);
// 如果客户端缓存是最新的
if ($clientModified >= $lastModifiedTime) {
// 返回 304 Not Modified 状态码
header('HTTP/1.1 304 Not Modified');
exit; // 不再输出内容
}
}
已更新,才输出完整内容
echo "这是页面内容...";
?>
结合 ETag 使用(推荐)
<?php
$content = "这是动态生成的内容";
$lastModifiedTime = filemtime(__FILE__); // 或其他时间源
// 生成 ETag(基于内容哈希)
$etag = md5($content . $lastModifiedTime);
// 设置缓存相关头
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $lastModifiedTime) . ' GMT');
header('ETag: "' . $etag . '"');
header('Cache-Control: public, max-age=3600');
// 检查 If-None-Match 和 If-Modified-Since
$httpIfNoneMatch = isset($_SERVER['HTTP_IF_NONE_MATCH']) ? trim($_SERVER['HTTP_IF_NONE_MATCH']) : '';
$httpIfModifiedSince = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) : 0;
// 判断是否需要发送 304
$notModified = false;
// ETag 优先考虑
if ($httpIfNoneMatch && $httpIfNoneMatch == '"' . $etag . '"') {
$notModified = true;
}
// 然后检查 Last-Modified
elseif ($httpIfModifiedSince && $httpIfModifiedSince >= $lastModifiedTime) {
$notModified = true;
}
if ($notModified) {
header('HTTP/1.1 304 Not Modified');
exit;
}
// 输出完整内容
echo $content;
?>
静态文件的处理
如果是静态文件,可以直接设置,但更推荐使用服务器配置(如 Nginx/Apache):
<?php
$file = '/path/to/your/file.pdf';
if (file_exists($file)) {
$lastModifiedTime = filemtime($file);
header('Content-Type: application/pdf');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $lastModifiedTime) . ' GMT');
// 检查条件请求
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
$ifModifiedSince = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']);
if ($ifModifiedSince >= $lastModifiedTime) {
header('HTTP/1.1 304 Not Modified');
exit;
}
}
// 输出文件
readfile($file);
}
?>
注意事项
时间格式必须正确
// 正确的格式
$gmtDate = gmdate('D, d M Y H:i:s', time()) . ' GMT';
// 示例输出: Mon, 15 Jan 2024 10:30:00 GMT
使用缓存控制策略
// 示例:组合使用
header('Cache-Control: private, must-revalidate');
header('Last-Modified: ' . $lastModified);
完整请求流程
- 首次请求:服务器发送
Last-Modified头和完整内容 - 客户端缓存:浏览器存储内容和修改时间
- 再次请求:浏览器发送
If-Modified-Since头 - 服务器对比:如果时间相同,返回 304 状态码,不发送内容
完整示例:动态内容缓存
<?php
// 模拟数据库查询
function getContentModifiedTime() {
// 实际应用中返回内容的最后修改时间
return strtotime('2024-01-20 14:00:00');
}
// 主逻辑
$lastModifiedTime = getContentModifiedTime();
$lastModified = gmdate('D, d M Y H:i:s', $lastModifiedTime) . ' GMT';
header('Last-Modified: ' . $lastModified);
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
$ifModifiedSince = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']);
if ($ifModifiedSince >= $lastModifiedTime) {
header('HTTP/1.1 304 Not Modified');
exit;
}
}
有更新时才重新生成
$content = "最新内容 - 更新时间: " . date('Y-m-d H:i:s', $lastModifiedTime);
echo $content;
?>
最佳实践
- 优先使用 ETag:ETag 比 Last-Modified 更精确
- 组合使用:两者可以同时使用
- 配合 Cache-Control:设置合适的缓存策略
- 注意时区:始终使用 GMT 格式
- 验证条件:
If-Modified-Since优先于If-Modified-Since的处理顺序
这样实现后,你的 PHP 页面就能正确利用 HTTP 缓存机制,减少不必要的服务器负载和网络传输。