|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace Wordlift\Cache; |
|
4
|
|
|
|
|
5
|
|
|
use Wordlift_Log_Service; |
|
6
|
|
|
|
|
7
|
|
|
/** |
|
8
|
|
|
* Define an a time lived cache. |
|
9
|
|
|
* |
|
10
|
|
|
* Cache has a ttl set by default to 900 seconds. Cached responses are stored in the temp |
|
11
|
|
|
* folder returned by WordPress' {@link get_temp_dir} function. |
|
12
|
|
|
* |
|
13
|
|
|
* Currently the class doesn't cleanup stale cache files. |
|
14
|
|
|
* |
|
15
|
|
|
* @since 3.21.2 |
|
16
|
|
|
*/ |
|
17
|
|
|
// @@todo: add a hook to clear the cached files now and then. |
|
18
|
|
|
class Ttl_Cache { |
|
19
|
|
|
|
|
20
|
|
|
/** |
|
21
|
|
|
* The cache name. |
|
22
|
|
|
* |
|
23
|
|
|
* @var string $name The cache name. |
|
24
|
|
|
* @access private |
|
25
|
|
|
* @since 3.21.2 |
|
26
|
|
|
*/ |
|
27
|
|
|
private $name; |
|
28
|
|
|
|
|
29
|
|
|
/** |
|
30
|
|
|
* The TTL of cached responses in seconds. |
|
31
|
|
|
* |
|
32
|
|
|
* @var int $ttl The TTL in seconds. |
|
33
|
|
|
* @access private |
|
34
|
|
|
* @since 3.21.2 |
|
35
|
|
|
*/ |
|
36
|
|
|
private $ttl; |
|
37
|
|
|
|
|
38
|
|
|
/** |
|
39
|
|
|
* The cache dir where the cached data is written. |
|
40
|
|
|
* |
|
41
|
|
|
* @since 3.21.2 |
|
42
|
|
|
* @access private |
|
43
|
|
|
* @var string $cache_dir The cache dir where the cached responses are written. |
|
44
|
|
|
*/ |
|
45
|
|
|
private $cache_dir; |
|
46
|
|
|
|
|
47
|
|
|
/** |
|
48
|
|
|
* A {@link Wordlift_Log_Service} instance. |
|
49
|
|
|
* |
|
50
|
|
|
* @var Wordlift_Log_Service $log A {@link Wordlift_Log_Service} instance. |
|
51
|
|
|
* @access private |
|
52
|
|
|
* @since 3.21.2 |
|
53
|
|
|
*/ |
|
54
|
|
|
private $log; |
|
55
|
|
|
|
|
56
|
|
|
/** |
|
57
|
|
|
* @var array |
|
58
|
|
|
*/ |
|
59
|
|
|
private static $caches = array(); |
|
60
|
|
|
|
|
61
|
|
|
/** |
|
62
|
|
|
* Create a {@link Ttl_Cache} with the specified TTL, default 900 secs. |
|
63
|
|
|
* |
|
64
|
|
|
* @param string $name The cache name. |
|
65
|
|
|
* @param int $ttl The cache TTL, default 900 secs. |
|
66
|
|
|
* |
|
67
|
|
|
* @since 3.21.2 |
|
68
|
|
|
*/ |
|
69
|
|
|
public function __construct( $name, $ttl = 900 ) { |
|
70
|
|
|
|
|
71
|
|
|
$this->log = Wordlift_Log_Service::get_logger( get_class() ); |
|
72
|
|
|
|
|
73
|
|
|
$this->name = $name; |
|
74
|
|
|
$this->ttl = $ttl; |
|
75
|
|
|
|
|
76
|
|
|
// Get the temp dir and add the directory separator if missing. |
|
77
|
|
|
$temp_dir = get_temp_dir(); |
|
78
|
|
View Code Duplication |
if ( DIRECTORY_SEPARATOR !== substr( $temp_dir, - strlen( DIRECTORY_SEPARATOR ) ) ) { |
|
|
|
|
|
|
79
|
|
|
$temp_dir .= DIRECTORY_SEPARATOR; |
|
80
|
|
|
} |
|
81
|
|
|
$this->cache_dir = self::get_cache_folder() . DIRECTORY_SEPARATOR . md5( $name ); |
|
82
|
|
|
|
|
83
|
|
|
$this->log->trace( "Creating the cache folder {$this->cache_dir}..." ); |
|
84
|
|
|
wp_mkdir_p( $this->cache_dir ); |
|
85
|
|
|
|
|
86
|
|
|
self::$caches[ $name ] = $this; |
|
87
|
|
|
|
|
88
|
|
|
} |
|
89
|
|
|
|
|
90
|
|
|
/** |
|
91
|
|
|
* Get the root cache folder. |
|
92
|
|
|
* |
|
93
|
|
|
* This is useful to introduce a cache cleaning procedure which will scan and delete older stale cache files. |
|
94
|
|
|
* |
|
95
|
|
|
* @return string The root cache folder. |
|
96
|
|
|
* @since 3.22.5 |
|
97
|
|
|
*/ |
|
98
|
|
|
public static function get_cache_folder() { |
|
99
|
|
|
|
|
100
|
|
|
// Get the temp dir and add the directory separator if missing. |
|
101
|
|
|
$temp_dir = get_temp_dir(); |
|
102
|
|
View Code Duplication |
if ( DIRECTORY_SEPARATOR !== substr( $temp_dir, - strlen( DIRECTORY_SEPARATOR ) ) ) { |
|
|
|
|
|
|
103
|
|
|
$temp_dir .= DIRECTORY_SEPARATOR; |
|
104
|
|
|
} |
|
105
|
|
|
|
|
106
|
|
|
return $temp_dir . 'wl.cache'; |
|
107
|
|
|
} |
|
108
|
|
|
|
|
109
|
|
|
/** |
|
110
|
|
|
* Get the cached data for the specified key. |
|
111
|
|
|
* |
|
112
|
|
|
* @param mixed $key A serializable key. |
|
113
|
|
|
* |
|
114
|
|
|
* @return mixed|null |
|
115
|
|
|
* @since 3.21.2 |
|
116
|
|
|
*/ |
|
117
|
|
|
public function get( $key ) { |
|
118
|
|
|
|
|
119
|
|
|
$filename = $this->get_filename( $key ); |
|
120
|
|
|
|
|
121
|
|
|
// If the cache file exists and it's not too old, then return it. |
|
122
|
|
|
if ( file_exists( $filename ) && $this->ttl >= time() - filemtime( $filename ) ) { |
|
123
|
|
|
$this->log->trace( "Cache HIT.\n" ); |
|
124
|
|
|
|
|
125
|
|
|
return json_decode( file_get_contents( $filename ), true ); |
|
126
|
|
|
} |
|
127
|
|
|
|
|
128
|
|
|
$this->log->trace( "Cache MISS, filename $filename.\n" ); |
|
129
|
|
|
|
|
130
|
|
|
return null; |
|
131
|
|
|
} |
|
132
|
|
|
|
|
133
|
|
|
public function put( $key, $data ) { |
|
134
|
|
|
|
|
135
|
|
|
$filename = $this->get_filename( $key ); |
|
136
|
|
|
|
|
137
|
|
|
// Cache. |
|
138
|
|
|
@unlink( $filename ); |
|
|
|
|
|
|
139
|
|
|
@file_put_contents( $filename, wp_json_encode( $data ) ); |
|
|
|
|
|
|
140
|
|
|
|
|
141
|
|
|
} |
|
142
|
|
|
|
|
143
|
|
|
public function flush() { |
|
144
|
|
|
|
|
145
|
|
|
$files = glob( $this->cache_dir . DIRECTORY_SEPARATOR . '*' ); |
|
146
|
|
|
foreach ( $files as $file ) { // iterate files |
|
147
|
|
|
if ( is_file( $file ) ) { |
|
148
|
|
|
@unlink( $file ); |
|
|
|
|
|
|
149
|
|
|
} |
|
150
|
|
|
} |
|
151
|
|
|
|
|
152
|
|
|
} |
|
153
|
|
|
|
|
154
|
|
|
public static function flush_all() { |
|
155
|
|
|
|
|
156
|
|
|
/** @var Ttl_Cache $cache */ |
|
157
|
|
|
foreach ( self::$caches as $cache ) { |
|
158
|
|
|
$cache->flush(); |
|
159
|
|
|
} |
|
160
|
|
|
|
|
161
|
|
|
} |
|
162
|
|
|
|
|
163
|
|
|
/** |
|
164
|
|
|
* Get the full path for the given `$hash`. The file is not checked for its existence. |
|
165
|
|
|
* |
|
166
|
|
|
* @param string $hash A file hash. |
|
167
|
|
|
* |
|
168
|
|
|
* @return string The full path to the file. |
|
169
|
|
|
* @since 3.21.2 |
|
170
|
|
|
*/ |
|
171
|
|
|
private function get_path( $hash ) { |
|
172
|
|
|
|
|
173
|
|
|
return $this->cache_dir . DIRECTORY_SEPARATOR . $hash; |
|
174
|
|
|
} |
|
175
|
|
|
|
|
176
|
|
|
private function get_filename( $key ) { |
|
177
|
|
|
|
|
178
|
|
|
// Create a hash and a path to the cache file. |
|
179
|
|
|
$hash = md5( json_encode( $key ) ); |
|
180
|
|
|
$filename = $this->get_path( $hash ); |
|
181
|
|
|
|
|
182
|
|
|
return $filename; |
|
183
|
|
|
} |
|
184
|
|
|
|
|
185
|
|
|
} |
|
186
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.