Location: PHPKode > projects > Slooze > src/slooze.php
<?php  /* -*- Mode: C++; indent-tabs-mode: nil; c-basic-indent: 2 -*- */
/*
 * Slooze PHP Web Photo Album
 * Copyright (c) 2000-2005 Slooze developers (see AUTHORS file)
 * $Id: slooze.php,v 1.58 2006/07/16 23:03:37 mdkendall Exp $
 */

class Slooze {

  /* Redefine these parameters by deriving your own class */

  var $admin = FALSE;         /* enable full admin mode */
  var $enableComments = TRUE; /* enable user addition of comments */
  var $enableRatings = TRUE;  /* enable user rating of pictures */
  var $enableViews = FALSE;   /* enable counting how many times a picture has been viewed */
  var $enableNav = TRUE;      /* enable First|Prev|Next|Last navigation */
  var $enableCache = FALSE;   /* enable caching of pages for speed */
  var $enableSearch = TRUE;   /* enable user search functionality */
  var $enableCommentsEmail = FALSE; /* enable email of new comments */

  var $allPathsLower = FALSE; /* make all image paths lower-case, no matter their recorded case */
  var $showCommentIPs = FALSE; /* put IP of commenter before comment */
  var $ownIPSubstring = "192.168.1."; /* don't count picture views coming from this address substring */
  var $sortThreshold = 5;  /* number of pics in topic before sorting offered */

  var $basePath = "./"; /* path to photos directory */
  var $cachePath = "./cache/"; /* path to cache directory */
  var $baseURL = "./";  /* URL of photos directory */
  var $actionURL = "";  /* URL for further actions */
  var $picture_suffix = ".jpg";  /* filename suffix for pictures */
  var $thumb_suffix = "-t.jpg";  /* filename suffix for thumbnails */
  var $thumb_height = 64;        /* height for auto-generated thumbnails */
  var $nl = "\r\n";              /* newline sequence */
  var $parentSelectPad = "&nbsp;&nbsp;"; /* what to pad the parent select with */
  var $emailTo = "hide@address.com"; /* email address notifications are sent to */
  var $emailFrom = "hide@address.com"; /* email address notifications are sent from */

  var $ctClass = "SloozeCtCsv";   /* type of container for picture metadata */
  var $ct;                        /* container for picture metadata */

  var $htmlStr;   /* string to return for output to browser */


  /* public: constructor */
  function Slooze() {
    global $HTTP_SERVER_VARS;
    if (!isset($HTTP_SERVER_VARS) && isset($_SERVER)) $HTTP_SERVER_VARS = $_SERVER;
    if( $this->actionURL == "" ) {
      $this->actionURL = $HTTP_SERVER_VARS['PHP_SELF'];
    }
    $name = $this->ctClass;
    $this->ct = new $name;
  }

  /* public: construct valid inputs from GET or POST variables */
  function validateInputs() {
    global $HTTP_POST_VARS;
    global $HTTP_GET_VARS;
    $vars = count($_POST) > 0 ? $_POST :
              (count($_GET) > 0 ? $_GET :
                (count($HTTP_POST_VARS) > 0 ? $HTTP_POST_VARS :
                  (count($HTTP_GET_VARS) > 0 ? $HTTP_GET_VARS : array() )));
    $cleanvars = array();
    reset($vars);
    while( list($var, $value) = each($vars) ) {
      $cleanvars[$var] = $this->validateInput($value);
    }
    return $cleanvars;
  }

  /* private: sanitise a single variable */
  function validateInput($var) {
    if (get_magic_quotes_gpc()) {
      $var = stripslashes($var);
    }
    $var = strip_tags($var);
    $var = htmlspecialchars($var);
    $var = str_replace("\n", " ", $var);
    $var = str_replace("\r", " ", $var);
    $var = trim($var);
    return $var;
  }

  /* ------------------------------------------------------------------- */

  /* public: renderPage() does the work of producing the required html page.
   * It produces body text only, which must be wrapped by other html to
   * form a complete page. The effect of renderPage() depends on the
   * variables passed to it. */

  function renderPage( $vars ) {

    $this->htmlStr = "";

    $this->ct->resetError();

    /* handle database update actions */
    if(isset($vars['action'])) {
      $this->handleAction($vars);
      /* if we have just deleted something, don't carry on and try to render it */
      if(strstr($vars['action'],'delete')) {
        $this->renderTopic();
        return $this->htmlStr;
      }
    }

    /* return an appropriate page body */
    /* first, try the cache */
    if (!$this->admin && $this->enableCache && $this->cacheRead(md5(serialize($vars)))) {
      return $this->htmlStr;
    }

    /* no cache hit (or cache not enabled) so render the page body */
    if(isset($vars['TopicID'])) {
      if(isset($vars['sort'])) {
        $this->renderTopic($vars['TopicID'], $vars['sort']);
      } else {
        $this->renderTopic($vars['TopicID']);
      }
    }
    else if(isset($vars['RollID']) && isset($vars['FrameID'])) {
      $this->renderPicture($vars['RollID'], $vars['FrameID']);
    }
    else if(isset($vars['RollID'])) {
      $this->renderRoll($vars['RollID']);
    }
    else if(isset($vars['search'])) {
      $this->renderSearch($vars['search']);
    }
    else {
      /* default action is render top-level topics */
      $this->renderTopic();
    }
    /* save the page in the cache for next time */
    if (!$this->admin && $this->enableCache) {
      $this->cacheWrite(md5(serialize($vars)));
    }
    return $this->htmlStr;
  }

