FileStore::lock()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 15
ccs 10
cts 10
cp 1
rs 9.7666
c 0
b 0
f 0
cc 3
nc 4
nop 2
crap 3
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 14
    public function __construct($root, $currentPath = '/', $mode = 0770)
30
    {
31 14
        $this->root = $root;
32 14
        $this->currentPath = $currentPath;
33 14
        $this->basePath = $root . \arc\path::collapse( $currentPath );
34 14
        $this->mode = $mode;
35 14
    }
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 16
    protected function getPath($name)
43
    {
44 16
        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 10
    public function getVar($name)
53
    {
54 10
        $filePath = $this->getPath( $name );
55 10
        if (file_exists( $filePath )) {
56 8
            return file_get_contents( $filePath );
57
        }
58 4
    }
59
60
    /**
61
     * Store a value as a cached image.
62
     * @param string $name
63
     * @param string $value
64
     * @return int
65
     */
66 16
    public function putVar($name, $value)
67
    {
68 16
        $filePath = $this->getPath( $name );
69 16
        $dir = dirname( $filePath );
70 16
        if (!file_exists( $dir )) {
71 4
            mkdir( $dir, $this->mode, true ); //recursive
72
        }
73
74 16
        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 8
    public function getInfo($name)
83
    {
84 8
        $filePath = $this->getPath( $name );
85 8
        if (file_exists( $filePath ) && is_readable( $filePath )) {
86
            return array(
87 4
                'size' => filesize($filePath),
88 4
                'ctime' => filectime( $filePath ),
89 4
                'mtime' => filemtime( $filePath )
90
            );
91
        } else {
92 6
            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 10
    public function setInfo($name, $info)
103
    {
104 10
        $filePath = $this->getPath( $name );
105 10
        if (file_exists( $filePath ) && is_readable( $filePath )) {
106 10
            foreach ($info as $key => $value) {
107 10
                switch ($key) {
108 10
                    case 'mtime':
109 10
                        touch( $filePath, $value );
110 10
                        break;
111
                    case 'size':
112
                    case 'ctime':
113
                        // FIXME: ignore silently? other storage mechanisms might need this set explicitly?
114
                        break;
115
                }
116
            }
117
118 10
            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 8
    public function cd($path)
130
    {
131 8
        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 4
    public function remove($name)
161
    {
162 4
        $filePath = $this->getPath( $name );
163
164 4
        return unlink( $filePath );
165
    }
166
167
    /**
168
     * @param $dir
169
     */
170 2
    protected function cleanup($dir)
171
    {
172 2
        foreach (glob( $dir . '/*' ) as $file) {
173 2
            if (is_dir( $file )) {
174 2
                $this->cleanup( $file );
175
            } else {
176 2
                unlink( $file );
177
            }
178
        }
179 2
        rmdir( $dir );
180 2
    }
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 6
    public function purge($name = '')
188
    {
189 6
        if ($name) {
190 2
            $this->remove( $name );
191
        }
192 6
        $dirPath = $this->basePath . \arc\path::collapse( $name );
193 6
        if (file_exists( $dirPath ) && is_dir( $dirPath )) {
194 2
            $this->cleanup( $dirPath );
195
        }
196
197 6
        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 4
    public function lock($name, $blocking = false)
207
    {
208 4
        $filePath = $this->getPath( $name );
209 4
        $dir = dirname( $filePath );
210 4
        if (!file_exists( $dir )) {
211 4
            mkdir( $dir, $this->mode, true ); //recursive
212
        }
213 4
        $lockFile = fopen( $filePath, 'c' );
214 4
        $lockMode = LOCK_EX;
215 4
        if (!$blocking) {
216 4
            $lockMode = $lockMode | LOCK_NB;
217
        }
218
219 4
        return flock( $lockFile, $lockMode );
220
    }
221
222
    /**
223
     * Unlocks a cache image.
224
     * @param $name
225
     * @return bool
226
     */
227 10
    public function unlock($name)
228
    {
229 10
        $filePath = $this->getPath( $name );
230 10
        $lockFile = fopen( $filePath, 'c' );
231
232 10
        return flock( $lockFile, LOCK_UN);
233
    }
234
}
235