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

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

First set of changes towards 2.2.0. Improved functinoality with integration in wordpress; bugs fixed.

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