Logo Search packages:      
Sourcecode: dacode version File versions  Download package

cache.php3

<?php
/**
 * This Class will handle all cache system
 *
 * daCode http://www.dacode.org/
 * src/phplib/cache.php3
 * $Id: cache.php3,v 1.66.2.3 2002/05/15 17:27:03 jbcombes Exp $
 *
 * Depends: Config
 */

Class Cache {

      /**
       * State used in write_html()
       * 0: HTML page is written to file
       * 1: outdated, because some boxes were not up-to-date
       * 2: a .del file has been found
       *@var boolean
       */
      var $state;

      /**
       * When an HTML file is locked up, wait x seconds
       * for the new version being regenerated
       *@var integer
       */
      var   $lock_delay;

      /**
       * Is set to Config::mark_outdated
       *@var boolean 
       */
      var $mark_outdated;

      /**
       * Is set to Config::topdir
       *@var
       */
      var $topdir;

      /**
       * Is set to Config::cachedir
       *@var
       */
      var   $cachedir;
      
      /**
       * Is set to Config::htmldir
       *@var
       */
      var $htmldir;
      
      /**
       * Db abstraction layer
       *@var object Db
       */
      var $db;

      /**
       * Session instance
       *@var object Session
       */
      var $session;

      /**
       * Utils instance
       *@var object Utils
       */
      var $utils;

      /**
       * Class constructor
       */
      Function Cache() {
            global $config;

            $this->db = LoadClass('Db');
            $this->session = LoadClass('Session');
            $this->utils = LoadClass('Utils');

            //   When an HTML file is locked up, wait x seconds
            //   for the new version being regenerated
            $this->lock_delay = 3;

            // State used in write_html()
            //   0: HTML page is written to file
            //   1: outdated, because some boxes were not up-to-date
            //   2: a .del file has been found
            $this->state = 0;

            $this->mark_outdated = $config->mark_outdated;
            $this->topdir = $config->topdir;
            $this->cachedir = $config->cachedir;
            if (isset($config->htmldir) &&
                        $config->htmldir != "") {
                  $this->htmldir = $config->topdir.$config->htmldir;
            } else {
                  $this->htmldir = '';
            }
      }

      /**
       * Return contents of cached box when it exists
       *@access public
       *@param string integer validity of the cache (seconds)
       *@param string name of the box
       *@param mixed  string or array of options.
       *@return string content of the file, void if file does not exist.
       */
      Function check_box($cache_time="60",$name,$options="") {
            $cache_file = str_replace('//','/',$this->cachedir.$name."/#");
            if (gettype($options) == "array") {
                  reset($options);
                  while (list ($key, $val) = each ($options)) {
                        $cache_file .= $val.".";
                  }
            } else {
                  $cache_file .= $options.".";
            }

            if ($this->box_file_exists($cache_file)) {
                  $filedate = filectime($cache_file);
                  if ($filedate && time() < $filedate + $cache_time) {
                        return @join ('', file($cache_file));
                  }
            }
      }
      
      /**
       * Writes a box in cache
       *@access public
       *@param string the name of the box
       *@param mixed string or array of options
       *@param string the content of box.
       *@return void or string the input if failed to created cache dir.
       */
      Function write_box($name,$options,$input) {
            global $config;
            if (empty($input) || empty($this->cachedir) || isset($config->nosave)) {
                  return;
            }
            $cache_dir = $this->cachedir.$name;
            if (!$this->utils->createdir($cache_dir, 0755)) {
                  return $input;
            }
            $cache_file = $cache_dir."/#";
            if (gettype($options) == "array") {
                  reset($options);
                  while (list ($key, $val) = each ($options)) {
                        $cache_file .= $val.".";
                  }
            } else {
                  $cache_file .= $options.".";
            }
            $this->utils->write_file($cache_file, $input);
            @unlink($cache_file.'.lock');
      }

      /**
       *  Check whether file exists, with a lock mechanism to reduce SQL queries.
       *@access private
       *@param string name of file  to check
       *@return integer 0 if file doesn't exist, 1 otherwise.
       */
      Function box_file_exists($file) {
            if (!file_exists($file)) {
                  return 0;
            }

            $ret = 0;
            if (file_exists($file.'.del') && file_exists($file.'.lock')) {
                  $filedate = filectime($file.'.lock');
                  if ($filedate && time() < $filedate + $this->lock_delay) {
                        //   This box is being regenerated ;
                        //   do not wait, but tell HTML files it
                        //   will be outdated
                        $this->state = max(1, $this->state);
                        $ret = 1;
                  } else {
                        //   Lock file is outdated, regenerate it
                        $ret = 0;
                  }
            } elseif (file_exists($file.'.del')) {
                  $ret = 0;
            } else {
                  $ret = 1;
            }

            if (!$ret) {
                  // we now ignore STOP from user
                  ignore_user_abort(true);

                  //   File will be regenerated, so remove .del flag
                  //   and add a lock
                  $this->tag_file($file.'.lock', 1);
                  @unlink($file.'.del');
            }
            return $ret;
      }

      /**
       * Return contents of HTML file if it exists
       * Calls include or readfile to pass the content to the browser, then exit.
       * Returns void if file exists.
       *@access private
       *@param string the name of the file
       */
      Function check_html($name) {
            if (substr($name,-1) == '/') {
                  return;
            }
            $cache_file = str_replace('//','/',$this->htmldir.$name);
            if ($this->html_file_exists($cache_file)) {
                  if (substr($cache_file,-5) == '.html') {
                        readfile($cache_file);
                  } else {
                        $topdir = $this->topdir;
                        include $cache_file;
                  }
                  @unlink($cache_file.'.lock');
                  exit;
            }
      }

      /**
       * Writes a full page in cache?
       *@access public
       *@param string the filename
       *@param string the text to write
       *@todo what's this global $news_id???
       */
      Function write_html($file,$text) {
            global $config;
            global $news_id;
            global $date;

            if (empty($text) || empty($this->htmldir) || isset($config->nosave)) {
                  return;
            }
            if (substr($file,-5) != '.html') {
                  //  Remove some boxes
                  if (ereg('/', $file)) {
                        $alttopdir = '.';
                        $tmp = split('/', $file);
                        $i = 1;
                        while ($i < count($tmp)) {
                              $alttopdir .= '/..';
                              $i++;
                        }
                  } else {
                        $alttopdir = '.';
                  }

                  $tmp = '<?php if (empty($topdir)) {'.
                        '$topdir="'.$alttopdir.'";'.
                        'include $topdir."/dacode.php3"; }';
                  if (isset($news_id) && $news_id != 0) {
                        $tmp .= '$news_id = '.$news_id.';';
                  }
                  if (isset($date) && $date != 0) {
                        $tmp .= '$date = '.$date.';';
                  }
                  $tmp .= '$html = LoadClass("Html");'.
                        '$user = LoadClass("User");'.
                        '$message = LoadClass("Message");'.
                        '$board = LoadClass("Board");'.
                        '$admin = LoadClass("Admin"); ?>';
                  $text = $tmp . $text;

                  $patterns = array('/<!-- LASTSEEN:(\d+) -->.*<!-- \/LASTSEEN -->/',
                                                '/<!-- ADMIN -->.*<!-- \/ADMIN -->/',
                                                '/<!-- ADMINSCORE:(\d+):(\d+):"(.*)":"(.*)":"(\d+)":"(\d+)":"(-?\d+)":"([^"]*)" -->.*<!-- \/ADMINSCORE -->/',
                                                '/<!-- ADMINEDIT:(\d+) -->.*<!-- \/ADMINEDIT -->/',
                                                '/<!-- SIDEBOX login -->.*<!-- \/SIDEBOX login -->/s',
                                                '/<!-- MESSAGESHOW -->.*<!-- \/MESSAGESHOW -->/',
                                                '/<!-- SIDEBOX board -->.*<!-- \/SIDEBOX board -->/',
                                                '/<!-- TIPTITLE:(\d+) -->.*<!-- \/TIPTITLE -->/',
                                                '/<!-- WEBCAMTITLE:(\d+) -->.*<!-- \/WEBCAMTITLE -->/');

                  $replaces = array('<?php echo $user->lastseen_show("\\1"); ?>',
                                                '<?php echo $admin->adminbox(); ?>',
                                                '<?php echo $admin->comments_showscore("\\1","\\2","\\3","\\4","\\5","\\6","\\7","\\8"); ?>',
                                                '<?php echo $admin->news_showedit("\\1"); ?>',
                                                '<?php echo $user->loginbox(); ?>',
                                                '<?php echo $message->show_new_title(); ?>',
                                                '<?php echo $board->print_message(); ?>',
                                                '<?php echo $admin->tips_showtitle("\\1"); ?>',
                                                '<?php echo $admin->webcam_showtitle("\\1"); ?>');

                  $text = preg_replace ($patterns, $replaces, $text);

                  if ($config->userboxes) {
                        $text = preg_replace('/<!-- USERBOXES:(.*) -->.*<!-- \/USERBOXES -->/s',
                                    '<?php echo $user->show_userboxes("\\1"); ?>',$text);
                  } else {
                        $text = preg_replace('/<!-- USERBOXES:[^\s]* -->(.*)<!-- \/USERBOXES -->/s',
                                    '\\1',$text);
                  }

                  if ($this->session->has_user_boxes == $config->userboxes) {
                        $this->utils->write_file($file,$text);
                  }
            } elseif (!$this->session->checked) {

                  $patterns = array('/<!-- LASTSEEN:\d+ -->.*<!-- \/LASTSEEN -->/',
                                                '/<!-- ADMIN -->.*<!-- \/ADMIN -->/',
                                                '/<!-- ADMINSCORE:\d+:\d+:".*":".*":"\d+":"\d+":"-?\d+":"[^"]*" -->(.*)<!-- \/ADMINSCORE -->/',
                                                '/<!-- ADMINEDIT:(\d+) -->.*<!-- \/ADMINEDIT -->/',
                                                '/<!-- SIDEBOX login -->(.*)<!-- \/SIDEBOX login -->/s',
                                                '/<!-- MESSAGESHOW -->.*<!-- \/MESSAGESHOW -->/',
                                                '/<!-- SIDEBOX board -->.*<!-- \/SIDEBOX board -->/',
                                                '/<!-- TIPTITLE:\d+ -->(.*)<!-- \/TIPTITLE -->/',
                                                '/<!-- WEBCAMTITLE:\d+ -->(.*)<!-- \/WEBCAMTITLE -->/',
                                                '/<!-- USERBOXES:[^\s]* -->(.*)<!-- \/USERBOXES -->/s');

                  $replaces = array('','','\\1','','\\1','','','\\1','\\1','\\1');

                  $text = preg_replace ($patterns, $replaces, $text);

                  $this->utils->write_file($file,$text);
            }
            @unlink($file.'.lock');
      }

      /**
       * Check whether file exists, with a lock mechanism to reduce SQL queries
       *@access private
       *@param string filename
       *@return integer 0 if does not exist, 1 if it does.
       */
      Function html_file_exists($file) {
            $ret = 0;
            $delfile = (file_exists($file.'.del') || $this->state >= 2);
            if ($delfile && file_exists($file.'.lock')) {
                  $filedate = filectime($file.'.lock');
                  while (file_exists($file.'.lock') && $filedate &&
                              time() < $filedate + $this->lock_delay) {
                        sleep(1);
                  }
                  if (file_exists($file.'.lock')) {
                        //   An outdated lock file exists
                        $ret = 0;
                  }
                  $this->state = 2;
            } elseif ($delfile) {
                  $this->state = 2;
                  $ret = 0;
            } elseif (file_exists($file.'.lock') && file_exists($file)) {
                  $ret = 1;
            } elseif (file_exists($file.'.lock')) {
                  $filedate = filectime($file.'.lock');
                  while (file_exists($file.'.lock') && $filedate &&
                              time() < $filedate + $this->lock_delay) {
                        sleep(1);
                  }
                  $ret = (file_exists($file) ? 1 : 0);
            } else {
                  $ret = (file_exists($file) ? 1 : 0);
            }

            if (!$ret && (!$this->session->checked || substr($file,-5) != '.html')) {
                  //   File is regenerated
                  // we now ignore STOP from user
                  ignore_user_abort(true);

                  //   File will be regenerated, so remove .del flag
                  //   and add a lock
                  $this->tag_file($file.'.lock', 1);
                  @unlink($file.'.del');
            }
            return $ret;
      }

      /**
       * Delete cached files
       *@access public
       *@param string $dir directory where are the files to delete
       *@param boolean $location if true, $dir is subdir of htmldir, else of cachedir
       *@param boolean $recurs if true, runs through directories recursively
       *@param boolean $rmdir delete directories?
       *@param boolean $rmtag tag files for deletion?
       *@param string $pattern name pattern of files to delete (english?!?)
       *@param string $dirpattern name pattern of dirss to delete
       */
      Function delete_files($dir,$location,$recurs,$rmdir,
                                                                        $rmtag,$pattern,$dirpattern) {
            $dir = ereg_replace('/$', '', $dir);
            if ($location) {
                  if (!$this->htmldir) return;
                  $fulldir = $this->htmldir . $dir;
            } else {
                  if (!$this->cachedir) return;
                  $fulldir = $this->cachedir . $dir;
            }
            if (!file_exists($fulldir) ||
                  !is_dir($fulldir)) {
                  return;
            }
            $handle=opendir($fulldir);
            while ($file = readdir($handle)) {
                  if ($file == '.' || $file == '..') continue;
                  if (!$rmtag && (substr($file, -4) == '.del' ||
                              substr($file, -5) == '.lock')) {
                        continue;
                  }

                  if (is_dir($fulldir.'/'.$file)) {
                        if ($recurs && ereg($dirpattern, $file)) {
                              $this->delete_files($dir.'/'.$file,$location,1,$rmdir,$rmtag,
                                                                                          $pattern,$dirpattern);
                              @rmdir($fulldir.'/'.$file);
                        }
                  } elseif (ereg($pattern, $file)) {
                        /* Sometimes the file already disappeared...*/
                        if (file_exists($fulldir.'/'.$file)) {
                              unlink($fulldir.'/'.$file);
                        }
                  }
            }
            closedir($handle);
            if ($rmdir) {
                  @rmdir($fulldir);
            }
      }

      /** 
       * Mnemonic shorthand
       *@access public
       *@param string $dir directory where are the files to delete
       *@param boolean $recurs if true, runs through directories recursively
       *@param boolean $rmdir delete directories?
       *@param boolean $rmtag tag files for deletion?
       *@param string $pattern name pattern of files to delete (english?!?)
       *@param string $dirpattern name pattern of dirss to delete 
       *@see delete_files()
       */
      Function delete_htmlfiles($dir,$recurs=false,$rmdir=false,$rmtag=false,
                                                                                    $pattern=".*",$dirpattern="") {
            if (!$dirpattern) {
                  $dirpattern = $pattern;
            }
            if ($this->mark_outdated) {
                  $this->tag_delete_files($dir,1,$recurs,$pattern,$dirpattern);
            } else {
                  $this->delete_files($dir,1,$recurs,$rmdir,$rmtag,$pattern,$dirpattern);
            }
      }

      /**
       *  Mnemonic shorthand
       *@access public
       *@param string $dir directory where are the files to delete
       *@param boolean $recurs if true, runs through directories recursively
       *@param boolean $rmdir delete directories?
       *@param boolean $rmtag tag files for deletion?
       *@param string $pattern name pattern of files to delete (english?!?)
       *@see delete_files()
       */
      Function delete_boxfiles($dir,$recurs=false,$rmdir=false,$rmtag=false,$pattern=".*") {
            if ($this->mark_outdated && !$rmtag) {
                  $this->tag_delete_files($dir,0,$recurs,$pattern,".");
            } else {
                  $this->delete_files($dir,0,$recurs,$rmdir,$rmtag,$pattern,".");
            }
      }

      /**
       * Tag files for deletion
       *@access private
       *@param string $dir directory where are the files to delete
       *@param boolean $location if true, $dir is subdir of htmldir, else of cachedir
       *@param boolean $recurs if true, runs through directories recursively
       *@param string $pattern name pattern of files to delete (english?!?)
       *@param string $dirpattern name pattern of dirss to delete
       */
      Function tag_delete_files($dir,$location,$recurs,$pattern,$dirpattern) {
            $dir = ereg_replace('/$', '', $dir);
            if ($location) {
                  if (!$this->htmldir) return;
                  $fulldir = $this->htmldir . $dir;
            } else {
                  if (!$this->cachedir) return;
                  $fulldir = $this->cachedir . $dir;
            }
            if (!is_dir($fulldir))
                  return;
            $handle=opendir($fulldir);
            while ($file = readdir($handle)) {
                  if ($file == '.' || $file == '..') continue;
                  if (substr($file, -4) == '.del' ||
                              substr($file, -5) == '.lock') {
                        continue;
                  }

                  if (is_dir($fulldir.'/'.$file)) {
                        if ($recurs && ereg($dirpattern, $file)) {
                              $this->tag_delete_files($dir.'/'.$file,$location,
                                                                                                      1,$pattern,$dirpattern);
                        }
                  } elseif (ereg($pattern, $file)) {
                        $this->tag_file($fulldir.'/'.$file.'.del');
                  }
            }
            closedir($handle);
      }


      /**
       * Delete outdated cache files for news $news_id
       *@access public
       *@param integer id of the news 
       */
      Function delete_obsolete_news ($news_id) {
            global $config;
            if (empty($this->htmldir))
                  return;

            $sqlc_q = "SELECT timestamp,section,topic FROM ".
                  $config->tables['news'].",".
                  $config->tables['sections'].",".
                  $config->tables['topics'].
                  " WHERE ".$config->tables['news'].".id='".addslashes($news_id).
                  "' AND ".$config->tables['news'].".section_id=".
                  $config->tables['sections'].".id".
                  " AND ".$config->tables['news'].".topic_id=".
                  $config->tables['topics'].".id";
            $ret = $this->db->query($sqlc_q);
            if (!$ret) {
                  echo "<!-- SQL failed: ".$this->db->error() . " -->\n";
                  echo "<!-- SQL Command: ".$sqlc_q." -->\n";
                  return -1;
            }
            $row = $this->db->fetch_array();
            $regs = $this->utils->stamp2array( $row['timestamp']);
            $this->delete_htmlfiles($regs[1].'/'.$regs[2].'/'.$regs[3], 0, 0, 0, "^".
                  $news_id.'[,.]');
            $this->delete_htmlfiles('section/'.$row['section'], 0, 0, 0, '^'.$news_id.'[,.]');
            $this->delete_htmlfiles('topic/'.$row['topic'], 0, 0, 0, '^'.$news_id.'[,.]');
            $this->delete_htmlfiles('.', 0, 0, 0, '^index[,.]');
            $this->delete_boxfiles('news_show', 0, 0, 0, '^#'.$news_id.'\.');
            $this->delete_boxfiles('news_index', 0, 0, 0, '^#'.$row['section'].'\.');
            $this->delete_boxfiles('news_index', 0, 0, 0, '^#\.');
      }

      /**
       * Creates a tag file
       *@access private
       *@param string the filename
       *@param boolean force making if true.
       */
      Function tag_file ($file,$force=false) {
            if ($this->mark_outdated || $force) {
                  $fp = @fopen($file, 'wb');
                  if ($fp) {
                        fclose($fp);
                  }
            }
      }

}

?>

Generated by  Doxygen 1.6.0   Back to index