<?php
/* Revision 620
 * ALL EXAMPLE & DOCUMENT ARE ON www.phpFastCache.com
 * IF YOU FOUND A BUG, PLEASE GO THERE: http://www.codehelper.io <-- Post your issues and I will fix it.
 * Open new issue and I will fix it for you in 24 hours
 * I stopped support issues on GitHub
 */

class phpFastCache {
    // Public OPTIONS
    // Can be set by phpFastCache::$option_name = $value|array|string
    public static $storage = "auto"; // PDO | mpdo | Auto | Files | memcache | apc | wincache | xcache
    public static $files_cleanup_after = 1; // hour | auto clean up files after this
    public static $autosize = 40; // Megabytes
    public static $path = ""; // PATH/TO/CACHE/ default will be current path
    public static $securityKey = "cache.storage"; // phpFastCache::$securityKey = "newKey";
    public static $securityHtAccess = true; // auto create .htaccess
    public static $option = array();
    public static $server = array(array("localhost",11211)); // for MemCache
    public static $useTmpCache = false; // use for get from Tmp Memory, will be faster in checking cache on LOOP.
    public static $debugging = false; // turn true for debugging


    // NOTHING TO CHANGE FROM HERE
    private static $step_debugging = 0;
    private static $Tmp = array();
    private static $supported_api = array("pdo","mpdo","files","memcache","memcached","apc","xcache","wincache");
    private static $filename = "pdo.caching";
    private static $table = "objects";
    private static $autodb = "";
    private static $multiPDO = array();


    public static $sys = array();
    private static $checked = array(
        "path"  =>  false,
        "servers"   =>  array(),
        "config_file"   => "",
    );
    private static $objects = array(
        "memcache"  =>  "",
        "memcached" =>  "",
        "pdo"       =>  "",
    );


    private static function getOS() {
        $os = array(
            "os" => PHP_OS,
            "php" => PHP_SAPI,
            "system"    => php_uname(),
            "unique"    => md5(php_uname().PHP_OS.PHP_SAPI)
        );
        return $os;
    }



    public static function systemInfo() {
        // self::startDebug(self::$sys,"Check Sys",__LINE__,__FUNCTION__);

        if(count(self::$sys) == 0 ) {

            // self::startDebug("Start System Info");

            self::$sys['os'] = self::getOS();

            self::$sys['errors'] = array();
            self::$sys['storage'] = "";
            self::$sys['method'] = "pdo";
            self::$sys['drivers'] = array(
                "apc"   =>  false,
                "xcache"    => false,
                "memcache"  => false,
                "memcached"  => false,
                "wincache"  => false,
                "pdo"       => false,
                "mpdo"     => false,
                "files"     => false,

            );



            // Check apc
            if(extension_loaded('apc') && ini_get('apc.enabled'))
            {
                self::$sys['drivers']['apc']   = true;
                self::$sys['storage'] = "memory";
                self::$sys['method'] = "apc";
            }

            // Check xcache
            if(extension_loaded('xcache') && function_exists("xcache_get"))
            {
                self::$sys['drivers']['xcache']   = true;
                self::$sys['storage'] = "memory";
                self::$sys['method'] = "xcache";
            }

            if(extension_loaded('wincache') && function_exists("wincache_ucache_set"))
            {
                self::$sys['drivers']['wincache']   = true;
                self::$sys['storage'] = "memory";
                self::$sys['method'] = "wincache";
            }

            // Check memcache
            if(function_exists("memcache_connect")) {
                self::$sys['drivers']['memcache'] = true;

                try {
                    memcache_connect("127.0.0.1");
                    self::$sys['storage'] = "memory";
                    self::$sys['method'] = "memcache";
                } catch (Exception $e) {

                }
            }


            // Check memcached
            if(class_exists("memcached")) {
                self::$sys['drivers']['memcached'] = true;

                try {
                    $memcached = new memcached();
                    $memcached->addServer("127.0.0.1","11211");
                    self::$sys['storage'] = "memory";
                    self::$sys['method'] = "memcached";

                } catch (Exception $e) {

                }
            }

            if(extension_loaded('pdo_sqlite')) {
                self::$sys['drivers']['pdo']   = true;
                self::$sys['drivers']['mpdo']   = true;
            }

            if(is_writable(self::getPath(true))) {
                self::$sys['drivers']['files'] = true;
            }

            if(self::$sys['storage'] == "") {

                if(extension_loaded('pdo_sqlite')) {
                    self::$sys['storage'] = "disk";
                    self::$sys['method'] = "pdo";

                } else {

                    self::$sys['storage'] = "disk";
                    self::$sys['method'] = "files";

                }

            }



            if(self::$sys['storage'] == "disk" && !is_writable(self::getPath())) {
                self::$sys['errors'][] = "Please Create & CHMOD 0777 or any Writeable Mode for ".self::getPath();
            }




        }

        // self::startDebug(self::$sys);
        return self::$sys;
    }

    // return Folder Cache PATH
    // PATH Edit by SecurityKey
    // Auto create, Chmod and Warning

    // Revision 618
    // PHP_SAPI =  apache2handler should go to tmp
    private static function isPHPModule() {
        if(PHP_SAPI == "apache2handler") {
            return true;
        } else {
            if(strpos(PHP_SAPI,"handler") !== false) {
                return true;
            }
        }
        return false;
    }
    // Revision 618
    // Security with .htaccess
    static function htaccessGen($path = "") {
        if(self::$securityHtAccess == true) {

            if(!file_exists($path."/.htaccess")) {
             //   echo "write me";
                $html = "order deny, allow \r\n
deny from all \r\n
allow from 127.0.0.1";
                $f = @fopen($path."/.htaccess","w+");
                @fwrite($f,$html);
                @fclose($f);
            } else {
             //   echo "got me";
            }
        }

    }

    private static function getPath($skip_create = false) {

        if (self::$path=='')
        {
            // revision 618
            if(self::isPHPModule()) {
                $tmp_dir = ini_get('upload_tmp_dir') ? ini_get('upload_tmp_dir') : sys_get_temp_dir();
                self::$path = $tmp_dir;
            } else {
                self::$path = dirname(__FILE__);
            }

        }

        if($skip_create == false && self::$checked['path'] == false) {
            if(!file_exists(self::$path."/".self::$securityKey."/") || !is_writable(self::$path."/".self::$securityKey."/")) {
                if(!file_exists(self::$path."/".self::$securityKey."/")) {
                    @mkdir(self::$path."/".self::$securityKey."/",0777);
                }
                if(!is_writable(self::$path."/".self::$securityKey."/")) {
                    @chmod(self::$path."/".self::$securityKey."/",0777);
                }
                if(!file_exists(self::$path."/".self::$securityKey."/") || !is_writable(self::$path."/".self::$securityKey."/")) {
                    die("Sorry, Please create ".self::$path."/".self::$securityKey."/ and SET Mode 0777 or any Writable Permission!" );
                }

            }

            self::$checked['path'] = true;
            // Revision 618
            self::htaccessGen(self::$path."/".self::$securityKey."/");

        }



        return self::$path."/".self::$securityKey."/";


    }

