parent
a766a43444
commit
31367471ef
7 changed files with 832 additions and 0 deletions
@ -0,0 +1,455 @@ |
||||
<?php |
||||
if (!defined('__TYPECHO_ROOT_DIR__')) exit; |
||||
|
||||
/** |
||||
* Typecho缓存插件 |
||||
* |
||||
* @package TpCache |
||||
* @author 老高 |
||||
* @version 0.7 |
||||
* @link http://www.phpgao.com |
||||
*/ |
||||
class TpCache_Plugin implements Typecho_Plugin_Interface |
||||
{ |
||||
public static $key = null; |
||||
public static $cache = null; |
||||
public static $html = null; |
||||
public static $path = null; |
||||
public static $sys_config = null; |
||||
public static $plugin_config = null; |
||||
public static $request = null; |
||||
|
||||
public static function activate() |
||||
{ |
||||
//页面收尾 |
||||
Typecho_Plugin::factory('index.php')->begin = array('TpCache_Plugin', 'C'); |
||||
Typecho_Plugin::factory('index.php')->end = array('TpCache_Plugin', 'S'); |
||||
|
||||
//页面编辑 |
||||
Typecho_Plugin::factory('Widget_Contents_Post_Edit')->finishPublish = array('TpCache_Plugin', 'post_update'); |
||||
Typecho_Plugin::factory('Widget_Contents_Page_Edit')->finishPublish = array('TpCache_Plugin', 'post_update'); |
||||
|
||||
//评论 |
||||
Typecho_Plugin::factory('Widget_Feedback')->finishComment = array('TpCache_Plugin', 'comment_update'); |
||||
|
||||
|
||||
return '插件安装成功,请设置需要缓存的页面'; |
||||
} |
||||
|
||||
/** |
||||
* 禁用插件方法,如果禁用失败,直接抛出异常 |
||||
* |
||||
* @static |
||||
* @access public |
||||
* @throws Typecho_Plugin_Exception |
||||
*/ |
||||
public static function deactivate() |
||||
{ |
||||
try { |
||||
$uninstall_sql = 'DROP TABLE IF EXISTS `%prefix%cache`'; |
||||
$db = Typecho_Db::get(); |
||||
$prefix = $db->getPrefix(); |
||||
$sql = str_replace('%prefix%', $prefix, $uninstall_sql); |
||||
$db->query($sql); |
||||
} catch (Exception $e) { |
||||
echo $e->getMessage(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 获取插件配置面板 |
||||
* |
||||
* @access public |
||||
* @param Typecho_Widget_Helper_Form $form 配置面板 |
||||
* @return void |
||||
*/ |
||||
public static function config(Typecho_Widget_Helper_Form $form) |
||||
{ |
||||
|
||||
$list = array( |
||||
'index' => '首页', |
||||
'archive' => '归档', |
||||
'post' => '文章', |
||||
'attachment' => '附件', |
||||
'category' => '分类', |
||||
'tag' => '标签', |
||||
'author' => '作者', |
||||
'search' => '搜索', |
||||
'feed' => 'feed', |
||||
'page' => '页面', |
||||
); |
||||
$element = new Typecho_Widget_Helper_Form_Element_Checkbox('cache_page', $list, array('index', 'post', 'search', 'page', 'author', 'tag'), '需要缓存的页面'); |
||||
$form->addInput($element); |
||||
|
||||
$list = array('关闭', '开启'); |
||||
$element = new Typecho_Widget_Helper_Form_Element_Radio('login', $list, 1, '是否对已登录用户失效', '已经录用户不会触发缓存策略'); |
||||
$form->addInput($element); |
||||
|
||||
$list = array('关闭', '开启'); |
||||
$element = new Typecho_Widget_Helper_Form_Element_Radio('enable_ssl', $list, '0', '是否支持SSL'); |
||||
$form->addInput($element); |
||||
|
||||
$list = array( |
||||
'0' => '不使用缓存', |
||||
'memcached' => 'Memcached', |
||||
'memcache' => 'Memcache', |
||||
'redis' => 'Redis', |
||||
'mysql' => 'Mysql' |
||||
); |
||||
$element = new Typecho_Widget_Helper_Form_Element_Radio('cache_driver', $list, '0', '缓存驱动'); |
||||
$form->addInput($element); |
||||
|
||||
$element = new Typecho_Widget_Helper_Form_Element_Text('expire', null, '86400', '缓存过期时间', '86400 = 60s * 60m *24h,即一天的秒数'); |
||||
$form->addInput($element); |
||||
|
||||
$element = new Typecho_Widget_Helper_Form_Element_Text('host', null, '127.0.0.1', '主机地址', '主机地址,一般为127.0.0.1'); |
||||
$form->addInput($element); |
||||
|
||||
$element = new Typecho_Widget_Helper_Form_Element_Text('port', null, '11211', '端口号', '端口号,memcache对应11211,Redis对应6379,其他类型随意填写'); |
||||
$form->addInput($element); |
||||
|
||||
$list = array('关闭', '开启'); |
||||
$element = new Typecho_Widget_Helper_Form_Element_Radio('is_debug', $list, 0, '是否开启debug'); |
||||
$form->addInput($element); |
||||
|
||||
$list = array('关闭', '清除所有数据'); |
||||
$element = new Typecho_Widget_Helper_Form_Element_Radio('is_clean', $list, 0, '清除所有数据'); |
||||
$form->addInput($element); |
||||
} |
||||
|
||||
/** |
||||
* 手动保存配置句柄 |
||||
* @param $config array 插件配置 |
||||
* @param $is_init bool 是否初始化 |
||||
*/ |
||||
public static function configHandle($config, $is_init) |
||||
{ |
||||
if ($is_init != true && $config['cache_driver'] != '0') { |
||||
|
||||
$driver_name = $config['cache_driver']; |
||||
$class_name = "typecho_$driver_name"; |
||||
$file_path = "driver/$class_name.class.php"; |
||||
require_once 'driver/cache.interface.php'; |
||||
require_once $file_path; |
||||
self::$cache = call_user_func(array($class_name, 'getInstance'), self::$plugin_config); |
||||
try { |
||||
if ($config['is_clean'] == '1') self::$cache->flush(); |
||||
} catch (Exception $e) { |
||||
print $e->getMessage(); |
||||
die; |
||||
} |
||||
// 删除缓存仅生效一次 |
||||
$config['is_clean'] = '0'; |
||||
} |
||||
|
||||
Helper::configPlugin('TpCache', $config); |
||||
} |
||||
|
||||
/** |
||||
* 个人用户的配置面板 |
||||
* |
||||
* @access public |
||||
* @param Typecho_Widget_Helper_Form $form |
||||
* @return void |
||||
*/ |
||||
public static function personalConfig(Typecho_Widget_Helper_Form $form) |
||||
{ |
||||
} |
||||
|
||||
/** |
||||
* 缓存前置操作 |
||||
*/ |
||||
public static function C() |
||||
{ |
||||
$start = microtime(true); |
||||
// 插件初始化 |
||||
if (self::init() == false) return false; |
||||
// 前置条件检查 |
||||
if (self::pre_check() == false) return false; |
||||
|
||||
//获取路径信息 |
||||
$pathInfo = self::$request->getPathInfo(); |
||||
|
||||
//判断是否需要缓存 |
||||
if (!self::needCache($pathInfo)) return false; |
||||
|
||||
try { |
||||
$data = self::get(self::$path); |
||||
if ($data != false) { |
||||
$data = unserialize($data); |
||||
//如果超时 |
||||
if ($data['c_time'] + self::$plugin_config->expire <= time()) { |
||||
|
||||
if (self::$plugin_config->is_debug) echo "Expired!\n"; |
||||
$data['c_time'] = $data['c_time'] + 20; |
||||
self::set(self::$path, serialize($data)); |
||||
} else { |
||||
if (self::$plugin_config->is_debug) echo "Hit!\n"; |
||||
if ($data['html']) echo $data['html']; |
||||
$end = microtime(true); |
||||
$time = number_format(($end - $start), 6); |
||||
if (self::$plugin_config->is_debug) echo 'This page loaded in ', $time, ' seconds'; |
||||
die; |
||||
} |
||||
} else { |
||||
if (self::$plugin_config->is_debug) echo "Can't find cache!"; |
||||
} |
||||
|
||||
} catch (Exception $e) { |
||||
echo $e->getMessage(); |
||||
} |
||||
// 先进行一次刷新 |
||||
ob_flush(); |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 前置检查 |
||||
* @return bool |
||||
*/ |
||||
public static function pre_check() |
||||
{ |
||||
//对登录用户失效 |
||||
if (self::check_login()) return false; |
||||
//针对POST失效 |
||||
if (self::$request->isPost()) return false; |
||||
//是否支持SSL |
||||
if (self::$plugin_config->enable_ssl == '0' && self::$request->isSecure() == true) return false; |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* 判断用户是否登录 |
||||
* @return bool |
||||
* @throws Typecho_Widget_Exception |
||||
*/ |
||||
public static function check_login() |
||||
{ |
||||
//http与https相互独立 |
||||
return (self::$plugin_config->login && Typecho_Widget::widget('Widget_User')->hasLogin()); |
||||
} |
||||
|
||||
/** |
||||
* 根据配置判断是否需要缓存 |
||||
* @param string 路径信息 |
||||
* @return bool |
||||
*/ |
||||
public static function needCache($path) |
||||
{ |
||||
//后台数据不缓存 |
||||
$pattern = '#^' . __TYPECHO_ADMIN_DIR__ . '#i'; |
||||
if (preg_match($pattern, $path)) return false; |
||||
|
||||
//action动作不缓存 |
||||
$pattern = '#^/action#i'; |
||||
if (preg_match($pattern, $path)) return false; |
||||
|
||||
$_routingTable = self::$sys_config->routingTable; |
||||
|
||||
$exclude = array('_year', '_month', '_day', '_page'); |
||||
|
||||
foreach ($_routingTable[0] as $key => $route) { |
||||
if ($route['widget'] != 'Widget_Archive') continue; |
||||
|
||||
if (preg_match($route['regx'], $path, $matches)) { |
||||
$key = str_replace($exclude, '', str_replace($exclude, '', $key)); |
||||
|
||||
if (in_array($key, self::$plugin_config->cache_page)) { |
||||
if (self::$plugin_config->is_debug) echo "This page needs to be cached!\n" . ' |
||||
<a href="http://www.phpgao.com/tpcache_for_typecho.html" target="_blank"> Bug Report </a>'; |
||||
self::$path = $path; |
||||
return true; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 缓存后置操作 |
||||
*/ |
||||
public static function S() |
||||
{ |
||||
//对登录用户失效 |
||||
if (self::check_login()) return; |
||||
|
||||
//若self::$key不为空,则使用缓存 |
||||
if (is_null(self::$key)) return; |
||||
|
||||
|
||||
$html = ob_get_contents(); |
||||
|
||||
if (!empty($html)) { |
||||
$data = array(); |
||||
$data['c_time'] = time(); |
||||
$data['html'] = $html; |
||||
//更新缓存 |
||||
if (self::$plugin_config->is_debug) echo "Cache updated!\n"; |
||||
self::set(self::$key, serialize($data)); |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
/** |
||||
* 编辑文章后更新缓存 |
||||
* @param $contents |
||||
* @param $class |
||||
*/ |
||||
public static function post_update($contents, $class) |
||||
{ |
||||
if ('publish' != $contents['visibility'] || $contents['created'] > time()) { |
||||
return; |
||||
} |
||||
//获取系统配置 |
||||
$options = Helper::options(); |
||||
|
||||
if(!$options->plugin('TpCache')->cache_driver){ |
||||
return; |
||||
} |
||||
//获取文章类型 |
||||
$type = $contents['type']; |
||||
//获取路由信息 |
||||
$routeExists = (NULL != Typecho_Router::get($type)); |
||||
|
||||
if (!is_null($routeExists)) { |
||||
$db = Typecho_Db::get(); |
||||
$contents['cid'] = $class->cid; |
||||
$contents['categories'] = $db->fetchAll($db->select()->from('table.metas') |
||||
->join('table.relationships', 'table.relationships.mid = table.metas.mid') |
||||
->where('table.relationships.cid = ?', $contents['cid']) |
||||
->where('table.metas.type = ?', 'category') |
||||
->order('table.metas.order', Typecho_Db::SORT_ASC)); |
||||
$contents['category'] = urlencode(current(Typecho_Common::arrayFlatten($contents['categories'], 'slug'))); |
||||
$contents['slug'] = urlencode($contents['slug']); |
||||
$contents['date'] = new Typecho_Date($contents['created']); |
||||
$contents['year'] = $contents['date']->year; |
||||
$contents['month'] = $contents['date']->month; |
||||
$contents['day'] = $contents['date']->day; |
||||
} |
||||
|
||||
//生成永久连接 |
||||
$path_info = $routeExists ? Typecho_Router::url($type, $contents) : '#'; |
||||
|
||||
self::init(); |
||||
|
||||
if (self::needCache($path_info)) self::delete(self::$path); |
||||
} |
||||
|
||||
/** |
||||
* 评论更新 |
||||
* |
||||
* @access public |
||||
* @param array $comment 评论结构 |
||||
* @param Typecho_Widget $post 被评论的文章 |
||||
* @param array $result 返回的结果上下文 |
||||
* @param string $api api地址 |
||||
* @return void |
||||
*/ |
||||
public static function comment_update($comment) |
||||
{ |
||||
$req = new Typecho_Request(); |
||||
self::delete(str_replace($req->getRequestRoot(), '', $req->getReferer())); |
||||
} |
||||
|
||||
/** |
||||
* 插件配置初始化 |
||||
* @return bool |
||||
* @throws Typecho_Plugin_Exception |
||||
*/ |
||||
public static function init() |
||||
{ |
||||
if (is_null(self::$sys_config)) { |
||||
self::$sys_config = Helper::options(); |
||||
} |
||||
if (is_null(self::$plugin_config)) { |
||||
self::$plugin_config = self::$sys_config->plugin('TpCache'); |
||||
} |
||||
|
||||
if (self::$plugin_config->cache_driver == '0') { |
||||
return false; |
||||
} |
||||
|
||||
if (is_null(self::$cache)) { |
||||
$driver_name = self::$plugin_config->cache_driver; |
||||
$class_name = "typecho_$driver_name"; |
||||
$file_path = "driver/$class_name.class.php"; |
||||
require_once 'driver/cache.interface.php'; |
||||
require_once $file_path; |
||||
self::$cache = call_user_func(array($class_name, 'getInstance'), self::$plugin_config); |
||||
} |
||||
if (is_null(self::$request)) { |
||||
self::$request = new Typecho_Request(); |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
|
||||
public static function set($path, $data) |
||||
{ |
||||
|
||||
if (!is_null(self::$key)) return self::$cache->set(self::$key, $data); |
||||
$prefix = self::$request->getUrlPrefix(); |
||||
self::$key = md5($prefix . $path); |
||||
|
||||
return self::$cache->set(self::$key, $data); |
||||
} |
||||
|
||||
public static function add($path, $data) |
||||
{ |
||||
|
||||
} |
||||
|
||||
public static function get($path) |
||||
{ |
||||
if (!is_null(self::$key)) return self::$cache->get(self::$key); |
||||
$prefix = self::$request->getUrlPrefix(); |
||||
self::$key = md5($prefix . $path); |
||||
return self::$cache->get(self::$key); |
||||
} |
||||
|
||||
/** |
||||
* 删除指定路径 |
||||
* @param string $path 待删除路径 |
||||
* @param null $del_home 是否删除首页缓存 |
||||
*/ |
||||
public static function delete($path, $del_home = null) |
||||
{ |
||||
$prefixs = array( |
||||
'http' |
||||
. '://' . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : |
||||
($_SERVER['SERVER_NAME'] . (in_array($_SERVER['SERVER_PORT'], array(80, 443)) |
||||
? '' : ':' . $_SERVER['SERVER_PORT'])) |
||||
), |
||||
'https' |
||||
. '://' . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : |
||||
($_SERVER['SERVER_NAME'] . (in_array($_SERVER['SERVER_PORT'], array(80, 443)) |
||||
? '' : ':' . $_SERVER['SERVER_PORT'])) |
||||
), |
||||
); |
||||
$keys = array(); |
||||
if (!is_array($path)) { |
||||
$keys[] = $path; |
||||
} else { |
||||
$keys = $path; |
||||
} |
||||
|
||||
|
||||
foreach ($keys as $v) { |
||||
foreach ($prefixs as $prefix) { |
||||
echo $prefix . $v; |
||||
@self::$cache->delete(md5($prefix . $v)); |
||||
} |
||||
} |
||||
|
||||
if (is_null($del_home)) { |
||||
foreach ($prefixs as $prefix) { |
||||
echo $prefix . '/'; |
||||
@self::$cache->delete(md5($prefix . '/')); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,70 @@ |
||||
## 功能 |
||||
|
||||
减缓网站并发压力而开发的缓存插件。 |
||||
|
||||
## 注意 |
||||
|
||||
1. 支持**Memcache**,**Redis**,**Mysql**三种驱动。 |
||||
1. **非js方式的**访问统计插件会失效 |
||||
1. BUG请在[缓存插件TpCache for Typecho][1]页汇报 |
||||
|
||||
|
||||
<!--more--> |
||||
|
||||
|
||||
## 使用说明 |
||||
|
||||
### 后台设置 |
||||
|
||||
![后台设置截图][2] |
||||
|
||||
### 组件支持 |
||||
|
||||
**请确保你的服务器memcache套件工作正常。** |
||||
|
||||
目前老高提供了php**memcache**与**memcached**的支持,请选择对应的驱动。 |
||||
|
||||
memcached配置请参考[Linux服务器配置memcached并启用PHP支持][3]。 |
||||
|
||||
Redis配置请参考[Linux服务器配置Redis并启用PHP支持][4]。 |
||||
|
||||
### 缓存更新机制 |
||||
|
||||
**目前以下操作会触发缓存更新** |
||||
|
||||
- 来自原生评论系统的评论 |
||||
- 后台文章或页面更新 |
||||
- 重启memcached |
||||
- 缓存到期 |
||||
|
||||
### 评论 |
||||
|
||||
原生评论简单测试过,没有大问题。 |
||||
|
||||
不过既然使用缓存了不如直接使用第三方评论系统,如多说。 |
||||
|
||||
## 性能 |
||||
|
||||
在老高的烂主机上随便就能跑到保守800的并发(CPU占用不到70%),什么概念呢? |
||||
|
||||
理论上支持每天**69120000**(60\*60\*24\*800)的PV。 |
||||
|
||||
## 下载 |
||||
|
||||
<gb user="phpgao" type="download" count="1" size="1" width="200"> TpCache </gb> |
||||
|
||||
<gb user="phpgao" type="star" count="1" size="1" width="200"> TpCache </gb> |
||||
|
||||
## 安装 |
||||
|
||||
请将文件夹**重命名**为TpCache。再拷贝至`usr/plugins/下`。 |
||||
|
||||
## 升级 |
||||
|
||||
请先**禁用此插件**后再升级,很多莫名其妙的问题都是因为没有先禁用而直接升级导致的! |
||||
|
||||
|
||||
[1]: http://www.phpgao.com/tpcache_for_typecho.html |
||||
[2]: http://www.phpgao.com/usr/uploads/2015/05/3901966986.jpeg |
||||
[3]: http://www.phpgao.com/php-memcached-extension-installation.html |
||||
[4]: http://www.phpgao.com/redis_php.html |
@ -0,0 +1,23 @@ |
||||
<?php |
||||
|
||||
|
||||
interface TpCache |
||||
{ |
||||
//初始化 |
||||
public function init($option); |
||||
|
||||
//添加缓存 |
||||
public function add($key, $value, $expire=null); |
||||
|
||||
//删除缓存 |
||||
public function delete($key); |
||||
|
||||
//设置缓存 |
||||
public function set($key, $value, $expire=null); |
||||
|
||||
//获取缓存 |
||||
public function get($key); |
||||
|
||||
//清空缓存 |
||||
public function flush(); |
||||
} |
@ -0,0 +1,62 @@ |
||||
<?php |
||||
|
||||
class typecho_memcache implements TpCache |
||||
{ |
||||
|
||||
private static $_instance = null; |
||||
private $mc = null; |
||||
private $host = '127.0.0.1'; |
||||
private $port = 11211; |
||||
private $expire = 86400; |
||||
|
||||
private function __construct($option = null) |
||||
{ |
||||
$this->host = $option->host; |
||||
$this->port = $option->port; |
||||
$this->expire = $option->expire; |
||||
$this->init($option); |
||||
} |
||||
|
||||
static public function getInstance($option) |
||||
{ |
||||
if (is_null(self::$_instance) || isset (self::$_instance)) { |
||||
self::$_instance = new self($option); |
||||
} |
||||
return self::$_instance; |
||||
} |
||||
|
||||
public function init($option) |
||||
{ |
||||
try { |
||||
$this->mc = new Memcache; |
||||
$this->mc->addServer($this->host, $this->port); |
||||
} catch (Exception $e) { |
||||
echo $e->getMessage(); |
||||
} |
||||
} |
||||
|
||||
public function add($key, $value, $expire = null) |
||||
{ |
||||
return $this->mc->add($key, $value, false, is_null($expire) ? $this->expire : $expire); |
||||
} |
||||
|
||||
public function delete($key) |
||||
{ |
||||
return $this->mc->delete($key); |
||||
} |
||||
|
||||
public function set($key, $value, $expire = null) |
||||
{ |
||||
return $this->mc->set($key, $value, false, is_null($expire) ? $this->expire : $expire); |
||||
} |
||||
|
||||
public function get($key) |
||||
{ |
||||
return $this->mc->get($key); |
||||
} |
||||
|
||||
public function flush() |
||||
{ |
||||
return $this->mc->flush(); |
||||
} |
||||
} |
@ -0,0 +1,59 @@ |
||||
<?php |
||||
|
||||
class typecho_memcached implements TpCache{ |
||||
|
||||
private static $_instance = null; |
||||
private $mc = null; |
||||
private $host = '127.0.0.1'; |
||||
private $port = 11211; |
||||
private $expire = 86400; |
||||
|
||||
private function __construct($option=null) { |
||||
$this->host = $option->host; |
||||
$this->port = $option->port; |
||||
$this->expire = $option->expire; |
||||
$this->init($option); |
||||
} |
||||
|
||||
static public function getInstance($option) { |
||||
if (is_null ( self::$_instance ) || isset ( self::$_instance )) { |
||||
self::$_instance = new self($option); |
||||
} |
||||
return self::$_instance; |
||||
} |
||||
|
||||
public function init($option) |
||||
{ |
||||
try{ |
||||
$this->mc = new Memcached; |
||||
$this->mc->addServer($this->host, $this->port); |
||||
}catch (Exception $e){ |
||||
echo $e->getMessage(); |
||||
} |
||||
} |
||||
|
||||
public function add($key, $value, $expire=null) |
||||
{ |
||||
return $this->mc->add($key, $value, is_null($expire) ? $this->expire : $expire); |
||||
} |
||||
|
||||
public function delete($key) |
||||
{ |
||||
return $this->mc->delete($key); |
||||
} |
||||
|
||||
public function set($key, $value, $expire=null) |
||||
{ |
||||
return $this->mc->set($key, $value, is_null($expire) ? $this->expire : $expire); |
||||
} |
||||
|
||||
public function get($key) |
||||
{ |
||||
return $this->mc->get($key); |
||||
} |
||||
|
||||
public function flush() |
||||
{ |
||||
return $this->mc->flush(); |
||||
} |
||||
} |
@ -0,0 +1,104 @@ |
||||
<?php |
||||
|
||||
class typecho_mysql implements TpCache |
||||
{ |
||||
|
||||
private static $_instance = null; |
||||
private $mc = null; |
||||
private $host = '127.0.0.1'; |
||||
private $port = 11211; |
||||
private $expire = 86400; |
||||
private $db = null; |
||||
|
||||
private function __construct($option = null) |
||||
{ |
||||
$this->host = $option->host; |
||||
$this->port = $option->port; |
||||
$this->expire = $option->expire; |
||||
$this->init($option); |
||||
} |
||||
|
||||
static public function getInstance($option) |
||||
{ |
||||
if (is_null(self::$_instance) || isset (self::$_instance)) { |
||||
self::$_instance = new self($option); |
||||
} |
||||
return self::$_instance; |
||||
} |
||||
|
||||
public function init($option) |
||||
{ |
||||
$this->db = Typecho_Db::get(); |
||||
$prefix = $this->db->getPrefix(); |
||||
$table_name = $prefix . 'cache'; |
||||
$sql_detect = "SHOW TABLES LIKE '%" . $table_name . "%'"; |
||||
|
||||
if(count($this->db->fetchAll($sql_detect)) == 0){ |
||||
$this->install_db(); |
||||
}else{ |
||||
// 用访问触发缓存过期 |
||||
$this->db->query($this->db->delete('table.cache')->where('time <= ?', (time() - $this->expire) )); |
||||
} |
||||
} |
||||
|
||||
public function install_db() |
||||
{ |
||||
$install_sql = ' |
||||
DROP TABLE IF EXISTS `%prefix%cache`; |
||||
CREATE TABLE `%prefix%cache` ( |
||||
`key` char(32) NOT NULL, |
||||
`data` text, |
||||
`time` bigint(20) DEFAULT NULL, |
||||
PRIMARY KEY (`key`) |
||||
) ENGINE=MyISAM DEFAULT CHARSET=%charset%'; |
||||
|
||||
$prefix = $this->db->getPrefix(); |
||||
$search = array('%prefix%', '%charset%'); |
||||
$replace = array($prefix, str_replace('UTF-8', 'utf8', Helper::options()->charset)); |
||||
$sql = str_replace($search, $replace, $install_sql); |
||||
$sqls = explode(';', $sql); |
||||
|
||||
foreach ($sqls as $sql) { |
||||
try{ |
||||
$this->db->query($sql); |
||||
}catch (Typecho_Db_Exception $e){ |
||||
echo $e->getMessage(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public function add($key, $value, $expire = null) |
||||
{ |
||||
$this->db->query($this->db->insert('table.cache')->rows(array( |
||||
'key' => $key, |
||||
'data' => $value, |
||||
'time' => time() |
||||
))); |
||||
} |
||||
|
||||
public function delete($key) |
||||
{ |
||||
return $this->db->query($this->db->delete('table.cache')->where('key = ?', $key)); |
||||
} |
||||
|
||||
public function set($key, $value, $expire = null) |
||||
{ |
||||
$this->delete($key); |
||||
$this->add($key, $value); |
||||
} |
||||
|
||||
public function get($key) |
||||
{ |
||||
$rs = $this->db->fetchRow($this->db->select('*')->from('table.cache')->where('key = ?', $key)); |
||||
if(count($rs) == 0){ |
||||
return false; |
||||
}else{ |
||||
return $rs['data']; |
||||
} |
||||
} |
||||
|
||||
public function flush() |
||||
{ |
||||
return $this->db->query($this->db->delete('table.cache')); |
||||
} |
||||
} |
@ -0,0 +1,59 @@ |
||||
<?php |
||||
|
||||
class typecho_redis implements TpCache{ |
||||
|
||||
private static $_instance = null; |
||||
private $redis = null; |
||||
private $host = '127.0.0.1'; |
||||
private $port = 11211; |
||||
private $expire = 86400; |
||||
|
||||
private function __construct($option=null) { |
||||
$this->host = $option->host; |
||||
$this->port = $option->port; |
||||
$this->expire = $option->expire + 0; |
||||
$this->init($option); |
||||
} |
||||
|
||||
static public function getInstance($option) { |
||||
if (is_null ( self::$_instance ) || isset ( self::$_instance )) { |
||||
self::$_instance = new self($option); |
||||
} |
||||
return self::$_instance; |
||||
} |
||||
|
||||
public function init($option) |
||||
{ |
||||
try{ |
||||
$this->redis = new Redis(); |
||||
$this->redis->connect($this->host, $this->port); |
||||
}catch (Exception $e){ |
||||
echo $e->getMessage(); |
||||
} |
||||
} |
||||
|
||||
public function add($key, $value, $expire=null) |
||||
{ |
||||
return $this->redis->set($key, $value, is_null($expire) ? $this->expire : $expire); |
||||
} |
||||
|
||||
public function delete($key) |
||||
{ |
||||
return $this->redis->delete($key); |
||||
} |
||||
|
||||
public function set($key, $value, $expire=null) |
||||
{ |
||||
return $this->redis->set($key, $value, is_null($expire) ? $this->expire : $expire); |
||||
} |
||||
|
||||
public function get($key) |
||||
{ |
||||
return $this->redis->get($key); |
||||
} |
||||
|
||||
public function flush() |
||||
{ |
||||
return $this->redis->flushDB(); |
||||
} |
||||
} |
Loading…
Reference in new issue