New naming convention applied to many functions, see #118 for details
[mailer.git] / inc / libs / cache_functions.php
1 <?php
2 /************************************************************************
3  * MXChange v0.2.1                                    Start: 10/11/2003 *
4  * ===============                              Last change: 10/11/2003 *
5  *                                                                      *
6  * -------------------------------------------------------------------- *
7  * File              : admins_functions.php                             *
8  * -------------------------------------------------------------------- *
9  * Short description : Functions for the admins extension               *
10  * -------------------------------------------------------------------- *
11  * Kurzbeschreibung  : Funktionen fuer die admins-Erweiterung           *
12  * -------------------------------------------------------------------- *
13  * $Revision::                                                        $ *
14  * $Date::                                                            $ *
15  * $Tag:: 0.2.1-FINAL                                                 $ *
16  * $Author::                                                          $ *
17  * Needs to be in all Files and every File needs "svn propset           *
18  * svn:keywords Date Revision" (autoprobset!) at least!!!!!!            *
19  * -------------------------------------------------------------------- *
20  * Copyright (c) 2003 - 2008 by Roland Haeder                           *
21  * For more information visit: http://www.mxchange.org                  *
22  *                                                                      *
23  * This program is free software; you can redistribute it and/or modify *
24  * it under the terms of the GNU General Public License as published by *
25  * the Free Software Foundation; either version 2 of the License, or    *
26  * (at your option) any later version.                                  *
27  *                                                                      *
28  * This program is distributed in the hope that it will be useful,      *
29  * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
30  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
31  * GNU General Public License for more details.                         *
32  *                                                                      *
33  * You should have received a copy of the GNU General Public License    *
34  * along with this program; if not, write to the Free Software          *
35  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,               *
36  * MA  02110-1301  USA                                                  *
37  ************************************************************************/
38
39 // Some security stuff...
40 if (!defined('__SECURITY')) {
41         $INC = substr(dirname(__FILE__), 0, strpos(dirname(__FILE__), '/inc') + 4) . '/security.php';
42         require($INC);
43 }
44
45 // Caching class
46 class CacheSystem {
47         // Define variables
48         var $ret = 'init';
49         var $path = '';
50         var $inc = '';
51         var $fqfn = '';
52         var $pointer = false;
53         var $data = array();
54         var $version = array();
55         var $name = '';
56         var $rebuilt = array();
57         var $extension = '.cache';
58         var $statusDone = 'done';
59
60         // Constructor
61         function CacheSystem ($interval, $path, $tested) {
62                 // Failed is the default
63                 $this->ret = 'failed';
64
65                 // Remeber path
66                 $this->path = $path;
67
68                 // Check if path exists
69                 if ((isDirectory($path)) && (!$tested)) {
70                         // Make FQFN for dummy file
71                         $fqfn = $path . 'dummy.tmp';
72
73                         // Check if we can create a file inside the path
74                         touch($fqfn, 'w');
75
76                         // Is the file there?
77                         if (isFileReadable($fqfn)) {
78                                 // Yes, we can do. So let's remove it
79                                 unlink($fqfn);
80
81                                 // Is there a .htaccess file?
82                                 if (isFileReadable($path . '.htaccess')) {
83                                         // Update database that we have tested it
84                                         updateConfiguration('cache_tested', 1);
85
86                                         // All done!
87                                         $this->ret = $this->statusDone;
88                                 } else {
89                                         // Stop! Set a .htaccess file first
90                                         $this->ret = 'htaccess';
91                                 }
92                         }
93                 } elseif ($tested) {
94                         // System already tested
95                         $this->ret = $this->statusDone;
96                 }
97         }
98
99         // Checks validity of cache file and if content is given
100         function loadCacheFile ($cacheName, $forceContent = false) {
101                 // Remember cache file
102                 $this->name = $cacheName;
103
104                 // Construct include filename for loadIncludeOnce() call
105                 $this->inc = $this->path . $cacheName . $this->extension;
106
107                 // Construct FQFN (full qualified file name)
108                 $this->fqfn = constant('PATH') . $this->inc;
109
110                 // Check if file exists and if version matches
111                 $status = ($this->isCacheReadable() && (is_writeable($this->fqfn)) && ($this->extensionVersionMatches('cache')));
112
113                 // Return status
114                 return $status;
115         }
116
117         // Initializes the cache file
118         function init () {
119                 // This will destory an existing cache file!
120                 if ($this->ret == $this->statusDone) {
121                         // Create file
122                         if ($this->isCacheReadable()) chmod($this->fqfn, 0666);
123                         $this->pointer = fopen($this->fqfn, 'w') or app_die(__METHOD__, __LINE__, "Cannot write to cache ".$this->fqfn." !");
124
125                         // Add open PHP tag
126                         fwrite($this->pointer, "<?php\n");
127
128                         // Add default depency
129                         $this->storeExtensionVersion('cache');
130                 } else {
131                         // Cannot create file
132                         addFatalMessage(__METHOD__, __LINE__, "(<font color=\"#0000aa\">".__LINE__."</font>): ".getMessage('CACHE_PROBLEMS_DETECTED'));
133                 }
134         }
135
136         function addRow ($data) {
137                 // Is the pointe rvalid?
138                 if (is_resource($this->pointer)) {
139                         // Write every array element to cache file
140                         foreach ($data as $k => $v) {
141                                 // Write global cache array for immediate access
142                                 if ((substr($k, 0, 4) == 'ext_') && (isset($data['ext_name'])) && (isset($data['ext_id']))) {
143                                         if ($k != 'ext_name') {
144                                                 $GLOBALS['cache_array']['extensions'][$k][$data['ext_name']] = $v;
145                                         } else {
146                                                 $GLOBALS['cache_array']['extensions'][$k][$data['ext_id']] = $v;
147                                         }
148                                         if (($k == 'ext_keep') && ($v == 'Y')) {
149                                                 $GLOBALS['cache_array']['active_extensions'][$data['ext_name']] = $v;
150                                         } // END - if
151                                 } elseif (is_array($v)) {
152                                         // Serialize and BASE64-encode the array
153                                         $v = base64_encode(serialize($v));
154                                 }
155
156                                 // Write cache line to file
157                                 fwrite($this->pointer, $this->rewriteEntry($k, $v));
158                         }
159                 } else {
160                         // Cannot create file
161                         addFatalMessage(__METHOD__, __LINE__, "(<font color=\"#0000aa\">".__LINE__."</font>): ".getMessage('CACHE_PROBLEMS_DETECTED'));
162                 }
163         }
164
165         function finalize () {
166                 // Quit function when no pointer is set
167                 if (is_resource($this->pointer)) {
168                         // Write footer
169                         fwrite($this->pointer, "?>\n");
170
171                         // Close file add destroy handler
172                         fclose($this->pointer);
173
174                         // Set rights
175                         if ($this->isCacheReadable()) chmod($this->fqfn, 0666);
176
177                         // Remove pointer
178                         $this->pointer = false;
179                         //* DEBUG: */ print __METHOD__."(<font color=\"#0000aa\">".__LINE__."</font>): {$this->name} - FINALIZED!<br />\n";
180                 } // END - if
181         }
182
183         function getArrayFromCache () {
184                 // Is the cache already loaded?
185                 if (isset($this->data[$this->name])) {
186                         // Return it's content!
187                         return $this->data[$this->name];
188                 } // END - if
189
190                 // Is the cache file there?
191                 if ($this->isCacheReadable()) {
192                         // Prepare temporary array
193                         $data = array();
194                         $cache_version = null;
195
196                         // Load cache file
197                         require($this->inc);
198
199                         // Is there an array?
200                         if (is_array($data)) {
201                                 // Cache data
202                                 $this->data[$this->name] = $data;
203
204                                 // Cache version found?
205                                 if ((is_array($cache_version)) && (count($cache_version) > 0)) {
206                                         // Remember it as well...
207                                         $this->version[$this->name] = $cache_version;
208                                 } else {
209                                         // Invalid cache so destroy it
210                                         $this->destroyCacheFile();
211
212                                         // Clear cached data
213                                         $this->data[$this->name] = array();
214                                 }
215
216                                 // Return cache
217                                 return $this->data[$this->name];
218                         } else {
219                                 // Cache problem detected!
220                                 $this->destroyCacheFile();
221                         }
222                 } else {
223                         // Cache file not found or not readable
224                         addFatalMessage(__METHOD__, __LINE__, "(<font color=\"#0000aa\">".__LINE__."</font>): ".CACHE_CANNOT_LOAD_1.$this->fqfn.CACHE_CANNOT_LOAD_2);
225                 }
226         }
227
228         // Destroy an existing cache file
229         function destroyCacheFile () {
230                 // Is the cache file there?
231                 if ((!isset($this->rebuilt[$this->name])) && ($this->isCacheReadable())) {
232                         // Close cache
233                         $this->finalize();
234
235                         // Remove cache file from system
236                         //* DEBUG: */ print __METHOD__."(<font color=\"#0000aa\">".__LINE__."</font>): {$this->name} - DESTROYED!<br />\n";
237                         unlink($this->fqfn);
238                         // @TODO remove from $GLOBALS['cache_array']!!!
239
240                         // Is the file there?
241                         if (!$this->isCacheReadable()) {
242                                 // The cache does no longer exist so kill the content
243                                 unset($this->data[$this->name]);
244                                 unset($this->version[$this->name]);
245                                 $this->rebuilt[$this->name] = true;
246                         } else {
247                                 // Not removed!
248                                 addFatalMessage(__METHOD__, __LINE__, "(<font color=\"#0000aa\">".__LINE__."</font>): ".CACHE_CANNOT_UNLINK_1.$this->fqfn.CACHE_CANNOT_UNLINK_2);
249                         }
250                 } // END - if
251         }
252
253         // Unused method:
254         function removeEntry ($search, $data, $array) {
255                 if (($this->isCacheReadable()) && (is_writeable($this->fqfn))) {
256                         // Load cache into dummy array
257                         $dummy = $this->getArrayFromCache();
258
259                         // Search for key in array
260                         $key = array_search($data, $dummy[$search]);
261                         if (!empty($key)) {
262                                 // Key (hopefully) found?
263                                 foreach ($array as $a) {
264                                         // So we can remove all elements as requested
265                                         unset($dummy[$a][$key]);
266                                 } // END - foreach
267
268                                 // Flush array to cache file
269                                 $this->init();
270
271                                 // Write array out
272                                 $this->writeArray($dummy);
273
274                                 // Close cache file
275                                 $this->finalize();
276                         }
277                 } else {
278                         // Cannot write to cache!
279                         addFatalMessage(__METHOD__, __LINE__, "(<font color=\"#0000aa\">".__LINE__."</font>): ".getMessage('CACHE_PROBLEMS_DETECTED'));
280                 }
281         }
282
283         function writeArray ($array) {
284                 if (is_resource($this->pointer)) {
285                         foreach ($array as $k => $v) {
286                                 if (is_array($v)) {
287                                         // Multi line(s) found
288                                         $LINE = '';
289                                         foreach($v as $k2 => $v2) {
290                                                 // Put every array element in a row...
291                                                 $LINE .= $this->rewriteEntry($k, $v2);
292                                         }
293                                 } else {
294                                         // Single line found
295                                         $LINE = $this->rewriteEntry($k, $v);
296                                 }
297
298                                 // Write line(s)
299                                 fwrite($this->pointer, $LINE);
300                         } // END - foreach
301                 } else {
302                         // Cannot write array!
303                         addFatalMessage(__METHOD__, __LINE__, "(<font color=\"#0000aa\">".__LINE__."</font>): ".getMessage('CACHE_PROBLEMS_DETECTED'));
304                 }
305         }
306
307         // Unused method
308         function replaceEntry ($search, $replace, $search_key, $array) {
309                 if (($this->isCacheReadable()) && (is_writeable($this->fqfn))) {
310                         // Load cache into dummy array
311                         $dummy = $this->getArrayFromCache();
312
313                         // Check if $dummy is valid (prevents some errors)
314                         if ((is_array($dummy)) && (isset($dummy[$search])) && (is_array($dummy[$search]))) {
315                                 // Search for key in array
316                                 $key_found = array_key_exists($search_key, $dummy[$search]);
317                                 if ($key_found == true) {
318                                         $key = $search_key;
319                                         // Key (hopefully) found?
320                                         foreach ($dummy as $a => $v) {
321                                                 // So we can update all entries
322                                                 if ($a == $search) {
323                                                         // Update now...
324                                                         $dummy[$a][$search_key] = $replace;
325                                                 } // END - if
326                                         } // END - foreach
327
328                                         // Flush array to cache file
329                                         $this->init();
330
331                                         // Write array out
332                                         $this->writeArray($dummy);
333
334                                         // Close cache file
335                                         $this->finalize();
336                                 } // END - if
337                         } // END - if
338                 } else {
339                         // Cannot write to cache!
340                         addFatalMessage(__METHOD__, __LINE__, "(<font color=\"#0000aa\">".__LINE__."</font>): ".getMessage('CACHE_PROBLEMS_DETECTED'));
341                 }
342         }
343
344         // Writes the version of given extension to the cache file
345         function storeExtensionVersion ($ext_name) {
346                 // Valid cache pointer?
347                 if (is_resource($this->pointer)) {
348                         // Get extension version
349                         $ext_ver = GET_EXT_VERSION($ext_name);
350
351                         // Write cache line to file
352                         fwrite($this->pointer, "\$cache_version['".$ext_name."'] = \"".$ext_ver."\";\n");
353
354                         // Add the extension version to object (DO NOT REMOVE IT! Endless loop...)
355                         $this->version[$this->name][$ext_name] = $ext_ver;
356                         //* DEBUG: */ print __METHOD__."(<font color=\"#0000aa\">".__LINE__."</font>): {$this->name} - {$ext_name}={$ext_ver}<br />\n";
357                 } else {
358                         // Cannot create file
359                         addFatalMessage(__METHOD__, __LINE__, "(<font color=\"#0000aa\">".__LINE__."</font>): ".getMessage('CACHE_PROBLEMS_DETECTED'));
360                 }
361         }
362
363         // Checks wether versions from cache and extension matches
364         function extensionVersionMatches ($ext_name) {
365                 // Load cache (dummy)
366                 $this->getArrayFromCache();
367
368                 // Get extension version
369                 $ext_ver = GET_EXT_VERSION($ext_name);
370
371                 // Debug messages
372                 if (isset($this->version[$this->name][$ext_name])) {
373                         //* DEBUG: */ print __METHOD__."(<font color=\"#0000aa\">".__LINE__."</font>): cache={$this->name},ext_name={$ext_name} - {$ext_ver}/{$this->version[$this->name][$ext_name]}<br />\n";
374                 } else {
375                         // No cache version found!
376                         DEBUG_LOG(__METHOD__, __LINE__, "Cache {$this->name} has missing version entry for extension {$ext_name}!");
377                 }
378
379                 // Compare both
380                 return ((isset($this->version[$this->name][$ext_name])) && ($this->version[$this->name][$ext_name] == $ext_ver));
381         }
382
383         // Rewrit the entry so it can be stored in cache file
384         // @TODO Add support for more types which break in last else-block
385         function rewriteEntry ($key, $value) {
386                 // Init line
387                 $line = '';
388
389                 // String or non-string? ;-)
390                 if (is_string($value)) {
391                         // String...
392                         $line = "\$data['".$key."'][] = \"".$value."\";\n";
393                 } elseif (is_null($value)) {
394                         // Null
395                         $line = "\$data['".$key."'][] = null;\n";
396                 } elseif (is_bool($value)) {
397                         // Boolean value
398                         if ($value === true) {
399                                 // True
400                                 $line = "\$data['".$key."'][] = true;\n";
401                         } else {
402                                 // False
403                                 $line = "\$data['".$key."'][] = false;\n";
404                         }
405                 } else {
406                         // Non-string
407                         $line = "\$data['".$key."'][] = ".$value.";\n";
408                 }
409
410                 // Return line
411                 return $line;
412         }
413
414         // Getter for cache status
415         function getStatus () {
416                 return $this->ret;
417         }
418
419         // Checks wether the current cache file is readable
420         function isCacheReadable () {
421                 return isIncludeReadable($this->inc);
422         }
423
424 } // END - class
425
426 // Destroy the cache on extension changes
427 function FILTER_CACHE_DESTROY_ON_EXT_CHANGE ($data) {
428         // Return the data anyway if there is no cache extension
429         if (!isCacheInstanceValid()) return $data;
430
431         // Remove cache
432         if ($GLOBALS['cache_instance']->loadCacheFile('config'))     $GLOBALS['cache_instance']->destroyCacheFile();
433         if ($GLOBALS['cache_instance']->loadCacheFile('extensions')) $GLOBALS['cache_instance']->destroyCacheFile();
434         if ($GLOBALS['cache_instance']->loadCacheFile('modreg'))     $GLOBALS['cache_instance']->destroyCacheFile();
435
436         // Return it
437         return $data;
438 }
439
440 // Destroy the cache on changing admin
441 function FILTER_CACHE_DESTROY_ON_ADMIN_CHANGE () {
442         // Skip this step if the cache instance is not there
443         if (!isCacheInstanceValid()) return false;
444
445         // Remove cache
446         if ($GLOBALS['cache_instance']->loadCacheFile('admins')) $GLOBALS['cache_instance']->destroyCacheFile();
447 }
448
449 // Destroy all cache files
450 function FILTER_CACHE_DESTROY_ALL () {
451         // Skip this step if the cache instance is not there
452         if (!isCacheInstanceValid()) return false;
453
454         // Remove cache files
455         if ($GLOBALS['cache_instance']->loadCacheFile('admins'))      $GLOBALS['cache_instance']->destroyCacheFile();
456         if ($GLOBALS['cache_instance']->loadCacheFile('admins_acls')) $GLOBALS['cache_instance']->destroyCacheFile();
457         if ($GLOBALS['cache_instance']->loadCacheFile('config'))      $GLOBALS['cache_instance']->destroyCacheFile();
458         if ($GLOBALS['cache_instance']->loadCacheFile('extensions'))  $GLOBALS['cache_instance']->destroyCacheFile();
459         if ($GLOBALS['cache_instance']->loadCacheFile('modreg'))      $GLOBALS['cache_instance']->destroyCacheFile();
460         if ($GLOBALS['cache_instance']->loadCacheFile('refdepths'))   $GLOBALS['cache_instance']->destroyCacheFile();
461         if ($GLOBALS['cache_instance']->loadCacheFile('refsystem'))   $GLOBALS['cache_instance']->destroyCacheFile();
462         if ($GLOBALS['cache_instance']->loadCacheFile('themes'))      $GLOBALS['cache_instance']->destroyCacheFile();
463         if ($GLOBALS['cache_instance']->loadCacheFile('revision'))    $GLOBALS['cache_instance']->destroyCacheFile();
464 }
465
466 // Filter for purging entire admin menu cache
467 function FILTER_CACHE_PURGE_ADMIN_MENU () {
468         // Just call the function
469         cachePurgeAdminMenu();
470 }
471
472 //
473 ?>