    // return method automatic;
    // APC will be TOP, then Memcached, Memcache, PDO and Files
    public static function autoconfig($name = "") {
        // self::startDebug($name,"Check Name",__LINE__,__FUNCTION__);

        $cache = self::cacheMethod($name);
        if($cache != "" && $cache != self::$storage && $cache!="auto") {
            return $cache;
        }

        // self::startDebug($cache,"Check Cache",__LINE__,__FUNCTION__);

        $os = self::getOS();
        // self::startDebug(self::$storage,"User Set",__LINE__,__FUNCTION__);
        if(self::$storage == "" || self::$storage == "auto") {
            // self::startDebug(self::$storage,"User Set Auto",__LINE__,__FUNCTION__);

            if(extension_loaded('apc') && ini_get('apc.enabled') && strpos(PHP_SAPI,"CGI") === false)
            {

                self::$sys['drivers']['apc']   = true;
                self::$sys['storage'] = "memory";
                self::$sys['method'] = "apc";

                // self::startDebug(self::$sys,"GOT APC",__LINE__,__FUNCTION__);

            }elseif(extension_loaded('xcache'))
            {
                self::$sys['drivers']['xcache']   = true;
                self::$sys['storage'] = "memory";
                self::$sys['method'] = "xcache";
                // self::startDebug(self::$sys,"GOT XCACHE",__LINE__,__FUNCTION__);

            } else {
                // fix PATH for existing
                $reconfig = false;
                // self::startDebug(self::getPath()."/config.".$os['unique'].".cache.ini","CHECK CONFIG FILE",__LINE__,__FUNCTION__);


                if (file_exists(self::getPath()."/config.".$os['unique'].".cache.ini"))
                {
                    $info = self::decode(file_get_contents(self::getPath()."/config.".$os['unique'].".cache.ini"));

                    // self::startDebug($info,"CHECK INFO",__LINE__,__FUNCTION__);

                    if(!isset($info['value'])) {
                        $reconfig = true;

                    } else {
                        $info = $info['value'];
                        self::$sys = $info;

                    }


                } else {

                    $info = self::systemInfo();
                    // self::startDebug($info,"CHECK INFO BY SYSTEM INFO",__LINE__,__FUNCTION__);
                }

                if(isset($info['os']['unique'])) {

                    if($info['os']['unique'] != $os['unique']) {
                        $reconfig = true;
                    }
                } else {
                    $reconfig = true;
                }

                if(!file_exists(self::getPath()."/config.".$os['unique'].".cache.ini") || $reconfig == true) {

                    $info = self::systemInfo();
                    self::$sys = $info;
                    // self::startDebug($info,"Check Info",__LINE__,__FUNCTION__);

                    try {
                        $f = fopen(self::getPath()."/config.".$os['unique'].".cache.ini","w+");
                        fwrite($f,self::encode($info));
                        fclose($f);

                    } catch (Exception $e) {
                        die("Please chmod 0777 ".self::getPath()."/config.".$os['unique'].".cache.ini");
                    }
                } else {

                }

            }



            self::$storage = self::$sys['method'];


        } else {

            if(in_array(self::$storage,array("files","pdo","mpdo"))) {
                self::$sys['storage'] = "disk";
            }elseif(in_array(self::$storage,array("apc","memcache","memcached","wincache","xcache"))) {
                self::$sys['storage'] = "memory";
            } else {
                self::$sys['storage'] = "";
            }

            if(self::$sys['storage'] == "" || !in_array(self::$storage,self::$supported_api)) {
                die("Don't have this Cache ".self::$storage." In your System! Please double check!");
            }

            self::$sys['method'] = strtolower(self::$storage);

        }

        if(self::$sys['method'] == "files") {
            $last_cleanup = self::files_get("last_cleanup_cache");
            if($last_cleanup == null) {
                self::files_cleanup();
                self::files_set("last_cleanup_cache",@date("U"),3600*self::$files_cleanup_after);
            }
        }

        // self::startDebug(self::$sys,"Check RETURN SYS",__LINE__,__FUNCTION__);

        return self::$sys['method'];

    }



    private static function cacheMethod($name = "") {
        $cache = self::$storage;
        if(is_array($name)) {
            $key = array_keys($name);
            $key = $key[0];
            if(in_array($key,self::$supported_api)) {
                $cache = $key;
            }
        }
        return $cache;
    }


    public static function safename($name) {
        return strtolower(preg_replace("/[^a-zA-Z0-9_\s\.]+/","",$name));
    }





    private static function encode($value,$time_in_second = "") {
        $value = serialize(array(
            "time"  => @date("U"),
            "value" => $value,
            "endin" => $time_in_second
        ));
        return $value;
    }

    private static function decode($value) {
        $x = @unserialize($value);
        if($x == false) {
            return $value;
        } else {
            return $x;
        }
    }

    /*
     * Start Public Static
     */

    public static function cleanup($option = "") {
        $api = self::autoconfig();
        self::$Tmp = array();

        switch ($api) {
            case "pdo":
                return self::pdo_cleanup($option);
                break;
            case "mpdo":
                return self::pdo_cleanup($option);
                break;
            case "files":
                return self::files_cleanup($option);
                break;
            case "memcache":
                return self::memcache_cleanup($option);
                break;
            case "memcached":
                return self::memcached_cleanup($option);
                break;
            case "wincache":
                return self::wincache_cleanup($option);
                break;
            case "apc":
                return self::apc_cleanup($option);
                break;
            case "xcache":
                return self::xcache_cleanup($option);
                break;
            default:
                return self::pdo_cleanup($option);
                break;
        }

    }

