Passed
Push — master ( d6dac1...ba598e )
by Mihail
03:07 queued 01:05
created

ShmopClient::delete()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 2
eloc 3
c 1
b 0
f 1
nc 2
nop 1
dl 0
loc 7
ccs 4
cts 4
cp 1
crap 2
rs 10
1
<?php
2
3
/*
4
 * This file is part of the Koded package.
5
 *
6
 * (c) Mihail Binev <[email protected]>
7
 *
8
 * Please view the LICENSE distributed with this source code
9
 * for the full copyright and license information.
10
 *
11
 */
12
13
namespace Koded\Caching\Client;
14
15
use Exception;
16
use Koded\Caching\{Cache, CacheException};
17
use function Koded\Caching\verify_key;
18
19
/**
20
 * @property ShmopClient client
21
 *
22
 */
23
final class ShmopClient implements Cache
24
{
25
    use ClientTrait, MultiplesTrait;
26
27
    /** @var string */
28
    private $dir;
29
30 187
    public function __construct(string $dir, ?int $ttl)
31
    {
32 187
        $this->dir = $dir;
33 187
        $this->ttl = $ttl;
34 187
        $this->setDirectory($dir);
35 187
    }
36
37
38 61
    public function get($key, $default = null)
39
    {
40 61
        if (false === $this->has($key, $filename)) {
41 12
            return $default;
42
        }
43
44
        try {
45 37
            $resource = shmop_open(fileinode($filename), 'a', 0, 0);
46 37
            return unserialize(shmop_read($resource, 0, shmop_size($resource)));
47
        } finally {
48 37
            shmop_close($resource);
49
        }
50
    }
51
52
53 70
    public function set($key, $value, $ttl = null)
54
    {
55 70
        verify_key($key);
56
57 53
        if (1 > $expiration = $this->timestampWithGlobalTtl($ttl, Cache::DATE_FAR_FAR_AWAY)) {
58
            // The item is considered expired and must be deleted
59 1
            return $this->delete($key);
60
        }
61
62 43
        $value = serialize($value);
63 43
        $size = strlen($value);
64 43
        $filename = $this->filename($key, true);
65
66
        try {
67 43
            $resource = shmop_open(fileinode($filename), 'n', 0666, $size);
68 1
        } catch (Exception $e) {
69 1
            $resource = shmop_open(fileinode($filename), 'w', 0666, $size);
70
        }
71
72
        try {
73 43
            return shmop_write($resource, $value, 0) === $size
74 43
                && false !== file_put_contents($filename . '-ttl', $expiration);
75
76
        } finally {
77 43
            shmop_close($resource);
78
        }
79
    }
80
81
82 23
    public function delete($key)
83
    {
84 23
        if (false === $this->has($key, $filename)) {
85 5
            return true;
86
        }
87
88 5
        return $this->expire($filename);
89
    }
90
91
92 187
    public function clear()
93
    {
94 187
        foreach ((glob($this->dir . 'shmop-*.cache*') ?: []) as $filename) {
95 187
            $this->expire($filename);
96
        }
97 187
        return true;
98
    }
99
100
101 96
    public function has($key, &$filename = '')
102
    {
103 96
        verify_key($key);
104 45
        $filename = $this->filename($key, false);
105 45
        $expiration = (int)(@file_get_contents($filename . '-ttl') ?: 0);
106
107 45
        if ($expiration <= time()) {
108 14
            $this->expire($filename);
109 14
            return false;
110
        }
111
112 42
        return true;
113
    }
114
115
116 45
    private function filename(string $key, bool $create): string
117
    {
118 45
        $filename = $this->dir . 'shmop-' . sha1($key) . '.cache';
119
120 45
        if ($create) {
121 43
            touch($filename);
122 43
            touch($filename . '-ttl');
123 43
            chmod($filename, 0666);
124 43
            chmod($filename . '-ttl', 0666);
125
        }
126
127 45
        return $filename;
128
    }
129
130
    /**
131
     * Prepares the cache directory.
132
     *
133
     * @param string $directory
134
     *
135
     * @throws CacheException
136
     */
137 187
    private function setDirectory(string $directory): void
138
    {
139
        // Overrule shell misconfiguration or the web server
140 187
        umask(umask() | 0002);
141 187
        $dir = $directory ?: sys_get_temp_dir();
142 187
        $dir = rtrim($dir, '/') . '/';
143
144 187
        if (false === is_dir($dir) && false === mkdir($dir, 0775, true)) {
145
            throw CacheException::forCreatingDirectory($dir);
146
        }
147
148 187
        $this->dir = $dir;
149 187
    }
150
151 187
    private function expire(string $filename): bool
152
    {
153 187
        if (false === $resource = @shmop_open(fileinode($filename), 'w', 0, 0)) {
154 187
            return false;
155
        }
156
157
        try {
158 43
            unlink($filename . '-ttl');
159 43
            return shmop_delete($resource);
160
        } finally {
161 43
            shmop_close($resource);
162
        }
163
    }
164
}
165