1 <?php
2 3 4 5 6 7 8
9
10 defined('JPATH_PLATFORM') or die;
11
12 use Joomla\String\StringHelper;
13
14 15 16 17 18
19 class JCache
20 {
21 22 23 24 25 26
27 public static $_handler = array();
28
29 30 31 32 33 34
35 public $_options;
36
37 38 39 40 41 42 43
44 public function __construct($options)
45 {
46 $conf = JFactory::getConfig();
47
48 $this->_options = array(
49 'cachebase' => $conf->get('cache_path', JPATH_CACHE),
50 'lifetime' => (int) $conf->get('cachetime'),
51 'language' => $conf->get('language', 'en-GB'),
52 'storage' => $conf->get('cache_handler', ''),
53 'defaultgroup' => 'default',
54 'locking' => true,
55 'locktime' => 15,
56 'checkTime' => true,
57 'caching' => ($conf->get('caching') >= 1) ? true : false,
58 );
59
60
61 foreach ($options as $option => $value)
62 {
63 if (isset($options[$option]) && $options[$option] !== '')
64 {
65 $this->_options[$option] = $options[$option];
66 }
67 }
68
69 if (empty($this->_options['storage']))
70 {
71 $this->setCaching(false);
72 }
73 }
74
75 76 77 78 79 80 81 82 83 84
85 public static function getInstance($type = 'output', $options = array())
86 {
87 return JCacheController::getInstance($type, $options);
88 }
89
90 91 92 93 94 95 96
97 public static function getStores()
98 {
99 $handlers = array();
100
101
102 $iterator = new DirectoryIterator(__DIR__ . '/storage');
103
104
105 foreach ($iterator as $file)
106 {
107 $fileName = $file->getFilename();
108
109
110 if (!$file->isFile() || $file->getExtension() != 'php' || $fileName == 'helper.php')
111 {
112 continue;
113 }
114
115
116 $class = str_ireplace('.php', '', 'JCacheStorage' . ucfirst(trim($fileName)));
117
118
119 if (!class_exists($class))
120 {
121 continue;
122 }
123
124
125 if ($class::isSupported())
126 {
127
128 $handlers[] = str_ireplace('.php', '', $fileName);
129 }
130 }
131
132 return $handlers;
133 }
134
135 136 137 138 139 140 141 142 143
144 public function setCaching($enabled)
145 {
146 $this->_options['caching'] = $enabled;
147 }
148
149 150 151 152 153 154 155
156 public function getCaching()
157 {
158 return $this->_options['caching'];
159 }
160
161 162 163 164 165 166 167 168 169
170 public function setLifeTime($lt)
171 {
172 $this->_options['lifetime'] = $lt;
173 }
174
175 176 177 178 179 180 181 182 183 184
185 public function contains($id, $group = null)
186 {
187 if (!$this->getCaching())
188 {
189 return false;
190 }
191
192
193 $group = $group ?: $this->_options['defaultgroup'];
194
195 return $this->_getStorage()->contains($id, $group);
196 }
197
198 199 200 201 202 203 204 205 206 207
208 public function get($id, $group = null)
209 {
210 if (!$this->getCaching())
211 {
212 return false;
213 }
214
215
216 $group = $group ?: $this->_options['defaultgroup'];
217
218 return $this->_getStorage()->get($id, $group, $this->_options['checkTime']);
219 }
220
221 222 223 224 225 226 227
228 public function getAll()
229 {
230 if (!$this->getCaching())
231 {
232 return false;
233 }
234
235 return $this->_getStorage()->getAll();
236 }
237
238 239 240 241 242 243 244 245 246 247 248
249 public function store($data, $id, $group = null)
250 {
251 if (!$this->getCaching())
252 {
253 return false;
254 }
255
256
257 $group = $group ?: $this->_options['defaultgroup'];
258
259
260 return $this->_getStorage()->store($id, $group, $data);
261 }
262
263 264 265 266 267 268 269 270 271 272
273 public function remove($id, $group = null)
274 {
275
276 $group = $group ?: $this->_options['defaultgroup'];
277
278 return $this->_getStorage()->remove($id, $group);
279 }
280
281 282 283 284 285 286 287 288 289 290 291 292 293
294 public function clean($group = null, $mode = 'group')
295 {
296
297 $group = $group ?: $this->_options['defaultgroup'];
298
299 return $this->_getStorage()->clean($group, $mode);
300 }
301
302 303 304 305 306 307 308
309 public function gc()
310 {
311 return $this->_getStorage()->gc();
312 }
313
314 315 316 317 318 319 320 321 322 323 324
325 public function lock($id, $group = null, $locktime = null)
326 {
327 $returning = new stdClass;
328 $returning->locklooped = false;
329
330 if (!$this->getCaching())
331 {
332 $returning->locked = false;
333
334 return $returning;
335 }
336
337
338 $group = $group ?: $this->_options['defaultgroup'];
339
340
341 $locktime = $locktime ?: $this->_options['locktime'];
342
343 344 345 346
347 $handler = $this->_getStorage();
348
349 if ($this->_options['locking'] == true)
350 {
351 $locked = $handler->lock($id, $group, $locktime);
352
353 if ($locked !== false)
354 {
355 return $locked;
356 }
357 }
358
359
360 $curentlifetime = $this->_options['lifetime'];
361
362
363 $this->_options['lifetime'] = $locktime;
364
365 $looptime = $locktime * 10;
366 $id2 = $id . '_lock';
367
368 if ($this->_options['locking'] == true)
369 {
370 $data_lock = $handler->get($id2, $group, $this->_options['checkTime']);
371 }
372 else
373 {
374 $data_lock = false;
375 $returning->locked = false;
376 }
377
378 if ($data_lock !== false)
379 {
380 $lock_counter = 0;
381
382
383 while ($data_lock !== false)
384 {
385 if ($lock_counter > $looptime)
386 {
387 $returning->locked = false;
388 $returning->locklooped = true;
389 break;
390 }
391
392 usleep(100);
393 $data_lock = $handler->get($id2, $group, $this->_options['checkTime']);
394 $lock_counter++;
395 }
396 }
397
398 if ($this->_options['locking'] == true)
399 {
400 $returning->locked = $handler->store(1, $id2, $group);
401 }
402
403
404 $this->_options['lifetime'] = $curentlifetime;
405
406 return $returning;
407 }
408
409 410 411 412 413 414 415 416 417 418
419 public function unlock($id, $group = null)
420 {
421 if (!$this->getCaching())
422 {
423 return false;
424 }
425
426
427 $group = $group ?: $this->_options['defaultgroup'];
428
429
430 $handler = $this->_getStorage();
431
432 $unlocked = $handler->unlock($id, $group);
433
434 if ($unlocked !== false)
435 {
436 return $unlocked;
437 }
438
439
440 return $handler->remove($id . '_lock', $group);
441 }
442
443 444 445 446 447 448 449
450 public function &_getStorage()
451 {
452 $hash = md5(serialize($this->_options));
453
454 if (isset(self::$_handler[$hash]))
455 {
456 return self::$_handler[$hash];
457 }
458
459 self::$_handler[$hash] = JCacheStorage::getInstance($this->_options['storage'], $this->_options);
460
461 return self::$_handler[$hash];
462 }
463
464 465 466 467 468 469 470 471 472 473
474 public static function getWorkarounds($data, $options = array())
475 {
476 $app = JFactory::getApplication();
477 $document = JFactory::getDocument();
478 $body = null;
479
480
481 if (isset($options['mergehead']) && $options['mergehead'] == 1 && isset($data['head']) && !empty($data['head'])
482 && method_exists($document, 'mergeHeadData'))
483 {
484 $document->mergeHeadData($data['head']);
485 }
486 elseif (isset($data['head']) && method_exists($document, 'setHeadData'))
487 {
488 $document->setHeadData($data['head']);
489 }
490
491
492 if (isset($data['mime_encoding']))
493 {
494 $document->setMimeEncoding($data['mime_encoding'], true);
495 }
496
497
498 if (isset($data['pathway']) && is_array($data['pathway']))
499 {
500
501 $app->getPathway()->setPathway($data['pathway']);
502 }
503
504
505
506 if (isset($data['module']) && is_array($data['module']))
507 {
508
509 foreach ($data['module'] as $name => $contents)
510 {
511 $document->setBuffer($contents, 'module', $name);
512 }
513 }
514
515
516 if (isset($data['headers']) && $data['headers'])
517 {
518 foreach ($data['headers'] as $header)
519 {
520 $app->setHeader($header['name'], $header['value']);
521 }
522 }
523
524
525 if (isset($data['body']))
526 {
527 $token = JSession::getFormToken();
528 $search = '#<input type="hidden" name="[0-9a-f]{32}" value="1" />#';
529 $replacement = '<input type="hidden" name="' . $token . '" value="1" />';
530
531 $data['body'] = preg_replace($search, $replacement, $data['body']);
532 $body = $data['body'];
533 }
534
535
536 return $body;
537 }
538
539 540 541 542 543 544 545 546 547 548
549 public static function setWorkarounds($data, $options = array())
550 {
551 $loptions = array(
552 'nopathway' => 0,
553 'nohead' => 0,
554 'nomodules' => 0,
555 'modulemode' => 0,
556 );
557
558 if (isset($options['nopathway']))
559 {
560 $loptions['nopathway'] = $options['nopathway'];
561 }
562
563 if (isset($options['nohead']))
564 {
565 $loptions['nohead'] = $options['nohead'];
566 }
567
568 if (isset($options['nomodules']))
569 {
570 $loptions['nomodules'] = $options['nomodules'];
571 }
572
573 if (isset($options['modulemode']))
574 {
575 $loptions['modulemode'] = $options['modulemode'];
576 }
577
578 $app = JFactory::getApplication();
579 $document = JFactory::getDocument();
580
581 if ($loptions['nomodules'] != 1)
582 {
583
584 $buffer1 = $document->getBuffer();
585
586 if (!is_array($buffer1))
587 {
588 $buffer1 = array();
589 }
590
591
592 if (!isset($buffer1['module']) || !is_array($buffer1['module']))
593 {
594 $buffer1['module'] = array();
595 }
596 }
597
598
599 $cached['body'] = $data;
600
601
602 if ($loptions['nohead'] != 1 && method_exists($document, 'getHeadData'))
603 {
604 if ($loptions['modulemode'] == 1)
605 {
606 $headnow = $document->getHeadData();
607 $unset = array('title', 'description', 'link', 'links', 'metaTags');
608
609 foreach ($unset as $un)
610 {
611 unset($headnow[$un]);
612 unset($options['headerbefore'][$un]);
613 }
614
615 $cached['head'] = array();
616
617
618 foreach ($headnow as $now => $value)
619 {
620 if (isset($options['headerbefore'][$now]))
621 {
622
623 $nowvalue = array_map('serialize', $headnow[$now]);
624 $beforevalue = array_map('serialize', $options['headerbefore'][$now]);
625
626 $newvalue = array_diff_assoc($nowvalue, $beforevalue);
627 $newvalue = array_map('unserialize', $newvalue);
628
629
630 if (($now == 'script' || $now == 'style') && is_array($newvalue) && is_array($options['headerbefore'][$now]))
631 {
632 foreach ($newvalue as $type => $currentScriptStr)
633 {
634 if (isset($options['headerbefore'][$now][strtolower($type)]))
635 {
636 $oldScriptStr = $options['headerbefore'][$now][strtolower($type)];
637
638 if ($oldScriptStr != $currentScriptStr)
639 {
640
641 $newvalue[strtolower($type)] = StringHelper::substr($currentScriptStr, StringHelper::strlen($oldScriptStr));
642 }
643 }
644 }
645 }
646 }
647 else
648 {
649 $newvalue = $headnow[$now];
650 }
651
652 if (!empty($newvalue))
653 {
654 $cached['head'][$now] = $newvalue;
655 }
656 }
657 }
658 else
659 {
660 $cached['head'] = $document->getHeadData();
661 }
662 }
663
664
665 $cached['mime_encoding'] = $document->getMimeEncoding();
666
667
668 if ($app->isClient('site') && $loptions['nopathway'] != 1)
669 {
670 $cached['pathway'] = is_array($data) && isset($data['pathway']) ? $data['pathway'] : $app->getPathway()->getPathway();
671 }
672
673 if ($loptions['nomodules'] != 1)
674 {
675
676
677 $buffer2 = $document->getBuffer();
678
679 if (!is_array($buffer2))
680 {
681 $buffer2 = array();
682 }
683
684
685 if (!isset($buffer2['module']) || !is_array($buffer2['module']))
686 {
687 $buffer2['module'] = array();
688 }
689
690
691 $cached['module'] = array_diff_assoc($buffer2['module'], $buffer1['module']);
692 }
693
694
695 if (isset($options['headers']) && $options['headers'])
696 {
697 $cached['headers'] = $app->getHeaders();
698 }
699
700 return $cached;
701 }
702
703 704 705 706 707 708 709
710 public static function makeId()
711 {
712 $app = JFactory::getApplication();
713
714 $registeredurlparams = new stdClass;
715
716
717 if (!empty($app->registeredurlparams))
718 {
719 $registeredurlparams = $app->registeredurlparams;
720 }
721
722
723 $defaulturlparams = array(
724 'format' => 'WORD',
725 'option' => 'WORD',
726 'view' => 'WORD',
727 'layout' => 'WORD',
728 'tpl' => 'CMD',
729 'id' => 'INT',
730 );
731
732
733 foreach ($defaulturlparams as $param => $type)
734 {
735 if (!property_exists($registeredurlparams, $param))
736 {
737 $registeredurlparams->$param = $type;
738 }
739 }
740
741 $safeuriaddon = new stdClass;
742
743 foreach ($registeredurlparams as $key => $value)
744 {
745 $safeuriaddon->$key = $app->input->get($key, null, $value);
746 }
747
748 return md5(serialize($safeuriaddon));
749 }
750
751 752 753 754 755 756 757
758 public static function getPlatformPrefix()
759 {
760
761 if (!JFactory::getConfig()->get('cache_platformprefix', '0'))
762 {
763 return '';
764 }
765
766 $webclient = new JApplicationWebClient;
767
768 if ($webclient->mobile)
769 {
770 return 'M-';
771 }
772
773 return '';
774 }
775
776 777 778 779 780 781 782 783 784
785 public static function addIncludePath($path = '')
786 {
787 static $paths;
788
789 if (!isset($paths))
790 {
791 $paths = array();
792 }
793
794 if (!empty($path) && !in_array($path, $paths))
795 {
796 jimport('joomla.filesystem.path');
797 array_unshift($paths, JPath::clean($path));
798 }
799
800 return $paths;
801 }
802 }
803