1<?php 2/** 3 * Copyright 2011-2017 Horde LLC (http://www.horde.org/) 4 * 5 * See the enclosed file COPYING for license information (LGPL). If you 6 * did not receive this file, see http://www.horde.org/licenses/lgpl21. 7 * 8 * @author Jan Schneider <jan@horde.org> 9 * @author Michael Slusarz <slusarz@horde.org> 10 * @category Horde 11 * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 12 * @package Autoloader_Cache 13 */ 14 15require_once 'Horde/Autoloader/Default.php'; 16require_once 'Horde/Autoloader/Cache/Bootstrap.php'; 17 18/** 19 * Decorator for Horde_Autoloader that implements caching of class-file-maps. 20 * 21 * @author Jan Schneider <jan@horde.org> 22 * @author Michael Slusarz <slusarz@horde.org> 23 * @category Horde 24 * @copyright 2011-2017 Horde LLC 25 * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 26 * @package Autoloader_Cache 27 */ 28class Horde_Autoloader_Cache extends Horde_Autoloader_Default 29{ 30 /* Cache types. @todo: Remove (not used) */ 31 const APC = 1; 32 const XCACHE = 2; 33 const EACCELERATOR = 3; 34 const TEMPFILE = 4; 35 36 /* Cache key prefix. */ 37 const PREFIX = 'horde_autoloader_cache'; 38 39 /* Key that holds list of autoloader cache keys. */ 40 const KEYLIST = 'horde_autoloader_keys'; 41 42 /** 43 * Map of all classes already looked up. 44 * 45 * @var array 46 */ 47 protected $_cache = array(); 48 49 /** 50 * Cache key name. 51 * 52 * @var string 53 */ 54 protected $_cachekey; 55 56 /** 57 * Has the cache changed since the last save? 58 * 59 * @var boolean 60 */ 61 protected $_changed = false; 62 63 /** 64 * Is this a new key? 65 * 66 * @var boolean 67 */ 68 protected $_newkey = false; 69 70 /** 71 */ 72 protected $_storage; 73 74 /** 75 * Constructor. 76 */ 77 public function __construct() 78 { 79 parent::__construct(); 80 81 $key = isset($_SERVER['SERVER_NAME']) 82 ? $_SERVER['SERVER_NAME'] 83 : ''; 84 $key .= '|' . __FILE__; 85 86 $this->_cachekey = self::PREFIX . '_' . hash('md5', $key); 87 $this->_storage = new Horde_Autoloader_Cache_Bootstrap(); 88 89 $data = $this->_storage->get($this->_cachekey); 90 if ($data === false) { 91 $this->_newkey = true; 92 } else { 93 $this->_cache = $data; 94 } 95 96 register_shutdown_function(array($this, 'shutdown')); 97 } 98 99 /** 100 * Shutdown method. 101 * 102 * Attempts to save the class map to the cache. 103 */ 104 public function shutdown() 105 { 106 if (!$this->_changed) { 107 return; 108 } 109 110 if (!$this->_storage->set($this->_cachekey, $this->_cache)) { 111 error_log('Cannot write Autoloader cache to backend.', 4); 112 } 113 114 if ($this->_newkey) { 115 $keylist = $this->_getKeylist(); 116 $keylist[] = $this->_cachekey; 117 $this->_saveKeylist($keylist); 118 } 119 } 120 121 /** 122 */ 123 public function loadClass($className) 124 { 125 $exists = isset($this->_cache[$className]); 126 127 if (parent::loadClass($className)) { 128 return true; 129 } 130 131 /* Cache miss. Remove cache entry and try to load again. */ 132 if ($exists) { 133 unset($this->_cache[$className]); 134 return parent::loadClass($className); 135 } 136 137 return false; 138 } 139 140 /** 141 * Search registered mappers in LIFO order. 142 * 143 * @param string $className Classname. 144 * 145 * @return string Path. 146 */ 147 public function mapToPath($className) 148 { 149 if (isset($this->_cache[$className])) { 150 return $this->_cache[$className]; 151 } 152 153 if ($res = parent::mapToPath($className)) { 154 $this->_cache[$className] = $res; 155 $this->_changed = true; 156 } 157 158 return $res; 159 } 160 161 /** 162 * Prunes the autoloader cache. 163 * 164 * @return boolean True if pruning succeeded. 165 */ 166 public function prune() 167 { 168 foreach (array_unique(array_merge($this->_getKeylist(), array($this->_cachekey))) as $val) { 169 $this->_storage->delete($val); 170 } 171 172 $this->_cache = array(); 173 174 $this->_saveKeylist(array()); 175 176 return true; 177 } 178 179 /** 180 * Returns the keylist. 181 * 182 * @return array Keylist. 183 */ 184 protected function _getKeylist() 185 { 186 $keylist = $this->_storage->get(self::KEYLIST); 187 188 return empty($keylist) 189 ? array() 190 : $keylist; 191 } 192 193 /** 194 * Saves the keylist. 195 * 196 * @param array $keylist Keylist to save. 197 */ 198 protected function _saveKeylist($keylist) 199 { 200 $keylist = $this->_storage->set(self::KEYLIST, $keylist); 201 } 202 203} 204 205spl_autoload_unregister(array($__autoloader, 'loadClass')); 206$__autoloader = new Horde_Autoloader_Cache(); 207$__autoloader->registerAutoloader(); 208