  /* ------------------------------------------------------------------- */

  /* High-level functions to render page bodies */

  /* private: render a page body for a given topic */
  function renderTopic( $topicID = "/", $sort="" ) {
    $topic = $this->ct->getTopic($topicID);
    $this->showTopic($topic);
    $subTopics = $this->ct->getTopicsInParentTopic($topicID);
    $this->showTopics($subTopics);
    $pictures = $this->ct->getPicturesInTopic($topicID);
    if ($sort != "") {
      $this->showSortType($sort);
      $pictures = $this->sortPictures($pictures, $sort, $this->sortThreshold);
    }
    $this->showThumbs($pictures);
    if ( (count($pictures) > $this->sortThreshold) || $sort!="" )
      $this->showSort($topicID);
    if ($this->admin) {
      $this->showFormUpdateTopic($topicID);
      if ($topicID == "/") {
        $this->showFormAddTopic();
        $this->showRolls();
        $this->showFormAddRoll();
      }
      else {
        if (count($pictures)== 0 ) {
          $this->showFormDeleteTopic($topicID);
        }
      }
    }
    if ($topicID != "/") {
      $this->showNav($topicID);
    }
    if ($this->enableSearch) {
      $this->showFormSearch();
    }
  }

  /* private: render a page body for a given picture */
  function renderPicture( $rollID, $frameID ) {
    if ($picture = $this->ct->getPicture($rollID, $frameID)) {
      $topic = $this->ct->getTopic($picture['ParentTopicID']);
      $this->showTopic($topic, false);
      $this->showPicture($picture);
      $comments = $this->ct->getCommentsInPicture($rollID, $frameID);
      $this->showNav($picture['ParentTopicID']);
      if ($this->enableNav) {
        $this->showNavigation($picture);
      }
      $this->showComments($comments);
      if ($this->enableComments) {
        $this->showFormAddComment($rollID, $frameID);
      }
      if ($this->enableRatings) {
        $this->showFormAddRating($rollID, $frameID, $picture['Rating']);
      }
      if ($this->admin) {
        $this->showFormUpdatePicture($rollID, $frameID);
        $this->showFormDeletePicture($rollID, $frameID);
      }
      // if conditions are appropriate, increment times a picture has been viewed
      if (!$this->admin && $this->enableViews) {
        global $HTTP_SERVER_VARS;
        if ( !strlen($this->ownIPSubstring) || !strstr($HTTP_SERVER_VARS['REMOTE_ADDR'], $this->ownIPSubstring) )
          $this->ct->incrementPictureViews($rollID, $frameID, $picture);
      }
    }
  }

  /* private: render a page body for a given roll */
  function renderRoll( $rollID ) {
    $this->showRoll($rollID);
    $pictures = $this->ct->getPicturesInRoll($rollID);
    $this->showThumbs($pictures);
    $this->showNav();
    if ($this->admin) {
//    $this->showFormUpdateRoll($rollID);
      if (count($pictures)== 0 ) {
        $this->showFormDeleteRoll($rollID);
      }
      $this->showFormAddPicture($rollID);
      $this->showFormAddAllPictures($rollID);
    }
  }

  /* private: render a page body for a given search */
  function renderSearch( $search ) {
    $this->showSearch($search);
    $pictures = $this->ct->getPicturesInSearch($search);
    $this->showThumbs($pictures);
    $this->showNav();
    $this->showFormSearch();
  }

  /* ------------------------------------------------------------------- */

  /* High-level functions to handle database updates */

