00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00018 final class RubberFileSystem extends CachePeer
00019 {
00020 private $directory = null;
00021
00025 public static function create($directory = 'cache/')
00026 {
00027 return new self($directory);
00028 }
00029
00030 public function __construct($directory = 'cache/')
00031 {
00032 $directory = ONPHP_TEMP_PATH.$directory;
00033
00034 if (!is_writable($directory)) {
00035 if (!mkdir($directory, 0700, true)) {
00036 throw new WrongArgumentException(
00037 "can not write to '{$directory}'"
00038 );
00039 }
00040 }
00041
00042 if ($directory[strlen($directory) - 1] != DIRECTORY_SEPARATOR)
00043 $directory .= DIRECTORY_SEPARATOR;
00044
00045 $this->directory = $directory;
00046 }
00047
00048 public function isAlive()
00049 {
00050 return is_writable($this->directory);
00051 }
00052
00053 public function clean()
00054 {
00055
00056 FileUtils::removeDirectory($this->directory, true);
00057
00058 return parent::clean();
00059 }
00060
00061 public function get($key)
00062 {
00063 $path = $this->makePath($key);
00064
00065 if (is_readable($path)) {
00066
00067 if (filemtime($path) <= time()) {
00068 try {
00069 unlink($path);
00070 } catch (BaseException $e) {
00071
00072 }
00073 return null;
00074 }
00075
00076 return $this->operate($path);
00077 }
00078
00079 return null;
00080 }
00081
00082 public function delete($key)
00083 {
00084 try {
00085 unlink($this->makePath($key));
00086 } catch (BaseException $e) {
00087 return false;
00088 }
00089
00090 return true;
00091 }
00092
00093 protected function store($action, $key, &$value, $expires = 0)
00094 {
00095 $path = $this->makePath($key);
00096 $time = time();
00097
00098 $directory = dirname($path);
00099
00100 if (!file_exists($directory)) {
00101 try {
00102 mkdir($directory);
00103 } catch (BaseException $e) {
00104
00105 }
00106 }
00107
00108
00109 if (
00110 $action == 'add'
00111 && is_readable($path)
00112 && filemtime($path) > $time
00113 )
00114 return true;
00115
00116
00117 if (
00118 $action == 'replace'
00119 ) {
00120 if (!is_readable($path)) {
00121 return false;
00122 } elseif (filemtime($path) <= $time) {
00123 $this->delete($key);
00124 return false;
00125 }
00126 }
00127
00128 $this->operate($path, $value, $expires);
00129
00130 return true;
00131 }
00132
00133 private function operate($path, $value = null, $expires = null)
00134 {
00135 $key = hexdec(substr(md5($path), 3, 2)) + 1;
00136
00137 $pool = SemaphorePool::me();
00138
00139 if (!$pool->get($key))
00140 return null;
00141
00142 try {
00143 $old = umask();
00144 umask(0077);
00145 $fp = fopen($path, $value !== null ? 'wb' : 'rb');
00146 umask($old);
00147 } catch (BaseException $e) {
00148 $pool->drop($key);
00149 return null;
00150 }
00151
00152 if ($value !== null) {
00153 fwrite($fp, $this->prepareData($value));
00154 fclose($fp);
00155
00156 if ($expires < parent::TIME_SWITCH)
00157 $expires += time();
00158
00159 touch($path, $expires);
00160
00161 return $pool->drop($key);
00162 } else {
00163 if (($size = filesize($path)) > 0)
00164 $data = fread($fp, $size);
00165
00166 fclose($fp);
00167
00168 $pool->drop($key);
00169
00170 return $this->restoreData($data);
00171 }
00172
00173 Assert::isUnreachable();
00174 }
00175
00176 private function makePath($key)
00177 {
00178 return
00179 $this->directory
00180 .$key[0].$key[1]
00181 .DIRECTORY_SEPARATOR
00182 .substr($key, 2);
00183 }
00184 }
00185 ?>