PHP文件修改时间(以毫秒为单位)

发布于 2024-09-03 09:27:58 字数 264 浏览 10 评论 0原文

我在那里,目前正在编写一个单元测试,断言文件没有被修改。测试代码执行时间不到一秒,因此我想知道是否可以以毫秒为单位检索文件修改时间。 filemtime() 函数返回 UNIX 时间戳(以秒为单位)。

我当前的解决方案是使用 sleep(1) 函数,这将确保我在检查它是否被修改之前经过 1 秒。我不喜欢这个解决方案,因为它大大减慢了测试速度。

我无法通过 get_file_contents() 断言内容相等,因为可以重写的数据是相同的。

我猜这是不可能的,是吗?

I there, I am currently writing a unit test which asserts that a file did not get modified. The test code execution takes less than one second and therefore I would like to know if it is possible to retrieve the file modification time in milliseconds. filemtime() function returns the UNIX timestamp in seconds.

My current solution is using the sleep(1) function which will assure me that 1 second passed before checking if it was modified or not. I don't like that solution since it slows down the test by a great deal.

I cannot assert the content equality via get_file_contents() since the data that can be rewritten would be the same.

I am guessing it is impossible, is it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

枕花眠 2024-09-10 09:27:58
function getTime($path){
    clearstatcache($path);
    $dateUnix = shell_exec('stat --format "%y" '.$path);
    $date = explode(".", $dateUnix);
    return filemtime($path).".".substr($date[1], 0, 8);
}

getTime("我的文件");

function getTime($path){
    clearstatcache($path);
    $dateUnix = shell_exec('stat --format "%y" '.$path);
    $date = explode(".", $dateUnix);
    return filemtime($path).".".substr($date[1], 0, 8);
}

getTime("myFile");

美胚控场 2024-09-10 09:27:58

尝试这个简单的命令:

ls --full-time 'filename'

您可以看到文件时间戳精度不是秒,而是更精确。
(使用Linux,但不认为它在Unix上有什么不同)
但我仍然不知道用于获取精确时间戳的 PHP 函数,也许您可​​以解析系统调用的结果。

Try this simple command:

ls --full-time 'filename'

and you can see the file timestamp precision is not second, it is more precise.
(using Linux, but don't think it differs in Unix)
but I still don't know of a PHP function for getting precise timestamp, maybe you can parse the result of the system call.

栀子花开つ 2024-09-10 09:27:58

如果文件系统是 ext4(常见于较新的 unix/linux,如 Ubuntu)或 ntfs (Windows),则 mtime 确实有子系统-秒精度。

如果文件系统是 ext3(或者可能是其他文件系统;这是不久前的标准,并且 RHEL 仍在使用),则 mtime 仅存储到最接近的秒。也许旧的默认设置就是 PHP 仅支持精确到秒的 mtime 的原因。

要在 PHP 中获取值,您需要调用外部 util,因为 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";
    }
}

If the file system is ext4 (common on more recent unixes / linuxes like Ubuntu) or ntfs (Windows), then the mtime does have sub-second precision.

If the file system is ext3 (or perhaps others; this was the standard a while ago and is still used by RHEL), then the mtime is only stored to the nearest second. Perhaps that old default is why PHP only supports mtime to the nearest second.

To fetch the value in PHP, you need to call an external util, since PHP itself does not support it.

(I have tested the following on a system with an English locale only; the "human readable" output of stat may differ, or the strtotime behaviour may differ on non-English locales. It should work fine in any timezone, as the output of stat includes a timezone specifier which is honoured by 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";
    }
}
一抹微笑 2024-09-10 09:27:58

AFAIK UNIX 时间戳的精度是秒,所以这可能是不可能的。

顺便说一句,请注意 PHP 在内部缓存了 filemtime() 的返回值,因此 clearstatcache() 应该在之前调用。

另一种方法可能是首先修改(或删除)文件的内容,以便您可以轻松识别更改。由于执行每个测试后系统的状态应保持不变,因此在单元测试运行后恢复原始文件内容无论如何都是有意义的。

AFAIK UNIX timestamp's precision is seconds, so this may not be a possibility.

BTW, note that PHP caches the return value of filemtime() internally, thus clearstatcache() should be called before.

An alternative method could be to modify (or delete) the contents of the file first so that you can easily identify changes. Since the state of the system should remain the same after each test is executed, it would make sense anyways to restore the original file contents after the unit test has run.

Saygoodbye 2024-09-10 09:27:58

唔。想象一下一个 Web 服务器,我们使用 PHP 和 NodeJS 的组合。在nodeJS领域,当我们获取文件的修改时间时,它包括毫秒。在 PHP 中则不然。现在假设对于我们允许用户下载的任何大文件(许多 GB),我们拥有并维护包含整个文件的预先计算的 MD5 校验和的相应文件。我们将此校验和存储在与原始文件同名的文件中,但前面还添加了文件的大小和修改时间。包括毫秒!
(所有这些都是由节点完成的)

示例:
GEBCO_2019.nc(11723617646 字节)

GEBCO_2019.nc.11723617646-2019-10-31T15-03-06.687Z.md5

现在,我们决定在下载页面上显示 MD5 校验和
这是使用 PHP 代码

哦不!!!

我们调用 filemtime,但遗憾的是我们无法获取毫秒数,因此无法计算出 Md5 文件的名称。

我们可以更改节点代码以忽略毫秒部分。

就像 PHP 的缺陷导致我们选择了一个比我们应该选择的更低的公分母。

不得不依靠运行外部程序来获取文件修改时间也是非常可怕的。如果您必须为单个页面加载执行 50 或 60 次,我预计这会减慢速度!

现在,文件修改时间的准确性当然取决于系统。 PHP应该直接给我们提供一个获取这个时间的方法,如果不能的话那就是严重的缺陷了。

Hmm. Imagine a web server where we use a combination of PHP and say for example nodeJS. In nodeJS land when we get the modification time of a file it includes the milliseconds. In PHP it does not. Now lets say that for any large files (many Gigabytes) which we allow the user to download we have and maintain corresponding file containing the pre-calculated MD5 checksum of the entire file. We store this checksum in a file with the same name as the original file but prepended also with the size and modification time of the file. INCLUDING THE MILLISECONDS!
(with all of that being done by node)

Example:
GEBCO_2019.nc (11723617646 bytes)
and
GEBCO_2019.nc.11723617646-2019-10-31T15-03-06.687Z.md5

Now on the downloads page we decide to display the MD5 checksum
This is using PHP code

OH NO!!!

We call filemtime but alas we can't get the milliseconds so we can't work out the name of the Md5 file.

WE COULD CHANGE THE NODE CODE to ignore the millisecond part.

Its like the deficiency in PHP here is causing us to choose a lower common denominator than we should have to.

It's also exceptionally HORRIBLE to have to resort to running an external program just to get the file modification time. If you had to do this 50 or 60 times for a single page load I expect it would slow things down just a bit!!!

Now the accuracy of file mod time is of course system dependent. PHP should directly provide us with a way to get this time and it's a serious deficiency if it cannot.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文