Completed
Pull Request — master (#15)
by Robbert
02:28
created

FileStore::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 4
Bugs 1 Features 1
Metric Value
c 4
b 1
f 1
dl 0
loc 7
ccs 6
cts 6
cp 1
rs 9.4286
cc 1
eloc 5
nc 1
nop 3
crap 1
1
<?php
2
3
/*
4
 * This file is part of the Ariadne Component Library.
5
 *
6
 * (c) Muze <[email protected]>0
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
namespace arc\cache;
12
13
/**
14
 * Class FileStore
15
 * @package arc\cache
16
 */
17
class FileStore
18
{
19
    protected $root = null;
20
    protected $currentPath = null;
21
    protected $basePath = null;
22
    protected $mode = null;
23
24
    /**
25
     * @param        $root          The root directory to store cache images
26
     * @param string $currentPath   The path within the root to use
27
     * @param int    $mode          The filemode to use
28
     */
29 7
    public function __construct($root, $currentPath = '/', $mode = 0770)
30
    {
31 7
        $this->root = $root;
32 7
        $this->currentPath = $currentPath;
33 7
        $this->basePath = $root . \arc\path::collapse( $currentPath );
34 7
        $this->mode = $mode;
35 7
    }
36
37
    /**
38
     * Returns the path for an image based on the current path and the name given
39
     * @param $name     The name for the cache image. The name is base64 encoded, so you cannot use full paths, only filenames.
40
     * @return string
41
     */
42 8
    protected function getPath($name)
43
    {
44 8
        return $this->basePath . base64_encode( $name );
45
    }
46
47
    /**
48
     * Returns the contents for a cached image, if it exists, null otherwise.
49
     * @param string $name
50
     * @return string|null
51
     */
52 5
    public function getVar($name)
53
    {
54 5
        $filePath = $this->getPath( $name );
55 5
        if (file_exists( $filePath )) {
56 4
            return file_get_contents( $filePath );
57
        }
58 2
    }
59
60
    /**
61
     * Store a value as a cached image.
62
     * @param string $name
63
     * @param string $value
64
     * @return int
65
     */
66 8
    public function putVar($name, $value)
67
    {
68 8
        $filePath = $this->getPath( $name );
69 8
        $dir = dirname( $filePath );
70 8
        if (!file_exists( $dir )) {
71 2
            mkdir( $dir, $this->mode, true ); //recursive
72 2
        }
73
74 8
        return file_put_contents( $filePath, $value, LOCK_EX );
75
    }
76
77
    /**
78
     * Return a fileinfo array (size, ctime, mtime) for a cached image, or null if it isn't found.
79
     * @param $name
80
     * @return array|null
81
     */
82 4
    public function getInfo($name)
83
    {
84 4
        $filePath = $this->getPath( $name );
85 4
        if (file_exists( $filePath ) && is_readable( $filePath )) {
86
            return array(
87 2
                'size' => filesize($filePath),
88 2
                'ctime' => filectime( $filePath ),
89 2
                'mtime' => filemtime( $filePath )
90 2
            );
91
        } else {
92 3
            return null;
93
        }
94
    }
95
96
    /**
97
     * Change the file info, only supports mtime in this implementation. Returns true if the cache image is found.
98
     * @param string $name The name of the cache image
99
     * @param array  $info The new file information - an array with 'mtime','size' and/or 'ctime' keys.
100
     * @return bool
101
     */
102 5
    public function setInfo($name, $info)
103
    {
104 5
        $filePath = $this->getPath( $name );
105 5
        if (file_exists( $filePath ) && is_readable( $filePath )) {
106 5
            foreach ($info as $key => $value) {
107
                switch ($key) {
108 5
                    case 'mtime':
109 5
                        touch( $filePath, $value );
110 5
                        break;
111
                    case 'size':
112
                    case 'ctime':
113
                        // FIXME: ignore silently? other storage mechanisms might need this set explicitly?
114
                        break;
115
                }
116 5
            }
117
118 5
            return true;
119
        } else {
120
            return false;
121
        }
122
    }
123
124
    /**
125
     * Change the path to store/retrieve cache images.
126
     * @param $path
127
     * @return FileStore
128
     */
129 4
    public function cd($path)
130
    {
131 4
        return new FileStore( $this->root, \arc\path::collapse( $path, $this->currentPath ), $this->mode );
132
    }
133
134
    /**
135
     * Returns an array with cache image names in the current path.
136
     * @return array
137
     */
138
    public function ls()
139
    {
140
        $dir = dir( $this->basePath );
141
        $result = array();
142
        if ($dir) {
143
            while ($name = $dir->read()) {
144
                if (!is_dir($this->basePath . $name )) {
145
                    $name = base64_decode($name);
146
                }
147
                $result[] = $name;
148
            }
149
            $dir->close();
150
        }
151
152
        return $result;
153
    }
154
155
    /**
156
     * Remove a cache image.
157
     * @param $name
158
     * @return bool
159
     */
160 2
    public function remove($name)
161
    {
162 2
        $filePath = $this->getPath( $name );
163
164 2
        return unlink( $filePath );
165
    }
166
167
    /**
168
     * @param $dir
169
     */
170 1
    protected function cleanup($dir)
171
    {
172 1
        foreach (glob( $dir . '/*' ) as $file) {
173 1
            if (is_dir( $file )) {
174 1
                $this->cleanup( $file );
175 1
            } else {
176 1
                unlink( $file );
177
            }
178 1
        }
179 1
        rmdir( $dir );
180 1
    }
181
182
    /**
183
     * Removes an entire subtree of cache images.
184
     * @param string $name The name of the image / subdir to remove.
185
     * @return bool
186
     */
187 3
    public function purge($name = '')
188
    {
189 3
        if ($name) {
190 1
            $this->remove( $name );
191 1
        }
192 3
        $dirPath = $this->basePath . \arc\path::collapse( $name );
193 3
        if (file_exists( $dirPath ) && is_dir( $dirPath )) {
194 1
            $this->cleanup( $dirPath );
195 1
        }
196
197 3
        return true;
198
    }
199
200
    /**
201
     * Locks a cache image. Default a write only lock, so you can still read the cache.
202
     * @param string $name
203
     * @param bool $blocking
204
     * @return bool
205
     */
206 2
    public function lock($name, $blocking = false)
207
    {
208 2
        $filePath = $this->getPath( $name );
209 2
        $dir = dirname( $filePath );
210 2
        if (!file_exists( $dir )) {
211 2
            mkdir( $dir, $this->mode, true ); //recursive
212 2
        }
213 2
        $lockFile = fopen( $filePath, 'c' );
214 2
        $lockMode = LOCK_EX;
215 2
        if (!$blocking) {
216 2
            $lockMode = $lockMode | LOCK_NB;
217 2
        }
218
219 2
        return flock( $lockFile, $lockMode );
220
    }
221
222
    /**
223
     * Unlocks a cache image.
224
     * @param $name
225
     * @return bool
226
     */
227 5
    public function unlock($name)
228
    {
229 5
        $filePath = $this->getPath( $name );
230 5
        $lockFile = fopen( $filePath, 'c' );
231
232 5
        return flock( $lockFile, LOCK_UN);
233
    }
234
}
235