touch() 函数用于设置文件的访问和修改时间。如果指定的文件不存在,PHP会尝试创建它。
这个函数常用于以下场景:创建空文件、更新文件时间戳以触发某些操作(如缓存失效)、或者模拟文件的存在。
touch ( string $filename [, int $time = time() [, int $atime ]] ) : bool
参数说明:
$filename:要设置时间的文件名(必需)$time:要设置的修改时间(Unix时间戳),默认是当前时间(可选)$atime:要设置的访问时间(Unix时间戳),如果指定,则单独设置访问时间(可选)| 参数 | 描述 |
|---|---|
filename |
要设置时间的文件名。必需参数。
|
time |
修改时间(mtime)。可选参数。
|
atime |
访问时间(atime)。可选参数。
|
truefalse,通常是由于以下原因:
使用 touch() 创建空文件:
<?php
$filename = 'new_file.txt';
if (touch($filename)) {
echo "文件创建成功: $filename<br>";
// 检查文件是否存在
if (file_exists($filename)) {
echo "文件确实存在<br>";
// 获取文件信息
$fileSize = filesize($filename);
echo "文件大小: $fileSize 字节<br>";
}
} else {
echo "文件创建失败";
}
?>
更新现有文件的时间戳:
<?php
$filename = 'existing_file.txt';
if (file_exists($filename)) {
// 获取原始时间
$originalMtime = filemtime($filename);
echo "原始修改时间: " . date('Y-m-d H:i:s', $originalMtime) . "<br>";
// 更新为当前时间
if (touch($filename)) {
$newMtime = filemtime($filename);
echo "更新后修改时间: " . date('Y-m-d H:i:s', $newMtime) . "<br>";
echo "时间已更新";
}
} else {
echo "文件不存在,无法更新时间戳";
}
?>
将文件时间设置为过去的特定时间:
<?php
$filename = 'document.txt';
// 创建一个过去的时间(例如:2020年1月1日)
$pastTime = strtotime('2020-01-01 12:00:00');
if (touch($filename, $pastTime)) {
echo "文件时间已设置为 2020-01-01 12:00:00<br>";
$mtime = filemtime($filename);
$atime = fileatime($filename);
echo "修改时间: " . date('Y-m-d H:i:s', $mtime) . "<br>";
echo "访问时间: " . date('Y-m-d H:i:s', $atime) . "<br>";
// 注意:修改时间和访问时间都被设置为相同的值
if ($mtime === $atime) {
echo "修改时间和访问时间相同";
}
}
?>
单独设置文件的访问时间:
<?php
$filename = 'data.txt';
// 确保文件存在
if (!file_exists($filename)) {
touch($filename);
}
// 设置不同的修改时间和访问时间
$modificationTime = strtotime('2023-01-15 10:30:00');
$accessTime = strtotime('2023-02-20 14:45:00');
// PHP 5.3.0+ 支持第三个参数
if (touch($filename, $modificationTime, $accessTime)) {
echo "时间设置成功<br>";
// 验证设置结果
clearstatcache(true, $filename); // 清除缓存获取最新数据
$mtime = filemtime($filename);
$atime = fileatime($filename);
echo "设置的修改时间: " . date('Y-m-d H:i:s', $modificationTime) . "<br>";
echo "实际的修改时间: " . date('Y-m-d H:i:s', $mtime) . "<br>";
echo "设置的访问时间: " . date('Y-m-d H:i:s', $accessTime) . "<br>";
echo "实际的访问时间: " . date('Y-m-d H:i:s', $atime) . "<br>";
// 检查是否设置成功
if ($mtime === $modificationTime && $atime === $accessTime) {
echo "✓ 时间戳设置正确";
}
} else {
echo "时间设置失败";
}
?>
批量处理多个文件:
<?php
function batchTouchFiles($fileList, $time = null) {
$results = [
'success' => 0,
'failed' => 0,
'details' => []
];
foreach ($fileList as $index => $filename) {
if ($time === null) {
$result = touch($filename);
} else {
$result = touch($filename, $time);
}
$status = $result ? '成功' : '失败';
$results['details'][] = [
'file' => $filename,
'status' => $status,
'exists' => file_exists($filename)
];
if ($result) {
$results['success']++;
} else {
$results['failed']++;
}
}
return $results;
}
// 使用示例
$files = [
'file1.txt',
'file2.txt',
'file3.txt',
'/var/www/temp/file4.txt'
];
// 设置为明天的时间
$futureTime = strtotime('+1 day');
$batchResult = batchTouchFiles($files, $futureTime);
echo "批量处理结果:<br>";
echo "成功: {$batchResult['success']} 个<br>";
echo "失败: {$batchResult['failed']} 个<br><br>";
echo "详细信息:<br>";
foreach ($batchResult['details'] as $detail) {
$exists = $detail['exists'] ? '存在' : '不存在';
echo "文件: {$detail['file']} - 状态: {$detail['status']} - 存在: {$exists}<br>";
}
?>
Unix/Linux系统中,文件有三种主要的时间戳:
| 时间戳类型 | 缩写 | 描述 | touch() 函数影响 |
|---|---|---|---|
| 修改时间 | mtime | 文件内容最后被修改的时间 | 总是修改(通过第二个参数) |
| 访问时间 | atime | 文件最后被访问(读取)的时间 | 修改(如果指定第三个参数) |
| 状态更改时间 | ctime | 文件元数据(如权限)最后改变的时间 | 间接影响(当文件被创建或时间戳改变时) |
<?php
// 演示三种时间戳的区别
$filename = 'demo_times.txt';
// 确保文件存在
if (!file_exists($filename)) {
file_put_contents($filename, '初始内容');
}
echo "初始状态:<br>";
showFileTimes($filename);
// 使用 touch() 更新时间和访问时间
echo "<br>使用 touch() 后:<br>";
$newTime = strtotime('2023-12-25 10:00:00');
touch($filename, $newTime);
showFileTimes($filename);
// 修改文件内容
echo "<br>修改文件内容后:<br>";
file_put_contents($filename, '修改后的内容');
showFileTimes($filename);
// 修改文件权限
echo "<br>修改文件权限后:<br>";
chmod($filename, 0644);
clearstatcache(true, $filename);
showFileTimes($filename);
function showFileTimes($filename) {
clearstatcache(true, $filename);
$mtime = filemtime($filename); // 修改时间
$atime = fileatime($filename); // 访问时间
$ctime = filectime($filename); // 状态更改时间
echo "mtime: " . date('Y-m-d H:i:s', $mtime) . "<br>";
echo "atime: " . date('Y-m-d H:i:s', $atime) . "<br>";
echo "ctime: " . date('Y-m-d H:i:s', $ctime) . "<br>";
// 清理演示文件
if (strpos($filename, 'demo_') === 0) {
unlink($filename);
}
}
?>
使用文件时间戳作为缓存失效的标记:
<?php
class CacheManager {
private $cacheDir;
public function __construct($cacheDir = '/tmp/cache') {
$this->cacheDir = $cacheDir;
if (!is_dir($cacheDir)) {
mkdir($cacheDir, 0755, true);
}
}
public function isCacheValid($cacheKey, $ttl = 3600) {
$cacheFile = $this->getCacheFilePath($cacheKey);
if (!file_exists($cacheFile)) {
return false;
}
$cacheAge = time() - filemtime($cacheFile);
return $cacheAge <= $ttl;
}
public function invalidateCache($cacheKey) {
$cacheFile = $this->getCacheFilePath($cacheKey);
if (file_exists($cacheFile)) {
// 通过更新文件时间戳来标记缓存失效
touch($cacheFile, time() - 86400); // 设置为24小时前
return true;
}
return false;
}
public function refreshCache($cacheKey) {
$cacheFile = $this->getCacheFilePath($cacheKey);
// 更新缓存文件的时间戳
return touch($cacheFile);
}
public function getCacheFilePath($cacheKey) {
$hash = md5($cacheKey);
return $this->cacheDir . '/' . $hash . '.cache';
}
}
// 使用示例
$cache = new CacheManager();
if ($cache->isCacheValid('user_data_123')) {
echo "缓存有效";
// 从缓存读取数据
} else {
echo "缓存已过期或不存在";
// 重新生成缓存
// ...
$cache->refreshCache('user_data_123');
}
// 手动使缓存失效
$cache->invalidateCache('user_data_123');
?>
使用文件时间戳实现简单的文件锁定:
<?php
class FileLock {
private $lockDir;
private $lockTimeout = 300; // 5分钟超时
public function __construct($lockDir = '/tmp/locks') {
$this->lockDir = $lockDir;
if (!is_dir($lockDir)) {
mkdir($lockDir, 0755, true);
}
}
public function acquireLock($lockName) {
$lockFile = $this->getLockFilePath($lockName);
// 如果锁文件不存在,创建它并获取锁
if (!file_exists($lockFile)) {
return touch($lockFile);
}
// 检查锁是否已过期
$lockAge = time() - filemtime($lockFile);
if ($lockAge > $this->lockTimeout) {
// 锁已过期,更新它并获取锁
return touch($lockFile);
}
// 锁仍有效
return false;
}
public function releaseLock($lockName) {
$lockFile = $this->getLockFilePath($lockName);
if (file_exists($lockFile)) {
// 将锁文件时间设置为过去,使其立即过期
return touch($lockFile, time() - $this->lockTimeout - 1);
}
return true;
}
public function refreshLock($lockName) {
$lockFile = $this->getLockFilePath($lockName);
if (file_exists($lockFile)) {
// 更新锁的时间戳,延长锁的有效期
return touch($lockFile);
}
return false;
}
public function isLocked($lockName) {
$lockFile = $this->getLockFilePath($lockName);
if (!file_exists($lockFile)) {
return false;
}
$lockAge = time() - filemtime($lockFile);
return $lockAge <= $this->lockTimeout;
}
private function getLockFilePath($lockName) {
return $this->lockDir . '/' . md5($lockName) . '.lock';
}
}
// 使用示例
$lock = new FileLock();
if ($lock->acquireLock('critical_operation')) {
echo "获取锁成功,执行临界操作...<br>";
// 执行需要锁的操作
sleep(2);
// 操作完成后释放锁
$lock->releaseLock('critical_operation');
echo "操作完成,锁已释放";
} else {
echo "无法获取锁,可能有其他进程正在执行相同操作";
}
?>
clearstatcache() 清除文件状态缓存以获取最新时间戳<?php
// 1. 总是检查返回值
$filename = 'important.txt';
if (!touch($filename)) {
// 处理错误
$error = error_get_last();
echo "无法更新文件时间: " . ($error['message'] ?? '未知错误');
}
// 2. 使用clearstatcache()获取最新时间戳
$file = 'data.txt';
touch($file, strtotime('2023-01-01'));
clearstatcache(true, $file); // 清除指定文件的缓存
$mtime = filemtime($file);
// 3. 确保目录存在并有正确权限
function safeTouch($filename, $time = null) {
$dir = dirname($filename);
// 确保目录存在
if (!is_dir($dir)) {
if (!mkdir($dir, 0755, true)) {
return false;
}
}
// 检查目录是否可写
if (!is_writable($dir)) {
return false;
}
// 执行touch操作
if ($time === null) {
return touch($filename);
} else {
return touch($filename, $time);
}
}
// 4. 处理未来时间戳(某些文件系统可能不支持)
function touchWithValidation($filename, $time) {
$currentTime = time();
// 不允许设置未来的时间戳(除非有特殊需求)
if ($time > $currentTime + 3600) { // 超过当前时间1小时
return false;
}
return touch($filename, $time);
}
?>