    public static function delete($name = "string|array(db->item)") {

        $api = self::autoconfig($name);
        if(self::$useTmpCache == true) {
            $tmp_name = md5(serialize($api.$name));
            if(isset(self::$Tmp[$tmp_name])) {
                unset(self::$Tmp[$tmp_name]);
            }
        }

        switch ($api) {
            case "pdo":
                return self::pdo_delete($name);
                break;
            case "mpdo":
                return self::pdo_delete($name);
                break;
            case "files":
                return self::files_delete($name);
                break;
            case "memcache":
                return self::memcache_delete($name);
                break;
            case "memcached":
                return self::memcached_delete($name);
                break;
            case "wincache":
                return self::wincache_delete($name);
                break;
            case "apc":
                return self::apc_delete($name);
                break;
            case "xcache":
                return self::xcache_delete($name);
                break;
            default:
                return self::pdo_delete($name);
                break;
        }

    }


    public static function exists($name = "string|array(db->item)") {

        $api = self::autoconfig($name);
        switch ($api) {
            case "pdo":
                return self::pdo_exist($name);
                break;
            case "mpdo":
                return self::pdo_exist($name);
                break;
            case "files":
                return self::files_exist($name);
                break;
            case "memcache":
                return self::memcache_exist($name);
                break;
            case "memcached":
                return self::memcached_exist($name);
                break;
            case "wincache":
                return self::wincache_exist($name);
                break;
            case "apc":
                return self::apc_exist($name);
                break;
            case "xcache":
                return self::xcache_exist($name);
                break;
            default:
                return self::pdo_exist($name);
                break;
        }

    }

    public static function deleteMulti($object = array()) {
        $res = array();
        foreach($object as $driver=>$name)  {
            if(!is_numeric($driver)) {
                $n = $driver."_".$name;
                $name = array($driver=>$name);
            } else {
                $n = $name;
            }
            $res[$n] = self::delete($name);
        }
        return $res;

    }

    public static function setMulti($mname = array(), $time_in_second_for_all = 600, $skip_for_all = false) {
        $res = array();

        foreach($mname as $object){
            //   print_r($object);

            $keys = array_keys($object);

            if($keys[0] != "0") {
                $k = $keys[0];
                $name = isset($object[$k]) ? array($k => $object[$k]) : "";
                $n = $k."_".$object[$k];
                $x=0;
            } else {
                $name = isset($object[0]) ? $object[0] : "";
                $x=1;
                $n = $name;
            }

            $value = isset($object[$x]) ? $object[$x] : "";$x++;
            $time = isset($object[$x]) ? $object[$x] : $time_in_second_for_all;$x++;
            $skip = isset($object[$x]) ? $object[$x] : $skip_for_all;$x++;

            if($name!="" && $value!="") {
                $res[$n] = self::set($name,$value, $time, $skip);
            }
            // echo "<br> ----- <br>";

        }

        return $res;
    }



    public static function set($name,$value,$time_in_second = 600, $skip_if_existing = false) {
        $api = self::autoconfig($name);
        if(self::$useTmpCache == true) {
            $tmp_name = md5(serialize($api.$name));
            self::$Tmp[$tmp_name] = $value;
        }

        switch ($api) {
            case "pdo":
                return self::pdo_set($name,$value,$time_in_second, $skip_if_existing);
                break;
            case "mpdo":
                return self::pdo_set($name,$value,$time_in_second, $skip_if_existing);
                break;
            case "files":
                return self::files_set($name,$value,$time_in_second, $skip_if_existing);
                break;
            case "memcache":
                return self::memcache_set($name,$value,$time_in_second, $skip_if_existing);
                break;
            case "memcached":
                return self::memcached_set($name,$value,$time_in_second, $skip_if_existing);
                break;
            case "wincache":
                return self::wincache_set($name,$value,$time_in_second, $skip_if_existing);
                break;
            case "apc":
                return self::apc_set($name,$value,$time_in_second, $skip_if_existing);
                break;
            case "xcache":
                return self::xcache_set($name,$value,$time_in_second, $skip_if_existing);
                break;
            default:
                return self::pdo_set($name,$value,$time_in_second, $skip_if_existing);
                break;
        }

    }






    public static function decrement($name, $step = 1) {
        $api = self::autoconfig($name);
        if(self::$useTmpCache == true) {
            $tmp_name = md5(serialize($api.$name));
            if(isset(self::$Tmp[$tmp_name])) {
                self::$Tmp[$tmp_name] = (Int)self::$Tmp[$tmp_name] - $step;
            } else {
                self::$Tmp[$tmp_name] = $step;
            }

        }
        switch ($api) {
            case "pdo":
                return self::pdo_decrement($name, $step);
                break;
            case "mpdo":
                return self::pdo_decrement($name, $step);
                break;
            case "files":
                return self::files_decrement($name, $step);
                break;
            case "memcache":
                return self::memcache_decrement($name, $step);
                break;
            case "memcached":
                return self::memcached_decrement($name, $step);
                break;
            case "wincache":
                return self::wincache_decrement($name, $step);
                break;
            case "apc":
                return self::apc_decrement($name, $step);
                break;
            case "xcache":
                return self::xcache_decrement($name, $step);
                break;
            default:
                return self::pdo_decrement($name, $step);
                break;
        }
    }



    public static function get($name) {
        $api = self::autoconfig($name);
        if(self::$useTmpCache == true) {
            $tmp_name = md5(serialize($api.$name));
            if(isset(self::$Tmp[$tmp_name])) {
                return self::$Tmp[$tmp_name];
            }
        }

        // self::startDebug($api,"API",__LINE__,__FUNCTION__);

        // for files, check it if NULL and "empty" string
        switch ($api) {
            case "pdo":
                return self::pdo_get($name);
                break;
            case "mpdo":
                return self::pdo_get($name);

                break;
            case "files":
                return  self::files_get($name);
                break;
            case "memcache":
                return self::memcache_get($name);
                break;
            case "memcached":
                return self::memcached_get($name);
                break;
            case "wincache":
                return  self::wincache_get($name);
                break;
            case "apc":
                return  self::apc_get($name);
                break;
            case "xcache":
                return   self::xcache_get($name);
                break;
            default:
                return  self::pdo_get($name);
                break;
        }

    }


    public static function getMulti($object = array()) {
        $res = array();
        foreach($object as $driver=>$name)  {
            if(!is_numeric($driver)) {
                $n = $driver."_".$name;
                $name = array($driver=>$name);
            } else {
                $n = $name;
            }
            $res[$n] = self::get($name);
        }
        return $res;

    }



