2015-06-23 26 views
1

我正在研究一个小的类,它允许我将队列数据写入文件。类似的想法到PHP $_SESSION.如何添加或更新文件中的值使用PHP

我想下面的步骤就可以了

  1. 公开赛在'a+'模式下使用fopen()文件
  2. 锁使用flock()与LOCK_EX型,以阻止另一进程使用该文件相同的文件
  3. 使用fread()阅读文件的现有内容。然后把数据放入数组中使用json_decode(array, true)
  4. 现在数据是在数组中。如果数组中存在的键更新其值,则将该键插入数组中。
  5. 创建的所有数据需要去上的文件的数组后,我截断使用ftruncate()的文件,并使用fwrite()
  6. 写入新的数据文件与LOCK_UN型解锁使用flock()的文件,以允许其他过程来使用它。
  7. 最后关闭文件

我相信我写的代码,以满足我的updateCache()方法的上述步骤。但它似乎不能正常工作。它不会跟踪数据。

这里是我

<?php 

namespace ICWS; 

use \ICWS\showVar; 
use \DirectoryIterator; 
/** 
* CacheHandler 
* 
* @package ICWS 
*/ 
class CacheHandler { 

    /* Max time second allowed to keep a session File */ 
    private $maxTimeAllowed = 300; 


    private $filename = ''; 
    private $handle; 

    public function __construct($filename) 
    { 

     $this->filename = $filename; 

     // 5% chance to collect garbage when the class is initialized. 
     if(mt_rand(1, 100) <= 5){ 
      $this->collectGarbage(); 
     } 
    } 

    private function print_me($a) 
    { 
     echo '<pre>'; 
     print_r($a); 
     echo '</pre>'; 
    } 

    /** 
    * Add/Update the cached array in the session 
    * 
    * @param string $key 
    * @param bigint $id 
    * @param array $field 
    * @return void 
    */ 
    public function updateCache($key, $id, array $field) 
    { 

     $currentVal = $field; 
     $this->openFile(); 

     $this->lockFile(); 
     $storage = $this->readFile(); 

     //create a new if the $id does not exists in the cache 
     if(isset($storage[$key]) && array_key_exists($id, $storage[$key])){ 
      $currentVal = $storage[$key][$id]; 

      foreach($field as $k => $v){ 
       $currentVal[$k] = $v; //update existing key or add a new one 
      } 

     } 

     $storage[$key][$id] = $currentVal; 

     $this->updateFile($storage); 

     $this->unlockFile(); 

     $this->closeFile(); 

    } 

    /** 
    * gets the current cache/session for a giving $key 
    * 
    * @param string $key. If null is passed it will return everything in the cache 
    * @return object or boolean 
    */ 
    public function getCache($key = null) 
    { 
     $value = false; 
     $this->openFile(); 
     rewind($this->handle); 
     $storage = $this->readFile(); 

     if(!is_null($key) && isset($storage[$key])){ 
      $value = $storage[$key]; 
     } 


     if(is_null($key)){ 
      $value = $storage; 
     } 

     $this->closeFile(); 

     return $value; 
    } 

    /** 
    * removes the $id from the cache/session 
    * 
    * @param string $key 
    * @param bigint $id 
    * @return boolean 
    */  
    public function removeCache($key, $id) 
    { 

     $this->openFile(); 

     $this->lockFile(); 
     $storage = $this->readFile(); 

     if(!isset($storage[$key][$id])){ 
      $this->unlockFile(); 
      $this->closeFile(); 
      return false; 
     } 

     unset($storage[$key][$id]); 
     $this->updateFile($storage); 
     $this->unlockFile(); 
     $this->closeFile(); 
     return true; 
    } 

    /** 
    * unset a session 
    * 
    * @param argument $keys 
    * @return void 
    */ 
    public function truncateCache() 
    { 
     if(file_exists($this->filename)){ 
      unlink($this->filename); 
     } 
    } 

    /** 
    * Open a file in a giving mode 
    * 
    * @params string $mode 
    * @return void 
    */ 
    private function openFile($mode = "a+") 
    { 
     $this->handle = fopen($this->filename, $mode); 

     if(!$this->handle){ 
      throw new exception('The File could not be opened!'); 
     } 
    } 

    /** 
    * Close the file 
    * @return void 
    */ 
    private function closeFile() 
    { 
     fclose($this->handle); 
     $this->handle = null; 
    } 

    /** 
    * Update the file with array data 
    * 
    * @param array $data the array in that has the data 
    * @return void 
    */ 
    private function updateFile(array $data = array()) 
    { 
     $raw = json_encode($data); 
     $this->truncateFile(); 
     fwrite($this->handle, $raw); 
    } 

    /** 
    * Delete the file content; 
    * 
    * @return void 
    */ 
    private function truncateFile() 
    { 
     ftruncate($this->handle, 0); 
     rewind($this->handle); 
    } 


