Friendica Communications Platform (please note that this is a clone of the repository at github, issues are handled there) https://friendi.ca
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

212 lines
6.3KB

  1. <?php
  2. /**
  3. * @file include/cache.php
  4. *
  5. * @brief Class for storing data for a short time
  6. */
  7. use Friendica\Core\Config;
  8. use Friendica\Core\PConfig;
  9. use Friendica\Database\DBM;
  10. class Cache {
  11. /**
  12. * @brief Check for memcache and open a connection if configured
  13. *
  14. * @return object|boolean The memcache object - or "false" if not successful
  15. */
  16. public static function memcache() {
  17. if (!function_exists('memcache_connect')) {
  18. return false;
  19. }
  20. if (!Config::get('system', 'memcache')) {
  21. return false;
  22. }
  23. $memcache_host = Config::get('system', 'memcache_host', '127.0.0.1');
  24. $memcache_port = Config::get('system', 'memcache_port', 11211);
  25. $memcache = new Memcache;
  26. if (!$memcache->connect($memcache_host, $memcache_port)) {
  27. return false;
  28. }
  29. return $memcache;
  30. }
  31. /**
  32. * @brief Return the duration for a given cache level
  33. *
  34. * @param integer $level Cache level
  35. *
  36. * @return integer The cache duration in seconds
  37. */
  38. private static function duration($level) {
  39. switch($level) {
  40. case CACHE_MONTH;
  41. $seconds = 2592000;
  42. break;
  43. case CACHE_WEEK;
  44. $seconds = 604800;
  45. break;
  46. case CACHE_DAY;
  47. $seconds = 86400;
  48. break;
  49. case CACHE_HOUR;
  50. $seconds = 3600;
  51. break;
  52. case CACHE_HALF_HOUR;
  53. $seconds = 1800;
  54. break;
  55. case CACHE_QUARTER_HOUR;
  56. $seconds = 900;
  57. break;
  58. case CACHE_FIVE_MINUTES;
  59. $seconds = 300;
  60. break;
  61. case CACHE_MINUTE;
  62. $seconds = 60;
  63. break;
  64. }
  65. return $seconds;
  66. }
  67. /**
  68. * @brief Fetch cached data according to the key
  69. *
  70. * @param string $key The key to the cached data
  71. *
  72. * @return mixed Cached $value or "null" if not found
  73. */
  74. public static function get($key) {
  75. $memcache = self::memcache();
  76. if (is_object($memcache)) {
  77. // We fetch with the hostname as key to avoid problems with other applications
  78. $cached = $memcache->get(get_app()->get_hostname().":".$key);
  79. $value = @unserialize($cached);
  80. // Only return a value if the serialized value is valid.
  81. // We also check if the db entry is a serialized
  82. // boolean 'false' value (which we want to return).
  83. if ($cached === serialize(false) || $value !== false) {
  84. return $value;
  85. }
  86. return null;
  87. }
  88. // Frequently clear cache
  89. self::clear($duration);
  90. $r = q("SELECT `v` FROM `cache` WHERE `k`='%s' LIMIT 1",
  91. dbesc($key)
  92. );
  93. if (DBM::is_result($r)) {
  94. $cached = $r[0]['v'];
  95. $value = @unserialize($cached);
  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. * @brief Put data in the cache according to the key
  107. *
  108. * The input $value can have multiple formats.
  109. *
  110. * @param string $key The key to the cached data
  111. * @param mixed $valie The value that is about to be stored
  112. * @param integer $duration The cache lifespan
  113. */
  114. public static function set($key, $value, $duration = CACHE_MONTH) {
  115. // Do we have an installed memcache? Use it instead.
  116. $memcache = self::memcache();
  117. if (is_object($memcache)) {
  118. // We store with the hostname as key to avoid problems with other applications
  119. $memcache->set(get_app()->get_hostname().":".$key, serialize($value), MEMCACHE_COMPRESSED, self::duration($duration));
  120. return;
  121. }
  122. /// @todo store the cache data in the same way like the config data
  123. q("REPLACE INTO `cache` (`k`,`v`,`expire_mode`,`updated`) VALUES ('%s','%s',%d,'%s')",
  124. dbesc($key),
  125. dbesc(serialize($value)),
  126. intval($duration),
  127. dbesc(datetime_convert()));
  128. }
  129. /**
  130. * @brief Remove outdated data from the cache
  131. *
  132. * @param integer $maxlevel The maximum cache level that is to be cleared
  133. */
  134. public static function clear($max_level = CACHE_MONTH) {
  135. // Clear long lasting cache entries only once a day
  136. if (Config::get("system", "cache_cleared_day") < time() - self::duration(CACHE_DAY)) {
  137. if ($max_level == CACHE_MONTH) {
  138. q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d",
  139. dbesc(datetime_convert('UTC','UTC',"now - 30 days")), intval(CACHE_MONTH));
  140. }
  141. if ($max_level <= CACHE_WEEK) {
  142. q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d",
  143. dbesc(datetime_convert('UTC','UTC',"now - 7 days")), intval(CACHE_WEEK));
  144. }
  145. if ($max_level <= CACHE_DAY) {
  146. q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d",
  147. dbesc(datetime_convert('UTC','UTC',"now - 1 days")), intval(CACHE_DAY));
  148. }
  149. Config::set("system", "cache_cleared_day", time());
  150. }
  151. if (($max_level <= CACHE_HOUR) && (Config::get("system", "cache_cleared_hour")) < time() - self::duration(CACHE_HOUR)) {
  152. q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d",
  153. dbesc(datetime_convert('UTC','UTC',"now - 1 hours")), intval(CACHE_HOUR));
  154. Config::set("system", "cache_cleared_hour", time());
  155. }
  156. if (($max_level <= CACHE_HALF_HOUR) && (Config::get("system", "cache_cleared_half_hour")) < time() - self::duration(CACHE_HALF_HOUR)) {
  157. q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d",
  158. dbesc(datetime_convert('UTC','UTC',"now - 30 minutes")), intval(CACHE_HALF_HOUR));
  159. Config::set("system", "cache_cleared_half_hour", time());
  160. }
  161. if (($max_level <= CACHE_QUARTER_HOUR) && (Config::get("system", "cache_cleared_quarter_hour")) < time() - self::duration(CACHE_QUARTER_HOUR)) {
  162. q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d",
  163. dbesc(datetime_convert('UTC','UTC',"now - 15 minutes")), intval(CACHE_QUARTER_HOUR));
  164. Config::set("system", "cache_cleared_quarter_hour", time());
  165. }
  166. if (($max_level <= CACHE_FIVE_MINUTES) && (Config::get("system", "cache_cleared_five_minute")) < time() - self::duration(CACHE_FIVE_MINUTES)) {
  167. q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d",
  168. dbesc(datetime_convert('UTC','UTC',"now - 5 minutes")), intval(CACHE_FIVE_MINUTES));
  169. Config::set("system", "cache_cleared_five_minute", time());
  170. }
  171. if (($max_level <= CACHE_MINUTE) && (Config::get("system", "cache_cleared_minute")) < time() - self::duration(CACHE_MINUTE)) {
  172. q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d",
  173. dbesc(datetime_convert('UTC','UTC',"now - 1 minutes")), intval(CACHE_MINUTE));
  174. Config::set("system", "cache_cleared_minute", time());
  175. }
  176. }
  177. }