PHP文件缓存实现
有些时候,我们不希望使用redis等第三方缓存,使得系统依赖于其他服务。这时候,文件缓存会是一个不错的选择。
我们需要文件缓存实现哪些共更能:
功能实现:get、set、has、increment、decrement、delete、flush
能够在较短的时间内返回数据
支持key过期
为了避免一个文件内的数据过大,造成读取文件的时候延迟较高,我们采用一个key-value一个文件的方式实现存储结构。
为了支持key过期,我们需要把expire数据写入到文件中,所以需要对写入的数据进行序列化处理
为了能够快速的定位到文件路径,我们采用hash算法一次计算出文件位置
<?php /**
* Created by PhpStorm.
* User: qingyuan2
* Date: 2016/12/15
* Time: 15:40
*/
class FileCache implements CacheInterface
{ /**
* 缓存目录
* @var
*/
private $cache_dir; /**
* @param $cache_dir
* @throws Exception
*/
public function __construct($cache_dir)
{
$this->cache_dir = $cache_dir;
if (!is_dir($cache_dir)) {
$make_dir_result = mkdir($cache_dir, 0755, true);
if ($make_dir_result === false) throw new Exception('Cannot create the cache directory');
}
} /**
* 根据key获取值,会判断是否过期
* @param $key
* @return mixed
*/
public function get($key)
{
$cache_data = $this->getItem($key);
if ($cache_data === false || !is_array($cache_data)) return false; return $cache_data['data'];
} /**
* 添加或覆盖一个key
* @param $key
* @param $value
* @param $expire
* @return mixed
*/
public function set($key, $value, $expire = 0)
{
return $this->setItem($key, $value, time(), $expire);
} /**
* 设置包含元数据的信息
* @param $key
* @param $value
* @param $time
* @param $expire
* @return bool
*/
private function setItem($key, $value, $time, $expire)
{
$cache_file = $this->createCacheFile($key);
if ($cache_file === false) return false; $cache_data = array('data' => $value, 'time' => $time, 'expire' => $expire);
$cache_data = json_encode($cache_data); $put_result = file_put_contents($cache_file, $cache_data);
if ($put_result === false) return false; return true;
} /**
* 创建缓存文件
* @param $key
* @return bool|string
*/
private function createCacheFile($key)
{
$cache_file = $this->path($key);
if (!file_exists($cache_file)) {
$directory = dirname($cache_file);
if (!is_dir($directory)) {
$make_dir_result = mkdir($directory, 0755, true);
if ($make_dir_result === false) return false;
}
$create_result = touch($cache_file);
if ($create_result === false) return false;
} return $cache_file;
} /**
* 判断Key是否存在
* @param $key
* @return mixed
*/
public function has($key)
{
$value = $this->get($key);
if ($value === false) return false; return true;
} /**
* 加法递增
* @param $key
* @param int $value
* @return mixed
*/
public function increment($key, $value = 1)
{
$item = $this->getItem($key);
if ($item === false) {
$set_result = $this->set($key, $value);
if ($set_result === false) return false;
return $value;
} $check_expire = $this->checkExpire($item);
if ($check_expire === false) return false; $item['data'] += $value; $result = $this->setItem($key, $item['data'], $item['time'], $item['expire']);
if ($result === false) return false; return $item['data'];
} /**
* 减法递增
* @param $key
* @param int $value
* @return mixed
*/
public function decrement($key, $value = 1)
{
$item = $this->getItem($key);
if ($item === false) {
$value = 0 - $value;
$set_result = $this->set($key, $value);
if ($set_result === false) return false;
return $value;
} $check_expire = $this->checkExpire($item);
if ($check_expire === false) return false; $item['data'] -= $value; $result = $this->setItem($key, $item['data'], $item['time'], $item['expire']);
if ($result === false) return false; return $item['data'];
} /**
* 删除一个key,同事会删除缓存文件
* @param $key
* @return mixed
*/
public function delete($key)
{
$cache_file = $this->path($key);
if (file_exists($cache_file)) {
$unlink_result = unlink($cache_file);
if ($unlink_result === false) return false;
} return true;
} /**
* 清楚所有缓存
* @return mixed
*/
public function flush()
{
return $this->delTree($this->cache_dir);
} /**
* 递归删除目录
* @param $dir
* @return bool
*/
function delTree($dir)
{
$files = array_diff(scandir($dir), array('.', '..'));
foreach ($files as $file) {
(is_dir("$dir/$file")) ? $this->delTree("$dir/$file") : unlink("$dir/$file");
}
return rmdir($dir);
} /**
* 根据key获取缓存文件路径
*
* @param string $key
* @return string
*/
protected function path($key)
{
$parts = array_slice(str_split($hash = md5($key), 2), 0, 2);
return $this->cache_dir . '/' . implode('/', $parts) . '/' . $hash;
} /**
* 获取含有元数据的信息
* @param $key
* @return bool|mixed|string
*/
protected function getItem($key)
{
$cache_file = $this->path($key);
if (!file_exists($cache_file) || !is_readable($cache_file)) {
return false;
} $cache_data = file_get_contents($cache_file);
if (empty($cache_data)) return false;
$cache_data = json_decode($cache_data, true);
if ($cache_data) {
$check_expire = $this->checkExpire($cache_data);
if ($check_expire === false) {
$this->delete($key);
return false;
}
} return $cache_data;
} /**
* 检查key是否过期
* @param $cache_data
* @return bool
*/
protected function checkExpire($cache_data)
{
$time = time();
$is_expire = intval($cache_data['expire']) !== 0 && (intval($cache_data['time']) + intval($cache_data['expire']) < $time);
if ($is_expire) return false; return true;
}
}
转载自始终不够
原链接地址: PHP文件缓存实现
PHP文件缓存实现的更多相关文章
- 高性能文件缓存key-value存储—Redis
1.高性能文件缓存key-value存储-Memcached 2.ASP.NET HttpRuntime.Cache缓存类使用总结 备注:三篇博文结合阅读,简单理解并且使用,如果想深入学习,请多参考文 ...
- [Android]异步加载图片,内存缓存,文件缓存,imageview显示图片时增加淡入淡出动画
以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/3574131.html 这个可以实现ImageView异步加载 ...
- php使用文件缓存
使用php读取mysql中的数据很简单,数据量不大的时候,mysql的性能还是不错的.但是有些查询可能比较耗时,这时可以把查询出的结果,缓存起来,减轻mysql的查询压力. 缓存的方法有几种:使用me ...
- 高性能文件缓存key-value存储—Memcached
1.高性能文件缓存key-value存储—Redis 2.ASP.NET HttpRuntime.Cache缓存类使用总结 备注:三篇博文结合阅读,简单理解并且使用,如果想深入学习,请多参考文章中给出 ...
- htaccess 增加静态文件缓存和压缩
增加图片视频等静态文件缓存: <FilesMatch ".(flv|gif|jpg|jpeg|png|ico|swf)$"> Header set Cache-Cont ...
- PHP文件缓存与memcached缓存 相比 优缺点是什么呢【总结】
如果不考虑其他任何问题,只比较速度的话,那肯定是mem快,但他们各有优缺点.文件缓存优点:1.由于现在的硬盘都非常大,所有如果是大数据的时候,放硬盘里就比较合适,比如做一个cms网站,网站里有10万篇 ...
- app缓存设计-文件缓存
采用缓存,可以进一步大大缓解数据交互的压力,又能提供一定的离线浏览.下边我简略列举一下缓存管理的适用环境: 1. 提供网络服务的应用 2. 数据更新不需要实时更新,哪怕是3-5分钟的延迟也是可以采用缓 ...
- phalcon: 缓存片段,文件缓存,memcache缓存
几种缓存,需要用到前端配置,加后端实例配合着用 片段缓存: public function indexAction() { //渲染页面 $this->view->setTemplateA ...
- js和HTML结合(补充知识:如何防止文件缓存的js代码)
来自<javascript高级程序设计 第三版:作者Nicholas C. Zakas>的学习笔记(二) 使用html标签<script>可以把js嵌入到html页面中,让脚本 ...
随机推荐
- asp.net中使用基于角色role的Forms验证
http://www.cnblogs.com/yao/archive/2006/06/24/434783.html asp.net中使用基于角色role的Forms验证,大致经过几下四步:1.配置系统 ...
- Javascript技巧
Javascript数组转换为CSV格式 首先考虑如下的应用场景,有一个Javscript的字符型(或者数值型)数组,现在需要转换为以逗号分割的CSV格式文件.则我们可以使用如下的小技巧,代码如下: ...
- .NET 4.0运行.NET 2.0兼容方法
需要在相同目录下放一个.config文件,例如xxx.exe,就需要一个xxx.exe.config文件,内容如下: <?xml version="1.0"?> < ...
- 支持Cookie并开放了一些特殊设置项的HttpWebClient
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.N ...
- zend studio导入svn项目后不能代码提示的解决
把项目下.project的文件内容改成如下: <?xml version="1.0" encoding="UTF-8"?><projectDe ...
- 营业额统计(SBT)
营业额统计(SBT) #include<cstdio> #include<cstring> #include<string> #include<cstdlib ...
- UVA 494 Kindergarten Counting Game
题目大意:输入一个字字符串,输出该字符串中所包含的"word"个数,其中"word"是指连续的字母(大小写均可) 题目思路:其实这是道水题,不过我考虑的时候,太 ...
- 使用Java的Timer处理周期性任务
package timer; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; ...
- OAF_开发系列26_实现OAF中Java类型并发程式开发oracle.apps.fnd.cp.request(案例)
20150730 Created By BaoXinjian
- [转]-CSS 元素垂直居中的6种方法
原文地址:http://blog.zhourunsheng.com/2012/03/css-%E5%85%83%E7%B4%A0%E5%9E%82%E7%9B%B4%E5%B1%85%E4%B8%AD ...