Cache::fetch()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 1
dl 0
loc 14
rs 9.7998
c 0
b 0
f 0
1
<?php
2
3
namespace PhpDbaCache;
4
5
/**
6
 * CacheDba - This class provides the functionality required to store
7
 * and retrieve PHP objects, strings, integers or arrays.
8
 * It uses the database (dbm-style) abstraction layer for persistence.
9
 * Even instances of SimpleXMLElement can be stored. You don't have
10
 * to matter about the size of the cache-file. It depends on the free
11
 * space of your disk.
12
 */
13
14
/**
15
 * Cache Dba
16
 *
17
 * @category PhpDbaCache
18
 */
19
class Cache
20
{
21
    /**
22
     * @var resource
23
     */
24
    protected $dba;
25
26
    /**
27
     * @var string
28
     */
29
    protected $handler;
30
31
    /**
32
     * @var string
33
     */
34
    protected $storage;
35
36
    /**
37
     * @param string  $file    the cache-file.
38
     *
39
     * @param string  $handler the dba handler.
40
     *
41
     * You have to install one of this handlers before use.
42
     *
43
     * cdb      = Tiny Constant Database - for reading.
44
     * cdb_make = Tiny Constant Database - for writing.
45
     * db4      = Oracle Berkeley DB 4   - for reading and writing.
46
     * qdbm     = Quick Database Manager - for reading and writing.
47
     * gdbm     = GNU Database Manager   - for reading and writing.
48
     * inifile  = Ini File               - for reading and writing.
49
     * flatfile = default dba extension  - for reading and writing.
50
     *
51
     * Use "flatfile" only when you cannot install one, of the libraries
52
     * required by the other handlers, and when you cannot use bundled cdb handler.
53
     *
54
     * @param string  $mode    For read/write access, database creation if it doesn't currently exist.
55
     *
56
     * r  = for read access
57
     * w  = for read/write access to an already existing database
58
     * c  = for read/write access and database creation if it doesn't currently exist
59
     * n  = for create, truncate and read/write access
60
     *
61
     * When you are absolutely sure that you do not require database locking you can use "-" as suffix.
62
     *
63
     * @param boolean $persistently
64
     *
65
     * @throws \RuntimeException If no DBA extension or handler installed.
66
     */
67
    public function __construct($file, $handler = 'flatfile', $mode = 'c', $persistently = true)
68
    {
69
        if (!extension_loaded('dba')) {
70
            throw new \RuntimeException('missing ext/dba');
71
        }
72
73
        if (!function_exists('dba_handlers') || !in_array($handler, dba_handlers(false))) {
74
            throw new \RuntimeException("dba-handler '{$handler}' not supported");
75
        }
76
77
        $this->dba = (true === $persistently)
78
            ? @dba_popen($file, $mode, $handler)
79
            : @dba_open($file, $mode, $handler);
80
81
        if ($this->dba === false) {
82
            $err = error_get_last();
83
            throw new \RuntimeException($err['message']);
84
        }
85
86
        $this->storage = $file;
87
        $this->handler = $handler;
88
    }
89
90
    /**
91
     * Closes an open dba resource
92
     *
93
     * @return void
94
     */
95
    public function __destruct()
96
    {
97
        $this->closeDba();
98
    }
99
100
    /**
101
     * @param string   $key
102
     * @param mixed    $value
103
     * @param int|bool $ltime Lifetime in seconds otherwise cache forever.
104
     *
105
     * @return bool
106
     */
107
    public function put($key, $value, $ltime = false)
108
    {
109
        try {
110
            $value = Pack::wrap($value, $ltime);
111
        } catch (\RuntimeException $ret) {
112
            return false;
113
        }
114
115
        if (true === $this->has($key)) {
116
            return dba_replace($key, $value, $this->dba);
117
        }
118
119
        return dba_insert($key, $value, $this->dba);
120
    }
121
122
    /**
123
     * @param string $key
124
     * @param mixed  $value
125
     *
126
     * @return bool
127
     */
128
    public function forever($key, $value)
129
    {
130
        return $this->put($key, $value, false);
131
    }
132
133
    /**
134
     * @param string $key
135
     *
136
     * @return bool|object
137
     */
138
    public function get($key)
139
    {
140
        $res = $this->fetch($key);
141
142
        if (false === $res) {
143
            return false;
144
        }
145
146
        if (false === $res->ltime || (microtime(true) - $res->mtime) < $res->ltime) {
147
            return $res->object;
148
        }
149
150
        $this->delete($key);
151
152
        return false;
153
    }
154
155
    /**
156
     * @return string
157
     */
158
    public function getStorage()
159
    {
160
        return $this->storage;
161
    }
162
163
    /**
164
     * @param string $key
165
     *
166
     * @return Capsule|boolean
167
     */
168
    public function fetch($key)
169
    {
170
        $fetched = dba_fetch($key, $this->dba);
171
172
        if (false === $fetched) {
173
            return false;
174
        }
175
176
        try {
177
            return Pack::unwrap($fetched);
178
        } catch (\RuntimeException $ret) {
179
            return false;
180
        }
181
    }
182
183
    /**
184
     * @param string $key
185
     *
186
     * @return boolean
187
     */
188
    public function delete($key)
189
    {
190
        if (false === is_resource($this->dba)) {
191
            return false;
192
        }
193
194
        if ($this->erasable()) {
195
            return dba_delete($key, $this->dba);
196
        }
197
198
        return true;
199
    }
200
201
    /**
202
     * @param string $key
203
     *
204
     * @return boolean
205
     */
206
    public function has($key)
207
    {
208
        return dba_exists($key, $this->dba);
209
    }
210
211
    /**
212
     * Close the handler.
213
     */
214
    public function closeDba()
215
    {
216
        if ($this->dba) {
217
            dba_close($this->dba);
218
            $this->dba = null;
219
        }
220
    }
221
222
    /**
223
     * @return resource
224
     */
225
    public function getDba()
226
    {
227
        return $this->dba;
228
    }
229
230
    /**
231
     * @return \ArrayObject of stored cache ids (string).
232
     */
233
    public function getIds()
234
    {
235
        $ids = new \ArrayObject();
236
        $dba = $this->getDba();
237
        $key = dba_firstkey($dba);
238
239
        while ($key !== false && $key !== null) {
240
            $ids->offsetSet(null, $key);
241
            $key = dba_nextkey($dba);
242
        }
243
244
        return $ids;
245
    }
246
247
    /**
248
     * Return an array of metadata for the given cache id.
249
     *
250
     * - expire = the expire timestamp
251
     * - mtime = timestamp of last modification time
252
     *
253
     * @param string $key cache id
254
     *
255
     * @return array|boolean
256
     */
257
    public function getMetaData($key)
258
    {
259
        $res = $this->fetch($key);
260
261
        if ($res instanceof Capsule) {
262
            return array(
263
                'expire' => $res->mtime + $res->ltime,
264
                'mtime'  => $res->mtime,
265
            );
266
        }
267
268
        return false;
269
    }
270
271
    /**
272
     * Ensures if a single cache-item can be deleted.
273
     *
274
     * @param null|string $handler
275
     *
276
     * @return bool
277
     */
278
    public function erasable($handler = null)
279
    {
280
        $handler = (!$handler) ? $this->handler : $handler;
281
282
        return in_array($handler, array('inifile', 'gdbm', 'qdbm', 'db4'), true);
283
    }
284
}
285