1<?php 2/** 3 * Zend Framework 4 * 5 * LICENSE 6 * 7 * This source file is subject to the new BSD license that is bundled 8 * with this package in the file LICENSE.txt. 9 * It is also available through the world-wide-web at this URL: 10 * http://framework.zend.com/license/new-bsd 11 * If you did not receive a copy of the license and are unable to 12 * obtain it through the world-wide-web, please send an email 13 * to license@zend.com so we can send you a copy immediately. 14 * 15 * @category Zend 16 * @package Zend_Cache 17 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 18 * @license http://framework.zend.com/license/new-bsd New BSD License 19 * @version $Id$ 20 */ 21 22 23/** 24 * @package Zend_Cache 25 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 26 * @license http://framework.zend.com/license/new-bsd New BSD License 27 */ 28abstract class Zend_Cache 29{ 30 31 /** 32 * Standard frontends 33 * 34 * @var array 35 */ 36 public static $standardFrontends = array('Core', 'Output', 'Class', 'File', 'Function', 'Page'); 37 38 /** 39 * Standard backends 40 * 41 * @var array 42 */ 43 public static $standardBackends = array('File', 'Sqlite', 'Memcached', 'Libmemcached', 'Apc', 'ZendPlatform', 44 'Xcache', 'TwoLevels', 'WinCache', 'ZendServer_Disk', 'ZendServer_ShMem'); 45 46 /** 47 * Standard backends which implement the ExtendedInterface 48 * 49 * @var array 50 */ 51 public static $standardExtendedBackends = array('File', 'Apc', 'TwoLevels', 'Memcached', 'Libmemcached', 'Sqlite', 'WinCache'); 52 53 /** 54 * Only for backward compatibility (may be removed in next major release) 55 * 56 * @var array 57 * @deprecated 58 */ 59 public static $availableFrontends = array('Core', 'Output', 'Class', 'File', 'Function', 'Page'); 60 61 /** 62 * Only for backward compatibility (may be removed in next major release) 63 * 64 * @var array 65 * @deprecated 66 */ 67 public static $availableBackends = array('File', 'Sqlite', 'Memcached', 'Libmemcached', 'Apc', 'ZendPlatform', 'Xcache', 'WinCache', 'TwoLevels'); 68 69 /** 70 * Consts for clean() method 71 */ 72 const CLEANING_MODE_ALL = 'all'; 73 const CLEANING_MODE_OLD = 'old'; 74 const CLEANING_MODE_MATCHING_TAG = 'matchingTag'; 75 const CLEANING_MODE_NOT_MATCHING_TAG = 'notMatchingTag'; 76 const CLEANING_MODE_MATCHING_ANY_TAG = 'matchingAnyTag'; 77 78 /** 79 * Factory 80 * 81 * @param mixed $frontend frontend name (string) or Zend_Cache_Frontend_ object 82 * @param mixed $backend backend name (string) or Zend_Cache_Backend_ object 83 * @param array $frontendOptions associative array of options for the corresponding frontend constructor 84 * @param array $backendOptions associative array of options for the corresponding backend constructor 85 * @param boolean $customFrontendNaming if true, the frontend argument is used as a complete class name ; if false, the frontend argument is used as the end of "Zend_Cache_Frontend_[...]" class name 86 * @param boolean $customBackendNaming if true, the backend argument is used as a complete class name ; if false, the backend argument is used as the end of "Zend_Cache_Backend_[...]" class name 87 * @param boolean $autoload if true, there will no require_once for backend and frontend (useful only for custom backends/frontends) 88 * @throws Zend_Cache_Exception 89 * @return Zend_Cache_Core|Zend_Cache_Frontend 90 */ 91 public static function factory($frontend, $backend, $frontendOptions = array(), $backendOptions = array(), $customFrontendNaming = false, $customBackendNaming = false, $autoload = false) 92 { 93 if (is_string($backend)) { 94 $backendObject = self::_makeBackend($backend, $backendOptions, $customBackendNaming, $autoload); 95 } else { 96 if ((is_object($backend)) && (in_array('Zend_Cache_Backend_Interface', class_implements($backend)))) { 97 $backendObject = $backend; 98 } else { 99 self::throwException('backend must be a backend name (string) or an object which implements Zend_Cache_Backend_Interface'); 100 } 101 } 102 if (is_string($frontend)) { 103 $frontendObject = self::_makeFrontend($frontend, $frontendOptions, $customFrontendNaming, $autoload); 104 } else { 105 if (is_object($frontend)) { 106 $frontendObject = $frontend; 107 } else { 108 self::throwException('frontend must be a frontend name (string) or an object'); 109 } 110 } 111 $frontendObject->setBackend($backendObject); 112 return $frontendObject; 113 } 114 115 /** 116 * Backend Constructor 117 * 118 * @param string $backend 119 * @param array $backendOptions 120 * @param boolean $customBackendNaming 121 * @param boolean $autoload 122 * @return Zend_Cache_Backend 123 */ 124 public static function _makeBackend($backend, $backendOptions, $customBackendNaming = false, $autoload = false) 125 { 126 if (!$customBackendNaming) { 127 $backend = self::_normalizeName($backend); 128 } 129 if (in_array($backend, Zend_Cache::$standardBackends)) { 130 // we use a standard backend 131 $backendClass = 'Zend_Cache_Backend_' . $backend; 132 // security controls are explicit 133 } else { 134 // we use a custom backend 135 if (!preg_match('~^[\w\\\\]+$~D', $backend)) { 136 Zend_Cache::throwException("Invalid backend name [$backend]"); 137 } 138 if (!$customBackendNaming) { 139 // we use this boolean to avoid an API break 140 $backendClass = 'Zend_Cache_Backend_' . $backend; 141 } else { 142 $backendClass = $backend; 143 } 144 if (!$autoload) { 145 $file = str_replace('_', DIRECTORY_SEPARATOR, $backendClass) . '.php'; 146 if (!(self::_isReadable($file))) { 147 self::throwException("file $file not found in include_path"); 148 } 149 } 150 } 151 return new $backendClass($backendOptions); 152 } 153 154 /** 155 * Frontend Constructor 156 * 157 * @param string $frontend 158 * @param array $frontendOptions 159 * @param boolean $customFrontendNaming 160 * @param boolean $autoload 161 * @return Zend_Cache_Core|Zend_Cache_Frontend 162 */ 163 public static function _makeFrontend($frontend, $frontendOptions = array(), $customFrontendNaming = false, $autoload = false) 164 { 165 if (!$customFrontendNaming) { 166 $frontend = self::_normalizeName($frontend); 167 } 168 if (in_array($frontend, self::$standardFrontends)) { 169 // we use a standard frontend 170 // For perfs reasons, with frontend == 'Core', we can interact with the Core itself 171 $frontendClass = 'Zend_Cache_' . ($frontend != 'Core' ? 'Frontend_' : '') . $frontend; 172 // security controls are explicit 173 } else { 174 // we use a custom frontend 175 if (!preg_match('~^[\w\\\\]+$~D', $frontend)) { 176 Zend_Cache::throwException("Invalid frontend name [$frontend]"); 177 } 178 if (!$customFrontendNaming) { 179 // we use this boolean to avoid an API break 180 $frontendClass = 'Zend_Cache_Frontend_' . $frontend; 181 } else { 182 $frontendClass = $frontend; 183 } 184 if (!$autoload) { 185 $file = str_replace('_', DIRECTORY_SEPARATOR, $frontendClass) . '.php'; 186 if (!(self::_isReadable($file))) { 187 self::throwException("file $file not found in include_path"); 188 } 189 } 190 } 191 return new $frontendClass($frontendOptions); 192 } 193 194 /** 195 * Throw an exception 196 * 197 * Note : for perf reasons, the "load" of Zend/Cache/Exception is dynamic 198 * @param string $msg Message for the exception 199 * @throws Zend_Cache_Exception 200 */ 201 public static function throwException($msg, Exception $e = null) 202 { 203 // For perfs reasons, we use this dynamic inclusion 204 throw new Zend_Cache_Exception($msg, 0, $e); 205 } 206 207 /** 208 * Normalize frontend and backend names to allow multiple words TitleCased 209 * 210 * @param string $name Name to normalize 211 * @return string 212 */ 213 protected static function _normalizeName($name) 214 { 215 $name = ucfirst(strtolower($name)); 216 $name = str_replace(array('-', '_', '.'), ' ', $name); 217 $name = ucwords($name); 218 $name = str_replace(' ', '', $name); 219 if (stripos($name, 'ZendServer') === 0) { 220 $name = 'ZendServer_' . substr($name, strlen('ZendServer')); 221 } 222 223 return $name; 224 } 225 226 /** 227 * Returns TRUE if the $filename is readable, or FALSE otherwise. 228 * This function uses the PHP include_path, where PHP's is_readable() 229 * does not. 230 * 231 * Note : this method comes from Zend_Loader (see #ZF-2891 for details) 232 * 233 * @param string $filename 234 * @return boolean 235 */ 236 private static function _isReadable($filename) 237 { 238 if (!$fh = @fopen($filename, 'r', true)) { 239 return false; 240 } 241 @fclose($fh); 242 return true; 243 } 244 245} 246