DiskCachePlugin.php 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. <?php
  2. // This file is part of GNU social - https://www.gnu.org/software/social
  3. //
  4. // GNU social is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Affero General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // GNU social is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Affero General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Affero General Public License
  15. // along with GNU social. If not, see <http://www.gnu.org/licenses/>.
  16. /**
  17. * Plugin to implement cache interface with disk files
  18. *
  19. * @category Cache
  20. * @package GNUsocial
  21. * @author Evan Prodromou <evan@status.net>
  22. * @copyright 2009 StatusNet, Inc.
  23. * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
  24. */
  25. defined('GNUSOCIAL') || die();
  26. /**
  27. * A plugin to cache data on local disk
  28. *
  29. * @category Cache
  30. * @package GNUsocial
  31. * @author Evan Prodromou <evan@status.net>
  32. * @copyright 2009 StatusNet, Inc.
  33. * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
  34. */
  35. class DiskCachePlugin extends Plugin
  36. {
  37. const PLUGIN_VERSION = '2.0.0';
  38. public $root = '/tmp';
  39. public function keyToFilename($key)
  40. {
  41. return $this->root . '/' . str_replace(':', '/', $key);
  42. }
  43. /**
  44. * Get a value associated with a key
  45. *
  46. * The value should have been set previously.
  47. *
  48. * @param string &$key in; Lookup key
  49. * @param mixed &$value out; value associated with key
  50. *
  51. * @return boolean hook success
  52. */
  53. public function onStartCacheGet(&$key, &$value)
  54. {
  55. $filename = $this->keyToFilename($key);
  56. $data = false;
  57. if (file_exists($filename)) {
  58. $data = file_get_contents($filename);
  59. }
  60. if ($data === false) {
  61. return true;
  62. }
  63. $ret = unserialize($data);
  64. if ($ret === false && $data !== 'b:0;') {
  65. common_log(LOG_ERR, 'DiskCache could not handle: ' . $data);
  66. return true;
  67. }
  68. $value = $ret;
  69. return false;
  70. }
  71. /**
  72. * Associate a value with a key
  73. *
  74. * @param string &$key in; Key to use for lookups
  75. * @param mixed &$value in; Value to associate
  76. * @param integer &$flag in; Flag (passed through to Memcache)
  77. * @param integer &$expiry in; Expiry (passed through to Memcache)
  78. * @param boolean &$success out; Whether the set was successful
  79. *
  80. * @return boolean hook success
  81. */
  82. public function onStartCacheSet(&$key, &$value, &$flag, &$expiry, &$success)
  83. {
  84. $filename = $this->keyToFilename($key);
  85. $parent = dirname($filename);
  86. $sofar = '';
  87. foreach (explode('/', $parent) as $part) {
  88. if (empty($part)) {
  89. continue;
  90. }
  91. $sofar .= '/' . $part;
  92. if (!is_dir($sofar)) {
  93. $this->debug("Creating new directory '$sofar'");
  94. $success = mkdir($sofar, 0750);
  95. if (!$success) {
  96. $this->log(LOG_ERR, "Can't create directory '$sofar'");
  97. return false;
  98. }
  99. }
  100. }
  101. if (is_dir($filename)) {
  102. $success = false;
  103. return false;
  104. }
  105. // Write to a temp file and move to destination
  106. $tempname = tempnam(null, 'statusnetdiskcache');
  107. $result = file_put_contents($tempname, serialize($value));
  108. if ($result === false) {
  109. $this->log(LOG_ERR, "Couldn't write '$key' to temp file '$tempname'");
  110. return false;
  111. }
  112. $result = rename($tempname, $filename);
  113. if (!$result) {
  114. $this->log(LOG_ERR, "Couldn't move temp file '$tempname' to path '$filename' for key '$key'");
  115. @unlink($tempname);
  116. return false;
  117. }
  118. return false;
  119. }
  120. /**
  121. * Delete a value associated with a key
  122. *
  123. * @param string &$key in; Key to lookup
  124. * @param boolean &$success out; whether it worked
  125. *
  126. * @return boolean hook success
  127. */
  128. public function onStartCacheDelete(&$key, &$success)
  129. {
  130. $filename = $this->keyToFilename($key);
  131. if (file_exists($filename) && !is_dir($filename)) {
  132. unlink($filename);
  133. }
  134. return false;
  135. }
  136. public function onPluginVersion(array &$versions): bool
  137. {
  138. $versions[] = array('name' => 'DiskCache',
  139. 'version' => self::PLUGIN_VERSION,
  140. 'author' => 'Evan Prodromou',
  141. 'homepage' => GNUSOCIAL_ENGINE_REPO_URL . 'tree/master/plugins/DiskCache',
  142. 'rawdescription' =>
  143. // TRANS: Plugin description.
  144. _m('Plugin to implement cache interface with disk files.'));
  145. return true;
  146. }
  147. }