  /* private: update the appropriate database table */
  function handleAction($vars) {
    global $HTTP_SERVER_VARS;
    if ($this->admin) {
      /* add, update and delete Topics */
      if($vars['action'] == 'updateTopic') {
        if (!isset($vars['ParentTopicID'])) $vars['ParentTopicID'] = '';
        $topic = array( 'TopicID' => $vars['TopicID'],
                        'ParentTopicID' => $vars['ParentTopicID'],
                        'Description' => $vars['Description'],
                        'Summary' => $vars['Summary']);
        $this->ct->updateTopic($topic);
      }
      else if($vars['action'] == 'addTopic') {
        $topic = array( 'TopicID' => $vars['TopicID'],
                        'ParentTopicID' => $vars['ParentTopicID'],
                        'Description' => $vars['Description'],
                        'Summary' => $vars['Summary']);
        $this->ct->addTopic($topic);
      }
      else if($vars['action'] == 'deleteTopic') {
        if (!$this->ct->deleteTopic($vars['TopicID']))
          $this->show_error($this->ct->getError());
      }
      /* add, update and delete Pictures */
      else if($vars['action'] == 'updatePicture') {
        $picture = array( 'RollID' => $vars['RollID'],
                        'FrameID' => $vars['FrameID'],
                        'ParentTopicID' => $vars['ParentTopicID'],
                        'Description' => $vars['Description'] );
        $this->ct->updatePicture($picture);
      }
      else if($vars['action'] == 'addPicture') {
        $picture = array( 'RollID' => $vars['RollID'],
                        'FrameID' => $vars['FrameID'],
                        'ParentTopicID' => $vars['ParentTopicID'],
                        'Description' => $vars['Description'],
                        'Views' => '0', 'Rating' => '0');
        $this->ct->addPicture($picture);
      }
      else if($vars['action'] == 'addAllPictures') {
        $this->addAllPictures($vars['RollID'], $vars['ParentTopicID']);
      }
      else if($vars['action'] == 'deletePicture') {
        $this->ct->deletePicture($vars['RollID'], $vars['FrameID']);
      }
      /* add, update and delete Rolls */
      else if($vars['action'] == 'updateRoll') {
        $roll = array( 'RollID' => $vars['RollID'] );
        $this->ct->updateRoll($roll);
      }
      else if($vars['action'] == 'addRoll') {
        $roll = array( 'RollID' => $vars['RollID'] );
        $this->ct->addRoll($roll);
      }
      else if($vars['action'] == 'deleteRoll') {
        if (!$this->ct->deleteRoll($vars['RollID']))
          $this->show_error($this->ct->getError());
       }
      /* delete Comments */
      else if($vars['action'] == 'deleteComment') {
        $this->ct->deleteComment($vars['CommentID']);
      }
    } // endif admin enabled
    if ($this->enableComments) {
      /* add Comments */
      if($vars['action'] == 'addComment') {
        if($vars['Comment'] != "") {
          $comment = array( 'CommentID' => uniqid(""),
                            'RollID' => $vars['RollID'],
                            'FrameID' => $vars['FrameID'],
                            'Comment' => $vars['Comment'],
                            'IP' => $HTTP_SERVER_VARS['REMOTE_ADDR']);
          $this->ct->addComment($comment);
          if ($this->enableCommentsEmail) {
            mail($this->emailTo, SLZ_STR_COMMENT_EMAIL_SUBJECT,
                 SLZ_STR_COMMENT . ": $comment[CommentID]\n" .
                 SLZ_STR_ROLLID . ": $comment[RollID]\n" .
                 SLZ_STR_FRAMEID . ": $comment[FrameID]\n" .
                 SLZ_STR_COMMENT . ": $comment[Comment]\n" .
                 "IP: $comment[IP]\n",
                 "From: " . $this->emailFrom);
          }
        }
      }
    } // endif comments enabled
    if ($this->enableRatings) {
      /* add Ratings */
      if($vars['action'] == 'addRating') {
        if(($vars['Rating'] >= -2) && ($vars['Rating'] <= 2)) {
          $rating = array( 'RollID' => $vars['RollID'],
                           'FrameID' => $vars['FrameID'],
                           'Rating' => $vars['Rating'],
                           'IP' => $HTTP_SERVER_VARS['REMOTE_ADDR'],
                           'RateTime' => time() );
          $this->ct->addRating($rating);
        }
      }
    } // endif ratings enabled
    /* Action has potentially changed pages - clear the cache */
    if ($this->enableCache) {
      $this->cacheClear();
    }
  }

  /* private: addAllPictures() searches for and adds all pictures in a roll */
  function addAllPictures( $rollID, $parentTopicID ) {
    if ($handle = opendir($this->basePath . $rollID)) {
      while ($file = readdir($handle)) {
        /* if not thumb */
        if (!ereg('(.+)'.str_replace('.','\.',$this->thumb_suffix).'$', $file)) {
          /* if is picture */
          if (ereg('(.+)'.str_replace('.','\.',$this->picture_suffix).'$', $file, $arr)) {
            set_time_limit(10);
            $frameID = $arr[1];
            $picture = array( 'RollID' => $rollID, 'FrameID' => $frameID,
              'ParentTopicID' => $parentTopicID, 'Description' => '',
              'Views' => '0', 'Rating' => '0' );
            /* make thumbnail if required */
            $this->makeThumb($picture);
            /* add picture if not already present */
            if (!$this->ct->getPicture($rollID, $frameID)) {
              $this->ct->addPicture($picture);
            }
          }
        }
      }
      closedir($handle);
    }
  }

  /* private: make a thumbnail image if one does not exist */
  function makeThumb($picture) {
    $fileNameStem = $this->basePath . $picture['RollID'] . "/" . $picture['FrameID'];
    if ($this->allPathsLower)
      $fileNameStem = strtolower( $fileNameStem );
    /* if thumbnail does not exist */
    if (!file_exists($fileNameStem . $this->thumb_suffix)) {
      if (function_exists('imagetypes') && (imagetypes() & IMG_JPG)) {
        /* make thumbnail using GD library */
        $srcImg = imagecreatefromjpeg($fileNameStem . $this->picture_suffix);
        $srcImgX = imagesx($srcImg);
        $srcImgY = imagesy($srcImg);
        $dstImgY = $this->thumb_height;
        $dstImgX = $srcImgX * $dstImgY / $srcImgY;
        $dstImg = imagecreate($dstImgX, $dstImgY);
        imagejpeg($dstImg, $fileNameStem . $this->thumb_suffix);
        imagedestroy($dstImg);
        $dstImg = imagecreatefromjpeg($fileNameStem . $this->thumb_suffix);
        if (function_exists('imagecopyresampled')) {
          imagecopyresampled($dstImg, $srcImg, 0, 0, 0, 0, $dstImgX, $dstImgY, $srcImgX, $srcImgY);
        } else {
          imagecopyresized($dstImg, $srcImg, 0, 0, 0, 0, $dstImgX, $dstImgY, $srcImgX, $srcImgY);
        }
        imagejpeg($dstImg, $fileNameStem . $this->thumb_suffix, 75);
        imagedestroy($scrImg);
        imagedestroy($dstImg);
      } else {
        /* GD library JPEG support apparently not available */
      }
    }
  }

