Tăng cường sức mạnh cache page cho codeigniter (Improve CodeIgniter cache page - auto delete cache)
Ngày 22 tháng 5 năm 2013
Tuy nhiên một nhược điểm của cache page là nó không tự động xoá khi dữ liệu có thay đổi mà phải chờ hết thời gian sống của cache.
Điều đó đôi khi gây ra vài phiền toái đồng thời cứ mỗi lần hết thời gian sống của file cache hệ thống lại phải tạo ra file mới gây "lãng phí".
Để khắc phục chuyện đó, ta chỉ cần cải tiến cơ chế cache của CI một chút là cuộc đời lại tương sáng ngay.
Ý tưởng cải tiến của mình như sau:
- Thay file file cache có một cái gọi là thời gian sống, sau thời gian sống thì sẽ bị xoá, mình sẽ sử dụng cái gọi là "thời gian sinh ra", đánh dấu thời điểm file cache được tạo ra.
- Một mốc thời gian khác đó là thời điểm dữ liệu được cập nhật. Hay còn gọi là ngày cập nhật cuối cùng của dữ liệu.
- Mỗi khi dữ liệu có thay đổi, mình sẽ ghi nhận lại thời điểm này.
- Tất cả các file cache đã được tạo trước thời điểm cập nhật dữ liệu thì được xem như đã sử dụng dữ liệu cũ và cần xoá bỏ. Tất cả những file cache tạo sau thời điểm cập nhật cuối cùng của dữ liệu thì xem như là nội dung mới và cứ giữ như thế.
- Như vậy, chỉ cần so sánh thời điểm file cache được sinh ra so với thời điểm cập nhật cuối cùng của dữ liệu. Nếu file cache được tạo trước khi cập nhật thì xoá nó, được tạo sau khi cập nhật thì giữ lại và hiển thị.
-
Ví dụ:
- Ngày 20 tháng 5 mình có tạo file cache A
- Ngày 21 tháng 5 mình thay đổi dữ liệu
- Ngày 22 tháng 5 mình tạo file cache B
- Ngày 23 tháng 5, có yêu cầu hiển thị file A, mình kiểm tra và thấy nó được tạo này 20, trước thời điểm thay đổi dữ liệu => file cache quá cũ => xoá nó
- Ngày 23 tháng 5 có yêu cầu hiển thị file B, mình kiểm tra và thấy nó được tạo ngày 22 sau thời điểm thay đổi dữ liệu => hiển thị file cache B
Sau đây là những tính năng mà mình cải tiến được:
1. Thời gian sống của file cache là vĩnh viễn hoặc cho tới khi dữ liệu có thay đổi và bạn xoá cache.
2. Khi bạn có yêu cầu xoá cache, các file cache vẫn nằm đó, và chỉ bị xoá khi có yêu cầu hiển thị trang đã cache tương ứng => hệ thống sẽ tạo lại từng file cache khi thật cần thiết, không cần xoá và tạo lại ngay khi có yêu cầu xoá cache.
Trước khi bắt tay tiến hành cải tiến cache file, bạn lưu ý điểm sau:
KHÔNG ĐƯỢC dùng autoload để load database. Do autoload được load trước nên nếu bạn để database ở chế độ autoload thì nó sẽ giảm phần nào hiệu quả do CI sẽ tiến hành kết nối db trước, sau đó mới load cache. Hơn nữa, nếu mysql bị treo hoặc không kết nối được, CI sẽ báo lỗi kết nối chứ không tự động load cache như mong đợi.
Bây giờ tới lúc thực hiện.
Bước 1: Custom class output:
Trong application/core, bạn tạo file MY_Output.php (tên phân biệt hoa thường) nội dung như sau:
PHP Code:
<?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
* Description of My_Output
*
* @author Truong Chuong Duong
* @email: truong@chuongduong.net
*/
class MY_Output extends CI_Output
{
function __construct()
{
parent::__construct();
}
public function cache($n)
{
if (!empty($n))
$this->cache_expiration = 1/60;
else
$this->cache_expiration = 0;
}
public function clearCache()
{
global $CFG, $URI;
$cache_path = ($CFG->item('cache_path') == '') ? APPPATH.'cache/' : $CFG->item('cache_path');
$checkfile = $cache_path . 'CACHE_LAST_UPDATE_DATA.check';
@file_put_contents($checkfile, $checkTime);
}
/**
* Update/serve a cached file
*
* @access public
* @param object config class
* @param object uri class
* @return void
*/
function _display_cache(&$CFG, &$URI)
{
$cache_path = ($CFG->item('cache_path') == '') ? APPPATH.'cache/' : $CFG->item('cache_path');
// Build the file path. The file name is an MD5 hash of the full URI
$uri = $CFG->item('base_url').
$CFG->item('index_page').
$URI->uri_string;
$filepath = $cache_path.md5($uri);
if ( ! @file_exists($filepath))
{
return FALSE;
}
if ( ! $fp = @fopen($filepath, FOPEN_READ))
{
return FALSE;
}
flock($fp, LOCK_SH);
$cache = '';
if (filesize($filepath) > 0)
{
$cache = fread($fp, filesize($filepath));
}
flock($fp, LOCK_UN);
fclose($fp);
// Strip out the embedded timestamp
if ( ! preg_match("/(\d+TS--->)/", $cache, $match))
{
return FALSE;
}
//Đọc thời điểm dữ liệu bị thay đổi
$checkfile = $cache_path . 'CACHE_LAST_UPDATE_DATA.check';
$checkTime = @file_get_contents($checkfile);
//Nếu không có => giả định thời điểm thay đổi là ngay bây giờ
if (!$checkTime)
{
$checkTime = time();
//Lưu lại thời điểm dữ liệu có thay đổi
@file_put_contents($checkfile, $checkTime);
}
$checkTime = intval($checkTime);
//Lấy thời điểm file cache được tạo ra
$cacheCreatedTime = intval(trim(str_replace('TS--->', '', $match['1'])));
// Has the file expired? If so we'll delete it.
if ($cacheCreatedTime <= $checkTime)//Nếu thời điểm tạo file cache trước thời điểm dữ liệu có thay đổi => cache timeout
{
if (is_really_writable($cache_path))
{
@unlink($filepath);
log_message('debug', "Cache file has expired. File deleted");
return FALSE;
}
}
// Display the cache
$this->_display(str_replace($match['0'], '', $cache));
log_message('debug', "Cache file is current. Sending it to browser.");
return TRUE;
}
}
- Dòng 21: Thay phương thức cache thông thường thành phươn thức mới. Bây giờ thay vì truyền vào thời gian sống của file cache, bạn truyền vào TRUE để mở chế độ cache, FALSE để tắt cache.
- Dòng 29: Bất kỳ khi nào có sự thay đổi dữ liệu, bạn gọi phương thức này để báo hệ thống biết rằng các file cache cần phải được xoá.
- Dòng 85: Lấy ra thời điểm kiểm tra cuối cùng của lệnh xoá cache. Tất cả các file cache tạo trước thời điểm này sẽ bị xem là lỗi thời và bị xoá.
- Dòng 100: Kiểm tra xem nếu thời điểm tạo file cache nhỏ hơn thời điểm xoá cache thì file cache này đã cũ cần phải xoá nó.
Xong, vậy là đã cải tiến được cache của CI. Bây giờ tới khâu sử dụng.
Bất kỳ đâu trong controller, để bật chế độ cache bạn gọi lệnh:
PHP Code:
$this->output->cache(true);
PHP Code:
$this->output->cache(false);
Tiếp theo là MỘT CHÚ Ý CỰC KỲ QUAN TRỌNG:
- Mỗi khi dữ liệu có bất kỳ sự thay đổi nào, hoặc khi bạn muốn xoá cache, bạn hãy gọi function sau trong controller:
PHP Code:
$this->output->clearCache();
- Trong các action insert/update/delete dữ liệu.
- Trong chức năng clear cache nếu có
Điều gì khi bạn quên nó:
- CI sẽ luôn hiển thị dữ liệu cũ, người dùng sẽ không bao giờ thấy sự thay đổi trên website của bạn.
Ví dụ, đây là controller của mình:
PHP Code:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Welcome extends CI_Controller {
/**
* Index Page for this controller.
*
* Maps to the following URL
* http://example.com/index.php/welcome
* - or -
* http://example.com/index.php/welcome/index
* - or -
* Since this controller is set as the default controller in
* config/routes.php, it's displayed at http://example.com/
*
* So any other public methods not prefixed with an underscore will
* map to /index.php/welcome/<method_name>
* @see http://codeigniter.com/user_guide/general/urls.html
*/
public function index()
{
$this->output->cache(true);
$data = array(
'time' => date('d-m-Y h:m:s')
);
$this->load->view('welcome_message', $data);
}
public function clearCache()
{
$this->output->clearCache();
echo 'Cache da clear';
}
}
/* End of file welcome.php */
/* Location: ./application/controllers/welcome.php */
HTML Code:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Welcome to CodeIgniter</title> <style type="text/css"> ::selection{ background-color: #E13300; color: white; } ::moz-selection{ background-color: #E13300; color: white; } ::webkit-selection{ background-color: #E13300; color: white; } body { background-color: #fff; margin: 40px; font: 13px/20px normal Helvetica, Arial, sans-serif; color: #4F5155; } a { color: #003399; background-color: transparent; font-weight: normal; } h1 { color: #444; background-color: transparent; border-bottom: 1px solid #D0D0D0; font-size: 19px; font-weight: normal; margin: 0 0 14px 0; padding: 14px 15px 10px 15px; } code { font-family: Consolas, Monaco, Courier New, Courier, monospace; font-size: 12px; background-color: #f9f9f9; border: 1px solid #D0D0D0; color: #002166; display: block; margin: 14px 0 14px 0; padding: 12px 10px 12px 10px; } #body{ margin: 0 15px 0 15px; } p.footer{ text-align: right; font-size: 11px; border-top: 1px solid #D0D0D0; line-height: 32px; padding: 0 10px 0 10px; margin: 20px 0 0 0; } #container{ margin: 10px; border: 1px solid #D0D0D0; -webkit-box-shadow: 0 0 8px #D0D0D0; } </style> </head> <body> <div id="container"> <h1>Welcome to CodeIgniter!</h1> <div id="body"> <p>The page you are looking at is being generated dynamically by CodeIgniter.</p> <p>If you would like to edit this page you'll find it located at:</p> <code>application/views/welcome_message.php</code> <p>The corresponding controller for this page is found at:</p> <code>application/controllers/welcome.php</code> <p>If you are exploring CodeIgniter for the very first time, you should start by reading the <a href="user_guide/">User Guide</a>.</p> <p>Page is created at <b><?php echo $time ?></b></p> </div> <p class="footer">Page rendered in <strong></strong> seconds</p> </div> </body> </html>
Lần đầu tiên bạn chạy, nó hiển thị đúng giờ hiện hành của hệ thống, nhưng các lần sau thì nó không thay đổi. Bởi vì dữ liệu cache tạo lần đầu tiên được load và hiển thị lên, controller không hề chạy nên kết quả không thay đổi.
Bây giờ bạn thử vào link http://localhost/ci213/index.php/welcome/clearcache
Sau đó quay lại function index, bạn sẽ thấy thời gian ở chỗ "Page is created at " lại được cập nhật mới. Bởi vì trong function clearcache có lệnh $this->output->clearCache(); nên nó đã đánh dấu file cache được tạo ra lúc nãy đã cũ và cần làm mới.
Chỉ cần kết hợp đúng chỗ 2 function $this->output->clearCache(); và $this->output->cache(true); website của bạn sẽ mượt mà hơn bao giờ hết

Link dowbload full example: http://www.chuongduong.net/link/17031
Đang tải dữ liệu...