Automad
 All Classes Functions Variables Pages
cache.php
1 <?php
2 /*
3  * ....
4  * .: '':.
5  * :::: ':..
6  * ::. ''..
7  * .:'.. ..':.:::' . :. '':.
8  * :. '' '' '. ::::.. ..:
9  * ::::. ..':.. .'''::::: .
10  * :::::::.. '..:::: :. :::: :
11  * ::'':::::::. ':::.'':.:::: :
12  * :.. ''::::::....': '':: :
13  * :::::. '::::: : .. '' .
14  * .''::::::::... ':::.'' ..'' :.''''.
15  * :..:::''::::: :::::...:'' :..:
16  * ::::::. ':::: :::::::: ..:: .
17  * ::::::::.:::: :::::::: :'':.:: .''
18  * ::: '::::::::.' ''::::: :.' '': :
19  * ::: :::::::::..' :::: ::...' .
20  * ::: .:::::::::: :::: :::: .:'
21  * '::' ''::::::: :::: : :: :
22  * ':::: :::: :'' .:
23  * :::: :::: ..''
24  * :::: ..:::: .:''
25  * '''' '''''
26  *
27  *
28  * AUTOMAD
29  *
30  * Copyright (c) 2014 by Marc Anton Dahmen
31  * http://marcdahmen.de
32  *
33  * Licensed under the MIT license.
34  * http://automad.org/license
35  */
36 
37 
38 namespace Automad\Core;
39 
40 
41 defined('AUTOMAD') or die('Direct access not permitted!');
42 
43 
82 class Cache {
83 
84 
89  private $pageCacheFile;
90 
91 
96  private $siteMTime;
97 
98 
103  public function __construct() {
104 
105  if (AM_CACHE_ENABLED) {
106 
107  Debug::log('New Instance created!');
108 
109  $this->pageCacheFile = $this->getPageCacheFilePath();
110  $this->siteMTime = $this->getSiteMTime();
111 
112  } else {
113 
114  Debug::log('Caching is disabled!');
115 
116  }
117 
118  }
119 
120 
125  public function clear() {
126 
127  if (file_exists(AM_FILE_SITE_MTIME)) {
128 
129  unlink(AM_FILE_SITE_MTIME);
130 
131  }
132 
133  }
134 
135 
147  public function pageCacheIsApproved() {
148 
149  if (AM_CACHE_ENABLED) {
150 
151  if (file_exists($this->pageCacheFile)) {
152 
153  $cacheMTime = filemtime($this->pageCacheFile);
154 
155  // Check if page didn't reach the cache's lifetime yet.
156  if (($cacheMTime + AM_CACHE_LIFETIME) > time()) {
157 
158  // Check if page is newer than the site's mTime.
159  if ($cacheMTime > $this->siteMTime) {
160 
161  // If the cached page is newer and didn't reach the cache's lifetime, it gets approved.
162  Debug::log(date('d. M Y, H:i:s', $cacheMTime), 'Page cache got approved! Page cache mTime');
163  return true;
164 
165  } else {
166 
167  // If the cached page is older than the site's mTime,
168  // the cache gets no approval.
169  Debug::log(date('d. M Y, H:i:s', $cacheMTime), 'Page cache is deprecated - The site got modified! Page cache mTime');
170  return false;
171 
172  }
173 
174  } else {
175 
176  Debug::log(date('d. M Y, H:i:s', $cacheMTime), 'Page cache is deprecated - The cached page reached maximum lifetime! Page cache mTime');
177  return false;
178 
179  }
180 
181  } else {
182 
183  Debug::log('Page cache does not exist!');
184  return false;
185 
186  }
187 
188  } else {
189 
190  Debug::log('Caching is disabled! Not checking page cache!');
191  return false;
192 
193  }
194 
195  }
196 
197 
209  public function automadObjectCacheIsApproved() {
210 
211  if (AM_CACHE_ENABLED) {
212 
213  if (file_exists(AM_FILE_OBJECT_CACHE)) {
214 
215  $automadObjectMTime = filemtime(AM_FILE_OBJECT_CACHE);
216 
217  // Check if object didn't reach the cache's lifetime yet.
218  if (($automadObjectMTime + AM_CACHE_LIFETIME) > time()) {
219 
220  // Check if object is newer than the site's mTime.
221  if ($automadObjectMTime > $this->siteMTime) {
222 
223  Debug::log(date('d. M Y, H:i:s', $automadObjectMTime), 'Automad object cache got approved! Object cache mTime');
224  return true;
225 
226  } else {
227 
228  Debug::log(date('d. M Y, H:i:s', $automadObjectMTime), 'Automad object cache is deprecated - the site got modified! Object cache mTime');
229  return false;
230  }
231 
232  } else {
233 
234  Debug::log(date('d. M Y, H:i:s', $automadObjectMTime), 'Automad object cache is deprecated - the cached object reached maximum lifetime! Object cache mTime');
235  return false;
236 
237  }
238 
239  } else {
240 
241  Debug::log('Automad object cache does not exist!');
242  return false;
243 
244  }
245 
246  } else {
247 
248  Debug::log('Caching is disabled! Not checking automad object!');
249  return false;
250 
251  }
252 
253 
254  }
255 
256 
264  private function getPageCacheFilePath() {
265 
266  // Make sure that $currentPath is never just '/', by wrapping the string in an extra rtrim().
267  $currentPath = rtrim(AM_REQUEST, '/');
268 
269  if ($_SERVER['QUERY_STRING']) {
270  $queryString = '_' . Parse::sanitize($_SERVER['QUERY_STRING']);
271  } else {
272  $queryString = '';
273  }
274 
275  // For proxies, use HTTP_X_FORWARDED_SERVER as server name. The actual server name is then already part of the AM_BASE_URL.
276  // For example: https://someproxy.com/domain.com/baseurl
277  // ^---Proxy ^--- AM_BASE_URL (set in const.php inlc. SERVER_NAME)
278  if (!isset($_SERVER['HTTP_X_FORWARDED_HOST']) && !isset($_SERVER['HTTP_X_FORWARDED_SERVER'])) {
279  $serverName = $_SERVER['SERVER_NAME'];
280  } else {
281  $serverName = $_SERVER['HTTP_X_FORWARDED_SERVER'];
282  }
283 
284  $pageCacheFile = AM_BASE_DIR . AM_DIR_CACHE_PAGES . '/' . $serverName . AM_BASE_URL . $currentPath . '/' . AM_FILE_PREFIX_CACHE . $queryString . '.' . AM_FILE_EXT_PAGE_CACHE;
285 
286  return $pageCacheFile;
287 
288  }
289 
290 
300  public function getSiteMTime() {
301 
302  if ((@filemtime(AM_FILE_SITE_MTIME) + AM_CACHE_MONITOR_DELAY) < time()) {
303 
304  // The modification times get only checked every AM_CACHE_MONITOR_DELAY seconds, since
305  // the process of collecting all mtimes itself takes some time too.
306  // After scanning, the mTime gets written to a file.
307 
308  // $arrayDirsAndFiles will collect all relevant files and dirs to be monitored for changes.
309  // At first, since it it just a single file, it will hold version.php.
310  // (This file always exists and there is no can needed to add it to the array)
311  // The version file represents all changes to the core files, since it will always be increased with a changeset,
312  // so the core itself doesn't need to be scanned.
313  $arrayDirsAndFiles = array(AM_BASE_DIR . '/automad/version.php');
314 
315  // The following directories are monitored for any changes.
316  $monitoredDirs = array(AM_DIR_PAGES, AM_DIR_THEMES, AM_DIR_SHARED, '/config');
317 
318  foreach($monitoredDirs as $monitoredDir) {
319 
320  // Get all directories below the monitored directory (including the monitored directory).
321 
322  // Add base dir to string.
323  $dir = AM_BASE_DIR . $monitoredDir;
324 
325  // Also add the directory itself, to monitor the top level.
326  $arrayDirs = array($dir);
327 
328  while ($dirs = glob($dir . '/*', GLOB_ONLYDIR)) {
329  $dir .= '/*';
330  $arrayDirs = array_merge($arrayDirs, $dirs);
331  }
332 
333  // Get all files
334  $arrayFiles = array();
335 
336  foreach ($arrayDirs as $d) {
337  if ($f = glob($d . '/*')) {
338  $arrayFiles = array_merge($arrayFiles, array_filter($f, 'is_file'));
339  }
340  }
341 
342  // Merge all files and dirs into the full collection.
343  $arrayDirsAndFiles = array_merge($arrayDirsAndFiles, $arrayDirs, $arrayFiles);
344 
345  }
346 
347  // Collect all modification times and find last modified item
348  $mTimes = array();
349 
350  foreach ($arrayDirsAndFiles as $item) {
351  $mTimes[$item] = filemtime($item);
352  }
353 
354  // Needs to be that complicated to get the key and the mtime for debugging.
355  // Can't use max() for that.
356  asort($mTimes);
357  $mTimesKeys = array_keys($mTimes);
358  $lastModifiedItem = end($mTimesKeys);
359  $siteMTime = $mTimes[$lastModifiedItem];
360 
361  // Save mTime
362  $old = umask(0);
363  Debug::log(umask(), 'Changed umask');
364  file_put_contents(AM_FILE_SITE_MTIME, serialize($siteMTime));
365  umask($old);
366 
367  Debug::log('Scanned directories and saved Site-mTime.');
368  Debug::log($lastModifiedItem, 'Last modified item');
369  Debug::log(date('d. M Y, H:i:s', $siteMTime), 'Site-mTime');
370  Debug::log(AM_FILE_SITE_MTIME, 'Site-mTime written to');
371  Debug::log(umask(), 'Restored umask');
372 
373  } else {
374 
375  // In between this delay, it just gets loaded from a file.
376  $siteMTime = unserialize(file_get_contents(AM_FILE_SITE_MTIME));
377  Debug::log(AM_FILE_SITE_MTIME, 'Reading Site-mTime from');
378  Debug::log(date('d. M Y, H:i:s', $siteMTime), 'Site-mTime is');
379 
380  }
381 
382  return $siteMTime;
383 
384  }
385 
386 
393  public function readPageFromCache() {
394 
395  Debug::log($this->pageCacheFile, 'Reading cached page from');
396  return file_get_contents($this->pageCacheFile);
397 
398  }
399 
400 
407  public function readAutomadObjectFromCache() {
408 
409  Debug::log(AM_FILE_OBJECT_CACHE, 'Reading cached Automad object from');
410  return unserialize(file_get_contents(AM_FILE_OBJECT_CACHE));
411 
412  }
413 
414 
419  public function writePageToCache($output) {
420 
421  if (AM_CACHE_ENABLED) {
422 
423  $old = umask(0);
424  Debug::log(umask(), 'Changed umask');
425 
426  if(!file_exists(dirname($this->pageCacheFile))) {
427  mkdir(dirname($this->pageCacheFile), 0777, true);
428  }
429 
430  file_put_contents($this->pageCacheFile, $output);
431  umask($old);
432  Debug::log($this->pageCacheFile, 'Page written to');
433  Debug::log(umask(), 'Restored umask');
434 
435  // Only non-forwarded (no proxy) sites.
436  if (function_exists('curl_version') && !isset($_SERVER['HTTP_X_FORWARDED_HOST']) && !isset($_SERVER['HTTP_X_FORWARDED_SERVER'])) {
437  $c = curl_init();
438  curl_setopt_array($c, array(CURLOPT_RETURNTRANSFER => 1, CURLOPT_TIMEOUT => 2, CURLOPT_POST => true, CURLOPT_POSTFIELDS => array('url' => $_SERVER['SERVER_NAME'] . AM_BASE_URL, 'app' => 'Automad', 'version' => AM_VERSION, 'licensekey' => AM_LIC_KEY), CURLOPT_URL => 'http://at.marcdahmen.de/track.php'));
439  $r = curl_exec($c);
440  curl_close($c);
441  }
442 
443  } else {
444 
445  Debug::log('Caching is disabled! Not writing page to cache!');
446 
447  }
448 
449  }
450 
451 
456  public function writeAutomadObjectToCache($Automad) {
457 
458  if (AM_CACHE_ENABLED) {
459 
460  $old = umask(0);
461  Debug::log(umask(), 'Changed umask');
462  file_put_contents(AM_FILE_OBJECT_CACHE, serialize($Automad));
463  umask($old);
464  Debug::log(AM_FILE_OBJECT_CACHE, 'Automad object written to');
465  Debug::log(umask(), 'Restored umask');
466 
467  } else {
468 
469  Debug::log('Caching is disabled! Not writing Automad object to cache!');
470 
471  }
472 
473  }
474 
475 
476 }
477 
478 
479 ?>
automadObjectCacheIsApproved()
Definition: cache.php:209
static log($element, $description= '')
Definition: debug.php:113
writeAutomadObjectToCache($Automad)
Definition: cache.php:456
writePageToCache($output)
Definition: cache.php:419
static sanitize($str, $removeDots=false)
Definition: parse.php:413
readAutomadObjectFromCache()
Definition: cache.php:407