  /* private: sortPictures() delivers a sorted subset of pictures */
  function sortPictures($pictures, $sort, $num) {
    if ($sort == 'views')
      usort($pictures, 'cmpViews' );
    if ($sort == 'rating')
      usort($pictures, 'cmpRating' );
    reset($pictures);
    $subset = array();
    $count = 0;
    while ((list($key,$value) = each($pictures)) && $count < $num) {
      $count += 1;
      $subset[$key] = $value;
    }
    return $subset;
  }

  /* ------------------------------------------------------------------- */

  /*
   * Low-level functions to render individual page elements.
   * These are the only functions that actually generate any HTML.
   */

  /* private: show a single topic title */
  function showTopic($topic, $showSummary = true) {
    if(is_array($topic)) {
      $desc = $this->defaultText($topic['Description'], SLZ_STR_NO_DESC);
      $this->show("<h2>" . $desc . "</h2>");
      // if we've got a Summary, show it
      if ($showSummary && strlen($topic['Summary']))
        $this->show("<p>".$topic['Summary'] . "</p>");
    }
  }

  /* private: show a list of all the topics in $topics */
  function showTopics( $topics ) {
    if(is_array($topics) && count($topics) > 0 ) {
      $this->show("<ul>");
      reset($topics);
      while( list($key, $topic) = each($topics)) {
        $desc = $this->defaultText($topic['Description'], SLZ_STR_NO_DESC);
        $this->show("<li>");
        $this->showTopicThumb($topic);
        $this->show("<a href=\"" . $this->actionURL ."?TopicID=" .urlencode($topic['TopicID']). "\">");
        $this->show($desc . "</a></li>");
      }
      $this->show("</ul>");
    }
  }

  /* private: show hyperlinks to display sorted versions of this topic */
  function showSort( $topicID ) {
    if ($this->enableViews || $this->enableRatings) {
      $this->show("<ul>");
      if ($this->enableViews) {
        $this->show("<li><a href=\"" . $this->actionURL ."?TopicID=" .urlencode($topicID).
                    "&amp;sort=views\">".SLZ_STR_MOST_VIEWED."</a></li>");
        }
      if ($this->enableRatings) {
        $this->show("<li><a href=\"" . $this->actionURL ."?TopicID=" .urlencode($topicID).
                    "&amp;sort=rating\">".SLZ_STR_HIGHEST_RATED."</a></li>");
      }
      $this->show("</ul>");
    }
  }

  /* private: show a title for a sorted subset of a topic */
  function showSortType( $sort ) {
    if ($sort == 'views')
      $this->show("<h3>".SLZ_STR_MOST_VIEWED."</h3>");
    if ($sort == 'rating')
      $this->show("<h3>".SLZ_STR_HIGHEST_RATED."</h3>");
  }

  /* private: show a hyperlinked topic heirarchy down to the given topic */
  function showNav( $topicID = "/" ) {
    if ($topic = $this->ct->getTopic($topicID)) {
      $desc = $this->defaultText($topic['Description'], SLZ_STR_NO_DESC);
      if ($topicID == "/") {
        $this->show("<p><a href=\"" . $this->actionURL . "\">" . $desc . "</a>");
      }
      else {
        $this->showNav($topic['ParentTopicID']);
        $this->show(" : <a href=\"" . $this->actionURL .
            "?TopicID=" . urlencode($topic['TopicID']) .
            "\">" . $desc . "</a>");
      }
    }
  }

  /* private: show a navigation bar with hyperlinks for First | Prev | Next | Last */
  function showNavigation ( $picture ) {
    $pictures = $this->ct->getPicturesInTopic($picture['ParentTopicID']);
    $currentPictureIndex = -1;
    /* spin through pictures in topic and get our index */
    while (list ($key, $val) = each ($pictures)) {
      // PHP4 if ($val == $picture) $currentPictureIndex = $key;
      if (($val['RollID'] == $picture['RollID']) && ($val['FrameID'] == $picture['FrameID'])) {
        $currentPictureIndex = $key;
      }
    }
    $firstPictureIndex = 0;
    $lastPictureIndex = sizeof($pictures) - 1;
    $prevPictureIndex = $currentPictureIndex - 1;
    $nextPictureIndex = $currentPictureIndex + 1;
    $separator = "&nbsp;" . SLZ_STR_NAV_TEXT_SEPARATOR . "&nbsp;";

    /* navBar is an HTML string with navigation links */
    $navBar = "<p>" . $this->getNavigationLink(SLZ_STR_NAV_FIRST,
      ($firstPictureIndex == $currentPictureIndex) ? NULL : $pictures[$firstPictureIndex]);
    $navBar = $navBar . $separator;
    $navBar = $navBar . $this->getNavigationLink(SLZ_STR_NAV_PREVIOUS,
      ($prevPictureIndex >= 0) ? $pictures[$prevPictureIndex] : NULL);
    $navBar = $navBar . $separator;
    $navBar = $navBar . $this->getNavigationLink(SLZ_STR_NAV_NEXT,
      ($nextPictureIndex <= $lastPictureIndex) ? $pictures[$nextPictureIndex] : NULL);
    $navBar = $navBar . $separator;
    $navBar = $navBar . $this->getNavigationLink(SLZ_STR_NAV_LAST,
      ($lastPictureIndex == $currentPictureIndex) ? NULL : $pictures[$lastPictureIndex]);
    $navBar = $navBar . "</p>";
    $this->show($navBar);
  }

