Source for file Localfile.php

Documentation is available at Localfile.php

  1. <?php
  2. // vim: foldmethod=marker tabstop=4 shiftwidth=4 autoindent
  3. /**
  4.  *  Localfile.php
  5.  *
  6.  *  @author     Masaki Fujimoto <fujimoto@php.net>
  7.  *  @license    http://www.opensource.org/licenses/bsd-license.php The BSD License
  8.  *  @package    Ethna
  9.  *  @version    $Id: 6f3c32a99ad7268ad0ac36e2682bab0564f9e95a $
  10.  */
  11.  
  12. /**
  13.  *  キャッシュマネージャクラス(ローカルファイルキャッシュ版)
  14.  *
  15.  *  @author     Masaki Fujimoto <fujimoto@php.net>
  16.  *  @access     public
  17.  *  @package    Ethna
  18.  */
  19. {
  20.     /**#@+  @access private */
  21.  
  22.     /**#@-*/
  23.  
  24.     /**
  25.      *  キャッシュに設定された値を取得する
  26.      *
  27.      *  キャッシュに値が設定されている場合はキャッシュ値
  28.      *  が戻り値となる。キャッシュに値が無い場合やlifetime
  29.      *  を過ぎている場合、エラーが発生した場合はEthna_Error
  30.      *  オブジェクトが戻り値となる。
  31.      *
  32.      *  @access public
  33.      *  @param  string  $key        キャッシュキー
  34.      *  @param  int     $lifetime   キャッシュ有効期間
  35.      *  @param  string  $namespace  キャッシュネームスペース
  36.      *  @return array   キャッシュ値
  37.      */
  38.     public function get($key$lifetime null$namespace null)
  39.     {
  40.         $namespace $this->getNamespace($namespace);
  41.         $cache_file $this->_getCacheFile($namespace$key);
  42.  
  43.         // ライフタイムチェック
  44.         clearstatcache();
  45.         if (is_readable($cache_file=== false
  46.             || ($st stat($cache_file)) === false{
  47.             return Ethna::raiseError("No such cache (key=%s, file=%s)"E_CACHE_NO_VALUE$key$cache_file);
  48.         }
  49.         if (is_null($lifetime== false{
  50.             if (($st[9]+$lifetimetime()) {
  51.                 return Ethna::raiseError("Cache expired (key=%s, file=%s)"E_CACHE_EXPIRED$key$cache_file);
  52.             }
  53.         }
  54.  
  55.         $fp fopen($cache_file"r");
  56.         if ($fp == false{
  57.             return Ethna::raiseError('fopen failed'E_CACHE_NO_VALUE);
  58.         }
  59.         // ロック
  60.         $timeout 3;
  61.         while ($timeout 0{
  62.             $r flock($fpLOCK_EX|LOCK_NB);
  63.             if ($r{
  64.                 break;
  65.             }
  66.             $timeout--;
  67.             sleep(1);
  68.         }
  69.         if ($timeout <= 0{
  70.             fclose($fp);
  71.             return Ethna::raiseError('fopen failed'E_CACHE_GENERAL);
  72.         }
  73.  
  74.         $n 0;
  75.         while ($st[7== 0{
  76.             clearstatcache();
  77.             $st stat($cache_file);
  78.             usleep(1000*1);
  79.             $n++;
  80.             if ($n 5{
  81.                 break;
  82.             }
  83.         }
  84.  
  85.         if ($st == false || $n 5{
  86.             fclose($fp);
  87.             return Ethna::raiseError('stat failed'E_CACHE_NO_VALUE);
  88.         }
  89.         $value fread($fp$st[7]);
  90.         fclose($fp);
  91.  
  92.         return unserialize($value);
  93.     }
  94.  
  95.     /**
  96.      *  キャッシュの最終更新日時を取得する
  97.      *
  98.      *  @access public
  99.      *  @param  string  $key        キャッシュキー
  100.      *  @param  string  $namespace  キャッシュネームスペース
  101.      *  @return int     最終更新日時(unixtime)
  102.      */
  103.     public function getLastModified($key$namespace null)
  104.     {
  105.         $namespace $this->getNamespace($namespace);
  106.         $cache_file $this->_getCacheFile($namespace$key);
  107.  
  108.         clearstatcache();
  109.         if (is_readable($cache_file=== false
  110.             || ($st stat($cache_file)) === false{
  111.             return Ethna::raiseError('fopen failed'E_CACHE_NO_VALUE);
  112.         }
  113.         return $st[9];
  114.     }
  115.  
  116.     /**
  117.      *  値がキャッシュされているかどうかを取得する
  118.      *
  119.      *  @access public
  120.      *  @param  string  $key        キャッシュキー
  121.      *  @param  int     $lifetime   キャッシュ有効期間
  122.      *  @param  string  $namespace  キャッシュネームスペース
  123.      */
  124.     public function isCached($key$lifetime null$namespace null)
  125.     {
  126.         $namespace $this->getNamespace($namespace);
  127.         $cache_file $this->_getCacheFile($namespace$key);
  128.  
  129.         // ライフタイムチェック
  130.         clearstatcache();
  131.         if (is_readable($cache_file=== false
  132.             || ($st stat($cache_file)) === false{
  133.             return false;
  134.         }
  135.         if (is_null($lifetime== false{
  136.             if (($st[9]+$lifetimetime()) {
  137.                 return false;
  138.             }
  139.         }
  140.  
  141.         return true;
  142.     }
  143.  
  144.     /**
  145.      *  キャッシュに値を設定する
  146.      *
  147.      *  @access public
  148.      *  @param  string  $key        キャッシュキー
  149.      *  @param  mixed   $value      キャッシュ値
  150.      *  @param  int     $timestamp  キャッシュ最終更新時刻(unixtime)
  151.      *  @param  string  $namespace  キャッシュネームスペース
  152.      */
  153.     public function set($key$value$timestamp null$namespace null)
  154.     {
  155.         $namespace $this->getNamespace($namespace);
  156.         $dir $this->_getCacheDir($namespace$key);
  157.  
  158.         // キャッシュディレクトリチェック
  159.         $r Ethna_Util::mkdir($dir0777);
  160.         if ($r == false && is_dir($dir== false{
  161.             return Ethna::raiseError('mkdir(%s) failed'E_USER_WARNING$dir);
  162.         }
  163.  
  164.         $cache_file $this->_getCacheFile($namespace$key);
  165.         $fp fopen($cache_file"a+");
  166.         if ($fp == false{
  167.             return Ethna::raiseError('fopen failed'E_CACHE_GENERAL);
  168.         }
  169.  
  170.         // ロック
  171.         $timeout 3;
  172.         while ($timeout 0{
  173.             $r flock($fpLOCK_EX|LOCK_NB);
  174.             if ($r{
  175.                 break;
  176.             }
  177.             $timeout--;
  178.             sleep(1);
  179.         }
  180.         if ($timeout <= 0{
  181.             fclose($fp);
  182.             return Ethna::raiseError('fopen failed'E_CACHE_GENERAL);
  183.         }
  184.         rewind($fp);
  185.         ftruncate($fp0);
  186.         fwrite($fpserialize($value));
  187.         fclose($fp);
  188.         Ethna_Util::chmod($cache_file0666);
  189.  
  190.         if (is_null($timestamp)) {
  191.             // this could suppress warning
  192.             touch($cache_file);
  193.         else {
  194.             touch($cache_file$timestamp);
  195.         }
  196.  
  197.         return 0;
  198.     }
  199.  
  200.     /**
  201.      *  キャッシュ値を削除する
  202.      *
  203.      *  @access public
  204.      *  @param  string  $key        キャッシュキー
  205.      *  @param  string  $namespace  キャッシュネームスペース
  206.      */
  207.     public function clear($key$namespace null)
  208.     {
  209.         $namespace $this->getNamespace($namespace);
  210.         $cache_file $this->_getCacheFile($namespace$key);
  211.  
  212.         if (file_exists($cache_file)) {
  213.             unlink($cache_file);
  214.         }
  215.     }
  216.  
  217.     /**
  218.      *  キャッシュ対象ディレクトリを取得する
  219.      *
  220.      *  @access private
  221.      */
  222.     private function _getCacheDir($namespace$key)
  223.     {
  224.         $safe_mode ini_get('safe_mode');
  225.         if ($safe_mode{
  226.             return sprintf("%s"$this->backend->getTmpdir());
  227.         }
  228.  
  229.         $len strlen($key);
  230.         // intentionally avoid using -2 or -4
  231.         $dir1 substr($key$len-42);
  232.         if ($len-|| strlen($dir12{
  233.             $dir1 "__dir1";
  234.         }
  235.         $dir2 substr($key$len-22);
  236.         if ($len-|| strlen($dir22{
  237.             $dir2 "__dir2";
  238.         }
  239.  
  240.         //$map = $this->config->get('cachemanager_localfile');
  241.         $map $this->config;
  242.         $tmp_key $namespace "::" $key;
  243.         // PHP依存:)
  244.         $dir "default";
  245.  
  246.         if (is_array($map)) {
  247.             foreach ($map as $key => $value{
  248.                 if (strncmp($key$tmp_keystrlen($key)) == 0{
  249.                     $dir $value;
  250.                     break;
  251.                 }
  252.             }
  253.         }
  254.         return sprintf("%s/cache/%s/cache_%s/%s/%s"$this->backend->getTmpdir()$dir$this->_escape($namespace)$this->_escape($dir1)$this->_escape($dir2));
  255.     }
  256.  
  257.     /**
  258.      *  キャッシュファイルを取得する
  259.      *
  260.      *  @access private
  261.      */
  262.     private function _getCacheFile($namespace$key)
  263.     {
  264.         $safe_mode ini_get('safe_mode');
  265.         if ($safe_mode{
  266.             return sprintf("%s/cache_%s_%s"$this->_getCacheDir($namespace$key)$this->_escape($namespace)$this->_escape($key));
  267.         }
  268.  
  269.         return sprintf("%s/%s"$this->_getCacheDir($namespace$key)$this->_escape($key));
  270.     }
  271.  
  272.     /**
  273.      *  キーをファイルシステム用にエスケープする
  274.      *
  275.      *  @access private
  276.      */
  277.     private function _escape($string)
  278.     {
  279.         return preg_replace('/([^0-9A-Za-z_])/e'"sprintf('%%%02X', ord('\$1'))"$string);
  280.     }
  281. }

Documentation generated on Fri, 11 Nov 2011 03:58:29 +0900 by phpDocumentor 1.4.3