]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/utils/external_cache/SugarCache.php
Add .gitignore
[Github/sugarcrm.git] / include / utils / external_cache / SugarCache.php
1 <?php
2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4  * SugarCRM is a customer relationship management program developed by
5  * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
6  * 
7  * This program is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU Affero General Public License version 3 as published by the
9  * Free Software Foundation with the addition of the following permission added
10  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11  * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
13  * 
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
17  * details.
18  * 
19  * You should have received a copy of the GNU Affero General Public License along with
20  * this program; if not, see http://www.gnu.org/licenses or write to the Free
21  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22  * 02110-1301 USA.
23  * 
24  * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25  * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
26  * 
27  * The interactive user interfaces in modified source and object code versions
28  * of this program must display Appropriate Legal Notices, as required under
29  * Section 5 of the GNU Affero General Public License version 3.
30  * 
31  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32  * these Appropriate Legal Notices must retain the display of the "Powered by
33  * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34  * technical reasons, the Appropriate Legal Notices must display the words
35  * "Powered by SugarCRM".
36  ********************************************************************************/
37
38
39 class SugarCache
40 {
41     /**
42      * Discover and return available cache adapter of false if nothing is available
43      *
44      * @return SugarCache_Abstract|false
45      */
46     function discover()
47     {
48         // If the cache is manually disabled, turn it off.
49         if(!empty($GLOBALS['sugar_config']['external_cache_disabled']) && true == $GLOBALS['sugar_config']['external_cache_disabled'])
50         {
51             if (EXTERNAL_CACHE_DEBUG) {
52                 SugarCache::log("SugarCache::discover() -- caching explicitly disabled", 'fail');
53             }
54             $GLOBALS['external_cache_enabled'] = false;
55             return SugarCache::factory('Base');
56         }
57
58         // check for Zend caching
59         if(function_exists("output_cache_get") && empty($GLOBALS['sugar_config']['external_cache_disabled_zend']))
60         {
61             $GLOBALS['external_cache_enabled'] = true;
62             $GLOBALS['external_cache_type'] = "zend";
63             $cache = SugarCache::factory('Zend');
64             if (EXTERNAL_CACHE_DEBUG) {
65                 SugarCache::log('Found Zend - attempting to use', 'pass');
66             }
67         }
68         elseif (function_exists("zend_shm_cache_store") && empty($GLOBALS['sugar_config']['external_cache_disabled_zendserver'])) {
69             $GLOBALS['external_cache_enabled'] = true;
70             $GLOBALS['external_cache_type'] = 'zendserver';
71             $cache = SugarCache::factory('ZendServer');
72             if (EXTERNAL_CACHE_DEBUG) {
73                 SugarCache::log('Found Zend Server - attempting to use', 'pass');
74             }
75         }
76         elseif (extension_loaded('memcache') && empty($GLOBALS['sugar_config']['external_cache_disabled_memcache'])) {
77             $GLOBALS['external_cache_enabled'] = true;
78             $GLOBALS['external_cache_type'] = 'memcache';
79             $cache = SugarCache::factory('Memcache');
80             if (EXTERNAL_CACHE_DEBUG) {
81                 SugarCache::log('Found memcache - attempting to use', 'pass');
82             }
83         }
84         elseif(function_exists("apc_store") && empty($GLOBALS['sugar_config']['external_cache_disabled_apc']))
85         {
86             $GLOBALS['external_cache_enabled'] = true;
87             $GLOBALS['external_cache_type'] = "apc";
88             $cache = SugarCache::factory('APC');
89             if (EXTERNAL_CACHE_DEBUG) {
90                 SugarCache::log('Found APC - attempting to use', 'pass');
91             }
92         }
93         elseif(function_exists("wincache_ucache_set") && empty($GLOBALS['sugar_config']['external_cache_disabled_wincache']))
94         {
95             $GLOBALS['external_cache_enabled'] = true;
96             $GLOBALS['external_cache_type'] = "wincache";
97             $cache = SugarCache::factory('Wincache');
98             if (EXTERNAL_CACHE_DEBUG) {
99                 SugarCache::log('Found Wincache - attempting to use', 'pass');
100             }
101         }
102         elseif(function_exists("zget") && empty($GLOBALS['sugar_config']['external_cache_disabled_smash']))
103         {
104             $GLOBALS['external_cache_enabled'] = true;
105             $GLOBALS['external_cache_type'] = "smash";
106             $cache = SugarCache::factory('sMash');
107             if (EXTERNAL_CACHE_DEBUG) {
108                 SugarCache::log('Found sMash - attempting to use', 'pass');
109             }
110         }
111         // @todo memcache
112         // @todo file cache as fallback
113         else
114         {
115             // no cache available....return
116                 $GLOBALS['external_cache_enabled'] = true;
117             $GLOBALS['external_cache_type'] = 'base-in-memory';
118             $cache = SugarCache::factory('Base');
119             if (EXTERNAL_CACHE_DEBUG) {
120                 SugarCache::log('Found no caching solution - using base');
121             }
122         }
123
124         // Check the cache.
125         if(!$cache->initialized)
126         {
127                 // Validation failed.  Turn off the external cache and return SugarCache_Base
128             $GLOBALS['external_cache_enabled'] = false;
129                 if(EXTERNAL_CACHE_DEBUG) {
130                 SugarCache::log("external cache validation check failed...tried cache {$GLOBALS['external_cache_type']}", 'fail');
131                 SugarCache::log('returning Base');
132             }
133             return SugarCache::factory('Base');
134         }
135
136         // If the cache is being reset, turn it off for this round trip
137         $value = '';
138         if(isset($GLOBALS['sugar_config']) && isset($GLOBALS['sugar_config']['unique_key']))
139         {
140             $value = $cache->get($GLOBALS['sugar_config']['unique_key'].'EXTERNAL_CACHE_RESET');
141         }
142         if(!empty($value))
143         {
144             // We are in a cache reset, do not use the cache.
145             $GLOBALS['external_cache_enabled'] = false;
146         }
147         else
148         {
149             // Add one to the external cache hits.  This will keep the end user statistics simple.
150             // All real checks suceeding will result in 100%.  Otherwise people will be looking for
151             // the one check that did not pass.
152                 $GLOBALS['external_cache_request_external_hits']++;
153         }
154         return $cache;
155     }
156
157     function factory($type)
158     {
159         $class = 'SugarCache_' . $type;
160         $cache = new $class();
161         $cache->init();
162         return $cache;
163     }
164
165     /**
166      * Performs basic logging for messages generated by the external caching mechanism
167      *
168      * Currently this only outputs directly to the screen as it's only used internally.
169      *
170      * There are five supported $type values:
171      *  neutral     :: just a log message with information value
172      *  pass        :: a pass that attention should be brought to
173      *  lightpass   :: a pass without much consequence
174      *  fail        :: a fail that attention should be brought to
175      *  lightfail   :: a failure without much consequence, or one that might succeed later in
176      *                 the execution chain
177      *
178      * @param string $msg Message to output.  Note it will be filtered through htmlspecialchars()
179      * @param string $type Type of message to output
180      */
181     function log($msg, $type = 'neutral') {
182         static $messages = array();
183         static $valid_types = array(
184             'neutral' => '',
185             'pass' => '',
186             'lightpass' => '',
187             'fail' => '',
188             'lightfail' => '',
189         );
190
191         if (!isset($valid_types[$type])) {
192             SugarCache::log("Invalid type provided: {$type}", 'fail');
193             $type = 'neutral';
194         }
195         $session_id = session_id();
196         if (empty($session_id)) {
197             // add to stack of messages to output after the session starts so we don't kill the headers
198             $messages[] = array(
199                 'message' => htmlspecialchars($msg),
200                 'type' => $type,
201             );
202         } else {
203             if ($messages !== false) {
204                 // output base styles on first round trip - this doesn't worry that its
205                 // not in the proper place as its for debugging purposes only.
206                 echo "<style type='text/css'>"
207                     . "hr +span { padding:3px 5px; display:block; } "
208                     . "hr +.pass { background-color:green; color: white; } "
209                     . "hr +.lightpass { background-color: #CFC; color:black; }"
210                     . "hr +.fail { background-color:red; color:white; } "
211                     . "hr +.lightfail { background-color:#F99; color: black; }"
212                     . "hr +.neutral { background-color:#FFFFE0; color:black; } "
213                     . "</style>";
214             }
215             if ($messages !== false && count($messages) > 0) {
216                 // clear stack of messages;
217                 echo '<hr />Messages logged prior to session starting...<hr />', "\n";
218                 foreach ($messages as $id => $old_msg) {
219                     echo "<hr /><span class='{$old_msg['type']}'>{$id} -- {$old_msg['message']}</span><hr />\n";
220                 }
221                 echo "<hr />End of messages prior to session starting...<hr />\n";
222             }
223             $messages = false;
224             $msg = htmlspecialchars($msg);
225             echo "<hr /><span class='{$type}'>{$msg}</span><hr />\n";
226         }
227
228     }
229 }