  /* private: return a link to a picture, or plain text if no picture is specified */
  function getNavigationLink ( $displayText, $picture ) {
    if (is_array($picture)) {
      $text = "<a href=\"" . $this->actionURL . "?RollID=" . urlencode($picture['RollID']) .
        "&amp;FrameID=" . urlencode($picture['FrameID']) . "\">" . $displayText . "</a>";
    } else {
      $text = $displayText;
    }
    return  $text;
  }

  /* private: show a search result title */
  function showSearch($search) {
    $this->show("<h2>".SLZ_STR_HDR_SEARCH."</h2>");
    $this->show("<p>".SLZ_STR_SEARCH_TERM.": " . $search . "</p>");
  }

  /* private: show a single roll title */
  function showRoll($rollID) {
    $this->show("<h2>".SLZ_STR_HDR_ROLL." ".$rollID."</h2>");
  }

  /* private: show a list of all rolls */
  function showRolls() {
    $this->show("<h2>".SLZ_STR_HDR_ROLLS."</h2>");
    $this->show("<ul>");
    $rolls = $this->ct->getRolls();
    reset($rolls);
    while( list($key, $roll) = each($rolls)) {
      $this->show("<li>" .
         "<a href=\"" . $this->actionURL ."?RollID=" . urlencode($roll['RollID']) . "\">" .
        $roll['RollID'] . "</a>" .
        "</li>");
    }
    $this->show("</ul>");
  }

  /* private: show thumbnails for all pictures in $pictures */
  function showThumbs( $pictures ) {
    if(is_array($pictures) && count($pictures) > 0) {
      reset($pictures);
      $this->show("<p>");
      while( list($key, $picture) = each($pictures)) {
        $this->showThumb($picture);
      }
      $this->show("</p>");
    }
  }

  /* private: show thumbnail for a single picture */
  function showThumb( $picture ) {
    if (is_array($picture) && count($picture) > 0) {
      /* make img tag with size and caption plus a link to the fullsize picture */
      $fileName = $picture['RollID'] . "/" . $picture['FrameID'] . $this->thumb_suffix;
      if ($this->allPathsLower)
        $fileName = strtolower( $fileName );
      $size = GetImageSize( $this->basePath . $fileName );
      $description = $picture['Description'];
      if ($this->enableViews)
        $description .= ' [' . $picture['Views'] . ' ' . SLZ_STR_VIEWS . ']';
      if ($this->enableRatings)
        $description .= ' ['.SLZ_STR_RATING.' ' . $this->ratingText($picture['Rating']) . ']';
      $this->show("<a href=\"" . $this->actionURL .
         "?RollID=" . urlencode($picture['RollID']) .
         "&amp;FrameID=" . urlencode($picture['FrameID']) . "\">" .
         "<img src=\"" . $this->baseURL . $fileName . "\" " . $size[3] .
         " title=\"" . $description . "\"" .
         " alt=\"" . $description . "\"></a>");
    }
  }

  /* private: show thumbnail for a topic, if exists */
  function showTopicThumb( $topic ) {
    if (is_array($topic) && count($topic) > 0) {
      /* make img tag with size and caption */
      $fileName = "topics/" . $topic['TopicID'] . $this->thumb_suffix;
      if ($this->allPathsLower)
        $fileName = strtolower( $fileName );

      if (file_exists($this->basePath . $fileName)) {
        $size = GetImageSize( $this->basePath . $fileName );
        $description = $topic['Description'];
        $this->show("<img src=\"" . $this->baseURL . $fileName . "\" " . $size[3] .
           " title=\"" . $description . "\"" .
           " alt=\"" . $description . "\">");
      }
    }
  }

  /* private: show a single full-size picture */
  function showPicture( $picture ) {
    if (is_array($picture) && count($picture) > 0) {
      /* make img tag with size and caption */
      $this->show("<p>" .$picture['Description']. "</p>");
      $fileName = $picture['RollID'] . "/" . $picture['FrameID'] . $this->picture_suffix;
      if ($this->allPathsLower)
        $fileName = strtolower( $fileName );
      $size = GetImageSize( $this->basePath . $fileName );
      $description = $picture['Description'];
      $this->show("<p><img src=\"" . $this->baseURL . $fileName . "\" " . $size[3] .
         " title=\"" . $description . "\"" .
         " alt=\"" . $description . "\"></p>");
    }
  }