    public static function stats() {
        $api = self::autoconfig();
        switch ($api) {
            case "pdo":
                return self::pdo_stats();
                break;
            case "mpdo":
                return self::pdo_stats();
                break;
            case "files":
                return self::files_stats();
                break;
            case "memcache":
                return self::memcache_stats();
                break;
            case "memcached":
                return self::memcached_stats();
                break;
            case "wincache":
                return self::wincache_stats();
                break;
            case "apc":
                return self::apc_stats();
                break;
            case "xcache":
                return self::xcache_stats();
                break;
            default:
                return self::pdo_stats();
                break;
        }
    }

    public static function increment($name, $step = 1) {
        $api = self::autoconfig($name);

        if(self::$useTmpCache == true) {
            $tmp_name = md5(serialize($api.$name));
            if(isset(self::$Tmp[$tmp_name])) {
                self::$Tmp[$tmp_name] = (Int)self::$Tmp[$tmp_name] + $step;
            } else {
                self::$Tmp[$tmp_name] = $step;
            }

        }

        switch ($api) {
            case "pdo":
                return self::pdo_increment($name, $step);
                break;
            case "mpdo":
                return self::pdo_increment($name, $step);
                break;
            case "files":
                return self::files_increment($name, $step);
                break;
            case "memcache":
                return self::memcache_increment($name, $step);
                break;
            case "memcached":
                return self::memcached_increment($name, $step);
                break;
            case "wincache":
                return self::wincache_increment($name, $step);
                break;
            case "apc":
                return self::apc_increment($name, $step);
                break;
            case "xcache":
                return self::xcache_increment($name, $step);
                break;
            default:
                return self::pdo_increment($name, $step);
                break;
        }
    }


    /*
     * Begin FILES Cache Static
     * Use Files & Folders to cache
     */

    private static function files_exist($name) {
        $data = self::files_get($name);
        if($data == null) {
            return false;
        } else {
            return true;
        }
    }



    private static function files_set($name,$value,$time_in_second = 600, $skip_if_existing = false) {

        $db = self::selectDB($name);
        $name = $db['item'];
        $folder = $db['db'];

        $path = self::getPath();
        $tmp = explode("/",$folder);
        foreach($tmp as $dir) {
            if($dir!="" && $dir !="." && $dir!="..") {
                $path.="/".$dir;
                if(!file_exists($path)) {
                    mkdir($path,0777);
                }
            }
        }

        $file = $path."/".$name.".c.html";

        $write = true;
        if(file_exists($file)) {
            $data = self::decode(file_get_contents($file));
            if($skip_if_existing == true && ((Int)$data['time'] + (Int)$data['endin'] > @date("U")) ) {
                $write = false;
            }
        }

        if($write == true ) {
            try {
                $f = fopen($file,"w+");
                fwrite($f,self::encode($value,$time_in_second));
                fclose($f);
            } catch (Exception $e) {
                die("Sorry, can't write cache to file :".$file );
            }
        }

        return $value;
    }

    private static function files_get($name) {
        $db = self::selectDB($name);
        $name = $db['item'];
        $folder = $db['db'];

        $path = self::getPath();
        $tmp = explode("/",$folder);
        foreach($tmp as $dir) {
            if($dir!="" && $dir !="." && $dir!="..") {
                $path.="/".$dir;
            }
        }

        $file = $path."/".$name.".c.html";

        if(!file_exists($file)) {
            return null;
        }

        $data = self::decode(file_get_contents($file));

        if(!isset($data['time']) || !isset($data['endin']) || !isset($data['value'])) {
            return null;
        }

        if($data['time'] + $data['endin'] < @date("U")) {
            // exp
            unlink($file);
            return null;
        }

        return isset($data['value']) ? $data['value'] : null;
    }

    private static function files_stats($dir = "") {
        $total = array(
            "expired"   =>  0,
            "size"      =>  0,
            "files"     =>  0
        );
        if($dir == "") {
            $dir = self::getPath();
        }
        $d = opendir($dir);
        while($file = readdir($d))
        {
            if($file!="." && $file != "..") {
                $path = $dir."/".$file;
                if(is_dir($path)) {
                    $in = self::files_stats($path);
                    $total['expired'] = $total['expired'] + $in['expired'];
                    $total['size'] = $total['size'] + $in['size'];
                    $total['files'] = $total['files'] + $in['files'];
                }

                elseif(strpos($path,".c.html")!== false) {
                    $data = self::decode($path);
                    if(isset($data['value']) && isset($data['time']) && isset($data['endin'])) {
                        $total['files']++;
                        if($data['time'] + $data['endin'] < @date("U")) {
                            $total['expired']++;
                        }
                        $total['size'] = $total['size'] + filesize($path);
                    }
                }
            }

        }
        if($total['size'] > 0) {
            $total['size'] = $total['size']/1024/1024;
        }
        return $total;
    }

    private static function files_cleanup($dir = "") {
        $total = 0;
        if($dir == "") {
            $dir = self::getPath();
        }
        $d = opendir($dir);
        while($file = readdir($d))
        {
            if($file!="." && $file != "..") {
                $path = $dir."/".$file;
                if(is_dir($path)) {
                    $total = $total + self::files_cleanup($path);
                    try {
                        @unlink($path);
                    } catch (Exception $e) {
                        // nothing;
                    }
                }
                elseif(strpos($path,".c.html")!==false) {
                    $data = self::decode($path);
                    if(isset($data['value']) && isset($data['time']) && isset($data['endin'])) {
                        if((Int)$data['time'] + (Int)$data['endin'] < @date("U")) {
                            unlink($path);
                            $total++;
                        }
                    } else {
                        unlink($path);
                        $total++;
                    }
                }
            }

        }
        return $total;
    }

    private static function files_delete($name) {
        $db = self::selectDB($name);
        $name = $db['item'];
        $folder = $db['db'];

        $path = self::getPath();
        $tmp = explode("/",$folder);
        foreach($tmp as $dir) {
            if($dir!="" && $dir !="." && $dir!="..") {
                $path.="/".$dir;
            }
        }

        $file = $path."/".$name.".c.html";
        if(file_exists($file)) {
            try {
                unlink($file);
                return true;
            } catch(Exception $e) {
                return false;
            }

        }
        return true;
    }

