2 /************************************************************************
3 * MXChange v0.2.1 Start: 06/26/2004 *
4 * =============== Last change: 07/01/2005 *
6 * -------------------------------------------------------------------- *
7 * File : load_extensions.php *
8 * -------------------------------------------------------------------- *
9 * Short description : Load all extensions *
10 * -------------------------------------------------------------------- *
11 * Kurzbeschreibung : Alle Erweiterungen laden *
12 * -------------------------------------------------------------------- *
13 * @TODO Rewrite this whole file to load_cache-extensions.php *
14 * -------------------------------------------------------------------- *
17 * $Tag:: 0.2.1-FINAL $ *
19 * Needs to be in all Files and every File needs "svn propset *
20 * svn:keywords Date Revision" (autoprobset!) at least!!!!!! *
21 * -------------------------------------------------------------------- *
22 * Copyright (c) 2003 - 2008 by Roland Haeder *
23 * For more information visit: http://www.mxchange.org *
25 * This program is free software; you can redistribute it and/or modify *
26 * it under the terms of the GNU General Public License as published by *
27 * the Free Software Foundation; either version 2 of the License, or *
28 * (at your option) any later version. *
30 * This program is distributed in the hope that it will be useful, *
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
33 * GNU General Public License for more details. *
35 * You should have received a copy of the GNU General Public License *
36 * along with this program; if not, write to the Free Software *
37 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, *
39 ************************************************************************/
41 // Some security stuff...
42 if (!defined('__SECURITY')) {
43 $INC = substr(dirname(__FILE__), 0, strpos(dirname(__FILE__), '/inc') + 4) . '/security.php';
51 // Init cache instance and array
52 $GLOBALS['cache_instance'] = null;
53 $GLOBALS['cache_array'] = array();
55 // Skip loading extensions
56 if ((!isInstalled()) || (isInstalling())) {
57 // Init filter system here
64 // Initialize array for "always keep active extensions"
65 $GLOBALS['cache_array']['active_extensions'] = array();
67 // By default no cache is set
68 $GLOBALS['cache_mode'] = 'no';
70 // Load sql_patchrs extension alone
71 if (!LOAD_EXTENSION('sql_patches')) {
72 // Could not load sql_patches! ARGH!!!
73 trigger_error('Cannot load extension sql_patches.');
76 // Init inc pool array
82 if (EXT_IS_ACTIVE('cache')) {
83 // Load cache extension alone
84 if (!LOAD_EXTENSION('cache')) {
85 // Extension 'cache' was not loaded
86 trigger_error('Cannot load extension cache.');
89 // Check extension cache
90 switch (($GLOBALS['cache_instance']->loadCacheFile('extensions', true)) && ($GLOBALS['cache_instance']->extensionVersionMatches('sql_patches'))) {
91 case true : $GLOBALS['cache_mode'] = 'load'; break;
92 case false: $GLOBALS['cache_mode'] = 'init'; break;
95 // Do we need to init the cache? But not in "CSS mode".
96 if (($GLOBALS['cache_mode'] == 'init') && (getConfig('cache_exts') == 'Y') && (getOutputMode() == '0')) {
98 $GLOBALS['cache_instance']->init('EXTENSIONS');
99 $GLOBALS['cache_instance']->storeExtensionVersion('sql_patches');
100 } elseif (getConfig('cache_exts') != 'Y') {
101 // Cache will not be created for extensions
102 $GLOBALS['cache_mode'] = 'skip';
107 if ($GLOBALS['cache_mode'] == 'load') {
108 // Init include array
111 // Re-initialize handler
112 $GLOBALS['cache_instance']->loadCacheFile('extensions', true);
114 // Load extension data from cache file
115 $EXT_DUMMY = $GLOBALS['cache_instance']->getArrayFromCache();
117 // Is the cache file fine?
118 if (!isset($EXT_DUMMY['ext_name'])) {
119 // Cache file is damaged so kill it
120 $GLOBALS['cache_instance']->destroyCacheFile();
127 // Begin with the cache preparation of extensions
128 $EXT_NAMES = array();
129 foreach ($EXT_DUMMY['ext_name'] as $k => $name) {
131 if ($EXT_DUMMY['ext_css'][$k] == 'Y') EXT_ADD_CSS_FILE($name . '.css');
133 // Load extension file itself
134 if ((($EXT_DUMMY['ext_active'][$k] == 'Y') || ($EXT_DUMMY['ext_keep'][$k] == 'Y') || (IS_ADMIN())) && (!in_array($name, array('sql_patches', 'cache')))) {
139 $EXT_DUMMY['ext_version'][$name] = $EXT_DUMMY['ext_version'][$k];
140 unset($EXT_DUMMY['ext_version'][$k]);
142 // Extension is active
143 $EXT_DUMMY['ext_active'][$name] = $EXT_DUMMY['ext_active'][$k];
144 unset($EXT_DUMMY['ext_active'][$k]);
147 $EXT_DUMMY['ext_menu'][$name] = $EXT_DUMMY['ext_menu'][$k];
148 unset($EXT_DUMMY['ext_menu'][$k]);
151 $EXT_DUMMY['ext_id'][$name] = $EXT_DUMMY['ext_id'][$k];
152 $id = $EXT_DUMMY['ext_id'][$name];
153 unset($EXT_DUMMY['ext_id'][$k]);
156 $EXT_NAMES[$id] = $name;
158 // Add deprecated flag (defaults to 'not deprecated')
159 $EXT_DUMMY['ext_deprecated'][$name] = 'N';
161 // Mark it as active extension
162 $GLOBALS['cache_array']['active_extensions'][$name] = $EXT_DUMMY['ext_keep'][$k];
163 unset($EXT_DUMMY['ext_keep'][$k]);
165 // Remove unneccessary data from memory
166 unset($EXT_DUMMY['ext_css'][$k]);
169 // Write dummy array back
170 $EXT_DUMMY['ext_name'] = $EXT_NAMES;
173 // Loading cache is done so let's free some memory!
174 unset($EXT_DUMMY['ext_keep']);
175 unset($EXT_DUMMY['ext_css']);
176 $GLOBALS['cache_array']['extensions'] = $EXT_DUMMY;
179 // No database load needed
180 $res_ext_crt = false;
182 // Load all extension files
183 foreach ($EXT_POOL as $ext) {
184 LOAD_EXTENSION($ext);
187 // Load more cache files (like admins)
188 loadIncludeOnce('inc/load_cache.php');
193 // If current user is not admin load only activated extensions. But load
194 // them all if we are going to init the cache files. The admin shall use
195 // every available extension for testing purposes.
196 if ((!IS_ADMIN()) && ($GLOBALS['cache_mode'] != 'init')) $add = " WHERE `ext_active`='Y'";
198 if (GET_EXT_VERSION('sql_patches') >= '0.0.6') {
199 // Query with CSS file from DB
200 $res_ext_crt = SQL_QUERY("SELECT id AS ext_id, ext_name, ext_has_css AS ext_css, ext_active, ext_version
201 FROM `{!_MYSQL_PREFIX!}_extensions`" . $add . "
202 ORDER BY ext_name", __FILE__, __LINE__);
204 // Old obsolete query string
205 $res_ext_crt = SQL_QUERY("SELECT id AS ext_id, ext_name, ext_name, ext_active, ext_version
206 FROM `{!_MYSQL_PREFIX!}_extensions`" . $add . "
207 ORDER BY ext_name", __FILE__, __LINE__);
211 // Array for removed but not uninstalled extensions
214 // At least one found?
215 if ((SQL_NUMROWS($res_ext_crt) > 0) && ((($GLOBALS['cache_mode'] == 'init') && (getOutputMode() != '1') && (getOutputMode() != '-1')) || ($GLOBALS['cache_mode'] == 'no'))) {
216 // Extensions are registered so we load them
217 while ($content = SQL_FETCHARRAY($res_ext_crt)) {
219 $content['ext_menu'] = 'N';
220 if (MODULE_HAS_MENU($content['ext_name'], true)) {
221 $content['ext_menu'] = 'Y';
224 // Generate FQFN for extension
225 $FQFN = sprintf("%sinc/extensions/ext-%s.php", constant('PATH'), $content['ext_name']);
227 // Does the extension file exists?
228 if (isFileReadable($FQFN)) {
229 // By default no extension is always active, except sql_patches
230 EXT_SET_ALWAYS_ACTIVE('N');
233 if (($content['ext_name'] != 'sql_patches') && (($content['ext_name'] != 'cache') || (!EXT_IS_ACTIVE('cache')))) {
235 LOAD_EXTENSION($content['ext_name']);
237 // Keep sql_patches always active
238 EXT_SET_ALWAYS_ACTIVE('Y');
241 // Transfer EXT_ALWAYS_ACTIVE flag
242 $content['ext_keep'] = EXT_GET_ALWAYS_ACTIVE();
244 // CSS file handling:
245 if ((!isset($content['ext_css'])) || ($content['ext_css'] == 'Y')) {
246 // Create FQFN for the CSS file
247 $FQFN = sprintf("%stheme/%s/css/%s.css", constant('PATH'), getCurrentTheme(), $content['ext_name']);
249 // Is the file there?
250 if (isFileReadable($FQFN)) {
251 // CSS file for extension was found (use only relative path for now!)
252 EXT_ADD_CSS_FILE($content['ext_name'] . '.css');
253 $content['ext_css'] = 'Y';
255 // Don't load CSS file
256 $content['ext_css'] = 'N';
261 if ($GLOBALS['cache_mode'] == 'init') {
263 $GLOBALS['cache_instance']->addRow($content);
264 } elseif ($GLOBALS['cache_mode'] == 'no') {
265 // Remember this value for later usage
266 $GLOBALS['cache_array']['active_extensions'][$content['ext_name']] = EXT_GET_ALWAYS_ACTIVE();
268 } elseif (!isFileReadable($FQFN)) {
269 // Deleted extension file so we mark it for removal from DB
270 $DEL[] = $content['ext_name'];
274 if ($GLOBALS['cache_mode'] == 'init') {
276 $GLOBALS['cache_instance']->finalize();
278 // Load more cache files (like admins)
279 loadIncludeOnce('inc/load_cache.php');
281 // Init filter system for non-init mode
286 SQL_FREERESULT($res_ext_crt);
287 } elseif ((!EXT_IS_ACTIVE('cache')) || (($GLOBALS['cache_mode'] == 'init') && (getOutputMode() != 0))) {
288 // Init filter system even when there are no extensions installed. #16
290 } elseif ($GLOBALS['cache_mode'] != 'load') {
291 // Something unexpected!
292 debug_report_bug('Unexpected state in '.basename(__FILE__).': cache_mode='.$GLOBALS['cache_mode'].', numRows='.SQL_NUMROWS($res_ext_crt));
296 runFilterChain('load_includes');
298 // Uninstall extensions that are no longer in our system
299 if (!empty($DEL[0])) {
300 // Remove extensions from two tables: extension registry and tasks table
301 foreach ($DEL as $del_ext) {
302 // First remove entry from extensions table
303 SQL_QUERY_ESC("DELETE LOW_PRIORITY FROM `{!_MYSQL_PREFIX!}_extensions` WHERE `ext_name`='%s' LIMIT 1",
304 array($del_ext), __FILE__, __LINE__);
306 // Remove (maybe?) found tasks (main task and possible updates
307 SQL_QUERY_ESC("DELETE LOW_PRIORITY FROM `{!_MYSQL_PREFIX!}_task_system` WHERE `subject`='[%s:]' AND (`task_type`='EXTENSION' OR `task_type`='EXTENSION_UPDATE')",
308 array($del_ext), __FILE__, __LINE__);
311 // I think it's not neccessary to run the optimization function here
312 // because we didn't delete so much data from database. Can you aggree?