我在那里,我目前正在编写一个单元测试,它断言文件没有被修改。测试代码执行时间不到一秒,因此我想知道是否可以以毫秒为单位检索文件修改时间。filemtime() 函数以秒为单位返回 UNIX 时间戳。
我当前的解决方案是使用 sleep(1) 函数,它可以确保在检查它是否被修改之前经过 1 秒。我不喜欢这种解决方案,因为它大大减慢了测试速度。
我不能通过 get_file_contents() 断言内容相等,因为可以重写的数据是相同的。
我猜这是不可能的,是吗?
function getTime($path){
clearstatcache($path);
$dateUnix = shell_exec('stat --format "%y" '.$path);
$date = explode(".", $dateUnix);
return filemtime($path).".".substr($date[1], 0, 8);
}
获取时间(“我的文件”);
试试这个简单的命令:
ls --full-time 'filename'
并且可以看到文件时间戳精度不是秒,而是更精确。(使用Linux,但不要认为它在Unix中有所不同)但我仍然不知道用于获取精确时间戳的PHP函数,也许您可以解析系统调用的结果。
AFAIK UNIX 时间戳的精度是秒,所以这可能是不可能的。
顺便说一句,请注意 PHP 会在filemtime()
内部缓存 的返回值,因此clearstatcache()
应该在之前调用。
另一种方法是先修改(或删除)文件的内容,以便您可以轻松识别更改。由于每次测试执行后系统的状态应该保持不变,因此在单元测试运行后恢复原始文件内容无论如何都是有意义的。
如果文件系统是ext4
(在最近的 unixes / linux 上很常见,如 Ubuntu)或ntfs
(Windows),那么它mtime
确实具有亚秒级精度。
如果文件系统是ext3
(或者可能是其他文件系统;这是不久前的标准,并且仍然被 RHEL 使用),那么mtime
它只存储到最接近的秒数。也许那个旧的默认值是 PHP 只支持mtime
最接近秒的原因。
要在 PHP 中获取值,您需要调用外部工具,因为 PHP 本身不支持它。
(我在仅具有英语语言环境的系统上测试了以下内容;“人类可读”的输出stat
可能会有所不同,或者strtotime
在非英语语言环境下的行为可能会有所不同。它应该在任何时区都可以正常工作,因为输出stat
包括时区说明符,由strtotime
.)
class FileModTimeHelper
{
/**
* Returns the file mtime for the specified file, in the format returned by microtime()
*
* On file systems which do not support sub-second mtime precision (such as ext3), the value
* will be rounded to the nearest second.
*
* There must be a posix standard "stat" on your path (e.g. on unix or Windows with Cygwin)
*
* @param $filename string the name of the file
* @return string like microtime()
*/
public static function getFileModMicrotime($filename)
{
$stat = `stat --format=%y $filename`;
$patt = '/^(\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d)\.(\d+) (.*)$/';
if (!preg_match($patt, $stat, $matches)) {
throw new \Exception("Unrecognised output from stat. Expecting something like '$patt', found: '$stat'");
}
$mtimeSeconds = strtotime("{$matches[1]} {$matches[3]}");
$mtimeMillis = $matches[2];
return "$mtimeSeconds.$mtimeMillis";
}
}
唔。想象一个 Web 服务器,我们使用 PHP 的组合,例如 nodeJS。在 nodeJS 中,当我们获得文件的修改时间时,它包括毫秒。在 PHP 中它没有。现在让我们说,对于我们允许用户下载的任何大文件(许多千兆字节),我们拥有并维护包含整个文件的预先计算的 MD5 校验和的相应文件。我们将此校验和存储在与原始文件同名的文件中,但前面还加上文件的大小和修改时间。包括毫秒!(所有这些都由节点完成)
示例:GEBCO_2019.nc(11723617646 字节)和 GEBCO_2019.nc.11723617646-2019-10-31T15-03-06.687Z.md5
现在在下载页面上,我们决定显示 MD5 校验和 这是使用 PHP 代码
不好了!!!
我们调用 filemtime 但可惜我们无法获得毫秒数,因此我们无法计算出 Md5 文件的名称。
我们可以更改节点代码以忽略毫秒部分。
就像这里 PHP 的缺陷导致我们选择了一个比我们应该选择的更低的公分母。
为了获得文件修改时间而不得不求助于运行外部程序也是非常可怕的。如果您必须为单个页面加载执行此操作 50 或 60 次,我希望它会减慢速度!!!
现在文件修改时间的准确性当然取决于系统。PHP应该直接为我们提供一个获取这个时间的方法,如果不能,那就是一个严重的缺陷。