source: trunk/lib/Cache.inc.php @ 534

Last change on this file since 534 was 534, checked in by anonymous, 9 years ago

Improved module maker validation output. Allow disabling cache at run time for ACL. Added ACL getList() method. Improved ACL CLI listing. Fixed app boomerang array initialization. Now retaining identical boomerang URLs if the key is different. Added a maximum boomerang time. Added a way to disable cache per request through a query string. Added validator isDecimal() method. Added disableSelectOptions() HTML method. Added getGravatarURL() method. Change how navigation page array is managed. Updated navigation currentPage() method to test an array of URLs.

File size: 10.4 KB
Line 
1<?php
2/**
3 * The Strangecode Codebase - a general application development framework for PHP
4 * For details visit the project site: <http://trac.strangecode.com/codebase/>
5 * Copyright 2001-2012 Strangecode, LLC
6 *
7 * This file is part of The Strangecode Codebase.
8 *
9 * The Strangecode Codebase is free software: you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as published by the
11 * Free Software Foundation, either version 3 of the License, or (at your option)
12 * any later version.
13 *
14 * The Strangecode Codebase is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * The Strangecode Codebase. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23/**
24 * Cache.inc.php
25 *
26 * Provides an API for storing a limited amount of data
27 * intended to have a short lifetime in a user's session.
28 *
29 * Disable cache per-request by adding '_disable_cache=1' to a GET or POST parameter.
30 *
31 * @author  Quinn Comendant <quinn@strangecode.com>
32 * @version 2.1
33 * @since   2001
34 */
35
36class Cache
37{
38
39    // A place to keep object instances for the singleton pattern.
40    protected static $instances = array();
41
42    // Namespace of this instance of Prefs.
43    protected $_ns;
44
45    // Configuration parameters for this object.
46    protected $_params = array(
47
48        // Type of cache. Currently only 'session' is supported.
49        'type' => 'session',
50
51        // If false nothing will be cached or retrieved. Useful for testing realtime data requests.
52        'enabled' => true,
53
54        // The maximum size in bytes of any one variable.
55        'item_size_limit' => 4194304, // 4 MB
56
57        // The maximum size in bytes before the cache will begin flushing out old items.
58        'stack_size_limit' => 4194304, // 4 MB
59
60        // The minimum items to keep in the cache regardless of item or cache size.
61        'min_items' => 5,
62    );
63
64    /*
65    * Constructor. This is publically accessible for compatability with older implementations,
66    * but the preferred method of instantiation is by use of the singleton pattern:
67    *   $cache =& Cache::getInstance('namespace');
68    *   $cache->setParam(array('enabled' => true));
69    *
70    * @access   public
71    * @param    string  $namespace  This object will store data under this realm.
72    * @author   Quinn Comendant <quinn@strangecode.com>
73    * @version  1.0
74    * @since    05 Jun 2006 23:14:21
75    */
76    public function __construct($namespace='')
77    {
78        $app =& App::getInstance();
79
80        $this->_ns = $namespace;
81
82        if (true !== $app->getParam('enable_session')) {
83            // Force disable the cache because there is no session to save to.
84            $app->logMsg('Cache disabled, enable_session != true.', LOG_DEBUG, __FILE__, __LINE__);
85            $this->setParam(array('enabled' => false));
86        } else if (!isset($_SESSION['_cache'][$this->_ns])) {
87            // Otherwise, clear to initialize the session variable.
88            $this->clear();
89        }
90    }
91
92    /**
93     * This method enforces the singleton pattern for this class.
94     *
95     * @return  object  Reference to the global Cache object.
96     * @access  public
97     * @static
98     */
99    public static function &getInstance($namespace='')
100    {
101        if (!array_key_exists($namespace, self::$instances)) {
102            self::$instances[$namespace] = new self($namespace);
103        }
104        return self::$instances[$namespace];
105    }
106
107    /**
108     * Set (or overwrite existing) parameters by passing an array of new parameters.
109     *
110     * @access public
111     * @param  array    $params     Array of parameters (key => val pairs).
112     */
113    public function setParam($params)
114    {
115        $app =& App::getInstance();
116
117        if (isset($params) && is_array($params)) {
118            // Merge new parameters with old overriding only those passed.
119            $this->_params = array_merge($this->_params, $params);
120        } else {
121            $app->logMsg(sprintf('Parameters are not an array: %s', $params), LOG_ERR, __FILE__, __LINE__);
122        }
123    }
124
125    /**
126     * Return the value of a parameter, if it exists.
127     *
128     * @access public
129     * @param string $param        Which parameter to return.
130     * @return mixed               Configured parameter value.
131     */
132    public function getParam($param)
133    {
134        $app =& App::getInstance();
135
136        if (array_key_exists($param, $this->_params)) {
137            return $this->_params[$param];
138        } else {
139            $app->logMsg(sprintf('Parameter is not set: %s', $param), LOG_DEBUG, __FILE__, __LINE__);
140            return null;
141        }
142    }
143
144    /**
145     * Stores a new variable in the session cache. The $key should not be numeric
146     * because the array_shift function will reset the key to the next largest
147     * int key. Weird behavior I can't understand. For example $cache["123"] will become $cache[0]
148     *
149     * @param str   $key                An identifier for the cached object.
150     * @param mixed $var                The data to store in the session cache.
151     * @param bool  $allow_oversized    If we have something really big that we still want to cache, setting this to true allows this.
152     * @return bool                     True on success, false otherwise.
153     */
154    public function set($key, $var, $allow_oversized=false)
155    {
156        $app =& App::getInstance();
157
158        if (true !== $this->getParam('enabled') || getFormData('_disable_cache')) {
159            $app->logMsg(sprintf('Cache disabled, not saving data.', null), LOG_DEBUG, __FILE__, __LINE__);
160            return false;
161        }
162
163        if (is_numeric($key)) {
164            $app->logMsg(sprintf('Cache::set key value should not be numeric (%s given)', $key), LOG_WARNING, __FILE__, __LINE__);
165        }
166
167        $var = serialize($var);
168        $var_len = mb_strlen($var);
169
170        if ($var_len >= $this->getParam('item_size_limit')) {
171            $app->logMsg(sprintf('Serialized variable (%s bytes) more than item_size_limit (%s bytes).', $var_len, $this->getParam('item_size_limit')), LOG_NOTICE, __FILE__, __LINE__);
172            return false;
173        }
174
175        if ($allow_oversized && $var_len >= $this->getParam('stack_size_limit')) {
176            $app->logMsg(sprintf('Serialized variable (%s bytes) more than stack_size_limit (%s bytes).', $var_len, $this->getParam('stack_size_limit')), LOG_NOTICE, __FILE__, __LINE__);
177            return false;
178        }
179
180        // Remove any value already stored under this key.
181        unset($_SESSION['_cache'][$this->_ns][$key]);
182
183        // Continue to prune the cache if its size is greater than stack_size_limit, but keep at least min_items.
184        while (mb_strlen(serialize($_SESSION['_cache'][$this->_ns])) + $var_len >= $this->getParam('stack_size_limit') && sizeof($_SESSION['_cache'][$this->_ns]) >= $this->getParam('min_items')) {
185            array_shift($_SESSION['_cache'][$this->_ns]);
186        }
187
188        // Save this value under the specified key.
189        $_SESSION['_cache'][$this->_ns][$key] =& $var;
190
191        if ($var_len >= 1024000) {
192            $app->logMsg(sprintf('Successfully cached oversized variable (%s bytes).', $var_len), LOG_DEBUG, __FILE__, __LINE__);
193        }
194
195        return true;
196    }
197
198    /**
199     * Retrieves an object from the session cache and returns it unserialized.
200     * It also moves it to the top of the stack, which makes it such that the
201     * cache flushing mechanism of putCache deletes the oldest referenced items
202     * first.
203     *
204     * @param string $key  The key for the datum to retrieve.
205     * @return mixed          The requested datum, or false on failure.
206     */
207    public function get($key)
208    {
209        $app =& App::getInstance();
210
211        if (true !== $this->getParam('enabled') || getFormData('_disable_cache')) {
212            $app->logMsg(sprintf('Cache disabled, not getting data.', null), LOG_DEBUG, __FILE__, __LINE__);
213            return false;
214        }
215
216        if (isset($_SESSION['_cache'][$this->_ns]) && array_key_exists($key, $_SESSION['_cache'][$this->_ns])) {
217            $app->logMsg(sprintf('Retreiving %s from cache.', $key), LOG_DEBUG, __FILE__, __LINE__);
218            // Move the accessed cached datum to the top of the stack. Maybe somebody knows a better way to do this?
219            $tmp =& $_SESSION['_cache'][$this->_ns][$key];
220            unset($_SESSION['_cache'][$this->_ns][$key]);
221            $_SESSION['_cache'][$this->_ns][$key] =& $tmp;
222            // Return the unserialized datum.
223            return unserialize($_SESSION['_cache'][$this->_ns][$key]);
224        } else {
225            $app->logMsg(sprintf('Missing %s from cache.', $key), LOG_DEBUG, __FILE__, __LINE__);
226            return false;
227        }
228    }
229
230    /**
231     * Tells you if the object is cached.
232     *
233     * @param string $key  The key of the object to check.
234     * @return bool         True if a value exists for the given key.
235     */
236    public function exists($key)
237    {
238        $app =& App::getInstance();
239
240        if (true !== $this->getParam('enabled') || getFormData('_disable_cache')) {
241            $app->logMsg(sprintf('Cache disabled on exist assertion.', null), LOG_DEBUG, __FILE__, __LINE__);
242            return false;
243        }
244
245        return (isset($_SESSION['_cache'][$this->_ns]) && array_key_exists($key, $_SESSION['_cache'][$this->_ns]));
246    }
247
248    /**
249     * Removes a cached object.
250     *
251     * @param string $key  The key of the object to check.
252     * @return bool         True if the value existed before being unset.
253     */
254    public function delete($key)
255    {
256        $app =& App::getInstance();
257
258        if (true !== $this->getParam('enabled') || getFormData('_disable_cache')) {
259            $app->logMsg(sprintf('Cache disabled, skipping delete of %s', $key), LOG_DEBUG, __FILE__, __LINE__);
260            return false;
261        }
262
263        if (isset($_SESSION['_cache'][$this->_ns]) && array_key_exists($key, $_SESSION['_cache'][$this->_ns])) {
264            unset($_SESSION['_cache'][$this->_ns][$key]);
265            return true;
266        } else {
267            return false;
268        }
269    }
270
271    /*
272    * Delete all existing items from the cache.
273    *
274    * @access   public
275    * @author   Quinn Comendant <quinn@strangecode.com>
276    * @version  1.0
277    * @since    05 Jun 2006 23:51:34
278    */
279    public function clear()
280    {
281        $_SESSION['_cache'][$this->_ns] = array();
282    }
283
284// END Cache
285}
286
Note: See TracBrowser for help on using the repository browser.