PHP中的5分钟文件缓存
我有一个非常简单的问题:用PHP下载文件的最佳方式是什么,但前提是本地版本在5分钟前已经下载了 在我的实际案例中,我希望从远程托管的csv文件中获取数据,我目前正在使用该文件PHP中的5分钟文件缓存,php,url,curl,download,Php,Url,Curl,Download,我有一个非常简单的问题:用PHP下载文件的最佳方式是什么,但前提是本地版本在5分钟前已经下载了 在我的实际案例中,我希望从远程托管的csv文件中获取数据,我目前正在使用该文件 $file = file_get_contents($url); 没有任何本地副本或缓存。将其转换为缓存版本的最简单方法是什么,最终结果不会改变($file保持不变),但如果不久前(比如5分钟)已获取,它将使用本地副本?您可以在第一次点击时保存文件副本,然后使用filemtime检查以下点击时本地文件上次修改的时间戳。如
$file = file_get_contents($url);
没有任何本地副本或缓存。将其转换为缓存版本的最简单方法是什么,最终结果不会改变($file保持不变),但如果不久前(比如5分钟)已获取,它将使用本地副本?您可以在第一次点击时保存文件副本,然后使用filemtime检查以下点击时本地文件上次修改的时间戳。如果您使用的是任何类型的数据库系统,您可以将此文件缓存在那里。为缓存信息创建一个表,并至少提供以下字段:
- 标识符;您可以在下次需要时使用它来检索文件。可能有点像文件名
- 上次从URL下载文件时的时间戳
- 文件的路径(存储在本地文件系统中),或者使用BLOB类型字段将文件本身的内容存储在数据库中。我个人建议只存储路径。如果文件很大,您肯定不想将其放入数据库
if ($file exists) {
if ($file time stamp older than 5 minutes) {
$file = file_get_contents($url)
}
} else {
$file = file_get_contents($url)
}
use $file
您可以将其扭曲为类似缓存的方法:
function getFile($name) {
// code stolen from @Peter M
if ($file exists) {
if ($file time stamp older than 5 minutes) {
$file = file_get_contents($url)
}
} else {
$file = file_get_contents($url)
}
return $file;
}
使用本地缓存文件,只需在使用该文件之前检查其存在性和修改时间。例如,如果
$cache\u file
是本地缓存文件名:
if (file_exists($cache_file) && (filemtime($cache_file) > (time() - 60 * 5 ))) {
// Cache file is less than five minutes old.
// Don't bother refreshing, just use the file as-is.
$file = file_get_contents($cache_file);
} else {
// Our cache is out-of-date, so load the data from our remote server,
// and also save it over our cache for next time.
$file = file_get_contents($url);
file_put_contents($cache_file, $file, LOCK_EX);
}
(未经测试,但基于我目前使用的代码。)
通过这段代码,$file最终成为您需要的数据,如果数据是新的,它将使用缓存;如果数据不是新的,它将从远程服务器抓取数据并刷新缓存
编辑:自从我写了上述内容后,我对文件锁定有了更多的了解。如果您关心此处的文件锁定,那么值得一读
如果您关心锁定和并发访问,我认为最干净的解决方案是将内容归档到临时文件中,然后覆盖
$cache\u file
,这应该是一个原子操作,即$cache\u file
将要么是旧内容,要么是完整的新内容,永远不会写到一半。首先,您可能需要检查设计模式:
实现应该更改为始终从本地缓存加载文件。
如果本地缓存不存在或文件时间抖动超过5分钟,则从服务器获取文件
伪代码如下所示:
$time = filetime($local_cache)
if ($time == false || (now() - $time) > 300000)
fetch_localcache($url) #You have to do it yourself
$file = fopen($local_cache)
试试看,它支持文件缓存,您不需要编写缓存类。易于在共享主机和VPS上使用
下面是一个例子:
<?php
// change files to memcached, wincache, xcache, apc, files, sqlite
$cache = phpFastCache("files");
$content = $cache->get($url);
if($content == null) {
$content = file_get_contents($url);
// 300 = 5 minutes
$cache->set($url, $content, 300);
}
// use ur $content here
echo $content;
这是一个简单的版本,它还将windows用户代理
字符串传递给远程主机,这样,如果没有合适的头,您就不会看起来像个麻烦制造者
<?php
function getCacheContent($cachefile, $remotepath, $cachetime = 120){
// Generate the cache version if it doesn't exist or it's too old!
if( ! file_exists($cachefile) OR (filemtime($cachefile) < (time() - $cachetime))) {
$options = array(
'method' => "GET",
'header' => "Accept-language: en\r\n" .
"User-Agent: Mozilla/5.0 (Windows; U; MSIE 7.0; Windows NT 6.0; en-US)\r\n"
);
$context = stream_context_create(array('http' => $options));
$contents = file_get_contents($remotepath, false, $context);
file_put_contents($cachefile, $contents, LOCK_EX);
return $contents;
}
return file_get_contents($cachefile);
}
就像Peter M的答案一样,我不知道为什么if和else是一样的?谢谢你的代码Matt!它超级干净,评论良好,无需任何修改即可工作@太酷了。但是一定要在那里进行一些错误检查:)例如,如果缓存目录不可由web服务器用户写入,您可能会遇到问题……是的,它可能需要一些错误检查,但它是一个如此小的项目,以至于没有其他人使用或部署此代码。如果它坏了,else部分实际上进入无缓存模式,而不是刹车。很好。确保在顶部定义$cache\u文件(示例):$cache\u文件=$\u服务器['DOCUMENT\u ROOT']/我的cache.php'
@Volomike据我所知,stat缓存在每次脚本运行开始时都会被清除,因此只要您没有在同一个脚本中多次调用此方法,就可以了。(我刚刚检查过,在中你会看到stat缓存在PHP_RINIT_函数
回调中被清除,因此它肯定会在每个请求开始时重置。)@zsero。。因为无法测试不存在的文件的时间戳,所以额外的一层在其中。您是否可以运行基准测试,看看doctrine cache是否更快,或者phpFastCache是否使用文件缓存?