issue78, move version information to main class
[phpfspot.git] / phpfspot.class.php
index f572759ed1262c8d98d01ef61ed009168b0f696f..6c150fa6c70ca9c97862ffb9c6d0a49ef55b1b23 100644 (file)
@@ -23,7 +23,6 @@
 
 require_once "phpfspot_cfg.php";
 require_once "phpfspot_db.php";
-require_once "phpfspot_tmpl.php";
 
 class PHPFSPOT {
 
@@ -43,23 +42,38 @@ class PHPFSPOT {
     */
    public function __construct()
    {
+      $this->cfg = new PHPFSPOT_CFG;
+
+      /* set application name and version information */
+      $this->cfg->product = "phpfspot";
+      $this->cfg->version = "1.1";
+
       /* Check necessary requirements */
       if(!$this->checkRequirements()) {
          exit(1);
       }
 
-      $this->cfg = new PHPFSPOT_CFG;
-
-      $this->db  = new PHPFSPOT_DB(&$this, $this->cfg->fspot_db);
+      $this->db  = new PHPFSPOT_DB($this, $this->cfg->fspot_db);
       
       if(!is_writeable(dirname($this->cfg->phpfspot_db))) {
          print dirname($this->cfg->phpfspot_db) .": directory is not writeable!";
          exit(1);
       }
          
-      $this->cfg_db = new PHPFSPOT_DB(&$this, $this->cfg->phpfspot_db);
+      $this->cfg_db = new PHPFSPOT_DB($this, $this->cfg->phpfspot_db);
+      if(!is_writeable($this->cfg->phpfspot_db)) {
+         print $this->cfg->phpfspot_db ." is not writeable for user ". $this->getuid() ."\n";
+         exit(1);
+      }
       $this->check_config_table();
 
+      /* include Smarty template engine */
+      if(!$this->check_readable($this->cfg->smarty_path .'/libs/Smarty.class.php')) {
+         exit(1);
+      }
+      require $this->cfg->smarty_path .'/libs/Smarty.class.php';
+      /* overload Smarty class if our own template handler */
+      require_once "phpfspot_tmpl.php";
       $this->tmpl = new PHPFSPOT_TMPL($this);
 
       $this->get_tags();
@@ -100,50 +114,70 @@ class PHPFSPOT {
       $this->tmpl->assign('searchfor', $_SESSION['searchfor']);
       $this->tmpl->assign('page_title', $this->cfg->page_title);
       $this->tmpl->assign('current_condition', $_SESSION['tag_condition']);
+      $this->tmpl->assign('template_path', 'themes/'. $this->cfg->theme_name);
 
       $_SESSION['start_action'] = $_GET['mode'];
 
       switch($_GET['mode']) {
          case 'showpi':
             if(isset($_GET['tags'])) {
-               $_SESSION['selected_tags'] = split(',', $_GET['tags']);
+               $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
             }
-            if(isset($_GET['from_date'])) {
-               $_SESSION['from_date'] = $_GET['from_date'];
+            if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
+               $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
             }
-            if(isset($_GET['to_date'])) {
-               $_SESSION['to_date'] = $_GET['to_date'];
+            if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
+               $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
             }
             break;
          case 'showp':
             if(isset($_GET['tags'])) {
-               $_SESSION['selected_tags'] = split(',', $_GET['tags']);
+               $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
                $_SESSION['start_action'] = 'showp';
             }
-            if(isset($_GET['id'])) {
+            if(isset($_GET['id']) && is_numeric($_GET['id'])) {
                $_SESSION['current_photo'] = $_GET['id'];
                $_SESSION['start_action'] = 'showp';
             }
-            if(isset($_GET['from_date'])) {
-               $_SESSION['from_date'] = $_GET['from_date'];
+            if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
+               $_SESSION['from_date'] = strtotime($_GET['from_date']);
             }
-            if(isset($_GET['to_date'])) {
-               $_SESSION['to_date'] = $_GET['to_date'];
+            if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
+               $_SESSION['to_date'] = strtotime($_GET['to_date']);
             }
             break;
          case 'export':
             $this->tmpl->show("export.tpl");
             return;
             break;
+         case 'slideshow':
+            $this->tmpl->show("slideshow.tpl");
+            return;
+            break;
+         case 'rss':
+            if(isset($_GET['tags'])) {
+               $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
+            }
+            if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
+               $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
+            }
+            if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
+               $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
+            }
+            $this->getRSSFeed();
+            return;
+            break;
       }
 
+      if(isset($_SESSION['from_date']) && isset($_SESSION['to_date']))
+         $this->tmpl->assign('date_search_enabled', true);
+
       $this->tmpl->assign('from_date', $this->get_calendar('from'));
       $this->tmpl->assign('to_date', $this->get_calendar('to'));
       $this->tmpl->assign('sort_field', $this->get_sort_field());
       $this->tmpl->assign('content_page', 'welcome.tpl');
       $this->tmpl->show("index.tpl");
 
-
    } // show()
 
    /**
@@ -214,15 +248,29 @@ class PHPFSPOT {
    public function getPhotoName($idx, $limit = 0)
    {
       if($details = $this->get_photo_details($idx)) {
-         $name = $details['name'];
-         if($limit != 0 && strlen($name) > $limit) {
-            $name = substr($name, 0, $limit-5) ."...". substr($name, -($limit-5));
-         }
+         $name = $this->shrink_text($details['name'], $limit);
          return $name;
       }
 
    } // getPhotoName()
 
+   /**
+    * shrink text according provided limit
+    *
+    * If the length of the name exceeds $limit the
+    * text will be shortend and some content in between
+    * will be replaced with "..." 
+    */
+   private function shrink_text($text, $limit)
+   {
+      if($limit != 0 && strlen($text) > $limit) {
+         $text = substr($text, 0, $limit-5) ."...". substr($text, -($limit-5));
+      }
+
+      return $text;
+
+   } // shrink_text();
+
    /**
     * translate f-spoth photo path
     * 
@@ -280,20 +328,20 @@ class PHPFSPOT {
       }
 
       $orig_path = $this->translate_path($details['directory_path']) ."/". $details['name'];
-      $thumb_path = $this->cfg->base_path ."/thumbs/". $this->cfg->photo_width ."_". $this->getMD5($photo);
+      $thumb_path = $this->get_thumb_path($this->cfg->photo_width, $photo);
 
       if(!file_exists($orig_path)) {
-         $this->_warning("Photo ". $orig_path ." does not exist!<br />\n");
+         $this->_error("Photo ". $orig_path ." does not exist!<br />\n");
       }
 
       if(!is_readable($orig_path)) {
-         $this->_warning("Photo ". $orig_path ." is not readable for user ". $this->getuid() ."<br />\n");
+         $this->_error("Photo ". $orig_path ." is not readable for user ". $this->getuid() ."<br />\n");
       }
 
       /* If the thumbnail doesn't exist yet, try to create it */
       if(!file_exists($thumb_path)) {
          $this->gen_thumb($photo, true);
-         $thumb_path = $this->cfg->base_path ."/thumbs/". $this->cfg->photo_width ."_". $this->getMD5($photo);
+         $thumb_path = $this->get_thumb_path($this->cfg->photo_width, $photo);
       }
 
       /* get f-spot database meta information */
@@ -317,7 +365,7 @@ class PHPFSPOT {
          $extern_link.= "&tags=". $current_tags;
       }
       if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
-         $extern_link.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
+         $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
       }
 
       $this->tmpl->assign('extern_link', $extern_link);
@@ -343,7 +391,7 @@ class PHPFSPOT {
          $this->tmpl->assign('current', $current);
       }
       else {
-         $this->_warning("Can't open file ". $thumb_path ."\n");
+         $this->_error("Can't open file ". $thumb_path ."\n");
          return;
       }
 
@@ -357,6 +405,8 @@ class PHPFSPOT {
          $this->tmpl->assign('next_img', $next_img);
       }
       $this->tmpl->assign('mini_width', $this->cfg->mini_width);
+      $this->tmpl->assign('photo_number', $i);
+      $this->tmpl->assign('photo_count', count($all_photos));
 
       $this->tmpl->show("single_photo.tpl");
 
@@ -552,8 +602,8 @@ class PHPFSPOT {
       $matched_photos = Array();
 
       if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
-         $from_date = strtotime($_SESSION['from_date']);
-         $to_date = strtotime($_SESSION['to_date']);
+         $from_date = $_SESSION['from_date'];
+         $to_date = $_SESSION['to_date'];
          $additional_where_cond = "
                p.time>='". $from_date ."'
             AND
@@ -636,6 +686,10 @@ class PHPFSPOT {
                      ON pt1.photo_id=pt". ($i+2) .".photo_id
                ";
             }
+            $query_str.= "
+               INNER JOIN photos p
+                  ON pt1.photo_id=p.id
+            ";
             $query_str.= "WHERE pt1.tag_id=". $_SESSION['selected_tags'][0];
             for($i = 1; $i < count($_SESSION['selected_tags']); $i++) {
                $query_str.= "
@@ -737,7 +791,7 @@ class PHPFSPOT {
          $img_name[$rows][$cols] = htmlspecialchars($this->getPhotoName($photos[$i], 15));
          $img_title[$rows][$cols] = "Click to view photo ". htmlspecialchars($this->getPhotoName($photos[$i], 0));
 
-         $thumb_path = $this->cfg->base_path ."/thumbs/". $this->cfg->thumb_width ."_". $this->getMD5($photos[$i]);
+         $thumb_path = $this->get_thumb_path($this->cfg->thumb_width, $photos[$i]);
 
          if(file_exists($thumb_path)) {
             $info = getimagesize($thumb_path); 
@@ -764,8 +818,8 @@ class PHPFSPOT {
          $this->tmpl->assign('searchfor', $_SESSION['searchfor']);
 
       if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
-         $this->tmpl->assign('from_date', $_SESSION['from_date']);
-         $this->tmpl->assign('to_date', $_SESSION['to_date']);
+         $this->tmpl->assign('from_date', $this->ts2str($_SESSION['from_date']));
+         $this->tmpl->assign('to_date', $this->ts2str($_SESSION['to_date']));
       }
 
       if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
@@ -802,7 +856,7 @@ class PHPFSPOT {
          for($i = 1; $i <= $last_page; $i++) {
 
             if($current_page == $i)
-               $style = "style=\"font-size: 125%;\"";
+               $style = "style=\"font-size: 125%; text-decoration: underline;\"";
             elseif($current_page-1 == $i || $current_page+1 == $i)
                $style = "style=\"font-size: 105%;\"";
             elseif(($current_page-5 >= $i) && ($i != 1) ||
@@ -853,17 +907,23 @@ class PHPFSPOT {
       
       $current_tags = $this->getCurrentTags();
       $extern_link = "index.php?mode=showpi";
+      $rss_link = "index.php?mode=rss";
       if($current_tags != "") {
          $extern_link.= "&tags=". $current_tags;
+         $rss_link.= "&tags=". $current_tags;
       }
       if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
-         $extern_link.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
+         $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
+         $rss_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
       }
 
       $export_link = "index.php?mode=export";
+      $slideshow_link = "index.php?mode=slideshow";
 
       $this->tmpl->assign('extern_link', $extern_link);
+      $this->tmpl->assign('slideshow_link', $slideshow_link);
       $this->tmpl->assign('export_link', $export_link);
+      $this->tmpl->assign('rss_link', $rss_link);
       $this->tmpl->assign('count', $count);
       $this->tmpl->assign('width', $this->cfg->thumb_width);
       $this->tmpl->assign('images', $images);
@@ -1094,22 +1154,27 @@ class PHPFSPOT {
       $full_path = $this->translate_path($details['directory_path'])  ."/". $details['name'];
 
       if(!file_exists($full_path)) {
-         $this->_warning("File ". $full_path ." does not exist\n");
+         $this->_error("File ". $full_path ." does not exist\n");
          return;
       }
 
       if(!is_readable($full_path)) {
-         $this->_warning("File ". $full_path ." is not readable for ". $this->getuid() ."\n");
+         $this->_error("File ". $full_path ." is not readable for ". $this->getuid() ."\n");
          return;
       }
 
       $file_md5 = md5_file($full_path);
 
-      $this->_debug("Image [". $idx ."] ". $details['name'] ." Thumbnails:");
+      $this->_debug("Image [". $idx ."] ". $this->shrink_text($details['name'], 20) ." Thumbnails:");
 
       foreach($resolutions as $resolution) {
 
-         $thumb_path = $this->cfg->base_path ."/thumbs/". $resolution ."_". $file_md5;
+         $thumb_sub_path = substr($file_md5, 0, 2);
+         $thumb_path = $this->cfg->thumb_path ."/". $thumb_sub_path ."/". $resolution ."_". $file_md5;
+
+         if(!file_exists(dirname($thumb_path))) {
+            mkdir(dirname($thumb_path), 0755);
+         }
 
          /* if the thumbnail file doesn't exist, create it */
          if(!file_exists($thumb_path)) {
@@ -1192,12 +1257,18 @@ class PHPFSPOT {
     * getPhotoSelection() will then only return the matching
     * photos.
     */
-   public function startSearch($searchfor, $from, $to, $sort_order)
+   public function startSearch($searchfor, $sort_order, $from = 0, $to = 0)
    {
       $_SESSION['searchfor'] = $searchfor;
-      $_SESSION['from_date'] = $from;
-      $_SESSION['to_date'] = $to;
       $_SESSION['sort_order'] = $sort_order;
+      if($from != 0)
+         $_SESSION['from_date'] = strtotime($from);
+      else
+         unset($_SESSION['from_date']);
+      if($to != 0)
+         $_SESSION['to_date'] = strtotime($to);
+      else
+         unset($_SESSION['to_date']);
 
       if($searchfor != "") {
          /* new search, reset the current selected tags */
@@ -1207,6 +1278,7 @@ class PHPFSPOT {
                array_push($_SESSION['selected_tags'], $tag);
          }
       }
+
    } // startSearch()
 
    /**
@@ -1347,7 +1419,7 @@ class PHPFSPOT {
          $missing = true;
       }
 
-      if(!function_exists("sqlite3_open")) {
+      if($this->cfg->db_access == "native" && !function_exists("sqlite3_open")) {
          print "PHP SQLite3 library extension is missing<br />\n";
          $missing = true;
       }
@@ -1393,21 +1465,31 @@ class PHPFSPOT {
 
    } // checkifImageSupported()
 
-   public function _warning($text)
+   public function _error($text)
    {
-      print "<img src=\"resources/green_info.png\" alt=\"warning\" />\n";
-      print $text;
+      switch($this->cfg->logging) {
+         case 'display':
+            print "<img src=\"resources/green_info.png\" alt=\"warning\" />\n";
+            print $text;
+            break;
+         case 'errorlog':  
+            error_log($text);
+            break;
+         case 'logfile':
+            error_log($text, 3, $his->cfg->log_file);
+            break;
+      }
 
-   } // _warning()
+   } // _error()
 
    /**
     * output calendard input fields
     */
    private function get_calendar($mode)
    {
-      $year = $_SESSION[$mode .'_date'] ? date("Y", strtotime($_SESSION[$mode .'_date'])) : date("Y");
-      $month = $_SESSION[$mode .'_date'] ? date("m", strtotime($_SESSION[$mode .'_date'])) : date("m");
-      $day = $_SESSION[$mode .'_date'] ? date("d", strtotime($_SESSION[$mode .'_date'])) : date("d");
+      $year = $_SESSION[$mode .'_date'] ? date("Y", $_SESSION[$mode .'_date']) : date("Y");
+      $month = $_SESSION[$mode .'_date'] ? date("m", $_SESSION[$mode .'_date']) : date("m");
+      $day = $_SESSION[$mode .'_date'] ? date("d", $_SESSION[$mode .'_date']) : date("d");
 
       $output = "<input type=\"text\" size=\"3\" id=\"". $mode ."year\" value=\"". $year ."\"";
       if(!isset($_SESSION[$mode .'_date'])) $output.= " disabled=\"disabled\"";
@@ -1508,14 +1590,9 @@ class PHPFSPOT {
       $pictures = $this->getPhotoSelection();
       $current_tags = $this->getCurrentTags();  
 
-      if(!isset($_SERVER['HTTPS'])) $protocol = "http";
-      else $protocol = "https";
-
-      $server_name = $_SERVER['SERVER_NAME'];
-
       foreach($pictures as $picture) {
 
-         $orig_url = $protocol ."://". $server_name . $this->cfg->web_path ."index.php?mode=showp&id=". $picture;
+         $orig_url = $this->get_phpfspot_url() ."index.php?mode=showp&id=". $picture;
          if($current_tags != "") {
             $orig_url.= "&tags=". $current_tags;
          } 
@@ -1523,7 +1600,7 @@ class PHPFSPOT {
             $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
          }
 
-         $thumb_url = $protocol ."://". $server_name . $this->cfg->web_path ."phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
+         $thumb_url = $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
 
          switch($mode) {
 
@@ -1533,8 +1610,13 @@ class PHPFSPOT {
                break;
                
             case 'MoinMoin':
-               // [%pictureurl% %thumbnailurl%]
-               print htmlspecialchars(" * [".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
+               // "[%pictureurl% %thumbnailurl%]"
+               print htmlspecialchars("[".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
+               break;
+
+            case 'MoinMoinList':
+               // " * [%pictureurl% %thumbnailurl%]"
+               print "&nbsp;" . htmlspecialchars("* [".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
                break;
          }
 
@@ -1542,6 +1624,74 @@ class PHPFSPOT {
 
    } // getExport()
 
+   /**
+    * output RSS feed
+    */
+   public function getRSSFeed()
+   {
+      Header("Content-type: text/xml; charset=utf-8");
+      print "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
+?>
+<rss version="2.0"
+   xmlns:media="http://search.yahoo.com/mrss/"
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+ >
+ <channel>
+  <title>phpfspot</title>
+  <description>phpfspot RSS feed</description>
+  <link><?php print htmlspecialchars($this->get_phpfspot_url()); ?></link>
+  <pubDate><?php print strftime("%a, %d %b %Y %T %z"); ?></pubDate>
+  <generator>phpfspot</generator>
+<?php
+
+      $pictures = $this->getPhotoSelection();
+      $current_tags = $this->getCurrentTags();  
+
+      foreach($pictures as $picture) {
+
+         $orig_url = $this->get_phpfspot_url() ."index.php?mode=showp&id=". $picture;
+         if($current_tags != "") {
+            $orig_url.= "&tags=". $current_tags;
+         } 
+         if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
+            $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
+         }
+
+         $details = $this->get_photo_details($picture);
+
+         $thumb_url = $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
+         $thumb_html = htmlspecialchars("
+<a href=\"". $orig_url ."\"><img src=\"". $thumb_url ."\" /></a>
+<br>
+". $details['description']);
+
+         $orig_path = $this->translate_path($details['directory_path']) ."/". $details['name'];
+         $meta = $this->get_meta_informations($orig_path);
+         $meta_date = isset($meta['FileDateTime']) ? $meta['FileDateTime'] : filemtime($orig_path);
+
+?>
+  <item>
+   <title><?php print htmlspecialchars($details['name']); ?></title>
+   <link><?php print htmlspecialchars($orig_url); ?></link>
+   <guid><?php print htmlspecialchars($orig_url); ?></guid>
+   <dc:date.Taken><?php print strftime("%Y-%m-%dT%H:%M:%S+00:00", $meta_date); ?></dc:date.Taken>
+   <description>
+    <?php print $thumb_html; ?> 
+   </description>
+   <pubDate><?php print strftime("%a, %d %b %Y %T %z", $meta_date); ?></pubDate>
+  </item>
+<?php
+
+      }
+?>
+ </channel>
+</rss>
+<?php
+
+
+   } // getExport()
+
    /**
     * return all selected tags as one string
     */
@@ -1581,9 +1731,8 @@ class PHPFSPOT {
       if(isset($_SESSION['current_photo']) && $_SESSION['start_action'] == 'showp') {
          return "show_photo";
       }
-      elseif((isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) ||
-         (isset($_SESSION['from_date']) && isset($_SESSION['to_date']))) {
-         return "showpi";
+      elseif(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
+         return "showpi_tags";
       }
       elseif(isset($_SESSION['start_action']) && $_SESSION['start_action'] == 'showpi') {
          return "showpi";
@@ -1633,22 +1782,201 @@ class PHPFSPOT {
    {
       switch($_SESSION['sort_order']) {
          case 'date_asc':
-            return "ORDER BY p.time ASC";
+            return " ORDER BY p.time ASC";
             break;
          case 'date_desc':
-            return "ORDER BY p.time DESC";
+            return " ORDER BY p.time DESC";
             break;
          case 'name_asc':
-            return "ORDER BY p.name ASC";
+            return " ORDER BY p.name ASC";
             break;
          case 'name_desc':
-            return "ORDER BY p.name DESC";
+            return " ORDER BY p.name DESC";
             break;
       }
 
-      return $_SESSION['sort_order'];
-
    } // get_sort_order()
+
+   /***
+     * return the next to be shown slide show image
+     *
+     * this function returns the URL of the next image
+     * in the slideshow sequence.
+     */
+   public function getNextSlideShowImage()
+   {
+      $all_photos = $this->getPhotoSelection();
+
+      if(!isset($_SESSION['slideshow_img']) || $_SESSION['slideshow_img'] == count($all_photos)-1) 
+         $_SESSION['slideshow_img'] = 0;
+      else
+         $_SESSION['slideshow_img']++;
+
+      return $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $all_photos[$_SESSION['slideshow_img']] ."&width=". $this->cfg->photo_width;
+
+   } // getNextSlideShowImage()
+
+   /***
+     * return the previous to be shown slide show image
+     *
+     * this function returns the URL of the previous image
+     * in the slideshow sequence.
+     */
+   public function getPrevSlideShowImage()
+   {
+      $all_photos = $this->getPhotoSelection();
+
+      if(!isset($_SESSION['slideshow_img']) || $_SESSION['slideshow_img'] == 0)
+         $_SESSION['slideshow_img'] = 0;
+      else
+         $_SESSION['slideshow_img']--;
+
+      return $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $all_photos[$_SESSION['slideshow_img']] ."&width=". $this->cfg->photo_width;
+
+   } // getPrevSlideShowImage()
+
+   public function resetSlideShow()
+   {
+      if(isset($_SESSION['slideshow_img']))
+         unset($_SESSION['slideshow_img']);
+   } // resetSlideShow()
+   
+   /***
+     * get random photo
+     *
+     * this function will get all photos from the fspot
+     * database and randomly return ONE entry
+     *
+     * saddly there is yet no sqlite3 function which returns
+     * the bulk result in array, so we have to fill up our
+     * own here.
+     */ 
+   public function get_random_photo()
+   {
+      $all = Array();
+
+      $result = $this->db->db_query("
+         SELECT id
+         FROM photos
+      ");
+      
+      while($row = $this->db->db_fetch_object($result)) {
+         array_push($all, $row['id']);
+      }
+
+      return $all[array_rand($all)];
+
+   } // get_random_photo()
+
+   /**
+    * validates provided date
+    *
+    * this function validates if the provided date
+    * contains a valid date and will return true 
+    * if it is.
+    */
+   public function isValidDate($date_str)
+   {
+      $timestamp = strtotime($date_str);
+   
+      if(is_numeric($timestamp))
+         return true;
+      
+      return false;
+
+   } // isValidDate()
+
+   /**
+    * timestamp to string conversion
+    */
+   private function ts2str($timestamp)
+   {
+      return strftime("%Y-%m-%d", $timestamp);
+   } // ts2str()
+
+   private function extractTags($tags_str)
+   {
+      $not_validated = split(',', $_GET['tags']);
+      $validated = array();
+
+      foreach($not_validated as $tag) {
+         if(is_numeric($tag))
+            array_push($validated, $tag);
+      }
+   
+      return $validated;
+   
+   } // extractTags()
+
+   /**
+    * returns the full path to a thumbnail
+    */
+   public function get_thumb_path($width, $photo)
+   {
+      $sub_path = substr($this->getMD5($photo), 0, 2);
+      return $this->cfg->thumb_path
+         . "/"
+         . $sub_path
+         . "/"
+         . $width
+         . "_"
+         . $this->getMD5($photo);
+
+   } // get_thumb_path()
+
+   /**
+    * returns server's virtual host name
+    */
+   private function get_server_name()
+   {
+      return $_SERVER['SERVER_NAME'];
+   } // get_server_name()
+
+   /**
+    * returns type of webprotocol which is
+    * currently used
+    */
+   private function get_web_protocol()
+   {
+      if(!isset($_SERVER['HTTPS']))
+         return "http";
+      else
+         return "https";
+   } // get_web_protocol()
+
+   /**
+    * return url to this phpfspot installation
+    */
+   private function get_phpfspot_url()
+   {
+      return $this->get_web_protocol() ."://". $this->get_server_name() . $this->cfg->web_path;
+   } // get_phpfspot_url()
+   
+   /**
+    * check file exists and is readable
+    *
+    * returns true, if everything is ok, otherwise false
+    * if $silent is not set, this function will output and
+    * error message
+    */
+   private function check_readable($file, $silent = null)
+   {
+      if(!file_exists($file)) {
+         if(!isset($silent))
+            print "File \"". $file ."\" does not exist.\n";
+         return false;
+      }
+
+      if(!is_readable($file)) {
+         if(!isset($silent))
+            print "File \"". $file ."\" is not reachable for user ". $this->getuid() ."\n";
+         return false;
+      }
+
+      return true;
+
+   } // check_readable()
+
 }
 
 ?>