Overview

Namespaces

  • None
  • Wei
    • Validator

Classes

  • Wei\Validator\All
  • Wei\Validator\AllOf
  • Wei\Validator\Alnum
  • Wei\Validator\Alpha
  • Wei\Validator\BaseValidator
  • Wei\Validator\Between
  • Wei\Validator\Blank
  • Wei\Validator\Callback
  • Wei\Validator\CharLength
  • Wei\Validator\Chinese
  • Wei\Validator\Color
  • Wei\Validator\Contains
  • Wei\Validator\CreditCard
  • Wei\Validator\Date
  • Wei\Validator\DateTime
  • Wei\Validator\Decimal
  • Wei\Validator\Digit
  • Wei\Validator\Dir
  • Wei\Validator\DivisibleBy
  • Wei\Validator\DoubleByte
  • Wei\Validator\Email
  • Wei\Validator\EndsWith
  • Wei\Validator\EqualTo
  • Wei\Validator\Exists
  • Wei\Validator\FieldExists
  • Wei\Validator\File
  • Wei\Validator\GreaterThan
  • Wei\Validator\GreaterThanOrEqual
  • Wei\Validator\IdCardCn
  • Wei\Validator\IdCardHk
  • Wei\Validator\IdCardMo
  • Wei\Validator\IdCardTw
  • Wei\Validator\IdenticalTo
  • Wei\Validator\Image
  • Wei\Validator\In
  • Wei\Validator\Ip
  • Wei\Validator\Length
  • Wei\Validator\LessThan
  • Wei\Validator\LessThanOrEqual
  • Wei\Validator\Lowercase
  • Wei\Validator\Luhn
  • Wei\Validator\MaxLength
  • Wei\Validator\MinLength
  • Wei\Validator\MobileCn
  • Wei\Validator\NaturalNumber
  • Wei\Validator\NoneOf
  • Wei\Validator\Null
  • Wei\Validator\Number
  • Wei\Validator\OneOf
  • Wei\Validator\Password
  • Wei\Validator\Phone
  • Wei\Validator\PhoneCn
  • Wei\Validator\PlateNumberCn
  • Wei\Validator\PositiveInteger
  • Wei\Validator\PostcodeCn
  • Wei\Validator\Present
  • Wei\Validator\QQ
  • Wei\Validator\RecordExists
  • Wei\Validator\Regex
  • Wei\Validator\Required
  • Wei\Validator\SomeOf
  • Wei\Validator\StartsWith
  • Wei\Validator\Time
  • Wei\Validator\Tld
  • Wei\Validator\Type
  • Wei\Validator\Uppercase
  • Wei\Validator\Url
  • Wei\Validator\Uuid
  • Overview
  • Namespace
  • Function
  1: <?php
  2: /**
  3:  * Wei Framework
  4:  *
  5:  * @copyright   Copyright (c) 2008-2015 Twin Huang
  6:  * @license     http://opensource.org/licenses/mit-license.php MIT License
  7:  */
  8: 
  9: namespace Wei;
 10: 
 11: /**
 12:  * A cache service that stored data in files
 13:  *
 14:  * @author      Twin Huang <twinhuang@qq.com>
 15:  */
 16: class FileCache extends BaseCache
 17: {
 18:     /**
 19:      * The cache directory
 20:      *
 21:      * @var string
 22:      */
 23:     protected $dir = 'cache';
 24: 
 25:     /**
 26:      * Illegal chars as the name of cache, would be replaced to "_"
 27:      *
 28:      * @var array
 29:      */
 30:     protected $illegalChars = array(
 31:         '\\', '/', ':', '*', '?', '"', '<', '>', '|', "\r", "\n"
 32:     );
 33: 
 34:     /**
 35:      * The cache file extension
 36:      *
 37:      * @var string
 38:      */
 39:     protected $ext = 'cache';
 40: 
 41:     /**
 42:      * Constructor
 43:      *
 44:      * @param array $options
 45:      */
 46:     public function __construct(array $options = array())
 47:     {
 48:         parent::__construct($options + array(
 49:             'dir' => $this->dir
 50:         ));
 51:     }
 52: 
 53:     /**
 54:      * {@inheritdoc}
 55:      */
 56:     public function get($key, $expire = null, $fn = null)
 57:     {
 58:         if (!is_file($file = $this->getFile($key))) {
 59:             $result = false;
 60:         } else {
 61:             $content = $this->getContent($file);;
 62:             if ($content && is_array($content) && time() < $content[0]) {
 63:                 $result = $content[1];
 64:             } else {
 65:                 $this->remove($key);
 66:                 $result = false;
 67:             }
 68:         }
 69:         return $this->processGetResult($key, $result, $expire, $fn);
 70:     }
 71: 
 72:     /**
 73:      * {@inheritdoc}
 74:      */
 75:     public function set($key, $value, $expire = 0)
 76:     {
 77:         $file = $this->getFile($key);
 78:         $content = $this->prepareContent($value, $expire);
 79:         return (bool) file_put_contents($file, $content, LOCK_EX);
 80:     }
 81: 
 82:     /**
 83:      * {@inheritdoc}
 84:      */
 85:     public function remove($key)
 86:     {
 87:         if (is_file($file = $this->getFile($key))) {
 88:             return unlink($file);
 89:         } else {
 90:             return false;
 91:         }
 92:     }
 93: 
 94:     /**
 95:      * {@inheritdoc}
 96:      */
 97:     public function exists($key)
 98:     {
 99:         if (!is_file($file = $this->getFile($key))) {
100:             return false;
101:         }
102: 
103:         $content = $this->getContent($file);
104:         if ($content && is_array($content) && time() < $content[0]) {
105:             return true;
106:         } else {
107:             $this->remove($key);
108:             return false;
109:         }
110:     }
111: 
112:     /**
113:      * {@inheritdoc}
114:      */
115:     public function add($key, $value, $expire = 0)
116:     {
117:         $file = $this->getFile($key);
118: 
119:         if (!is_file($file)) {
120:             // Open and try to lock file immediately
121:             if (!$handle = $this->openAndLock($file, 'wb', LOCK_EX | LOCK_NB)) {
122:                 return false;
123:             }
124: 
125:             $rewrite = false;
126:         } else {
127:             // Open file for reading and rewriting
128:             if (!$handle = $this->openAndLock($file, 'r+b', LOCK_EX)) {
129:                 return false;
130:             }
131: 
132:             // The cache is not expired
133:             if ($this->readAndVerify($handle, $file)) {
134:                 fclose($handle);
135:                 return false;
136:             }
137: 
138:             $rewrite = true;
139:         }
140: 
141:         $content = $this->prepareContent($value, $expire);
142:         return $this->writeAndRelease($handle, $content, $rewrite);
143:     }
144: 
145:     /**
146:      * {@inheritdoc}
147:      */
148:     public function replace($key, $value, $expire = 0)
149:     {
150:         if (!is_file($file = $this->getFile($key))) {
151:             return false;
152:         }
153: 
154:         // Open file for reading and rewriting
155:         if (!$handle = $this->openAndLock($file, 'r+b', LOCK_EX)) {
156:             return false;
157:         }
158: 
159:         if (!$this->readAndVerify($handle, $file)) {
160:             fclose($handle);
161:             return false;
162:         }
163: 
164:         $content = $this->prepareContent($value, $expire);
165:         return $this->writeAndRelease($handle, $content, true);
166:     }
167: 
168:     /**
169:      * {@inheritdoc}
170:      */
171:     public function incr($key, $offset = 1)
172:     {
173:         $file = $this->getFile($key);
174: 
175:         if (!is_file($file)) {
176:             return $this->set($key, $offset) ? $offset : false;
177:         }
178: 
179:         // Open file for reading and rewriting
180:         if (!$handle = $this->openAndLock($file, 'r+b', LOCK_EX)) {
181:             return false;
182:         }
183: 
184:         // Prepare file content
185:         if (!$content = $this->readAndVerify($handle, $file)) {
186:             $content = $this->prepareContent($offset, 0);
187:             $result = $offset;
188:         } else {
189:             $result = $content[1] += $offset;
190:             $content = $this->prepareContent($content[1], $content[0]);
191:         }
192: 
193:         // Rewrite content
194:         return $this->writeAndRelease($handle, $content, true) ? $result : false;
195:     }
196: 
197: 
198:     /**
199:      * {@inheritdoc}
200:      */
201:     public function clear()
202:     {
203:         $result = true;
204:         foreach (glob($this->dir . '/' . '*.' . $this->ext) as $file) {
205:             $result = $result && @unlink($file);
206:         }
207:         return $result;
208:     }
209: 
210:     /**
211:      * Get cache file by key
212:      *
213:      * @param  string $key
214:      * @return string
215:      */
216:     public function getFile($key)
217:     {
218:         $key = str_replace($this->illegalChars, '_', $this->namespace . $key);
219:         return $this->dir . '/' . $key . '.' . $this->ext;
220:     }
221: 
222:     /**
223:      * Set the cache directory
224:      *
225:      * @param string $dir
226:      * @return $this
227:      * @throws \RuntimeException When failed to create the cache directory
228:      */
229:     public function setDir($dir)
230:     {
231:         if (!is_dir($dir) && !@mkdir($dir, 0755, true)) {
232:             $message = sprintf('Failed to create directory "%s"', $dir);
233:             ($e = error_get_last()) && $message .= ': ' . $e['message'];
234:             throw new \RuntimeException($message);
235:         }
236:         $this->dir = realpath($dir);
237:         return $this;
238:     }
239: 
240:     /**
241:      * Returns the cache directory
242:      *
243:      * @return string
244:      */
245:     public function getDir()
246:     {
247:         return $this->dir;
248:     }
249: 
250:     /**
251:      * Open and lock file
252:      *
253:      * @param  string         $file      file path
254:      * @param  string         $mode      open mode
255:      * @param  int            $operation lock operation
256:      * @return resource|false file handle or false
257:      */
258:     protected function openAndLock($file, $mode, $operation)
259:     {
260:         if (!$handle = fopen($file, $mode)) {
261:             return false;
262:         }
263:         if (!flock($handle, $operation)) {
264:             fclose($handle);
265:             return false;
266:         }
267:         return $handle;
268:     }
269: 
270:     /**
271:      * Read file by handle and verify if content is expired
272:      *
273:      * @param  resource    $handle file handle
274:      * @param  string      $file   file path
275:      * @return false|array false or file content array
276:      */
277:     protected function readAndVerify($handle, $file)
278:     {
279:         // Read all content
280:         $content = fread($handle, filesize($file));
281:         $content = @unserialize($content);
282: 
283:         // Check if content is valid
284:         if ($content && is_array($content) && time() < $content[0]) {
285:             return $content;
286:         } else {
287:             return false;
288:         }
289:     }
290: 
291:     /**
292:      * Receive file content by file name
293:      *
294:      * @param string $file
295:      * @return array
296:      */
297:     protected function getContent($file)
298:     {
299:         return @unserialize(file_get_contents($file));
300:     }
301: 
302:     /**
303:      * Prepare content for writing
304:      *
305:      * @param  string $content the value of cache
306:      * @param  int    $expire  expire time
307:      * @return string file content
308:      */
309:     protected function prepareContent($content, $expire)
310:     {
311:         // 2147483647 = pow(2, 31) - 1
312:         // avoid year 2038 problem in 32-bit system when date coverts or compares
313:         // @see http://en.wikipedia.org/wiki/Year_2038_problem
314:         return serialize(array(
315:             0 => $expire ? time() + $expire : 2147483647,
316:             1 => $content,
317:         ));
318:     }
319: 
320:     /**
321:      * Write content, release lock and close file
322:      *
323:      * @param  resource $handle  file handle
324:      * @param  string   $content the value of cache
325:      * @param  bool     $rewrite whether rewrite the whole file
326:      * @return boolean
327:      */
328:     protected function writeAndRelease($handle, $content, $rewrite = false)
329:     {
330:         $rewrite && rewind($handle) && ftruncate($handle, 0);
331:         $result = fwrite($handle, $content);
332:         flock($handle, LOCK_UN);
333:         fclose($handle);
334:         return (bool) $result;
335:     }
336: }
337: 
Wei Framework API documentation generated by ApiGen