PHP比较全面的缓存类

Java代码  PHP比较全面的缓存类
  1. <?php  
  2. /* 
  3.  * Name:    wrapperCache 
  4.  * Notes:   wrapper cache for fileCache, memcache/memcached, APC, Xcache and eaccelerator 
  5. $cacheObj =wrapperCache::getInstance('memcache',30,array(array('host'=>'localhost'))); 
  6. echo $cacheObj->cache('key','value'); 
  7. */  
  8. class wrapperCache {  
  9.     const DEFAULT_MEMCACHE_PORT     = 11211;  
  10.   
  11.     const CACHE_TYPE_AUTO           = 'auto';  
  12.     const CACHE_TYPE_EACCELERATOR   = 'eaccelerator';  
  13.     const CACHE_TYPE_APC            = 'apc';  
  14.     const CACHE_TYPE_MEMCACHE       = 'memcache';  
  15.     const CACHE_TYPE_MEMCACHED      = 'memcached';  
  16.     const CACHE_TYPE_FILE           = 'filecache';  
  17.     const CACHE_TYPE_XCACHE         = 'xcache';  
  18.   
  19.     private $cache_params;   //extra params for external caches like path or connection option memcached  
  20.     public  $cache_expire;   //seconds that the cache expires  
  21.     private $cache_type;     //type of cache to use  
  22.     private $cache_external; //external instance of cache, can be fileCache or memcache  
  23.     private static $instance;//Instance of this class  
  24.   
  25.     // Always returns only one instance  
  26.     public static function getInstance($type=self::CACHE_TYPE_AUTO, $exp_time=3600, $params='cache/'){  
  27.         if (!isset(self::$instance)) { //doesn't exists the isntance  
  28.             self::$instance = new self($type, $exp_time, $params); //goes to the constructor  
  29.         }  
  30.         return self::$instance;  
  31.     }  
  32.   
  33.     //cache constructor, optional expiring time and cache path  
  34.     private function __construct($type, $exp_time, $params) {  
  35.         $this->cache_expire = $exp_time;  
  36.         $this->cache_params = $params;  
  37.         $this->setCacheType($type);  
  38.     }  
  39.   
  40.     public function __destruct() {  
  41.         unset($this->cache_external);  
  42.     }  
  43.   
  44.     // Prevent users to clone the instance  
  45.     public function __clone(){  
  46.         $this->cacheError('Clone is not allowed.');  
  47.     }  
  48.   
  49.     //deletes cache from folder  
  50.     public function clearCache(){  
  51.         switch($this->cache_type){  
  52.             case self::CACHE_TYPE_EACCELERATOR :  
  53.                 eaccelerator_clean();  
  54.                 eaccelerator_clear();  
  55.                 break;  
  56.   
  57.             case self::CACHE_TYPE_APC :  
  58.                 apc_clear_cache('user');  
  59.                 break;  
  60.   
  61.             case self::CACHE_TYPE_XCACHE :  
  62.                 xcache_clear_cache(XC_TYPE_VAR, 0);  
  63.                 break;  
  64.   
  65.             case self::CACHE_TYPE_MEMCACHE :  
  66.                 $this->cache_external->flush();  
  67.                 break;  
  68.   
  69.             case self::CACHE_TYPE_MEMCACHED :  
  70.                 $this->cache_external->flush();  
  71.                 break;  
  72.   
  73.             case self::CACHE_TYPE_FILE:  
  74.                 $this->cache_external->deleteCache();  
  75.                 break;  
  76.         }  
  77.     }  
  78.   
  79.     //writes or reads the cache  
  80.     public function cache($key, $value = '', $ttl = '') {  
  81.         if ($value != '') { //wants to write  
  82.             if ($ttl == '') $ttl = $this->cache_expire;  
  83.             $this->put($key, $value, $ttl);  
  84.         } else return $this->get($key);  
  85.         //reading value  
  86.     }  
  87.   
  88.     //creates new cache files with the given data, $key== name of the cache, data the info/values to store  
  89.     private function put($key, $data, $ttl = '') {  
  90.         if ($ttl == '') $ttl = $this->cache_expire;  
  91.   
  92.         switch($this->cache_type){  
  93.             case self::CACHE_TYPE_EACCELERATOR :  
  94.                 eaccelerator_put($key, serialize($data), $ttl);  
  95.                 break;  
  96.   
  97.             case self::CACHE_TYPE_APC :  
  98.                 apc_store($key, $data, $ttl);  
  99.                 break;  
  100.   
  101.             case self::CACHE_TYPE_XCACHE :  
  102.                 xcache_set($key, serialize($data), $ttl);  
  103.                 break;  
  104.   
  105.             case self::CACHE_TYPE_MEMCACHE :  
  106.                 $data=serialize($data);  
  107.                 $this->cache_external->set($key, $data, false, $ttl);  
  108.                 break;  
  109.   
  110.             case self::CACHE_TYPE_MEMCACHED :  
  111.                 $data=serialize($data);  
  112.                 $this->cache_external->set($key, $data, $ttl);  
  113.                 break;  
  114.   
  115.             case self::CACHE_TYPE_FILE :  
  116.                 $this->cache_external->cache($key,$data);  
  117.                 break;  
  118.         }  
  119.     }  
  120.   
  121.     //returns cache for the given key  
  122.     private function get($key){  
  123.         switch($this->cache_type){  
  124.             case self::CACHE_TYPE_EACCELERATOR :  
  125.                 $data =  unserialize(eaccelerator_get($key));  
  126.                 break;  
  127.   
  128.             case self::CACHE_TYPE_APC :  
  129.                 $data =  apc_fetch($key);  
  130.                 break;  
  131.   
  132.             case self::CACHE_TYPE_XCACHE :  
  133.                 $data =  unserialize(xcache_get($key));  
  134.                 break;  
  135.   
  136.             case self::CACHE_TYPE_MEMCACHE :  
  137.                 $data = unserialize($this->cache_external->get($key));  
  138.                 break;  
  139.   
  140.             case self::CACHE_TYPE_MEMCACHED :  
  141.                 $data = unserialize($this->cache_external->get($key));  
  142.                 break;  
  143.   
  144.             case self::CACHE_TYPE_FILE :  
  145.                 $data = $this->cache_external->cache($key);  
  146.                 break;  
  147.         }  
  148.         return $data;  
  149.     }  
  150.   
  151.     //delete key from cache  
  152.     public function delete($key){  
  153.         switch($this->cache_type){  
  154.             case self::CACHE_TYPE_EACCELERATOR :  
  155.                 eaccelerator_rm($key);  
  156.                 break;  
  157.   
  158.             case self::CACHE_TYPE_APC :  
  159.                 apc_delete($key);  
  160.                 break;  
  161.   
  162.             case self::CACHE_TYPE_XCACHE :  
  163.                 xcache_unset($key);  
  164.                 break;  
  165.   
  166.             case self::CACHE_TYPE_MEMCACHE :  
  167.                 $this->cache_external->delete($key);  
  168.                 break;  
  169.   
  170.             case self::CACHE_TYPE_MEMCACHED :  
  171.                 $this->cache_external->delete($key);  
  172.                 break;  
  173.   
  174.             case self::CACHE_TYPE_FILE :  
  175.                 $this->cache_external->delete($key);  
  176.                 break;  
  177.         }  
  178.   
  179.     }  
  180.     // Overloading for the Application variables and automatically cached  
  181.     public function __set($name, $value) {  
  182.         $this->put($name, $value, $this->cache_expire);  
  183.     }  
  184.   
  185.     public function __get($name) {  
  186.         return $this->get($name);  
  187.     }  
  188.   
  189.     public function __isset($key) {//echo "Is '$name' set?\n"  
  190.         if ($this->get($key) !== false)  return true;  
  191.         else return false;  
  192.     }  
  193.   
  194.     public function __unset($name) {//echo "Unsetting '$name'\n";  
  195.         $this->delete($name);  
  196.     }  
  197.     //end overloads  
  198.   
  199.     public function getCacheType(){  
  200.         return $this->cache_type;  
  201.     }  
  202.   
  203.     //sets the cache if its installed if not triggers error  
  204.     public function setCacheType($type){  
  205.         $this->cache_type=strtolower($type);  
  206.   
  207.         switch($this->cache_type){  
  208.             case self::CACHE_TYPE_EACCELERATOR :  
  209.                 if (!function_exists('eaccelerator_get')) $this->cacheError('eaccelerator not found');  
  210.                 break;  
  211.   
  212.             case self::CACHE_TYPE_APC :  
  213.                 if (!function_exists('apc_fetch')) $this->cacheError('APC not found');  
  214.                 break;  
  215.   
  216.             case self::CACHE_TYPE_XCACHE :  
  217.                 if (function_exists('xcache_get')) $this->cacheError('Xcache not found');  
  218.                 break;  
  219.   
  220.             case self::CACHE_TYPE_MEMCACHE :  
  221.                 if (class_exists('Memcache')) $this->init_mem();  
  222.                 else $this->cacheError('memcache not found');  
  223.                 break;  
  224.   
  225.             case self::CACHE_TYPE_MEMCACHED :  
  226.                 if (class_exists('Memcached')) $this->init_mem(true);  
  227.                 else $this->cacheError('memcached not found');  
  228.                 break;  
  229.   
  230.             case self::CACHE_TYPE_FILE :  
  231.                 if (class_exists('fileCache'))$this->init_filecache();  
  232.                 else $this->cacheError('fileCache not found');  
  233.                 break;  
  234.   
  235.             case self::CACHE_TYPE_AUTO ://try to auto select a cache system  
  236.                 if (function_exists('eaccelerator_get'))    $this->cache_type = self::CACHE_TYPE_EACCELERATOR;  
  237.                 elseif (function_exists('apc_fetch'))       $this->cache_type = self::CACHE_TYPE_APC ;  
  238.                 elseif (function_exists('xcache_get'))      $this->cache_type = self::CACHE_TYPE_XCACHE;  
  239.                 elseif (class_exists('Memcache'))           $this->init_mem();  
  240.                 elseif (class_exists('Memcached'))          $this->init_mem(true);  
  241.                 elseif (class_exists('fileCache'))          $this->init_filecache();  
  242.                 else $this->cacheError('not any compatible cache was found');  
  243.                 break;  
  244.   
  245.             default://not any cache selected or wrong one selected  
  246.                 $msg='Not any cache type selected';  
  247.                 if (isset($type)) $msg='Unrecognized cache type selected <b>'.$type.'</b>';  
  248.                 $this->cacheError($msg);  
  249.                 break;  
  250.         }  
  251.     }  
  252.   
  253.     private function init_mem($useMemecached = false) { //get instance of the memcache/memcached class  
  254.         if (is_array($this->cache_params)) {  
  255.             if ($useMemecached) {  
  256.                 $this->cache_type = self::CACHE_TYPE_MEMCACHED;  
  257.                 $this->cache_external = new Memcached();  
  258.             } else {  
  259.                 $this->cache_type = self::CACHE_TYPE_MEMCACHE;  
  260.                 $this->cache_external = new Memcache;  
  261.             }  
  262.             foreach ($this->cache_params as $server) {  
  263.                 $server['port'] = isset($server['port']) ? (int)$server['port'] : self::DEFAULT_MEMCACHE_PORT;  
  264.                 if ($useMemecached) {  
  265.                     $this->cache_external->addServer($server['host'], $server['port']);  
  266.                 } else {  
  267.                     $server['persistent'] = isset($server['persistent']) ? (bool)$server['persistent'] : true;  
  268.                     $this->cache_external->addServer($server['host'], $server['port'], $server['persistent']);  
  269.                 }  
  270.             }  
  271.         } else $this->cacheError($this->cache_type . ' needs an array, example:wrapperCache::getInstance("' . $this->cache_type . '",30,array(array("host"=>"localhost")));');  
  272.     }  
  273.   
  274.     private function init_filecache(){//get instance of the filecache class  
  275.         $this->cache_type = self::CACHE_TYPE_FILE ;  
  276.         $this->cache_external = fileCache::getInstance($this->cache_expire, $this->cache_params);  
  277.     }  
  278.   
  279.     public function getAvailableCache($return_format='html'){//returns the available cache  
  280.         $avCaches   = array();  
  281.         $avCaches[] = array(self::CACHE_TYPE_EACCELERATOR,function_exists('eaccelerator_get'));  
  282.         $avCaches[] = array(self::CACHE_TYPE_APC,         function_exists('apc_fetch')) ;  
  283.         $avCaches[] = array(self::CACHE_TYPE_XCACHE,      function_exists('xcache_get'));  
  284.         $avCaches[] = array(self::CACHE_TYPE_MEMCACHE,    class_exists('Memcache'));  
  285.         $avCaches[] = array(self::CACHE_TYPE_MEMCACHED,   class_exists('Memcached'));  
  286.         $avCaches[] = array(self::CACHE_TYPE_FILE,        class_exists('fileCache'));  
  287.   
  288.         if ($return_format == 'html') {  
  289.             $ret = '<ul>';  
  290.             foreach ($avCaches as $c) {  
  291.                 $ret .= '<li>' . $c[0] . ' - ';  
  292.                 if ($c[1]) $ret .= 'Found/Compatible';  
  293.                 else $ret .= 'Not Found/Incompatible';  
  294.                 $ret .= '</ll>';  
  295.             }  
  296.             return $ret . '</ul>';  
  297.         } else return $avCaches;  
  298.     }  
  299.   
  300.     private function cacheError($msg){//triggers error  
  301.         trigger_error('<br /><b>wrapperCache error</b>: '.$msg.  
  302.             '<br />If you want you can try with \'auto\' for auto select a compatible cache.  
  303.                     <br />Or choose a supported cache from list:'.$this->getAvailableCache(), E_USER_ERROR);  
  304.     }  
  305. }  
 wrapperCache基于文件的缓存处理类 :
Java代码  PHP比较全面的缓存类
  1. <?php  
  2. /* 
  3. * Name:    fileCache 
  4. fileCache::getInstance(3600,'E:\www\cache\\')->cache('key','value'); 
  5. * Notes:   fileCache class, caches variables in standalone files if value is too long or uses unique file for small ones 
  6. */  
  7.   
  8. class fileCache {  
  9.     private $cache_path;//path for the cache  
  10.     private $cache_expire;//seconds that the cache expires  
  11.     private $application=array();//application object like in ASP  
  12.     private $application_file;//file for the application object  
  13.     private $application_write=false;//if application write is true means there was changes and we need to write the app file  
  14.     private $debug=false//no debug by default  
  15.     private $log=array();//log for the debug system  
  16.     private $start_time=0;//application start time  
  17.     private static $content_size=64;//this is the max size can be used in APP cache if bigger writes independent file  
  18.     private static $instance;//Instance of this class  
  19.   
  20.     // Always returns only one instance  
  21.     public static function getInstance($exp_time=3600,$path='cache/'){  
  22.         if (!isset(self::$instance)){//doesn't exists the isntance  
  23.             self::$instance = new self($exp_time,$path);//goes to the constructor  
  24.         }  
  25.         return self::$instance;  
  26.     }  
  27.   
  28.     //cache constructor, optional expiring time and cache path  
  29.     private function __construct($exp_time,$path){  
  30.         $this->start_time=microtime(true);//time starts  
  31.         $this->cache_expire=$exp_time;  
  32.         if ( ! is_writable($path) ) trigger_error('Path not writable:'.$path);  
  33.         else $this->cache_path=$path;  
  34.         $this->APP_start();//starting application cache  
  35.     }  
  36.   
  37.     public function __destruct() {  
  38.         $this->addLog('destruct');  
  39.         $this->APP_write();//on destruct we write if needed  
  40.         $this->returnDebug();  
  41.     }  
  42.   
  43.     // Prevent users to clone the instance  
  44.     public function __clone(){  
  45.         trigger_error('Clone is not allowed.', E_USER_ERROR);  
  46.     }  
  47.   
  48.     //deletes cache from folder  
  49.     public function deleteCache($older_than=''){  
  50.         $this->addLog('delete cache');  
  51.         if (!is_numeric($older_than)) $older_than=0;  
  52.         $files = scandir($this->cache_path);  
  53.         foreach($files as $file){  
  54.             if (strlen($file)>2 && time() > (filemtime($this->cache_path.$file) + $older_than) ) {  
  55.                 unlink($this->cache_path.$file);//echo "<br />-".$file;  
  56.                 $this->addLog('delete cache file:'.$this->cache_path.$file);  
  57.             }  
  58.         }  
  59.   
  60.     }  
  61.   
  62.     //writes or reads the cache  
  63.     public function cache($key, $value=''){       
  64.         if ($value!=''){//wants to write  
  65.             if (strlen(serialize($value)) > 64 ){//write independent file it's a big result  
  66.                 $this->addLog('cache function write in file key:'. $key);  
  67.                 $this->put($key, $value);  
  68.             }else{  
  69.                 $this->addLog('cache function write in APP key:'. $key);  
  70.                 $this->APP($key,$value);//write in the APP cache  
  71.             }  
  72.         }else{//reading value  
  73.             if ( $this->APP($key)!=null ){  
  74.                 $this->addLog('cache function read APP key:'. $key);  
  75.                 return $this->APP($key);//returns from app cache  
  76.             }else{  
  77.                 $this->addLog('cache function read file key:'. $key);  
  78.                 return $this->get($key);//returns from file cache  
  79.             }  
  80.         }  
  81.     }  
  82.   
  83.     //deletes a key from cache  
  84.     public function delete($name){  
  85.         if ( $this->APP($name)!=null ){//unset the APP var  
  86.             $this->addLog('unset APP key:'. $name);  
  87.             unset($this->application[md5($name)]);  
  88.             $this->application_write=true;//says that we have changes to later save the APP  
  89.         }elseif ( file_exists($this->fileName($name)) ){//unlink filename  
  90.             $this->addLog('unset File key:'. $name);  
  91.             unlink($this->fileName($name));  
  92.         }  
  93.     }  
  94.   
  95.     // Overloading for the variables and automatically cached  
  96.     public function __set($name, $value) {  
  97.         $this->cache($name, $value);  
  98.     }  
  99.   
  100.     public function __get($name) {  
  101.         return $this->cache($name);  
  102.     }  
  103.   
  104.     public function __isset($name) {//echo "Is '$name' set?\n"  
  105.         $this->addLog('isset key:'. $name);  
  106.         $value=$this->cache($name);  
  107.         return isset($value);  
  108.     }  
  109.   
  110.     public function __unset($name) {//echo "Unsetting '$name'\n";  
  111.         $this->delete($name);  
  112.     }  
  113.     //end overloads  
  114.   
  115.     //////////Cache for files individually///////////////////  
  116.   
  117.     //creates new cache files with the given data, $key== name of the cache, data the info/values to store  
  118.     private function put($key, $data){  
  119.         if ( $this->get($key)!= $data ){//only write if it's different  
  120.             $values = serialize($data);  
  121.             $filename = $this->fileName($key);  
  122.             $file = fopen($filename, 'w');  
  123.             if ($file){//able to create the file  
  124.                 $this->addLog('writting key: '.$key.' file: '.$filename);  
  125.                 fwrite($file, $values);  
  126.                 fclose($file);  
  127.             }  
  128.             else  $this->addLog('unable to write key: '.$key.' file: '.$filename);  
  129.         }//end if different  
  130.     }  
  131.   
  132.     //returns cache for the given key  
  133.     private function get($key){  
  134.         $filename = $this->fileName($key);  
  135.         if (!file_exists($filename) || !is_readable($filename)){//can't read the cache  
  136.             $this->addLog('can\'t read key: '.$key.' file: '.$filename);  
  137.             return null;  
  138.         }  
  139.   
  140.         if ( time() < (filemtime($filename) + $this->cache_expire) ) {//cache for the key not expired  
  141.             $file = fopen($filename, 'r');// read data file  
  142.             if ($file){//able to open the file  
  143.                 $data = fread($file, filesize($filename));  
  144.                 fclose($file);  
  145.                 $this->addLog('reading key: '.$key.' file: '.$filename);  
  146.                 return unserialize($data);//return the values  
  147.             }else{  
  148.                 $this->addLog('unable to read key: '.$key.' file: '.$filename);  
  149.                 return null;  
  150.             }  
  151.         }else{  
  152.             $this->addLog('expired key: '.$key.' file: '.$filename);  
  153.             unlink($filename);  
  154.             return null;//was expired you need to create new  
  155.         }  
  156.     }  
  157.   
  158.     //returns the filename for the cache  
  159.     private function fileName($key){  
  160.         return $this->cache_path.md5($key);  
  161.     }  
  162.     //////////END Cache for files individually///////////////////  
  163.   
  164.     //////////Cache for APP variables///////////////////  
  165.   
  166.     //load variables from the file  
  167.     private function APP_start ($app_file='application'){  
  168.         $this->application_file=$app_file;  
  169.   
  170.         if (file_exists($this->cache_path.$this->application_file)){ // if data file exists, load the cached variables  
  171.             //erase the cache every X minutes  
  172.             $app_time=filemtime($this->cache_path.$this->application_file)+$this->cache_expire;  
  173.             if (time()>$app_time){  
  174.                 $this->addLog('deleting APP file: '.$this->cache_path.$this->application_file);  
  175.                 unlink ($this->cache_path.$this->application_file);//erase the cache  
  176.             }else{//not expired  
  177.                 $filesize=filesize($this->cache_path.$this->application_file);  
  178.                 if ($filesize>0){  
  179.                     $file = fopen($this->cache_path.$this->application_file, 'r');// read data file  
  180.                     if ($file){  
  181.                         $this->addLog('reading APP file: '.$this->cache_path.$this->application_file);  
  182.                         $data = fread($file, $filesize);  
  183.                         fclose($file);  
  184.                         $this->application = unserialize($data);// build application variables from data file  
  185.                     }//en if file could open  
  186.                 }//end if file size  
  187.   
  188.             }  
  189.         }else{//if the file does not exist we create it  
  190.             $this->addLog('creating APP file: '.$this->cache_path.$this->application_file);  
  191.             fopen($this->cache_path.$this->application_file, 'w');  
  192.         }  
  193.   
  194.     }  
  195.   
  196.     // write application data to file  
  197.     private function APP_write(){  
  198.         if ($this->application_write){  
  199.             $data = serialize($this->application);  
  200.             $file = fopen($this->cache_path.$this->application_file, 'w');  
  201.             if ($file){  
  202.                 $this->addLog('writting APP file: '.$this->cache_path.$this->application_file);  
  203.                 fwrite($file, $data);  
  204.                 fclose($file);  
  205.             }  
  206.         }  
  207.     }  
  208.   
  209.     //returns the value form APP cache or stores it  
  210.     private function APP($var,$value=''){  
  211.         if ($value!=''){//wants to write  
  212.             if (is_array($this->application)){  
  213.                 if ( array_key_exists(md5($var), $this->application) ){//exist the value in the APP  
  214.                     $write=false;//we don't need to wirte  
  215.                     if ($this->application[md5($var)]!=$value)$write=true;//but exists and is different then we write  
  216.                 }  
  217.                 else $write=true;//not set we write!  
  218.             }  
  219.             else $write=false;  
  220.   
  221.             if ($write){  
  222.                 $this->addLog('writting APP key:'.$var);  
  223.                 $this->application[md5($var)]=$value;  
  224.                 $this->application_write=true;//says that we have changes to later save the APP  
  225.             }  
  226.         }else{//reading  
  227.             if ( !is_array($this->application) || ! array_key_exists(md5($var), $this->application) ){  
  228.                 $this->addLog('nothing found for APP key:'.$var);  
  229.                 return null;//nothing found not in array  
  230.             }else{  
  231.                 $this->addLog('reading APP key:'.$var);  
  232.                 return $this->application[md5($var)];//return value  
  233.             }  
  234.         }  
  235.     }  
  236.     //////////End Cache for APP variables///////////////////  
  237.   
  238.     ////DEBUG  
  239.     //sets debug on or off  
  240.     public function setDebug($state){  
  241.         $this->debug=(bool) $state;  
  242.     }  
  243.   
  244.     public function returnDebug($type='HTML'){  
  245.         if ($this->debug){  
  246.             switch($type){  
  247.                 case 'array':  
  248.                     return $this->log;  
  249.                     break;  
  250.                 case 'HTML'://returns debug as HTML  
  251.                 echo '<ol>';  
  252.                 foreach($this->log as $key=>$value){//loop in the log var  
  253.                     echo '<li>'.$value.'</li>';  
  254.                 }  
  255.                 echo '</ol>';  
  256.                 break;  
  257.             }  
  258.         }  
  259.         else return false;  
  260.     }  
  261.   
  262.     //add debug log  
  263.     public function addLog($value){  
  264.         if ($this->debug){//only if debug enabled  
  265.             array_push($this->log, round((microtime(true) - $this->start_time),5).'s - '. $value);  
  266.         }  
  267.     }  
  268. }  
  269. ?>   
上一篇:Oracle Data Guard_ 主库添加或删除在线重做日志文件


下一篇:兼容各主浏览器透明的CSS