  /* private: show all comments in $comments */
  function showComments( $comments ) {
    if(is_array($comments) && count($comments) > 0) {
      reset($comments);
      while( list($key, $comment) = each($comments)) {
        $this->showComment($comment);
      }
    }
  }

  /* private: show a single comment */
  function showComment( $comment ) {
    if (is_array($comment) && count($comment) > 0) {
      $this->show("<p class=\"sloozecomment\">".SLZ_STR_COMMENT.": ");
      // show IP of commenter if it exists, and we're in admin mode
      if ( ($this->admin || $this->showCommentIPs) && strlen($comment['IP']) )
        $this->show("(". $comment['IP'] . ") ");
      $this->show($comment['Comment'] . "</p>");
      if ($this->admin) {
        $this->showFormDeleteComment($comment['CommentID']);
      }
    }
  }

  /* private: show a form to update a topic */
  function showFormUpdateTopic($topicID) {
    if ($topic = $this->ct->getTopic($topicID)) {
      $this->show("<h2>".SLZ_STR_HDR_UPDATE_TOPIC."</h2>");
      $this->showFormElementStart();
      $this->showFormElementTopicID($topicID);
      if ($topicID != "/") { /* root topic has no parent */
        $this->showFormElementParentTopicID($topic['ParentTopicID']);
      }
      $this->showFormElementDescriptionOneLine($topic['Description']);
      $this->showFormElementSummary($topic['Summary']);
      $this->showFormElementAction("updateTopic");
      $this->showFormElementEnd(SLZ_STR_BUTTON_UPDATE);
    }
  }

  /* private: show a form to delete a topic */
  function showFormDeleteTopic($topicID) {
    if ($this->ct->getTopic($topicID)) {
      $this->show("<h2>".SLZ_STR_HDR_DELETE_TOPIC."</h2>");
      $this->showFormElementStart();
      $this->showFormElementTopicID($topicID);
      $this->showFormElementAction("deleteTopic");
      $this->showFormElementEnd(SLZ_STR_BUTTON_DELETE);
    }
  }

  /* private: show a form to add a topic */
  function showFormAddTopic() {
    $this->show("<h2>".SLZ_STR_HDR_ADD_TOPIC."</h2>");
    $this->showFormElementStart();
    $this->showFormElementTopicID();
    $this->showFormElementParentTopicID();
    $this->showFormElementDescriptionOneLine();
    $this->showFormElementSummary();
    $this->showFormElementAction("addTopic");
    $this->showFormElementEnd(SLZ_STR_BUTTON_ADD);
  }

  /* private: show a form to update a picture */
  function showFormUpdatePicture($rollID, $frameID) {
    if ($picture = $this->ct->getPicture($rollID, $frameID)) {
      $this->show("<h2>".SLZ_STR_HDR_UPDATE_PICTURE."</h2>");
      $this->showFormElementStart();
      $this->showFormElementRollID($picture['RollID']);
      $this->showFormElementFrameID($picture['FrameID']);
      $this->showFormElementParentTopicID($picture['ParentTopicID']);
      $this->showFormElementDescriptionTextArea($picture['Description']);
      $this->showFormElementAction("updatePicture");
      $this->showFormElementEnd(SLZ_STR_BUTTON_UPDATE);
    }
  }

  /* private: show a form to delete a picture */
  function showFormDeletePicture($rollID, $frameID) {
    if ($this->ct->getPicture($rollID, $frameID)) {
      $this->show("<h2>".SLZ_STR_HDR_DELETE_PICTURE."</h2>");
      $this->showFormElementStart();
      $this->showFormElementRollID($rollID);
      $this->showFormElementFrameID($frameID);
      $this->showFormElementAction("deletePicture");
      $this->showFormElementEnd(SLZ_STR_BUTTON_DELETE);
    }
  }

  /* private: show a form to add a picture */
  function showFormAddPicture($rollID) {
    $this->show("<h2>".SLZ_STR_HDR_ADD_PICTURE."</h2>");
    $this->showFormElementStart();
    $this->showFormElementRollID($rollID);
    $this->showFormElementFrameID();
    $this->showFormElementParentTopicID();
    $this->showFormElementDescriptionTextArea();
    $this->showFormElementAction("addPicture");
    $this->showFormElementEnd(SLZ_STR_BUTTON_ADD);
  }

  /* private: show a form to add all pictures in a roll */
  function showFormAddAllPictures($rollID) {
    $this->show("<h2>".SLZ_STR_HDR_ADD_ALL_PICTURES."</h2>");
    $this->showFormElementStart();
    $this->showFormElementRollID($rollID);
    $this->showFormElementParentTopicID();
    $this->showFormElementAction("addAllPictures");
    $this->showFormElementEnd(SLZ_STR_BUTTON_ADDALL);
  }

  /* private: show a form to update a roll */
  function showFormUpdateRoll($rollID) {
    $this->show("<h2>".SLZ_STR_HDR_UPDATE_ROLL."</h2>");
    $this->showFormElementStart();
    $this->showFormElementRollID($rollID);
    $this->showFormElementAction("updateRoll");
    $this->showFormElementEnd(SLZ_STR_BUTTON_UPDATE);
  }

