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

Last change on this file since 468 was 468, checked in by anonymous, 10 years ago

Completed integrating /branches/eli_branch into /trunk. Changes include:

  • Removed closing ?> from end of files
  • Upgrade old-style contructor methods to use construct() instead.
  • Class properties and methods defined as public, private, static or protected
  • Ensure code runs under E_ALL with only mysql_* deprecated warnings
  • Search for the '@' symbol anywhere it might be used to supress runtime errors, then replace with proper error recovery.
  • Run the php cli -l option to check files for syntax errors.
  • Bring tests up-to-date with latest version and methods of PHPUnit
File size: 9.7 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 * @author  Quinn Comendant <quinn@strangecode.com>
30 * @version 2.1
31 * @since   2001
32 */
33
34class Cache {
35
36    // A place to keep object instances for the singleton pattern.
37    private static $instances = array();
38
39    // Namespace of this instance of Prefs.
40    private $_ns;
41
42    // Configuration parameters for this object.
43    private $_params = array(
44
45        // Type of cache. Currently only 'session' is supported.
46        'type' => 'session',
47
48        // If false nothing will be cached or retrieved. Useful for testing realtime data requests.
49        'enabled' => true,
50
51        // The maximum size in bytes of any one variable.
52        'item_size_limit' => 4194304, // 4 MB
53
54        // The maximum size in bytes before the cache will begin flushing out old items.
55        'stack_size_limit' => 4194304, // 4 MB
56
57        // The minimum items to keep in the cache regardless of item or cache size.
58        'min_items' => 5,
59    );
60
61    /*
62    * Constructor. This is publically accessible for compatability with older implementations,
63    * but the preferred method of instantiation is by use of the singleton pattern:
64    *   $cache =& Cache::getInstance('namespace');
65    *   $cache->setParam(array('enabled' => true));
66    *
67    * @access   public
68    * @param    string  $namespace  This object will store data under this realm.
69    * @author   Quinn Comendant <quinn@strangecode.com>
70    * @version  1.0
71    * @since    05 Jun 2006 23:14:21
72    */
73    public function __construct($namespace='')
74    {
75        $app =& App::getInstance();
76
77        $this->_ns = $namespace;
78
79        if (true !== $app->getParam('enable_session')) {
80            $app->logMsg('Cache disabled, enable_session is false.', LOG_DEBUG, __FILE__, __LINE__);
81            $this->setParam(array('enabled' => false));
82        }
83
84        if (!isset($_SESSION['_cache'][$this->_ns])) {
85            $this->clear();
86        }
87    }
88
89    /**
90     * This method enforces the singleton pattern for this class.
91     *
92     * @return  object  Reference to the global Cache object.
93     * @access  public
94     * @static
95     */
96    public static function &getInstance($namespace='')
97    {
98        if (!array_key_exists($namespace, self::$instances)) {
99            self::$instances[$namespace] = new self($namespace);
100        }
101        return self::$instances[$namespace];
102    }
103
104    /**
105     * Set (or overwrite existing) parameters by passing an array of new parameters.
106     *
107     * @access public
108     * @param  array    $params     Array of parameters (key => val pairs).
109     */
110    public function setParam($params)
111    {
112        $app =& App::getInstance();
113
114        if (isset($params) && is_array($params)) {
115            // Merge new parameters with old overriding only those passed.
116            $this->_params = array_merge($this->_params, $params);
117        } else {
118            $app->logMsg(sprintf('Parameters are not an array: %s', $params), LOG_ERR, __FILE__, __LINE__);
119        }
120    }
121
122    /**
123     * Return the value of a parameter, if it exists.
124     *
125     * @access public
126     * @param string $param        Which parameter to return.
127     * @return mixed               Configured parameter value.
128     */
129    public function getParam($param)
130    {
131        $app =& App::getInstance();
132
133        if (isset($this->_params[$param])) {
134            return $this->_params[$param];
135        } else {
136            $app->logMsg(sprintf('Parameter is not set: %s', $param), LOG_DEBUG, __FILE__, __LINE__);
137            return null;
138        }
139    }
140
141    /**
142     * Stores a new variable in the session cache. The $key should not be numeric
143     * because the array_shift function will reset the key to the next largest
144     * int key. Weird behavior I can't understand. For example $cache["123"] will become $cache[0]
145     *
146     * @param str   $key                An identifier for the cached object.
147     * @param mixed $var                The data to store in the session cache.
148     * @param bool  $allow_oversized    If we have something really big that we still want to cache, setting this to true allows this.
149     * @return bool                     True on success, false otherwise.
150     */
151    public function set($key, $var, $allow_oversized=false)
152    {
153        $app =& App::getInstance();
154
155        if (true !== $this->getParam('enabled')) {
156            $app->logMsg(sprintf('Cache disabled, not saving data.', null), LOG_DEBUG, __FILE__, __LINE__);
157            return false;
158        }
159
160        if (is_numeric($key)) {
161            $app->logMsg(sprintf('Cache::set key value should not be numeric (%s given)', $key), LOG_WARNING, __FILE__, __LINE__);
162        }
163
164        $var = serialize($var);
165        $var_len = mb_strlen($var);
166
167        if ($var_len >= $this->getParam('item_size_limit')) {
168            $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__);
169            return false;
170        }
171
172        if ($allow_oversized && $var_len >= $this->getParam('stack_size_limit')) {
173            $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__);
174            return false;
175        }
176
177        // Remove any value already stored under this key.
178        unset($_SESSION['_cache'][$this->_ns][$key]);
179
180        // Continue to prune the cache if its size is greater than stack_size_limit, but keep at least min_items.
181        while (mb_strlen(serialize($_SESSION['_cache'][$this->_ns])) + $var_len >= $this->getParam('stack_size_limit') && sizeof($_SESSION['_cache'][$this->_ns]) >= $this->getParam('min_items')) {
182            array_shift($_SESSION['_cache'][$this->_ns]);
183        }
184
185        // Save this value under the specified key.
186        $_SESSION['_cache'][$this->_ns][$key] =& $var;
187
188        if ($var_len >= 1024000) {
189            $app->logMsg(sprintf('Successfully cached oversized variable (%s bytes).', $var_len), LOG_DEBUG, __FILE__, __LINE__);
190        }
191
192        return true;
193    }
194
195    /**
196     * Retrieves an object from the session cache and returns it unserialized.
197     * It also moves it to the top of the stack, which makes it such that the
198     * cache flushing mechanism of putCache deletes the oldest referenced items
199     * first.
200     *
201     * @param string $key  The key for the datum to retrieve.
202     * @return mixed          The requested datum, or false on failure.
203     */
204    public function get($key)
205    {
206        $app =& App::getInstance();
207
208        if (true !== $this->getParam('enabled')) {
209            $app->logMsg(sprintf('Cache disabled, not getting data.', null), LOG_DEBUG, __FILE__, __LINE__);
210            return false;
211        }
212
213        if (array_key_exists($key, $_SESSION['_cache'][$this->_ns])) {
214            $app->logMsg(sprintf('Retreiving %s from cache.', $key), LOG_DEBUG, __FILE__, __LINE__);
215            // Move the accessed cached datum to the top of the stack. Maybe somebody knows a better way to do this?
216            $tmp =& $_SESSION['_cache'][$this->_ns][$key];
217            unset($_SESSION['_cache'][$this->_ns][$key]);
218            $_SESSION['_cache'][$this->_ns][$key] =& $tmp;
219            // Return the unserialized datum.
220            return unserialize($_SESSION['_cache'][$this->_ns][$key]);
221        } else {
222            $app->logMsg(sprintf('Missing %s from cache.', $key), LOG_DEBUG, __FILE__, __LINE__);
223            return false;
224        }
225    }
226
227    /**
228     * Tells you if the object is cached.
229     *
230     * @param string $key  The key of the object to check.
231     * @return bool         True if a value exists for the given key.
232     */
233    public function exists($key)
234    {
235        $app =& App::getInstance();
236
237        if (true !== $this->getParam('enabled')) {
238            $app->logMsg(sprintf('Cache disabled on exist assertion.', null), LOG_DEBUG, __FILE__, __LINE__);
239            return false;
240        }
241
242        return array_key_exists($key, $_SESSION['_cache'][$this->_ns]);
243    }
244
245    /**
246     * Removes a cached object.
247     *
248     * @param string $key  The key of the object to check.
249     * @return bool         True if the value existed before being unset.
250     */
251    public function delete($key)
252    {
253        if (array_key_exists($key, $_SESSION['_cache'][$this->_ns])) {
254            unset($_SESSION['_cache'][$this->_ns][$key]);
255            return true;
256        } else {
257            return false;
258        }
259    }
260
261    /*
262    * Delete all existing items from the cache.
263    *
264    * @access   public
265    * @author   Quinn Comendant <quinn@strangecode.com>
266    * @version  1.0
267    * @since    05 Jun 2006 23:51:34
268    */
269    public function clear()
270    {
271        $_SESSION['_cache'][$this->_ns] = array();
272    }
273
274// END Cache
275}
276
Note: See TracBrowser for help on using the repository browser.