fileatime() 函数是PHP中用于获取文件最后访问时间的内置函数。它返回文件最后一次被访问的时间戳,这对于日志分析、缓存管理和文件监控等场景非常有用。
语法
int fileatime ( string $filename )
参数说明
| 参数 |
描述 |
类型 |
是否必需 |
| filename |
要检查的文件路径 |
string |
是 |
返回值
- 成功时返回文件最后访问时间的Unix时间戳
- 失败时返回 FALSE
注意事项
fileatime() 返回的是Unix时间戳,需要转换为可读格式
- 在某些文件系统上,为了提高性能,访问时间可能不会实时更新
- 文件访问时间的精度取决于文件系统
- 使用
clearstatcache() 清除文件状态缓存以获得最新信息
- 对于不存在的文件或权限不足的文件,函数会返回FALSE
示例代码
示例1:基本使用 - 获取文件最后访问时间
<?php
$filename = 'test.txt';
// 获取文件的最后访问时间
$atime = fileatime($filename);
if ($atime !== false) {
echo "文件最后访问时间戳: " . $atime . "<br>";
echo "格式化时间: " . date('Y-m-d H:i:s', $atime);
} else {
echo "无法获取文件访问时间";
}
?>
示例2:比较文件的三种时间
<?php
function getFileTimes($filename) {
if (!file_exists($filename)) {
return "文件不存在";
}
// 获取三种时间
$atime = fileatime($filename); // 最后访问时间
$mtime = filemtime($filename); // 最后修改时间
$ctime = filectime($filename); // 最后改变时间(inode修改时间)
// 格式化输出
return [
'最后访问时间' => date('Y-m-d H:i:s', $atime),
'最后修改时间' => date('Y-m-d H:i:s', $mtime),
'最后改变时间' => date('Y-m-d H:i:s', $ctime)
];
}
// 使用示例
$times = getFileTimes('data.txt');
if (is_array($times)) {
echo "<h4>文件时间信息:</h4>";
foreach ($times as $label => $time) {
echo "{$label}: {$time}<br>";
}
} else {
echo $times;
}
?>
示例3:监控文件访问频率
<?php
class FileAccessMonitor {
private $log_file;
public function __construct($log_file = 'access_monitor.log') {
$this->log_file = $log_file;
}
public function checkFileAccess($filename, $threshold_seconds = 3600) {
if (!file_exists($filename)) {
return ['error' => "文件不存在"];
}
// 获取当前时间和文件最后访问时间
$current_time = time();
$last_access = fileatime($filename);
// 计算时间差
$time_diff = $current_time - $last_access;
// 判断是否在阈值内被访问过
$recently_accessed = $time_diff <= $threshold_seconds;
// 记录日志
$this->logAccess($filename, $last_access, $time_diff, $recently_accessed);
return [
'filename' => $filename,
'last_access' => date('Y-m-d H:i:s', $last_access),
'time_diff_seconds' => $time_diff,
'recently_accessed' => $recently_accessed,
'message' => $recently_accessed ?
"文件最近被访问过({$time_diff}秒前)" :
"文件很长时间未被访问({$time_diff}秒前)"
];
}
private function logAccess($filename, $timestamp, $time_diff, $recently_accessed) {
$log_entry = sprintf(
"[%s] 文件: %s, 最后访问: %s, 时间差: %d秒, 状态: %s\n",
date('Y-m-d H:i:s'),
$filename,
date('Y-m-d H:i:s', $timestamp),
$time_diff,
$recently_accessed ? '活跃' : '不活跃'
);
file_put_contents($this->log_file, $log_entry, FILE_APPEND);
}
}
// 使用示例
$monitor = new FileAccessMonitor();
$result = $monitor->checkFileAccess('important_config.php', 1800); // 30分钟阈值
echo "<pre>";
print_r($result);
echo "</pre>";
?>
示例4:自动清理长时间未访问的文件
<?php
function cleanupOldFiles($directory, $max_age_days = 30) {
if (!is_dir($directory)) {
return "目录不存在: {$directory}";
}
$max_age_seconds = $max_age_days * 24 * 3600;
$current_time = time();
$deleted_files = [];
$kept_files = [];
// 扫描目录
$files = scandir($directory);
foreach ($files as $file) {
if ($file === '.' || $file === '..') {
continue;
}
$filepath = $directory . '/' . $file;
// 跳过目录,只处理文件
if (!is_file($filepath)) {
continue;
}
// 获取最后访问时间
$atime = fileatime($filepath);
if ($atime === false) {
continue; // 无法获取时间,跳过
}
// 计算未访问天数
$days_since_access = floor(($current_time - $atime) / (24 * 3600));
if (($current_time - $atime) > $max_age_seconds) {
// 删除文件
if (unlink($filepath)) {
$deleted_files[] = [
'name' => $file,
'last_access' => date('Y-m-d H:i:s', $atime),
'days_since_access' => $days_since_access
];
}
} else {
$kept_files[] = [
'name' => $file,
'last_access' => date('Y-m-d H:i:s', $atime),
'days_since_access' => $days_since_access
];
}
}
return [
'deleted_count' => count($deleted_files),
'kept_count' => count($kept_files),
'deleted_files' => $deleted_files,
'kept_files' => $kept_files
];
}
// 使用示例
$result = cleanupOldFiles('temp_files', 7); // 清理超过7天未访问的文件
echo "清理完成: 删除了 {$result['deleted_count']} 个文件,保留了 {$result['kept_count']} 个文件";
?>
示例5:文件访问时间缓存管理
<?php
class FileTimeCache {
private $cache = [];
private $cache_ttl = 60; // 缓存60秒
public function getAccessTime($filename, $force_refresh = false) {
// 检查缓存
if (!$force_refresh && isset($this->cache[$filename])) {
$cached = $this->cache[$filename];
if (time() - $cached['timestamp'] < $this->cache_ttl) {
return $cached['data'];
}
}
// 清除文件状态缓存
clearstatcache(true, $filename);
// 获取访问时间
$atime = fileatime($filename);
if ($atime === false) {
return false;
}
// 格式化数据
$result = [
'timestamp' => $atime,
'formatted' => date('Y-m-d H:i:s', $atime),
'relative' => $this->getRelativeTime($atime)
];
// 更新缓存
$this->cache[$filename] = [
'data' => $result,
'timestamp' => time()
];
return $result;
}
private function getRelativeTime($timestamp) {
$diff = time() - $timestamp;
if ($diff < 60) {
return "刚刚";
} elseif ($diff < 3600) {
return floor($diff / 60) . "分钟前";
} elseif ($diff < 86400) {
return floor($diff / 3600) . "小时前";
} elseif ($diff < 2592000) {
return floor($diff / 86400) . "天前";
} else {
return floor($diff / 2592000) . "个月前";
}
}
public function clearCache() {
$this->cache = [];
}
}
// 使用示例
$cache = new FileTimeCache();
// 第一次获取(从文件系统读取)
$time1 = $cache->getAccessTime('data.txt');
echo "第一次获取: " . $time1['formatted'] . " ({$time1['relative']})<br>";
// 第二次获取(从缓存读取)
$time2 = $cache->getAccessTime('data.txt');
echo "第二次获取: " . $time2['formatted'] . " ({$time2['relative']})<br>";
// 强制刷新
$time3 = $cache->getAccessTime('data.txt', true);
echo "强制刷新: " . $time3['formatted'] . " ({$time3['relative']})";
?>
示例6:检测文件是否被篡改
<?php
class FileIntegrityChecker {
private $baseline_file = 'baseline.json';
public function createBaseline($directory) {
$baseline = [];
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($directory),
RecursiveIteratorIterator::SELF_FIRST
);
foreach ($files as $file) {
if ($file->isFile()) {
$filepath = $file->getPathname();
$baseline[$filepath] = [
'atime' => fileatime($filepath),
'mtime' => filemtime($filepath),
'ctime' => filectime($filepath),
'size' => filesize($filepath),
'hash' => md5_file($filepath)
];
}
}
// 保存基线数据
file_put_contents(
$this->baseline_file,
json_encode($baseline, JSON_PRETTY_PRINT)
);
return count($baseline);
}
public function checkIntegrity() {
if (!file_exists($this->baseline_file)) {
return ['error' => '基线文件不存在'];
}
$baseline = json_decode(file_get_contents($this->baseline_file), true);
$changes = [];
foreach ($baseline as $filepath => $original_data) {
if (!file_exists($filepath)) {
$changes[$filepath] = '文件已删除';
continue;
}
$current_atime = fileatime($filepath);
$current_mtime = filemtime($filepath);
$current_ctime = filectime($filepath);
$current_size = filesize($filepath);
$current_hash = md5_file($filepath);
$detected_changes = [];
if ($current_atime != $original_data['atime']) {
$detected_changes[] = '访问时间变化';
}
if ($current_mtime != $original_data['mtime']) {
$detected_changes[] = '修改时间变化';
}
if ($current_ctime != $original_data['ctime']) {
$detected_changes[] = 'inode变化';
}
if ($current_size != $original_data['size']) {
$detected_changes[] = '大小变化';
}
if ($current_hash != $original_data['hash']) {
$detected_changes[] = '内容变化';
}
if (!empty($detected_changes)) {
$changes[$filepath] = $detected_changes;
}
}
return [
'total_files' => count($baseline),
'changed_files' => count($changes),
'changes' => $changes
];
}
}
// 使用示例
$checker = new FileIntegrityChecker();
// 创建基线
$file_count = $checker->createBaseline('important_files');
echo "已创建基线,包含 {$file_count} 个文件<br>";
// 检查完整性
$result = $checker->checkIntegrity();
echo "完整性检查结果: {$result['changed_files']} 个文件发生变化";
?>
与类似函数的比较
| 函数 |
描述 |
返回内容 |
适用场景 |
fileatime() |
获取文件最后访问时间 |
Unix时间戳 |
监控文件访问频率、缓存管理 |
filemtime() |
获取文件最后修改时间 |
Unix时间戳 |
检测文件内容变化、版本控制 |
filectime() |
获取文件inode最后改变时间 |
Unix时间戳 |
检测权限、所有权变化 |
stat() |
获取文件所有状态信息 |
包含多个时间戳的数组 |
需要完整文件信息的场景 |
lstat() |
获取文件或符号链接状态 |
数组(与stat类似) |
处理符号链接的场景 |
性能优化建议
最佳实践
- 对于频繁查询的文件时间,使用缓存机制避免重复调用
- 在处理多个文件时,使用
clearstatcache()确保获取最新信息
- 注意某些文件系统可能为了性能而延迟更新访问时间
- 使用绝对路径而不是相对路径,避免路径解析开销
- 结合其他文件时间函数(filemtime、filectime)进行综合判断
常见错误和解决方法
常见问题
- 返回FALSE: 文件不存在或权限不足,先检查
file_exists()和is_readable()
- 时间不准确: 某些文件系统为了性能禁用访问时间更新,检查文件系统设置
- 缓存问题: 使用
clearstatcache()清除缓存以获得最新信息
- 性能问题: 避免在循环中多次调用,考虑批量处理或缓存结果
完整示例:文件访问统计系统
<?php
class FileAccessStatistics {
private $stats_file = 'access_stats.json';
private $stats;
public function __construct() {
$this->loadStats();
}
private function loadStats() {
if (file_exists($this->stats_file)) {
$this->stats = json_decode(file_get_contents($this->stats_file), true);
} else {
$this->stats = [];
}
}
private function saveStats() {
file_put_contents(
$this->stats_file,
json_encode($this->stats, JSON_PRETTY_PRINT)
);
}
public function recordAccess($filename) {
clearstatcache(true, $filename);
$atime = fileatime($filename);
if ($atime === false) {
return false;
}
$date = date('Y-m-d', $atime);
if (!isset($this->stats[$filename])) {
$this->stats[$filename] = [
'first_access' => $atime,
'last_access' => $atime,
'access_count' => 0,
'daily_stats' => []
];
}
// 更新统计
$this->stats[$filename]['last_access'] = $atime;
$this->stats[$filename]['access_count']++;
if (!isset($this->stats[$filename]['daily_stats'][$date])) {
$this->stats[$filename]['daily_stats'][$date] = 0;
}
$this->stats[$filename]['daily_stats'][$date]++;
$this->saveStats();
return true;
}
public function getStats($filename = null) {
if ($filename) {
return $this->stats[$filename] ?? null;
}
return $this->stats;
}
public function getMostAccessedFiles($limit = 10) {
$files = $this->stats;
uasort($files, function($a, $b) {
return $b['access_count'] - $a['access_count'];
});
return array_slice($files, 0, $limit, true);
}
}
// 使用示例
$stats = new FileAccessStatistics();
// 记录文件访问
$stats->recordAccess('config.php');
$stats->recordAccess('database.php');
// 获取统计信息
$top_files = $stats->getMostAccessedFiles(5);
echo "<h4>最常访问的文件:</h4>";
foreach ($top_files as $filename => $data) {
$first = date('Y-m-d H:i:s', $data['first_access']);
$last = date('Y-m-d H:i:s', $data['last_access']);
echo "{$filename}: 访问次数 {$data['access_count']}, 首次访问 {$first}, 最后访问 {$last}<br>";
}
?>