  /* private: show a form to delete a roll */
  function showFormDeleteRoll($rollID) {
    $this->show("<h2>".SLZ_STR_HDR_DELETE_ROLL."</h2>");
    $this->showFormElementStart();
    $this->showFormElementRollID($rollID);
    $this->showFormElementAction("deleteRoll");
    $this->showFormElementEnd(SLZ_STR_BUTTON_DELETE);
  }

  /* private: show a form to add a roll */
  function showFormAddRoll() {
    $this->show("<h2>".SLZ_STR_HDR_ADD_ROLL."</h2>");
    $this->showFormElementStart();
    $this->showFormElementRollID();
    $this->showFormElementAction("addRoll");
    $this->showFormElementEnd(SLZ_STR_BUTTON_ADD);
  }

  /* private: show a form to add a comment */
  function showFormAddComment($rollID, $frameID) {
//  $this->show("<h2>".SLZ_STR_HDR_ADD_COMMENT."</h2>");
    $this->showFormElementStart();
    $this->showFormElementRollID($rollID);
    $this->showFormElementFrameID($frameID);
    $this->showFormElementComment();
    $this->showFormElementAction("addComment");
    $this->showFormElementEnd(SLZ_STR_BUTTON_ADD);
  }

  /* private: show a form to delete a comment */
  function showFormDeleteComment($commentID) {
//  $this->show("<h2>".SLZ_STR_HDR_DELETE_COMMENT."</h2>");
    $this->showFormElementStart();
    $this->showFormElementCommentID($commentID);
    $this->showFormElementAction("deleteComment");
    $this->showFormElementEnd(SLZ_STR_BUTTON_DELETE);
  }

  /* private: show a form to add a rating */
  function showFormAddRating($rollID, $frameID, $rating=0) {
//  $this->show("<h2>".SLZ_STR_HDR_ADD_RATING."</h2>");
    $this->showFormElementStart();
    $this->showFormElementRollID($rollID);
    $this->showFormElementFrameID($frameID);
    $this->showFormElementRating($rating);
    $this->showFormElementAction("addRating");
    $this->showFormElementEnd(SLZ_STR_BUTTON_RATE);
  }

  /* private: show a search form */
  function showFormSearch() {
    $this->showFormElementStart();
    $this->showFormElementSearch();
    $this->showFormElementAction("search");
    $this->showFormElementEnd(SLZ_STR_BUTTON_SEARCH);
  }

  /* private: show form start */
  function showFormElementStart() {
    $this->show("<form action=\"" . $this->actionURL . "\" method=\"post\"><p>");
  }

  /* private: show submit button and form end */
  function showFormElementEnd($button) {
    $this->show("<input type=\"submit\" value=\"" . $button . "\">");
//  $this->show("</p></form>");
    $this->show("</form>");     /* Netscape rendering bug prohibits </p> */
  }

  /* private: show action form element */
  function showFormElementAction($action) {
      $this->show("<input type=\"hidden\" name=\"action\" " .
        "value=\"" . $action . "\">");
  }

  /* private: show Description form element as text input*/
  function showFormElementDescriptionOneLine($description = ""){
    $this->show(SLZ_STR_DESCRIPTION . ":<br>");
    $this->show("<input type=\"text\" size=\"32\" name=\"Description\" value=\"" . $description . "\"><br>");
  }

  /* private: show Description form element as textarea*/
  function showFormElementDescriptionTextArea($description = ""){
    $this->show(SLZ_STR_DESCRIPTION . ":<br>");
    $this->show("<textarea rows=\"4\" cols=\"40\" " . "name=\"Description\">" .
        $description . "</textarea><br>");
  }

  /* private: show Summary form element */
  function showFormElementSummary($Summary = ""){
    $this->show(SLZ_STR_SUMMARY . ":<br>");
    $this->show("<textarea rows=\"4\" cols=\"40\" " . "name=\"Summary\">" .
        $Summary . "</textarea><br>");
  }

  /* private: show Comment form element */
  function showFormElementComment($comment = ""){
    $this->show(SLZ_STR_COMMENT . ":<br>");
    $this->show("<textarea rows=\"3\" cols=\"40\" " . "name=\"Comment\">" .
        $comment . "</textarea><br>");
  }

  /* private: show Rating form element */
  function showFormElementRating($rating = 0){
    /* show current rating */
    $this->show(SLZ_STR_RATING . ": " . $this->ratingText($rating));
    /* show options for rating to add */
    $this->show("<br><br><select name=\"Rating\">");
    for( $i=2; $i>=-2; $i-- ) {
      $this->show("<option value=" . $i . ($i==0 ? " selected" : "") . ">" .
                  $this->ratingText($i) . "</option>");
    }
    $this->show("</select>");
  }

  /* private: show TopicID form element */
  function showFormElementTopicID($topicID = "") {
    if ($topicID != "") {
      $this->show("<input type=\"hidden\" name=\"TopicID\"");
      $this->show("value=\"" . $topicID . "\" >");
    }
    else {
      $this->show(SLZ_STR_TOPICID . ":<br>");
      $this->show("<input type=\"text\" name=\"TopicID\" ><br>");
    }
  }

