<?php
abstract class FileCache
{
    protected 
$path     '/tmp/';
    protected 
$prefix   'cache_';
    protected 
$ttl      3600;
    protected 
$use_hash true;

    public function 
__construct(array $options = array())
    {
        foreach(
$options as $key => $value) {
            
$this->setOption($key$value);
        }
    }

    private function 
getTTL($ttl)
    {
        return !empty(
$ttl) ? $ttl $this->ttl;
    }

    private function 
checkTrail($dir)
    {
        return 
substr($dir, -1) != DIRECTORY_SEPARATOR $dir .= DIRECTORY_SEPARATOR $dir;
    }

    protected function 
writeFile($id$data$ttl null)
    {
        
$filename $this->getFilename($id);
        if (
$fp fopen($filename'xb')) {
            if (
flock($fpLOCK_EX)) {
                
fwrite($fp$data);
            }
            
fclose($fp);
            
touch($filenametime() + $this->getTTL($ttl));
        }
    }

    protected function 
readFile($id)
    {
        return 
file_get_contents($this->getFilename($id));
    }

    protected function 
isCached($id)
    {
        
$filename $this->getFilename($id);

        if (
file_exists($filename)) {
            if (
filemtime($filename) > time()) {

                return 
true;
            } else {
                
unlink($filename);
            }
        }

        return 
false;
    }

    protected function 
getFilename($id)
    {
        
$id $this->use_hash md5($id) : $id;

        return 
$this->checkTrail($this->path) . $this->prefix $id;
    }

    public function 
setOption($key$value)
    {
        
$this->{$key} = $value;
    }

    public function 
deleteCache($id)
    {
        
$filename $this->getFilename($id);
        if (
file_exists($filename)) {
            
unlink($filename);
        }
    }
}


class 
FlowCache extends FileCache
{
    private 
$id;

    public function 
start($id$ttl null)
    {
        if (
parent::isCached($id)) {
            echo 
parent::readFile($id);

            return 
true;
        } else {
            
ob_start();
            
$this->id  $id;
            
$this->ttl $ttl;

            return 
false;
        }
    }

    public function 
stop()
    {
        
$data ob_get_contents();
        
ob_end_flush();

        
parent::writeFile($this->id$data$this->ttl);
    }
}

class 
VarCache extends FileCache
{
    protected 
$auto_serialize true;

    public function 
getVar($id)
    {
        if (
parent::isCached($id)) {
            
$data parent::readFile($id);

            return 
$this->auto_serialize unserialize($data) : $data;
        }

        return 
null;
    }

    public function 
putVar($id$data$ttl null)
    {
        
$data $this->auto_serialize serialize($data) : $data;
        
parent::writeFile($id$data$ttl);
    }
}

final class 
TinyCache
{
    public static function 
getInstance($type 'var'$options = array())
    {
        if (
in_array(strtolower($type), array('var''flow'))) {
            
$class ucfirst(strtolower($type)) . 'Cache';

            return new 
$class((array) $options);
        }
    }
}