]> git.mxchange.org Git - friendica.git/blob - src/Core/Cache.php
Merge pull request #3890 from zeroadam/Cache-#3878
[friendica.git] / src / Core / Cache.php
1 <?php
2 /**
3  * @file src/Core/Cache.php
4  */
5 namespace Friendica\Core;
6
7 use Friendica\Core\Config;
8 use Friendica\Core\PConfig;
9 use Friendica\Database\DBM;
10
11 /**
12  * @brief Class for storing data for a short time
13  */
14 class Cache
15 {
16         /**
17          * @brief Check for memcache and open a connection if configured
18          *
19          * @return object|boolean The memcache object - or "false" if not successful
20          */
21         public static function memcache()
22         {
23                 if (!function_exists('memcache_connect')) {
24                         return false;
25                 }
26
27                 if (!Config::get('system', 'memcache')) {
28                         return false;
29                 }
30
31                 $memcache_host = Config::get('system', 'memcache_host', '127.0.0.1');
32                 $memcache_port = Config::get('system', 'memcache_port', 11211);
33
34                 $memcache = new Memcache;
35
36                 if (!$memcache->connect($memcache_host, $memcache_port)) {
37                         return false;
38                 }
39
40                 return $memcache;
41         }
42
43         /**
44          * @brief Return the duration for a given cache level
45          *
46          * @param integer $level Cache level
47          *
48          * @return integer The cache duration in seconds
49          */
50         private static function duration($level)
51         {
52                 switch ($level) {
53                         case CACHE_MONTH:
54                                 $seconds = 2592000;
55                                 break;
56                         case CACHE_WEEK:
57                                 $seconds = 604800;
58                                 break;
59                         case CACHE_DAY:
60                                 $seconds = 86400;
61                                 break;
62                         case CACHE_HOUR:
63                                 $seconds = 3600;
64                                 break;
65                         case CACHE_HALF_HOUR:
66                                 $seconds = 1800;
67                                 break;
68                         case CACHE_QUARTER_HOUR:
69                                 $seconds = 900;
70                                 break;
71                         case CACHE_FIVE_MINUTES:
72                                 $seconds = 300;
73                                 break;
74                         case CACHE_MINUTE:
75                                 $seconds = 60;
76                                 break;
77                 }
78                 return $seconds;
79         }
80
81         /**
82          * @brief Fetch cached data according to the key
83          *
84          * @param string $key The key to the cached data
85          *
86          * @return mixed Cached $value or "null" if not found
87          */
88         public static function get($key)
89         {
90                 $memcache = self::memcache();
91                 if (is_object($memcache)) {
92                         // We fetch with the hostname as key to avoid problems with other applications
93                         $cached = $memcache->get(get_app()->get_hostname().":".$key);
94                         $value = @unserialize($cached);
95
96                         // Only return a value if the serialized value is valid.
97                         // We also check if the db entry is a serialized
98                         // boolean 'false' value (which we want to return).
99                         if ($cached === serialize(false) || $value !== false) {
100                                 return $value;
101                         }
102
103                         return null;
104                 }
105
106                 // Frequently clear cache
107                 self::clear($duration);
108
109                 $r = q(
110                         "SELECT `v` FROM `cache` WHERE `k`='%s' LIMIT 1",
111                         dbesc($key)
112                 );
113
114                 if (DBM::is_result($r)) {
115                         $cached = $r[0]['v'];
116                         $value = @unserialize($cached);
117
118                         // Only return a value if the serialized value is valid.
119                         // We also check if the db entry is a serialized
120                         // boolean 'false' value (which we want to return).
121                         if ($cached === serialize(false) || $value !== false) {
122                                 return $value;
123                         }
124                 }
125
126                 return null;
127         }
128
129         /**
130          * @brief Put data in the cache according to the key
131          *
132          * The input $value can have multiple formats.
133          *
134          * @param string  $key      The key to the cached data
135          * @param mixed   $value    The value that is about to be stored
136          * @param integer $duration The cache lifespan
137          */
138         public static function set($key, $value, $duration = CACHE_MONTH)
139         {
140                 // Do we have an installed memcache? Use it instead.
141                 $memcache = self::memcache();
142                 if (is_object($memcache)) {
143                         // We store with the hostname as key to avoid problems with other applications
144                         $memcache->set(get_app()->get_hostname().":".$key, serialize($value), MEMCACHE_COMPRESSED, self::duration($duration));
145                         return;
146                 }
147
148                 /// @todo store the cache data in the same way like the config data
149                 q(
150                         "REPLACE INTO `cache` (`k`,`v`,`expire_mode`,`updated`) VALUES ('%s','%s',%d,'%s')",
151                         dbesc($key),
152                         dbesc(serialize($value)),
153                         intval($duration),
154                         dbesc(datetime_convert())
155                 );
156         }
157
158         /**
159          * @brief Remove outdated data from the cache
160          *
161          * @param integer $max_level The maximum cache level that is to be cleared
162          */
163         public static function clear($max_level = CACHE_MONTH)
164         {
165                 // Clear long lasting cache entries only once a day
166                 if (Config::get("system", "cache_cleared_day") < time() - self::duration(CACHE_DAY)) {
167                         if ($max_level == CACHE_MONTH) {
168                                 q(
169                                         "DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d",
170                                         dbesc(datetime_convert('UTC', 'UTC', "now - 30 days")),
171                                         intval(CACHE_MONTH)
172                                 );
173                         }
174
175                         if ($max_level <= CACHE_WEEK) {
176                                 q(
177                                         "DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d",
178                                         dbesc(datetime_convert('UTC', 'UTC', "now - 7 days")),
179                                         intval(CACHE_WEEK)
180                                 );
181                         }
182
183                         if ($max_level <= CACHE_DAY) {
184                                 q(
185                                         "DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d",
186                                         dbesc(datetime_convert('UTC', 'UTC', "now - 1 days")),
187                                         intval(CACHE_DAY)
188                                 );
189                         }
190                         Config::set("system", "cache_cleared_day", time());
191                 }
192
193                 if (($max_level <= CACHE_HOUR) && (Config::get("system", "cache_cleared_hour")) < time() - self::duration(CACHE_HOUR)) {
194                         q(
195                                 "DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d",
196                                 dbesc(datetime_convert('UTC', 'UTC', "now - 1 hours")),
197                                 intval(CACHE_HOUR)
198                         );
199
200                         Config::set("system", "cache_cleared_hour", time());
201                 }
202
203                 if (($max_level <= CACHE_HALF_HOUR) && (Config::get("system", "cache_cleared_half_hour")) < time() - self::duration(CACHE_HALF_HOUR)) {
204                         q(
205                                 "DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d",
206                                 dbesc(datetime_convert('UTC', 'UTC', "now - 30 minutes")),
207                                 intval(CACHE_HALF_HOUR)
208                         );
209
210                         Config::set("system", "cache_cleared_half_hour", time());
211                 }
212
213                 if (($max_level <= CACHE_QUARTER_HOUR) && (Config::get("system", "cache_cleared_quarter_hour")) < time() - self::duration(CACHE_QUARTER_HOUR)) {
214                         q(
215                                 "DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d",
216                                 dbesc(datetime_convert('UTC', 'UTC', "now - 15 minutes")),
217                                 intval(CACHE_QUARTER_HOUR)
218                         );
219
220                         Config::set("system", "cache_cleared_quarter_hour", time());
221                 }
222
223                 if (($max_level <= CACHE_FIVE_MINUTES) && (Config::get("system", "cache_cleared_five_minute")) < time() - self::duration(CACHE_FIVE_MINUTES)) {
224                         q(
225                                 "DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d",
226                                 dbesc(datetime_convert('UTC', 'UTC', "now - 5 minutes")),
227                                 intval(CACHE_FIVE_MINUTES)
228                         );
229
230                         Config::set("system", "cache_cleared_five_minute", time());
231                 }
232
233                 if (($max_level <= CACHE_MINUTE) && (Config::get("system", "cache_cleared_minute")) < time() - self::duration(CACHE_MINUTE)) {
234                         q(
235                                 "DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d",
236                                 dbesc(datetime_convert('UTC', 'UTC', "now - 1 minutes")),
237                                 intval(CACHE_MINUTE)
238                         );
239
240                         Config::set("system", "cache_cleared_minute", time());
241                 }
242         }
243 }