  /* private: show ParentTopicID form element */
  function showFormElementParentTopicID($parentTopicID = "") {
    $this->show(SLZ_STR_PARENTTOPICID . ":<br>");
    $this->show("<select name=\"ParentTopicID\">");

    $topic = $this->ct->getTopic("/");
    $desc = $this->defaultText($topic['Description'], SLZ_STR_NO_DESC);
    $selectors = $this->getSelectFormElementParentTopicID($parentTopicID, "/", $desc);
    $this->show($selectors);

    $this->show("</select><br>");
  }

  /* private: get sorted (with indentation) ParentTopicID values for form */
  function getSelectFormElementParentTopicID($parentTopicID, $id, $desc, $count = 0) {
    $selectors = "<option value=\"" . $id . "\"" .
      (($id == $parentTopicID) ? " selected" : "") .
      ">" . $desc . "</option>" . $this->nl;

    $count++;

    $subTopics = $this->ct->getTopicsInParentTopic($id);
    reset($subTopics);
    while (list($key, $value) = each($subTopics)) {
      $desc = $this->defaultText($value['Description'], SLZ_STR_NO_DESC);
      $desc = str_pad("", $count*strlen($this->parentSelectPad),
                      $this->parentSelectPad) . $desc;
      $selectors = $selectors .
        $this->getSelectFormElementParentTopicID($parentTopicID, $value['TopicID'], $desc, $count);
    }
    return $selectors;
  }

  /* private: show RollID form element */
  function showFormElementRollID($rollID = "") {
    if ($rollID != "") {
      $this->show("<input type=\"hidden\" name=\"RollID\"");
      $this->show("value=\"" . $rollID . "\" >");
    }
    else {
      $this->show(SLZ_STR_ROLLID . ":<br>");
      $this->show("<input type=\"text\" name=\"RollID\" ><br>");
    }
  }

  /* private: show FrameID form element */
  function showFormElementFrameID($frameID = "") {
    if ($frameID != "") {
      $this->show("<input type=\"hidden\" name=\"FrameID\"");
      $this->show("value=\"" . $frameID . "\" >");
    }
    else {
      $this->show(SLZ_STR_FRAMEID . ":<br>");
      $this->show("<input type=\"text\" name=\"FrameID\" ><br>");
    }
  }

  /* private: show CommentID form element */
  function showFormElementCommentID($commentID) {
    $this->show("<input type=\"hidden\" name=\"CommentID\"");
    $this->show("value=\"" . $commentID . "\" >");
  }

  /* private: show search form element */
  function showFormElementSearch() {
    $this->show("<input type=\"text\" name=\"search\">");
  }

  /* private: generate a text representation of a rating value */
  function ratingText($rating) {
    $text[-2] = SLZ_STR_RATING_M2;
    $text[-1] = SLZ_STR_RATING_M1;
    $text[0] = SLZ_STR_RATING_0;
    $text[1] = SLZ_STR_RATING_P1;
    $text[2] = SLZ_STR_RATING_P2;
    $i = round(max(min(doubleval($rating), 2.0), -2.0));
    $r = sprintf("%1.2f", $rating);
    $r = str_replace( ".00", "", $r);
    $string = $r . " : " . $text[$i];
    return ($string);
  }

  /* private: generate a string, substituting a default if the text is blank */
  function defaultText($text, $deflt) {
    return( $text != '' ? $text : $deflt );
  }

  /* private: add a string to the html to be returned */
  function show($msg) {
    $this->htmlStr .= $msg . $this->nl;
  }

  /* private: add a string to the html to be returned */
  function show_error($msg) {
    if (!strlen($msg))
      $msg = SLZ_STR_ERR_DFLT; /* default error message */
    $this->show("<p class=\"sloozeerror\">Error: ".$msg."</p>");
  }

  /* private: write accumulated html to a cache file */
  function cacheWrite($tag) {
    if ($fp = @fopen($this->cachePath . $tag . '.tmp', 'w')) {
      $comment = '<!-- Cached -->' . $this->nl;
      fwrite($fp, $this->htmlStr . $comment);
      fclose($fp);
    }
  }

  /* private: read cache file to html string */
  function cacheRead($tag) {
    if ($fp = @fopen($this->cachePath . $tag . '.tmp', 'r')) {
      $this->htmlStr .= fread($fp, 32768);
      fclose($fp);
      return TRUE;
    }
    return FALSE;
  }

  /* private: clear the cache */
  function cacheClear() {
    if ($handle = opendir($this->cachePath)) {
      while ($file = readdir($handle)) {
        /* if is cache file */
        if(ereg('.+\.tmp$', $file)) {
          unlink($this->cachePath . $file);
//        system('del "' . $this->cachePath . $file . '"');   /* Windows platforms */
        }
      }
      closedir($handle);
    }
  }

} /* end of class Slooze */

  /* ------------------------------------------------------------------- */

  /* Private: cmpViews is a helper function for sortPictures */
  /* It has to be outside Slooze class due to limitations of the usort function */
  function cmpViews($a, $b) {
    if ($a['Views'] == $b['Views']) return 0;
    return ($a['Views'] > $b['Views']) ? -1 : 1;
  }

  /* Private: cmpRating is a helper function for sortPictures */
  /* It has to be outside Slooze class due to limitations of the usort function */
  function cmpRating($a, $b) {
    if ($a['Rating'] == $b['Rating']) return 0;
    return ($a['Rating'] > $b['Rating']) ? -1 : 1;
  }

?>
Return current item: Slooze