<?php
/*
 * 使用一个个的小文件作为文件缓存的存储端
 * 使用方法：
 *     添加define('CACHE_METHOD','cachedir');到你的config.php中。
 */
require_once(CORE_DIR.'/func_ext.php');
require_once('cachemgr.php');
class cachedir extends cachemgr{

    var $name = '独立文件缓存';
    var $desc = '一个个的小文件';

    function cachedir(){
        $system = &$GLOBALS['system'];
        $this->db = &$system->database();
        $this->totalBytes = 15<<20;

$sql = <<<EOF
create table if not exists sdb_cachedir
(
   cache_file                     varchar(32)                    not null,
   cache_size                     mediumint unsigned             not null,
   last_update                    int unsigned                   not null,
   primary key (cache_file)
)type = MyISAM
EOF;
$cachedir_sql=$this->db->exec($sql,1,1);

        if(true===$cachedir_sql){
            $row = $this->db->selectrow('select sum(cache_size) as size from sdb_cachedir');
            $this->curBytes = $row['size'];
            if($row['size'] > $this->totalBytes){
                $this->_free(10,$row['size']-$this->totalBytes);
            }
        }
        parent::cachemgr();
    }

    function _free($step,$to_free){
        $free = $i = 0;
        while($free<$to_free && $i++<10){
            $deleted = array();
            foreach($this->db->select('SELECT cache_file,cache_size FROM sdb_cachedir order by last_update limit 0,'.$step) as $cache_item){
                if($size = $this->_remove_file($cache_item)){
                    $free+=$size;
                    $deleted[] = $cache_item['cache_file'];
                }
            }
            $this->db->exec('delete from sdb_cachedir where cache_file in ("'.implode('","',$deleted).'")',1,1);
        }
    }

    function _path($key,$mkdir=false){
        $dir = HOME_DIR.'/cache/'.$key{0}.$key{1};
        if($mkdir){
            if(!mkdir_p($dir)){
                return false;
            }
        }
        return $dir.'/'.substr($key,2);
    }

    function store($key,&$value){
        $path = $this->_path($key,true);
        $data = serialize($value);
        $this->db->exec('replace into sdb_cachedir (cache_file,cache_size,last_update)VALUES("'.$key.'",'.strlen($data).','.time().')',1,1);
        return $path && file_put_contents($path,$data);
    }

    function fetch($key,&$data){
        $file = $this->_path($key);
        if(file_exists($file)){
            if(filemtime($file) < filemtime(HOME_DIR.'/cache/cache.stat')){
                return false;
            }
            $data = unserialize(file_get_contents($file));
            $this->db->exec('update sdb_cachedir set last_update='.time().' where cache_file="'.$key.'"',1,1);
            return $data!==false;
        }else{
            return false;
        }
    }

    function _remove_file($cache_item){
        $f=$this->_path($cache_item['cache_file']);
        if(!file_exists($f) || unlink($f)){
            return $cache_item['cache_size'];
        }else{
            error_log('Can\'t delete '.$f,3,HOME_DIR.'/log/cachedir.log'."\n");
            return false;
        }
    }

    function clear(){
        set_time_limit(2);
        $now = time();
        $rows = $this->db->select('SELECT cache_file,cache_size FROM sdb_cachedir where last_update<'.$now.' limit 0,10');
        while(count($rows)>0){
            $deleted = array();
            foreach($rows as $cache_item){
                if($this->_remove_file($cache_item)){
                    $deleted[] = $cache_item['cache_file'];
                }
            }
            $this->db->exec('delete from sdb_cachedir where cache_file in ("'.implode('","',$deleted).'")',1,1);
            $rows = $this->db->select('SELECT cache_file,cache_size FROM sdb_cachedir where last_update<'.$now.' limit 0,10');
        }
        return true;
    }

    function status(&$curBytes,&$totalBytes){
        $curBytes = $this->curBytes;
        $totalBytes = $this->totalBytes;
        $row = $this->db->selectrow('select count(*) as count from sdb_cachedir');
        return array(
                array('name'=>'总缓存对象数量','value'=>$row['count'])
            );
    }

}
?>