    private static function files_increment($name, $step = 1) {
        $db = self::selectDB($name);
        $name = $db['item'];
        $folder = $db['db'];

        $path = self::getPath();
        $tmp = explode("/",$folder);
        foreach($tmp as $dir) {
            if($dir!="" && $dir !="." && $dir!="..") {
                $path.="/".$dir;
            }
        }

        $file = $path."/".$name.".c.html";
        if(!file_exists($file)) {
            self::files_set($name,$step,3600);
            return $step;
        }

        $data = self::decode(file_get_contents($file));
        if(isset($data['time']) && isset($data['value']) && isset($data['endin'])) {
            $data['value'] = $data['value'] + $step;
            self::files_set($name,$data['value'],$data['endin']);
        }
        return $data['value'];
    }

    private static function files_decrement($name, $step = 1) {
        $db = self::selectDB($name);
        $name = $db['item'];
        $folder = $db['db'];

        $path = self::getPath();
        $tmp = explode("/",$folder);
        foreach($tmp as $dir) {
            if($dir!="" && $dir !="." && $dir!="..") {
                $path.="/".$dir;
            }
        }

        $file = $path."/".$name.".c.html";
        if(!file_exists($file)) {
            self::files_set($name,$step,3600);
            return $step;
        }

        $data = self::decode(file_get_contents($file));
        if(isset($data['time']) && isset($data['value']) && isset($data['endin'])) {
            $data['value'] = $data['value'] - $step;
            self::files_set($name,$data['value'],$data['endin']);
        }
        return $data['value'];
    }

    private static function getMemoryName($name) {
        $db = self::selectDB($name);
        $name = $db['item'];
        $folder = $db['db'];
        $name = $folder."_".$name;

        // connect memory server
        if(self::$sys['method'] == "memcache" || $db['db'] == "memcache") {
            self::memcache_addserver();
        }elseif(self::$sys['method'] == "memcached" || $db['db'] == "memcached") {
            self::memcached_addserver();
        }elseif(self::$sys['method'] == "wincache") {
            // init WinCache here

        }

        return $name;
    }


    /*
     * Begin XCache Static
     * http://xcache.lighttpd.net/wiki/XcacheApi
     */

    private static function xcache_exist($name) {
        $name = self::getMemoryName($name);
        if(xcache_isset($name)) {
            return true;
        } else {
            return false;
        }
    }


    private static function xcache_set($name,$value,$time_in_second = 600, $skip_if_existing = false) {
        $name = self::getMemoryName($name);
        if($skip_if_existing == true) {
            if(!self::xcache_exist($name)) {
                return xcache_set($name,$value,$time_in_second);
            }
        } else {
            return xcache_set($name,$value,$time_in_second);
        }
        return false;
    }

    private static function xcache_get($name) {

        $name = self::getMemoryName($name);

        $data = xcache_get($name);

        if($data === false || $data == "") {
            return null;
        }
        return $data;

    }

    private static function xcache_stats() {
        try {
            return xcache_list(XC_TYPE_VAR,100);
        } catch(Exception $e) {
            return array();
        }
    }

    private static function xcache_cleanup($option = array()) {
        // Revision 621

        $cnt = xcache_count(XC_TYPE_VAR);
        for ($i=0; $i < $cnt; $i++) {
            xcache_clear_cache(XC_TYPE_VAR, $i);
        }
        return true;
    }

    private static function xcache_delete($name) {
        $name = self::getMemoryName($name);
        return xcache_unset($name);
    }

    private static function xcache_increment($name, $step = 1) {
        $orgi = $name;
        $name = self::getMemoryName($name);
        $ret =xcache_inc($name, $step);
        if($ret === false) {
            self::xcache_set($orgi,$step,3600);
            return $step;
        } else {
            return $ret;
        }
    }

    private static function xcache_decrement($name, $step = 1) {
        $orgi = $name;
        $name = self::getMemoryName($name);
        $ret = xcache_dec($name, $step);
        if($ret === false) {
            self::xcache_set($orgi,$step,3600);
            return $step;
        } else {
            return $ret;
        }
    }


    /*
     * Begin APC Static
     * http://www.php.net/manual/en/ref.apc.php
     */

    private static function apc_exist($name) {
        $name = self::getMemoryName($name);
        if(apc_exists($name)) {
            return true;
        } else {
            return false;
        }
    }


    private static function apc_set($name,$value,$time_in_second = 600, $skip_if_existing = false) {
        $name = self::getMemoryName($name);
        if($skip_if_existing == true) {
            return apc_add($name,$value,$time_in_second);
        } else {
            return apc_store($name,$value,$time_in_second);
        }
    }

    private static function apc_get($name) {

        $name = self::getMemoryName($name);

        $data = apc_fetch($name,$bo);

        if($bo === false) {
            return null;
        }
        return $data;

    }

    private static function apc_stats() {
        try {
            return apc_cache_info("user");
        } catch(Exception $e) {
            return array();
        }
    }

    private static function apc_cleanup($option = array()) {
        return apc_clear_cache("user");
    }

    private static function apc_delete($name) {
        $name = self::getMemoryName($name);
        return apc_delete($name);
    }

    private static function apc_increment($name, $step = 1) {
        $orgi = $name;
        $name = self::getMemoryName($name);
        $ret = apc_inc($name, $step, $fail);
        if($ret === false) {
            self::apc_set($orgi,$step,3600);
            return $step;
        } else {
            return $ret;
        }
    }

    private static function apc_decrement($name, $step = 1) {
        $orgi = $name;
        $name = self::getMemoryName($name);
        $ret = apc_dec($name, $step, $fail);
        if($ret === false) {
            self::apc_set($orgi,$step,3600);
            return $step;
        } else {
            return $ret;
        }
    }


    /*
     * Begin Memcache Static
     * http://www.php.net/manual/en/class.memcache.php
     */
    public static function memcache_addserver() {
        if(!isset(self::$checked['memcache'])) {
            self::$checked['memcache'] = array();
        }

        if(self::$objects['memcache'] == "") {
            self::$objects['memcache'] = new Memcache();

            foreach(self::$server as $server) {
                $name = isset($server[0]) ? $server[0] : "";
                $port = isset($server[1]) ? $server[1] : 11211;
                if(!in_array($server, self::$checked['memcache']) && $name !="") {
                    self::$objects['memcache']->addServer($name,$port);
                    self::$checked['memcache'][] = $name;
                }
            }

        }

    }



    private static function memcache_exist($name) {
        $x = self::memcache_get($name);
        if($x == null) {
            return false;
        } else {
            return true;
        }
    }






    private static function memcache_set($name,$value,$time_in_second = 600, $skip_if_existing = false) {
        $orgi = $name;
        $name = self::getMemoryName($name);
        if($skip_if_existing == false) {
            return self::$objects['memcache']->set($name, $value, false, $time_in_second );
        } else {
            return self::$objects['memcache']->add($name, $value, false, $time_in_second );
        }

    }

