如何使用PHP

时间:2015-06-23 22:20:24

标签: php arrays file session fopen

我正在开发一个允许我将队列数据写入文件的小类。与PHP $_SESSION.

类似的想法

我认为以下步骤可以解决问题

  1. 使用fopen()模式
  2. 中的'a+'打开文件
  3. 使用flock(类型LOCK_EX锁定文件,以防止其他进程使用同一文件
  4. 使用fread()阅读文件的现有内容。然后使用json_decode(array, true)
  5. 将数据放入数组中
  6. 现在数据在数组中。如果数组中的密钥更新其值,则将密钥插入数组。
  7. 在创建包含需要在文件上生成的所有数据的数组后,我使用ftruncate()截断文件,并使用fwrite()
  8. 将新数据写入文件
  9. 使用flock(类型的LOCK_UN解锁文件,以允许其他进程使用它。
  10. 最后关闭文件
  11. 我相信我编写的代码是为了满足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 个答案:

答案 0 :(得分: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) ?: [];
}