Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/url/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHP中的5分钟文件缓存_Php_Url_Curl_Download - Fatal编程技术网

PHP中的5分钟文件缓存

PHP中的5分钟文件缓存,php,url,curl,download,Php,Url,Curl,Download,我有一个非常简单的问题:用PHP下载文件的最佳方式是什么,但前提是本地版本在5分钟前已经下载了 在我的实际案例中,我希望从远程托管的csv文件中获取数据,我目前正在使用该文件 $file = file_get_contents($url); 没有任何本地副本或缓存。将其转换为缓存版本的最简单方法是什么,最终结果不会改变($file保持不变),但如果不久前(比如5分钟)已获取,它将使用本地副本?您可以在第一次点击时保存文件副本,然后使用filemtime检查以下点击时本地文件上次修改的时间戳。如

我有一个非常简单的问题:用PHP下载文件的最佳方式是什么,但前提是本地版本在5分钟前已经下载了

在我的实际案例中,我希望从远程托管的csv文件中获取数据,我目前正在使用该文件

$file = file_get_contents($url);

没有任何本地副本或缓存。将其转换为缓存版本的最简单方法是什么,最终结果不会改变($file保持不变),但如果不久前(比如5分钟)已获取,它将使用本地副本?

您可以在第一次点击时保存文件副本,然后使用filemtime检查以下点击时本地文件上次修改的时间戳。

如果您使用的是任何类型的数据库系统,您可以将此文件缓存在那里。为缓存信息创建一个表,并至少提供以下字段:

  • 标识符;您可以在下次需要时使用它来检索文件。可能有点像文件名
  • 上次从URL下载文件时的时间戳
  • 文件的路径(存储在本地文件系统中),或者使用BLOB类型字段将文件本身的内容存储在数据库中。我个人建议只存储路径。如果文件很大,您肯定不想将其放入数据库
现在,下次运行上面的脚本时,首先检查数据库中的标识符,并提取时间戳。如果当前时间和存储的时间戳之间的差异大于5分钟,则从URL中提取并更新数据库。否则,请从数据库加载该文件

如果没有数据库设置,您也可以使用文件执行相同的操作,其中一个文件或文件中的字段将包含上次下载文件时的时间戳。

我想您需要一些(psuedo代码)逻辑,如:

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是否使用文件缓存?