    private static function memcache_get($name) {
        $name = self::getMemoryName($name);
        $x = self::$objects['memcache']->get($name);
        if($x == false) {
            return null;
        } else {
            return $x;
        }
    }

    private static function memcache_stats() {
        self::memcache_addserver();
        return self::$objects['memcache']->getStats();
    }

    private static function memcache_cleanup($option = "") {
        self::memcache_addserver();
        self::$objects['memcache']->flush();
        return true;
    }

    private static function memcache_delete($name) {
        $name = self::getMemoryName($name);
        return self::$objects['memcache']->delete($name);
    }

    private static function memcache_increment($name, $step = 1) {
        $name = self::getMemoryName($name);
        return self::$objects['memcache']->increment($name, $step);
    }

    private static function memcache_decrement($name, $step = 1) {
        $name = self::getMemoryName($name);
        return self::$objects['memcache']->decrement($name, $step);
    }



    /*
     * Begin Memcached Static
     */

    public static function memcached_addserver() {
        if(!isset(self::$checked['memcached'])) {
            self::$checked['memcached'] = array();
        }

        if(self::$objects['memcached'] == "") {
            self::$objects['memcached'] = new Memcached();

            foreach(self::$server as $server) {
                $name = isset($server[0]) ? $server[0] : "";
                $port = isset($server[1]) ? $server[1] : 11211;
                $sharing = isset($server[2]) ? $server[2] : 0;
                if(!in_array($server, self::$checked['memcached']) && $name !="") {
                    if($sharing >0 ) {
                        self::$objects['memcached']->addServer($name,$port,$sharing);
                    } else {
                        self::$objects['memcached']->addServer($name,$port);
                    }

                    self::$checked['memcached'][] = $name;
                }
            }

        }
    }


    private static function memcached_exist($name) {
        $x = self::memcached_get($name);
        if($x == null) {
            return false;
        } else {
            return true;
        }
    }



    private static function memcached_set($name,$value,$time_in_second = 600, $skip_if_existing = false) {
        $orgi = $name;
        $name = self::getMemoryName($name);
        if($skip_if_existing == false) {
            return self::$objects['memcached']->set($name, $value, time() + $time_in_second );
        } else {
            return self::$objects['memcached']->add($name, $value, time() + $time_in_second );
        }

    }

    private static function memcached_get($name) {
        $name = self::getMemoryName($name);
        $x = self::$objects['memcached']->get($name);
        if($x == false) {
            return null;
        } else {
            return $x;
        }
    }

    private static function memcached_stats() {
        self::memcached_addserver();
        return self::$objects['memcached']->getStats();
    }

    private static function memcached_cleanup($option = "") {
        self::memcached_addserver();
        self::$objects['memcached']->flush();
        return true;
    }

    private static function memcached_delete($name) {
        $name = self::getMemoryName($name);
        return self::$objects['memcached']->delete($name);
    }

    private static function memcached_increment($name, $step = 1) {
        $name = self::getMemoryName($name);
        return self::$objects['memcached']->increment($name, $step);
    }

    private static function memcached_decrement($name, $step = 1) {
        $name = self::getMemoryName($name);
        return self::$objects['memcached']->decrement($name, $step);
    }

    /*
     * Begin WinCache Static
     */

    private static function wincache_exist($name) {
        $name = self::getMemoryName($name);
        if(wincache_ucache_exists($name)) {
            return true;
        } else {
            return false;
        }
    }




    private static function wincache_set($name,$value,$time_in_second = 600, $skip_if_existing = false) {
        $orgi = $name;
        $name = self::getMemoryName($name);
        if($skip_if_existing == false) {
            return wincache_ucache_set($name, $value, $time_in_second );
        } else {
            return wincache_ucache_add($name, $value, $time_in_second );
        }

    }

    private static function wincache_get($name) {
        $name = self::getMemoryName($name);

        $x = wincache_ucache_get($name,$suc);

        if($suc == false) {
            return null;
        } else {
            return $x;
        }
    }

    private static function wincache_stats() {
        return wincache_scache_info();
    }

    private static function wincache_cleanup($option = "") {
        wincache_ucache_clear();
        return true;
    }

    private static function wincache_delete($name) {
        $name = self::getMemoryName($name);
        return wincache_ucache_delete($name);
    }

    private static function wincache_increment($name, $step = 1) {
        $name = self::getMemoryName($name);
        return wincache_ucache_inc($name, $step);
    }

    private static function wincache_decrement($name, $step = 1) {
        $name = self::getMemoryName($name);
        return wincache_ucache_dec($name, $step);
    }


    /*
     * Begin PDO Static
     */

    private static function pdo_exist($name) {
        $db = self::selectDB($name);
        $name = $db['item'];

        $x = self::db(array('db'=>$db['db']))->prepare("SELECT COUNT(*) as `total` FROM ".self::$table." WHERE `name`=:name");

        $x->execute(array(
            ":name" => $name,
        ));

        $row = $x->fetch(PDO::FETCH_ASSOC);
        if($row['total'] >0 ){
            return true;
        } else {
            return false;
        }

    }


    private static function pdo_cleanup($option = "") {
        self::db(array("skip_clean" => true))->exec("drop table if exists ".self::$table);
        self::initDatabase();
        return true;
    }

    private static function pdo_stats($full = false) {
        $res = array();
        if($full == true) {
            $stm = self::db()->prepare("SELECT * FROM ".self::$table."");
            $stm->execute();
            $result = $stm->fetchAll();
            $res['data'] = $result;
        }
        $stm = self::db()->prepare("SELECT COUNT(*) as `total` FROM ".self::$table."");
        $stm->execute();
        $result = $stm->fetch();
        $res['record'] = $result['total'];
        if(self::$path!="memory") {
            $res['size'] = filesize(self::getPath()."/".self::$filename);
        }

        return $res;
    }