    /** 
    * Read the data from the opned file 
    * 
    * @params string $mode 
    * @return array of the data found in the file 
    */ 
    private function readFile() 
    { 
     $length = filesize($this->filename); 
     if($length > 0){ 
      rewind($this->handle); 
      $raw = fread($this->handle, $length); 
      return json_decode($raw, true); 
     } 

     return array(); 
    } 


    /** 
    * Lock the file 
    * 
    * @return void 
    */ 
    private function lockFile($maxAttempts = 100, $lockType = LOCK_EX) 
    { 

     $i = 0; 
     while($i <= $maxAttempts){ 

      // acquire an exclusive lock 
      if(flock($this->handle, LOCK_EX)){ 
       break; 
      } 

      ++$i; 
     } 
    } 


    /** 
    * Unlock the file 
    * 
    * @return void 
    */ 
    private function unlockFile() 
    { 

     fflush($this->handle); 
     flock($this->handle, LOCK_UN); 
    } 

    /** 
    * Remove add cache files 
    * 
    * @return void 
    */ 
    private function collectGarbage() 
    { 
     $mydir = dirname($this->filename); 

     $dir = new DirectoryIterator($mydir); 
     $time = strtotime("now"); 
     foreach ($dir as $file) { 

      if ( !$file->isDot() 
       && $file->isFile() 
       && ($time - $file->getATime()) > $this->maxTimeAllowed 
       && $file->getFilename() != 'index.html' 
      ) { 
       unlink($file->getPathName()); 

      } 

     } 
    } 

    function addSlashes($str) 
    { 
     return addslashes($str); 
    } 


} 

这是我如何使用它

<?php 
    require 'autoloader.php'; 
    try { 
     $cache = new \ICWS\CacheHandler('cache/879'); 

     $field = array('name' => 'Mike A', 'Address' => '123 S Main', 'phone' => '2152456245', 'ext' => 123); 
     $cache->updateCache('NewKey', 'first', $field); 

     $cache->updateCache('NewKey', 'second', $field); 

     $field = array('Address' => '987 S Main', 'phone' => '000000000000', 'ext' => 5555); 
     $cache->updateCache('NewKey', 'first', $field); 

    $field = array('locations' => array('S' => 'South', 'N' => 'North', 'E' => 'East')); 
    $cache->updateCache('NewKey', 'first', $field); 

     echo '<pre>'; 
     print_r($cache->getCache()); 
     echo '</pre>'; 


    } catch (exception $e){ 

     echo $e->getMessage(); 
    } 

?> 

我期待的阵列看起来像这样

Array 
(
    [first] => stdClass Object 
     (
      [name] => Mike A 
      [Address] => 987 S Main 
      [phone] => 000000000000 
      [ext] => 5555 
      [locations] => Array 
       (
        [S] => South 
        [N] => North 
        [E] => East 
       ) 

     ) 

    [second] => stdClass Object 
     (
      [name] => Mike A 
      [Address] => 123 S Main 
      [phone] => 2152456245 
      [ext] => 123 
     ) 

) 

但执行后的第一次,我得到空白数组。然后,我再次执行脚本后,我得到以下数组。

Array 
(
    [NewKey] => Array 
     (
      [first] => Array 
       (
        [locations] => Array 
         (
          [S] => South 
          [N] => North 
          [E] => East 
         ) 

       ) 

     ) 

) 

什么可能会造成数据不正确更新?

updateCache()使用$_SESSION这给了我正确的输出我写的,但我需要做的这一点没有会话

这里是我的会话基础方法

public function updateCache($key, $id, array $field) 
{ 

    $currentVal = (object) $field; 

    //create a new if the $id does not exists in the cache 
    if(isset($_SESSION[$key]) && array_key_exists($id, $_SESSION[$key])){ 

     $currentVal = (object) $_SESSION[$key][$id]; 

     foreach($field as $k => $v){ 
      $currentVal->$k = $v; //update existing key or add a new one 
     } 

    } 

    $_SESSION[$key][$id] = $currentVal;  
} 
+1

这尖叫 - 使用DB我 –

+0

此外,你到处使用这个''NewKey'',但不要指望它是在输出...不知道为什么。在任何情况下,为什么不利用像[doctrine/cache](https://github.com/doctrine/cache)这样的东西来代替滚动自己的缓存事物? –

+0

@Dagon DB会过度杀伤。数据是暂时的。 –

回答

1

的问题就在这里:

private function readFile() 
{ 
    $length = filesize($this->filename); 
    if($length > 0){ 
     rewind($this->handle); 
     $raw = fread($this->handle, $length); 
     return json_decode($raw, true); 
    } 

    return array(); 
} 

filesize()的说明文件:

注意:该函数的结果被缓存。有关更多详细信息,请参见clearstatcache()

由于文件在启动时为空,因此它会缓存该信息,并且直到下一个脚本执行完成时才跳过分支。这应该可以解决它:

private function readFile() 
{ 
    rewind($this->handle); 
    $raw = stream_get_contents($this->handle); 
    return json_decode($raw, true) ?: []; 
} 
+0

精彩!我很高兴你咳嗽它,因为我错过了它。现在非常感谢你,它完美地工作。 –

相关问题