<?php
/* Copyright (c) 2003 Reimer Behrends
   
   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   as published by the Free Software Foundation; either version 2
   of the License, or (at your option) any later version.

   See http://www.gnu.org/copyleft/gpl.html for a copy of the
   license.

    Version: 0.5  Date: November 18, 2003
*/

$BrowseDirectives['[[nocache]]'] = '$GLOBALS["EnableCache"]=0;';

if (isset($EnableCache) && !$EnableCache) return;
$EnableCache = 1;
// Setting $DebugCache will append a [Cached] to the title of the
// page when a cached version is displayed.
// $DebugCache = 1;

// The directory path must be absolute, because by the time the shutdown
// function is called, we've lost track of the current directory.
$CacheDir = getcwd() . "/wiki.cache";
$CacheTimeStamp = "$CacheDir/.touched";

// Create $CacheDir and make it inaccessible
mkgiddir($CacheDir);
if (!file_exists("$CacheDir/.htaccess")) {
  $fp = @fopen("$CacheDir/.htaccess", "w");
  if ($fp) {
    fwrite($fp, "Order Deny,Allow\n");
    fwrite($fp, "Deny from all\n");
    fclose($fp);
  }
}

// Update $HandleActions

$CacheSavedBrowseAction = $HandleActions["browse"];
if (!$CacheSavedBrowseAction) $CacheSavedBrowseAction = "HandleBrowse";
$HandleActions["browse"] = 'CacheHandleBrowse';
$HandleActions["resetcache"] = 'ResetCache';
if (substr($action,0,4) == "post"
    || $action == "upload"
    || @$HTTP_POST_VARS["post"])
  register_shutdown_function("InvalidateCache");

if ($CacheAuthCheck) {
  $CacheSavedAuth = $AuthFunction;
  $AuthFunction = 'CacheAuthHook';
  $CacheReadAuthPages = array();
}
$CacheFailedAuth = false;

function InvalidateCache()
{
  global $CacheTimeStamp;
  touch($CacheTimeStamp);
}

function CacheHandleBrowse($pagename) {
  global $CacheDir, $PageFileFmt, $CacheFile, $CacheTimeStamp,
    $CacheSavedBrowseAction, $DebugCache, $EnableCache, $Now,
    $CacheSavedAuth, $CacheReadAuthPages, $CacheFailedAuth;
  if (!$EnableCache) {
    $CacheSavedBrowseAction($pagename);
    return;
  }
  $pagefile = FmtPageName($PageFileFmt,$pagename);
  $CacheFile = "$CacheDir/$pagefile";
  Lock(1);
  $cachedata = @unserialize(implode("", file($CacheFile)));
  $cachetime = $cachedata["time"];
  $lastchange = @filemtime($CacheTimeStamp);
  // The following loop traverses scripts and other files in
  // local/ so that changes to those will invalidate the cache.
  $dfp = @opendir("local");
  if ($dfp)
  {
    while ($file = readdir($dfp))
      if ($file[0] != ".")
        $lastchange = max($lastchange, @filemtime("local/$file"));
    closedir($dfp);
  }
  // Catch local.php too, in case somebody uses that.
  $lastchange = max($lastchange, @filemtime("local.php"));
  // Was the cached version created after the last change?
  if ($cachetime > $lastchange)
  {
    if ($CacheAuthCheck) {
      $authok = true;
      foreach ($cachedata["included"] as $readpage)
	if (!$CacheSavedAuth($readpage, "read", false)) {
	  $authok = false;
	  break;
	}
      if (!$authok) {
	Lock(0);
	return $CacheSavedBrowseAction($pagename);
      }
    }
    $contents = $cachedata["html"];
    if ($contents)
    {
      // Send our own headers, not the PHP default.
      PrintFmt("headers:", $pagename);
      if ($DebugCache)
        $contents = str_replace("</title>", " [Cached]</title>", $contents);
      print $contents;
      Lock(-1);
      return;
    }
  }
  // We have to drop back to Lock(0) to avoid a deadlock.
  Lock(0);
  ob_start();
  register_shutdown_function("FlushOutputBuffer");
  $CacheSavedBrowseAction($pagename);
  if ($EnableCache && !$CacheFailedAuth) {
    Lock(2);
    $fp = fopen($CacheFile, "w");
    $cachedata = array("time" => $Now,
      "included" => $CacheReadAuthPages, "html" => ob_get_contents());
    fwrite($fp, serialize($cachedata));
    fclose($fp);
  }
  Lock(-1);
}

function FlushOutputBuffer()
{
  ob_end_flush();
}

function ResetCache($pagename)
{
  global $HTMLTitleFmt, $CacheSavedBrowseAction;
  $HTMLTitleFmt = str_replace("</title>", " [Cache Reset]</title>", $HTMLTitleFmt);
  InvalidateCache();
  $CacheSavedBrowseAction($pagename);
}

function CacheAuthHook($pagename, $level, $authprompt=true) {
  global $CacheSavedAuth, $CacheReadAuthPages, $CacheFailedAuth;
  if ($level == "read")
    $CacheReadAuthPages[] = $pagename;
  $result = $CacheSavedAuth($pagename, $level, $authprompt);
  if (!$result && $level == "read")
    $CacheFailedAuth = true;
  return $result;
}

?>