    // for PDO return DB name,
    // For Files, return Dir
    private static function selectDB($object) {
        $res = array(
            'db'    => "",
            'item'  => "",
        );
        if(is_array($object)) {
            $key = array_keys($object);
            $key = $key[0];
            $res['db'] = $key;
            $res['item'] = self::safename($object[$key]);
        } else {
            $res['item'] = self::safename($object);
        }

        if($res['db'] == "" && self::$sys['method'] == "files") {
            $res['db'] = "files";
        }

        // for auto database
        if($res['db'] == "" && self::$storage== "mpdo") {
            $create_table = false;
            if(!file_exists('sqlite:'.self::getPath().'/phpfastcache.c')) {
                $create_table = true;
            }
            if(self::$autodb == "") {
                try {
                    self::$autodb = new PDO('sqlite:'.self::getPath().'/phpfastcache.c');
                    self::$autodb->setAttribute(PDO::ATTR_ERRMODE,
                        PDO::ERRMODE_EXCEPTION);

                } catch (PDOexception  $e) {
                    die("Please CHMOD 0777 or Writable Permission for ".self::getPath());
                }

            }

            if($create_table == true) {
                self::$autodb->exec('CREATE TABLE IF NOT EXISTS "main"."db" ("id" INTEGER PRIMARY KEY  AUTOINCREMENT  NOT NULL  UNIQUE , "item" VARCHAR NOT NULL  UNIQUE , "dbname" INTEGER NOT NULL )');
            }

            $db = self::$autodb->prepare("SELECT * FROM `db` WHERE `item`=:item");
            $db->execute(array(
                ":item" => $res['item'],
            ));
            $row = $db->fetch(PDO::FETCH_ASSOC);
            if(isset($row['dbname'])) {
                // found key
                $res['db'] = $row['dbname'];
            } else {
                // not key // check filesize
                if((Int)self::$autosize < 10) {
                    self::$autosize = 10;
                }
                // get last key
                $db = self::$autodb->prepare("SELECT * FROM `db` ORDER BY `id` DESC");
                $db->execute();
                $row = $db->fetch(PDO::FETCH_ASSOC);
                $dbname = isset($row['dbname']) ? $row['dbname'] : 1;
                $fsize = file_exists(self::getPath()."/".$dbname.".cache") ? filesize(self::getPath()."/".$dbname.".cache") : 0;
                if($fsize > (1024*1024*(Int)self::$autosize)) {
                    $dbname = (Int)$dbname + 1;
                }
                try {
                    $insert = self::$autodb->prepare("INSERT INTO `db` (`item`,`dbname`) VALUES(:item,:dbname)");
                    $insert->execute(array(
                        ":item" => $res['item'],
                        ":dbname"   => $dbname
                    ));
                } catch (PDOexception  $e) {
                    die('Database Error - Check A look at self::$autodb->prepare("INSERT INTO ');
                }

                $res['db'] = $dbname;

            }
        }

        return $res;

    }

    private static function pdo_get($name) {
        $db = self::selectDB($name);
        $name = $db['item'];
        // array('db'=>$db['db'])

        // self::startDebug($db,"",__LINE__,__FUNCTION__);

        $stm = self::db(array('db'=>$db['db']))->prepare("SELECT * FROM ".self::$table." WHERE `name`='".$name."'");
        $stm->execute();
        $res = $stm->fetch(PDO::FETCH_ASSOC);

        if(!isset($res['value'])) {
            return null;
        } elseif((Int)$res['added'] + (Int)$res['endin'] <= (Int)@date("U")) {
            return null;
        } else {
            // decode value on SQL;
            $data = self::decode($res['value']);
            // check if VALUE on string encode
            return isset($data['value']) ? $data['value'] : null;
        }
    }

    private static function pdo_decrement($name, $step = 1) {
        $db = self::selectDB($name);
        $name = $db['item'];
        // array('db'=>$db['db'])

        $int = self::get($name);
        try {
            $stm = self::db(array('db'=>$db['db']))->prepare("UPDATE ".self::$table." SET `value`=:new WHERE `name`=:name ");
            $stm->execute(array(
                ":new"  => self::encode($int - $step),
                ":name" =>  $name,
            ));

        } catch (PDOexception  $e) {
            die("Sorry! phpFastCache don't allow this type of value - Name: ".$name." -> Decrement: ".$step);
        }
        return $int - $step;

    }

    private static function pdo_increment($name ,$step = 1) {
        $db = self::selectDB($name);
        $name = $db['item'];
        // array('db'=>$db['db'])

        $int = self::get($name);
        // echo $int."xxx";
        try {
            $stm = self::db(array('db'=>$db['db']))->prepare("UPDATE ".self::$table." SET `value`=:new WHERE `name`=:name ");
            $stm->execute(array(
                ":new" => self::encode($int + $step),
                ":name" =>  $name,
            ));

        } catch (PDOexception  $e) {
            die("Sorry! phpFastCache don't allow this type of value - Name: ".$name." -> Increment: ".$step);
        }
        return $int + $step;

    }

    private static function pdo_delete($name) {
        $db = self::selectDB($name);
        $name = $db['item'];

        return self::db(array('db'=>$db['db']))->exec("DELETE FROM ".self::$table." WHERE `name`='".$name."'");
    }

    private static function pdo_set($name,$value,$time_in_second = 600, $skip_if_existing = false) {
        $db = self::selectDB($name);
        $name = $db['item'];
        // array('db'=>$db['db'])

        if($skip_if_existing == true) {
            try {
                $insert = self::db(array('db'=>$db['db']))->prepare("INSERT OR IGNORE INTO ".self::$table." (name,value,added,endin) VALUES(:name,:value,:added,:endin)");
                try {
                    $value = self::encode($value);
                } catch(Exception $e) {
                    die("Sorry! phpFastCache don't allow this type of value - Name: ".$name);
                }

                $insert->execute(array(
                    ":name"  => $name,
                    ":value"    => $value,
                    ":added"    => @date("U"),
                    ":endin"  =>  (Int)$time_in_second
                ));

                return true;
            } catch (PDOexception  $e) {
                return false;
            }

        } else {
            try {
                $insert = self::db(array('db'=>$db['db']))->prepare("INSERT OR REPLACE INTO ".self::$table." (name,value,added,endin) VALUES(:name,:value,:added,:endin)");
                try {
                    $value = self::encode($value);
                } catch(Exception $e) {
                    die("Sorry! phpFastCache don't allow this type of value - Name: ".$name);
                }

                $insert->execute(array(
                    ":name"  => $name,
                    ":value"    => $value,
                    ":added"    => @date("U"),
                    ":endin"  =>  (Int)$time_in_second
                ));

                return true;
            } catch (PDOexception  $e) {
                return false;
            }
        }
    }



