apc-emulation.php 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. <?php
  2. // Copyright (c) 2010-2017 Combodo SARL
  3. //
  4. // This file is part of iTop.
  5. //
  6. // iTop is free software; you can redistribute it and/or modify
  7. // it under the terms of the GNU Affero General Public License as published by
  8. // the Free Software Foundation, either version 3 of the License, or
  9. // (at your option) any later version.
  10. //
  11. // iTop is distributed in the hope that it will be useful,
  12. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. // GNU Affero General Public License for more details.
  15. //
  16. // You should have received a copy of the GNU Affero General Public License
  17. // along with iTop. If not, see <http://www.gnu.org/licenses/>
  18. //
  19. /**
  20. * Date: 27/09/2017
  21. */
  22. /**
  23. * @param string $cache_type
  24. * @param bool $limited
  25. * @return array|bool
  26. */
  27. function apc_cache_info($cache_type = '', $limited = false)
  28. {
  29. $aInfo = array();
  30. $sRootCacheDir = apc_emul_get_cache_filename('');
  31. $aInfo['cache_list'] = apc_emul_get_cache_entries($sRootCacheDir);
  32. return $aInfo;
  33. }
  34. function apc_emul_get_cache_entries($sEntry)
  35. {
  36. $aResult = array();
  37. if (is_dir($sEntry))
  38. {
  39. $aFiles = array_diff(scandir($sEntry), array('.', '..'));
  40. foreach($aFiles as $sFile)
  41. {
  42. $sSubFile = $sEntry.'/'.$sFile;
  43. $aResult = array_merge($aResult, apc_emul_get_cache_entries($sSubFile));
  44. }
  45. }
  46. else
  47. {
  48. $sKey = basename($sEntry);
  49. if (strpos($sKey, '-') === 0)
  50. {
  51. $sKey = substr($sKey, 1);
  52. }
  53. $aResult[] = array('info' => $sKey);
  54. }
  55. return $aResult;
  56. }
  57. /**
  58. * @param array|string $key
  59. * @param $var
  60. * @param int $ttl
  61. * @return array|bool
  62. */
  63. function apc_store($key, $var = NULL, $ttl = 0)
  64. {
  65. if (is_array($key))
  66. {
  67. $aResult = array();
  68. foreach($key as $sKey => $value)
  69. {
  70. $aResult[] = apc_emul_store_unit($sKey, $value, $ttl);
  71. }
  72. return $aResult;
  73. }
  74. return apc_emul_store_unit($key, $var, $ttl);
  75. }
  76. /**
  77. * @param string $sKey
  78. * @param $value
  79. * @param int $iTTL time to live
  80. * @return bool
  81. */
  82. function apc_emul_store_unit($sKey, $value, $iTTL)
  83. {
  84. if ($iTTL > 0)
  85. {
  86. // hint for ttl management
  87. $sKey = '-'.$sKey;
  88. }
  89. $sFilename = apc_emul_get_cache_filename($sKey);
  90. // try to create the folder
  91. $sDirname = dirname($sFilename);
  92. if (!file_exists($sDirname))
  93. {
  94. if (!@mkdir($sDirname, 0755, true))
  95. {
  96. return false;
  97. }
  98. }
  99. $bRes = !(@file_put_contents($sFilename, serialize($value), LOCK_EX) === false);
  100. apc_emul_manage_new_entry($sFilename);
  101. return $bRes;
  102. }
  103. /**
  104. * @param $key string|array
  105. * @return mixed
  106. */
  107. function apc_fetch($key)
  108. {
  109. if (is_array($key))
  110. {
  111. $aResult = array();
  112. foreach($key as $sKey)
  113. {
  114. $aResult[$sKey] = apc_emul_fetch_unit($sKey);
  115. }
  116. return $aResult;
  117. }
  118. return apc_emul_fetch_unit($key);
  119. }
  120. /**
  121. * @param $sKey
  122. * @return bool|mixed
  123. */
  124. function apc_emul_fetch_unit($sKey)
  125. {
  126. // Try the 'TTLed' version
  127. $sValue = apc_emul_readcache_locked(apc_emul_get_cache_filename('-'.$sKey));
  128. if ($sValue === false)
  129. {
  130. $sValue = apc_emul_readcache_locked(apc_emul_get_cache_filename($sKey));
  131. if ($sValue === false)
  132. {
  133. return false;
  134. }
  135. }
  136. $oRes = @unserialize($sValue);
  137. return $oRes;
  138. }
  139. function apc_emul_readcache_locked($sFilename)
  140. {
  141. $file = @fopen($sFilename, 'r');
  142. if ($file === false)
  143. {
  144. return false;
  145. }
  146. flock($file, LOCK_SH);
  147. $sContent = @fread($file, @filesize($sFilename));
  148. flock($file, LOCK_UN);
  149. fclose($file);
  150. return $sContent;
  151. }
  152. /**
  153. * @param string $cache_type
  154. * @return bool
  155. */
  156. function apc_clear_cache($cache_type = '')
  157. {
  158. $sRootCacheDir = apc_emul_get_cache_filename('');
  159. apc_emul_delete_entry($sRootCacheDir);
  160. return true;
  161. }
  162. function apc_emul_delete_entry($sCache)
  163. {
  164. if (is_dir($sCache))
  165. {
  166. $aFiles = array_diff(scandir($sCache), array('.', '..'));
  167. foreach($aFiles as $sFile)
  168. {
  169. $sSubFile = $sCache.'/'.$sFile;
  170. if (!apc_emul_delete_entry($sSubFile))
  171. {
  172. return false;
  173. }
  174. }
  175. if (!@rmdir($sCache))
  176. {
  177. return false;
  178. }
  179. }
  180. else
  181. {
  182. if (!@unlink($sCache))
  183. {
  184. return false;
  185. }
  186. }
  187. return true;
  188. }
  189. /**
  190. * @param $key
  191. * @return bool|string[]
  192. */
  193. function apc_delete($key)
  194. {
  195. return apc_emul_delete_entry(apc_emul_get_cache_filename($key));
  196. }
  197. function apc_emul_get_cache_filename($sKey)
  198. {
  199. $sPath = str_replace(array(' ', '/', '\\', '.'), '-', $sKey);
  200. return utils::GetCachePath().'apc-emul/'.$sPath;
  201. }
  202. /** Manage the cache files when a new cache entry is added
  203. * @param string $sNewFilename new cache file added
  204. */
  205. function apc_emul_manage_new_entry($sNewFilename)
  206. {
  207. // Check only once per request
  208. static $aFilesByTime = null;
  209. static $iFileCount = 0;
  210. $iMaxFiles = MetaModel::GetConfig()->Get('apc_cache_emulation.max_entries');
  211. if ($iMaxFiles == 0)
  212. {
  213. return;
  214. }
  215. if (!$aFilesByTime)
  216. {
  217. $sRootCacheDir = apc_emul_get_cache_filename('');
  218. $aFilesByTime = apc_emul_list_files_time($sRootCacheDir);
  219. $iFileCount = count($aFilesByTime);
  220. if ($iMaxFiles !== 0)
  221. {
  222. asort($aFilesByTime);
  223. }
  224. }
  225. else
  226. {
  227. $aFilesByTime[$sNewFilename] = time();
  228. $iFileCount++;
  229. }
  230. if ($iFileCount > $iMaxFiles)
  231. {
  232. $iFileNbToRemove = $iFileCount - $iMaxFiles;
  233. foreach($aFilesByTime as $sFileToRemove => $iTime)
  234. {
  235. @unlink($sFileToRemove);
  236. if ($iFileNbToRemove-- === 0)
  237. {
  238. break;
  239. }
  240. }
  241. $aFilesByTime = array_slice($aFilesByTime, $iFileCount - $iMaxFiles, null, true);
  242. $iFileCount = $iMaxFiles;
  243. }
  244. }
  245. /** Get the list of files with their associated access time
  246. * @param string $sCheck Directory to scan
  247. * @param array $aFilesByTime used by recursion
  248. * @return array
  249. */
  250. function apc_emul_list_files_time($sCheck, &$aFilesByTime = array())
  251. {
  252. // Garbage collection
  253. $aFiles = array_diff(@scandir($sCheck), array('.', '..'));
  254. foreach($aFiles as $sFile)
  255. {
  256. $sSubFile = $sCheck.'/'.$sFile;
  257. if (is_dir($sSubFile))
  258. {
  259. apc_emul_list_files_time($sSubFile, $aFilesByTime);
  260. }
  261. else
  262. {
  263. $iTime = apc_emul_get_file_time($sSubFile);
  264. if ($iTime !== false)
  265. {
  266. $aFilesByTime[$sSubFile] = $iTime;
  267. }
  268. }
  269. }
  270. return $aFilesByTime;
  271. }
  272. /** Get the file access time if TTL is managed
  273. * @param string $sFilename
  274. * @return bool|int returns the file atime or false if not relevant
  275. */
  276. function apc_emul_get_file_time($sFilename)
  277. {
  278. if (strpos(basename($sFilename), '-') === 0)
  279. {
  280. return @fileatime($sFilename);
  281. }
  282. return false;
  283. }