    private static function db($option = array()) {
        $vacuum = false;
        $dbname = isset($option['db']) ? $option['db'] : "";
        $dbname = $dbname != "" ? $dbname : self::$filename;
        if($dbname!=self::$filename) {
            $dbname = $dbname.".cache";
        }
        // debuging
        // self::startDebug(self::$storage,"Check Storage",__LINE__,__FUNCTION__);
        $initDB = false;

        if(self::$storage == "pdo") {
            // start self PDO
            if(self::$objects['pdo']=="") {

                //  self::$objects['pdo'] == new PDO("sqlite:".self::$path."/cachedb.sqlite");
                if(!file_exists(self::getPath()."/".$dbname)) {
                    $initDB = true;
                } else {
                    if(!is_writable(self::getPath()."/".$dbname)) {
                        @chmod(self::getPath()."/".$dbname,0777);
                        if(!is_writable(self::getPath()."/".$dbname)) {
                            die("Please CHMOD 0777 or any Writable Permission for ".self::getPath()."/".$dbname);
                        }
                    }
                }



                try {
                    self::$objects['pdo'] = new PDO("sqlite:".self::getPath()."/".$dbname);
                    self::$objects['pdo']->setAttribute(PDO::ATTR_ERRMODE,
                        PDO::ERRMODE_EXCEPTION);

                    if($initDB == true) {
                        self::initDatabase();
                    }

                    $time = filemtime(self::getPath()."/".$dbname);
                    if($time + (3600*24) < @date("U")) {
                        $vacuum = true;
                    }

                    // Revision 619
                    // auto Vaccuum() every 48 hours
                    if($vacuum == true) {
                        if(!isset($option['skip_clean'])) {
                            self::$objects['pdo']->exec("DELETE FROM ".self::$table." WHERE (`added` + `endin`) < ".@date("U"));
                        }
                        self::$objects['pdo']->exec('VACUUM');
                    }



                } catch (PDOexception  $e) {
                    die("Can't connect to caching file ".self::getPath()."/".$dbname);
                }






                return self::$objects['pdo'];

            } else {
                return self::$objects['pdo'];
            }
            // end self pdo

        } elseif(self::$storage == "mpdo") {

            // start self PDO
            if(!isset(self::$multiPDO[$dbname])) {
                //  self::$objects['pdo'] == new PDO("sqlite:".self::$path."/cachedb.sqlite");
                if(self::$path!="memory") {
                    if(!file_exists(self::getPath()."/".$dbname)) {
                        $initDB = true;
                    } else {
                        if(!is_writable(self::getPath()."/".$dbname)) {
                            @chmod(self::getPath()."/".$dbname,0777);
                            if(!is_writable(self::getPath()."/".$dbname)) {
                                die("Please CHMOD 0777 or any Writable Permission for PATH ".self::getPath());
                            }
                        }
                    }



                    try {
                        self::$multiPDO[$dbname] = new PDO("sqlite:".self::getPath()."/".$dbname);
                        self::$multiPDO[$dbname]->setAttribute(PDO::ATTR_ERRMODE,
                            PDO::ERRMODE_EXCEPTION);

                        if($initDB == true) {
                            self::initDatabase(self::$multiPDO[$dbname]);
                        }

                        $time = filemtime(self::getPath()."/".$dbname);
                        if($time + (3600*24) < @date("U")) {
                            $vacuum = true;
                        }

                        // Revision 619
                        if($vacuum == true) {
                            if(!isset($option['skip_clean'])) {
                                self::$multiPDO[$dbname]->exec("DELETE FROM ".self::$table." WHERE (`added` + `endin`) < ".@date("U"));
                            }
                            self::$multiPDO[$dbname]->exec('VACUUM');
                        }

                    } catch (PDOexception  $e) {
                        // Revision 619
                       die("Can't connect to caching file ".self::getPath()."/".$dbname);
                    }


                }




                return self::$multiPDO[$dbname];

            } else {
                return self::$multiPDO[$dbname];
            }
            // end self pdo

        }





    }

    private static function initDatabase($object = null) {
        if($object == null) {
            self::db(array("skip_clean" => true))->exec('CREATE TABLE IF NOT EXISTS "'.self::$table.'" ("id" INTEGER PRIMARY KEY  AUTOINCREMENT  NOT NULL  UNIQUE , "name" VARCHAR UNIQUE NOT NULL  , "value" BLOB, "added" INTEGER NOT NULL  DEFAULT 0, "endin" INTEGER NOT NULL  DEFAULT 0)');
            self::db(array("skip_clean" => true))->exec('CREATE INDEX "lookup" ON "'.self::$table.'" ("added" ASC, "endin" ASC)');
            self::db(array("skip_clean" => true))->exec('VACUUM');
        } else {
            $object->exec('CREATE TABLE IF NOT EXISTS "'.self::$table.'" ("id" INTEGER PRIMARY KEY  AUTOINCREMENT  NOT NULL  UNIQUE , "name" VARCHAR UNIQUE NOT NULL  , "value" BLOB, "added" INTEGER NOT NULL  DEFAULT 0, "endin" INTEGER NOT NULL  DEFAULT 0)');
            $object->exec('CREATE INDEX "lookup" ON "'.self::$table.'" ("added" ASC, "endin" ASC)');
            $object->exec('VACUUM');
        }
    }

    // send all bugs to my email
    // you can replace it to your email
    // maximum 1 email per hour
    // you can use phpFastCache::bugs($title, $e) in any code
    public static function bugs($title, $e) {
        $code = md5("error_".$title);
        $send = self::get($code);
        if($send == null) {
            $to = "khoaofgod@yahoo.com";
            $subject = "Bugs: ".$title;
            $message = "Error Serialize:".serialize($e);
            $from = "root@".$_SERVER['HTTP_HOST'];
            $headers = "From:" . $from;
            @mail($to,$subject,$message,$headers);
            self::set($code,1,3600);
        }
    }

    // use for debug
    // public function, you can use phpFastCache::debug($e|array|string) any time in any code
    public static function debug($e, $exit = false) {
        echo "<pre>";
        print_r($e);
        echo "</pre>";
        if($exit == true) {
            exit;
        }
    }

    public static function startDebug($value,$text = "", $line = __LINE__, $func = __FUNCTION__) {
        if(self::$debugging == true) {
            self::$step_debugging++;
            if(!is_array($value)) {
                echo "<br>".self::$step_debugging." => ".$line." | ".$func." | ".$text." | ".$value;
            } else {
                echo "<br>".self::$step_debugging." => ".$line." | ".$func." | ".$text." | ";
                print_r($value);
            }

        }
    }

}