Merge branch 'master' into checker
[phpfspot.git] / phpfspot.class.php
index 99b0d7b9fe1c767837205385d901ed421d2e5d7d..797c6047abbe299d2d15ad432550b5967c6eb775 100644 (file)
@@ -142,7 +142,9 @@ class PHPFSPOT {
 
       /* Check if database file is writeable */
       if(!is_writeable($this->cfg->fspot_db)) {
-         print $this->cfg->fspot_db ." is not writeable for user ". $this->getuid() ."\n";
+         print "Error: ". $this->cfg->fspot_db ." is not writeable for user ". $this->getuid() .".\n";
+         print "Please fix permissions so phpfspot can create indices within the F-Spot database to"
+            ." speed up some database operations.\n";
          exit(1);
       }
 
@@ -157,6 +159,7 @@ class PHPFSPOT {
          ");
       }
 
+      /* get F-Spot database version */
       $this->dbver = $this->getFspotDBVersion();
 
       if(!is_writeable($this->cfg->base_path ."/templates_c")) {
@@ -173,13 +176,15 @@ class PHPFSPOT {
 
       /* Check if directory where the database file is stored is writeable  */
       if(!is_writeable(dirname($this->cfg->phpfspot_db))) {
-         print dirname($this->cfg->phpfspot_db) .": directory is not writeable for user ". $this->getuid() ."\n";
+         print "Error: ". dirname($this->cfg->phpfspot_db) .": directory is not writeable for user ". $this->getuid() .".\n";
+         print "Please fix permissions so phpfspot can create its own sqlite database to store some settings.\n";
          exit(1);
       }
 
       /* Check if database file is writeable */
       if(!is_writeable($this->cfg->phpfspot_db)) {
-         print $this->cfg->phpfspot_db ." is not writeable for user ". $this->getuid() ."\n";
+         print "Error: ". $this->cfg->phpfspot_db ." is not writeable for user ". $this->getuid() .".\n";
+         print "Please fix permissions so phpfspot can create its own sqlite database to store some settings.\n";
          exit(1);
       }
 
@@ -201,6 +206,17 @@ class PHPFSPOT {
       require_once "phpfspot_tmpl.php";
       $this->tmpl = new PHPFSPOT_TMPL();
 
+      $this->tmpl->assign('web_path', $this->cfg->web_path);
+
+      /* Starting with F-Spot 0.4.2, the rating-feature was available */
+      if($this->dbver > 10) {
+         $this->tmpl->assign('has_rating', true);
+         $this->sort_orders = array_merge($this->sort_orders, array(
+            'rate_asc' => 'Rate ↑',
+            'rate_desc' => 'Rate ↓',
+         ));
+      }
+
       /* check if all necessary indices exist */
       $this->checkDbIndices();
 
@@ -221,6 +237,11 @@ class PHPFSPOT {
       if(isset($_SESSION['begin_with']) && $this->cfg->thumbs_per_page == 0)
          unset($_SESSION['begin_with']);
 
+      // if user-friendly-url's are enabled, set also a flag for the template handler
+      if($this->is_user_friendly_url()) {
+         $this->tmpl->assign('user_friendly_url', 'true');
+      }
+
    } // __construct()
 
    public function __destruct()
@@ -282,11 +303,15 @@ class PHPFSPOT {
                }
                break;
             case 'export':
-               $this->tmpl->show("export.tpl");
+               /* fetch export template */
+               print $this->tmpl->fetch("export.tpl");
+               /* no further execution necessary. */
                return;
                break;
             case 'slideshow':
-               $this->tmpl->show("slideshow.tpl");
+               /* fetch slideshow template */
+               print $this->tmpl->show("slideshow.tpl");
+               /* no further execution necessary. */
                return;
                break;
             case 'rss':
@@ -305,17 +330,46 @@ class PHPFSPOT {
          }
       }
 
+      /* if date-search variables are registered in the session, set the check
+         for "consider date-range" in the html output
+      */
       if(isset($_SESSION['from_date']) && isset($_SESSION['to_date']))
          $this->tmpl->assign('date_search_enabled', true);
 
-      $this->tmpl->register_function("sort_select_list", array(&$this, "smarty_sort_select_list"), false);
-      $this->tmpl->assign('from_date', $this->get_calendar('from'));
-      $this->tmpl->assign('to_date', $this->get_calendar('to'));
+      /* if rate-search variables are registered in the session, set the check
+         for "consider rate-range" in the html output
+      */
+      if(isset($_SESSION['rate_from']) && isset($_SESSION['rate_to'])) {
+         $this->tmpl->assign('rate_search_enabled', true);
+      }
 
-      if(!isset($content))
-         $this->tmpl->assign('content_page', $this->tmpl->fetch('welcome.tpl'));
+      $this->tmpl->register_function("sort_select_list", array(&$this, "smarty_sort_select_list"), false);
+      $this->tmpl->assign('search_from_date', $this->get_date_text_field('from'));
+      $this->tmpl->assign('search_to_date', $this->get_date_text_field('to'));
+
+      $this->tmpl->assign('preset_selected_tags', $this->getSelectedTags());
+      $this->tmpl->assign('preset_available_tags', $this->getAvailableTags());
+      $this->tmpl->assign('rate_search', $this->get_rate_search());
+
+      /* if no site-content has been set yet... */
+      if(!isset($content)) {
+         /* if tags are already selected, we can immediately display photo-index */
+         if((isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags']) &&
+             isset($_SESSION['start_action']) && $_SESSION['start_action'] != 'showp') ||
+            (isset($_SESSION['start_action']) && $_SESSION['start_action'] == 'showpi'))
+            $this->tmpl->assign('initial_content', $this->showPhotoIndex());
+         else {
+            /* if a photo is already selected, we can immediately display single-photo */
+            if(isset($_SESSION['current_photo']) && !empty($_SESSION['current_photo']))
+               $this->tmpl->assign('initial_content', $this->showPhoto($_SESSION['current_photo']));
+            else {
+               /* ok, then let us show the welcome page... */
+               $this->tmpl->assign('initial_content', $this->tmpl->fetch('welcome.tpl'));
+            }
+         }
+      }
       else
-         $this->tmpl->assign('content_page', $content);
+         $this->tmpl->assign('initial_content', $content);
 
       $this->tmpl->show("index.tpl");
 
@@ -411,10 +465,19 @@ class PHPFSPOT {
          ";
       }
       else {
-         $query_str = "
-            SELECT p.id, p.uri, p.time, p.description
-            FROM photos p
-         ";
+         /* till F-Spot version 0.4.1 */
+         if($this->dbver < 11) {
+            $query_str = "
+               SELECT p.id, p.uri, p.time, p.description
+               FROM photos p
+            ";
+         }
+         else {
+            $query_str = "
+               SELECT p.id, p.uri, p.time, p.description, p.rating
+               FROM photos p
+            ";
+         }
       }
 
       /* if show_tags is set, only return details for photos which
@@ -474,6 +537,75 @@ class PHPFSPOT {
 
    } // getPhotoName()
 
+   /**
+    * get photo rating level
+    *
+    * this function will return the integer-based rating
+    * level of the photo. This can only be done, if the F-Spot
+    * database is at a specific level. If rating value can not
+    * be found, zero will be returned indicating no rating value
+    * is available.
+    * @param integer idx
+    * @return integer
+    */
+   public function get_photo_rating($idx)
+   {
+      if($detail = $this->get_photo_details($idx)) {
+         if(isset($detail['rating']))
+            return $detail['rating'];
+      }
+
+      return 0;
+
+   } // get_photo_rating()
+
+   /**
+    * get rate-search bars
+    *
+    * this function will return the rating-bars for the
+    * search field.
+    * @return string
+    */
+   public function get_rate_search()
+   {
+      $bar = "";
+
+      for($i = 1; $i <= 5; $i++) {
+
+         $bar.= "<img id=\"rate_from_". $i ."\" src=\"";
+
+         if(isset($_SESSION['rate_from']) && $i <= $_SESSION['rate_from'])
+            $bar.= $this->cfg->web_path ."/resources/star.png";
+         else
+            $bar.= $this->cfg->web_path ."/resources/empty_rate.png";
+
+         $bar.= "\"
+            onmouseover=\"show_rate('from', ". $i .");\"
+            onmouseout=\"reset_rate('from');\"
+            onclick=\"set_rate('from', ". $i .")\" />";
+      }
+
+      $bar.= "<br />\n";
+
+       for($i = 1; $i <= 5; $i++) {
+
+         $bar.= "<img id=\"rate_to_". $i ."\" src=\"";
+
+         if(isset($_SESSION['rate_to']) && $i <= $_SESSION['rate_to'])
+            $bar.= $this->cfg->web_path ."/resources/star.png";
+         else
+            $bar.= $this->cfg->web_path ."/resources/empty_rate.png";
+
+         $bar.= "\"
+            onmouseover=\"show_rate('to', ". $i .");\"
+            onmouseout=\"reset_rate('to');\"
+            onclick=\"set_rate('to', ". $i .");\" />";
+      }
+
+      return $bar;
+
+   } // get_rate_search()
+
    /**
     * shrink text according provided limit
     *
@@ -576,7 +708,7 @@ class PHPFSPOT {
       $info = getimagesize($orig_path);
 
       /* get EXIF information if JPEG */
-      if($info['mime'] == "image/jpeg") {
+      if(isset($info['mime']) && $info['mime'] == "image/jpeg") {
          $meta = $this->get_meta_informations($orig_path);
       }
 
@@ -611,6 +743,7 @@ class PHPFSPOT {
 
       $this->tmpl->assign('description', $details['description']);
       $this->tmpl->assign('image_name', $this->parse_uri($details['uri'], 'filename'));
+      $this->tmpl->assign('image_rating', $this->get_photo_rating($photo));
 
       $this->tmpl->assign('width', $info_thumb[0]);
       $this->tmpl->assign('height', $info_thumb[1]);
@@ -634,15 +767,16 @@ class PHPFSPOT {
       $this->tmpl->assign('current_page', $this->getCurrentPage($current, $count));
       $this->tmpl->assign('current_img', $photo);
 
-      if($previous_img) {
-         $this->tmpl->assign('previous_url', "javascript:showImage(". $previous_img .");");
+      if(isset($previous_img)) {
+         $this->tmpl->assign('previous_url', "javascript:showPhoto(". $previous_img .");");
          $this->tmpl->assign('prev_img', $previous_img);
       }
 
-      if($next_img) {
-         $this->tmpl->assign('next_url', "javascript:showImage(". $next_img .");");
+      if(isset($next_img)) {
+         $this->tmpl->assign('next_url', "javascript:showPhoto(". $next_img .");");
          $this->tmpl->assign('next_img', $next_img);
       }
+
       $this->tmpl->assign('mini_width', $this->cfg->mini_width);
       $this->tmpl->assign('photo_width', $this->cfg->photo_width);
       $this->tmpl->assign('photo_number', $i);
@@ -725,13 +859,15 @@ class PHPFSPOT {
          $b = '88';
 
          if(isset($this->tags[$key])) {
-            $output.= "<a href=\"javascript:Tags('add', ". $key .");\" class=\"tag\" style=\"font-size: ". $size ."%; color: #". $r.$g.$b .";\">". $this->tags[$key] ."</a>, ";
+            if($this->is_user_friendly_url())
+               $output.= "<a href=\"". $this->cfg->web_path ."/tag/". $key ."\" onclick=\"Tags('add', ". $key ."); return false;\" class=\"tag\" style=\"font-size: ". $size ."%; color: #". $r.$g.$b .";\">". $this->tags[$key] ."</a>, ";
+            else
+               $output.= "<a href=\"". $this->cfg->web_path ."/index.php?mode=showpi\" onclick=\"Tags('add', ". $key ."); return false;\" class=\"tag\" style=\"font-size: ". $size ."%; color: #". $r.$g.$b .";\">". $this->tags[$key] ."</a>, ";
          }
-
       }
 
       $output = substr($output, 0, strlen($output)-2);
-      print $output;
+      return $output;
 
    } // getAvailableTags()
 
@@ -762,17 +898,10 @@ class PHPFSPOT {
                   break;
                case 'img':
                   $output.= "
-                  <div style=\"display: table-cell;\">
-                   <div style=\"display: table-row; text-align: center;\">
-                    <a href=\"javascript:Tags('del', ". $tag .");\" title=\"". $this->tags[$tag] ."\">
-                     <img src=\"phpfspot_img.php?tagidx=". $tag ."\" />
-                    </a>
-                   </div>
-                   <div style=\"display: table-row; text-align: center;\">
-                    <a href=\"javascript:Tags('del', ". $tag .");\" title=\"". $this->tags[$tag] ."\">
-                     <img src=\"resources/underbar.png\" />
-                    </a>
-                   </div>
+                  <div class=\"tagresulttag\">
+                   <a href=\"javascript:Tags('del', ". $tag .");\" title=\"". $this->tags[$tag] ."\">
+                    <img src=\"". $this->cfg->web_path ."/phpfspot_img.php?tagidx=". $tag ."\" />
+                   </a>
                   </div>
                   ";
                   break;
@@ -856,7 +985,7 @@ class PHPFSPOT {
    } // resetTags()
 
    /**
-    * returns the value for the autocomplet tag-search
+    * returns the value for the autocomplete tag-search
     * @return string
     */
    public function get_xml_tag_list()
@@ -947,8 +1076,7 @@ class PHPFSPOT {
    /**
     * reset date search
     *
-    * if any date search has taken place, reset
-    * it now
+    * if any date search has taken place, reset it now.
     */
    public function resetDateSearch()
    {
@@ -959,6 +1087,20 @@ class PHPFSPOT {
 
    } // resetDateSearch();
 
+   /**
+    * reset rate search
+    *
+    * if any rate search has taken place, reset it now.
+    */
+   public function resetRateSearch()
+   {
+      if(isset($_SESSION['rate_from']))
+         unset($_SESSION['rate_from']);
+      if(isset($_SESSION['rate_to']))
+         unset($_SESSION['rate_to']);
+
+   } // resetRateSearch();
+
    /**
     * return all photo according selection
     *
@@ -984,6 +1126,12 @@ class PHPFSPOT {
       } 
 
       if(isset($_SESSION['searchfor_name'])) {
+
+         /* check for previous conditions. if so add 'AND' */
+         if(!empty($additional_where_cond)) {
+            $additional_where_cond.= " AND ";
+         }
+
          if($this->dbver < 9) {
             $additional_where_cond.= "
                   (
@@ -1004,6 +1152,24 @@ class PHPFSPOT {
          }
       }
 
+      /* limit result based on rate-search */
+      if(isset($_SESSION['rate_from']) && isset($_SESSION['rate_to'])) {
+
+         if($this->dbver > 10) {
+
+            /* check for previous conditions. if so add 'AND' */
+            if(!empty($additional_where_cond)) {
+               $additional_where_cond.= " AND ";
+            }
+
+            $additional_where_cond.= "
+                     p.rating >= ". $_SESSION['rate_from'] ."
+                  AND
+                     p.rating <= ". $_SESSION['rate_to'] ."
+            ";
+         }
+      }
+
       if(isset($_SESSION['sort_order'])) {
          $order_str = $this->get_sort_order();
       }
@@ -1023,7 +1189,7 @@ class PHPFSPOT {
                ON pt2.tag_id=t2.id
             WHERE t.name LIKE '%". $_SESSION['searchfor_tag'] ."%' ";
 
-         if(isset($additional_where_cond) && !empty($additional_where_cond))
+         if(!empty($additional_where_cond))
             $query_str.= "AND ". $additional_where_cond ." ";
 
          if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
@@ -1060,7 +1226,7 @@ class PHPFSPOT {
                   ON pt1.photo_id=p.id
                WHERE pt1.tag_id IN (". $selected .")
             ";
-            if(isset($additional_where_cond) && !empty($additional_where_cond)) 
+            if(!empty($additional_where_cond))
                $query_str.= "AND ". $additional_where_cond ." ";
 
             if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
@@ -1116,7 +1282,7 @@ class PHPFSPOT {
                   AND pt". ($i+2) .".tag_id=". $_SESSION['selected_tags'][$i] ."
                "; 
             }
-            if(isset($additional_where_cond) && !empty($additional_where_cond)) 
+            if(!empty($additional_where_cond))
                $query_str.= "AND ". $additional_where_cond;
 
             if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
@@ -1145,11 +1311,11 @@ class PHPFSPOT {
             ON pt.tag_id=t.id
       ";
 
-      if(isset($additional_where_cond) && !empty($additional_where_cond)) 
+      if(!empty($additional_where_cond))
          $query_str.= "WHERE ". $additional_where_cond ." ";
 
       if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
-         if(isset($additional_where_cond) && !empty($additional_where_cond))
+         if(!empty($additional_where_cond))
             $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags). "')";
          else
             $query_str.= "WHERE t.name IN ('".implode("','",$this->cfg->show_tags). "')";
@@ -1171,10 +1337,12 @@ class PHPFSPOT {
     *
     * this function provides all the necessary information
     * for the photo index template.
+    * @return string
     */
    public function showPhotoIndex()
    {
       $photos = $this->getPhotoSelection();
+      $current_tags = $this->getCurrentTags();
 
       $count = count($photos);
 
@@ -1204,6 +1372,7 @@ class PHPFSPOT {
       $img_name[$thumbs] = Array();
       $img_fullname[$thumbs] = Array();
       $img_title = Array();
+      $img_rating = Array();
 
       for($i = $begin_with; $i < $end_with; $i++) {
 
@@ -1214,6 +1383,7 @@ class PHPFSPOT {
             $img_name[$thumbs] = htmlspecialchars($this->getPhotoName($photos[$i], 15));
             $img_fullname[$thumbs] = htmlspecialchars($this->getPhotoName($photos[$i], 0));
             $img_title[$thumbs] = "Click to view photo ". htmlspecialchars($this->getPhotoName($photos[$i], 0));
+            $img_rating[$thumbs] = $this->get_photo_rating($photos[$i]);
 
             $thumb_path = $this->get_thumb_path($this->cfg->thumb_width, $photos[$i]);
 
@@ -1282,7 +1452,16 @@ class PHPFSPOT {
             else
                $style = "";
 
-            $select = "<a href=\"javascript:showPhotoIndex(". (($i*$photo_per_page)-$photo_per_page) .");\"";
+            $start_with = ($i*$photo_per_page)-$photo_per_page;
+
+            if($this->is_user_friendly_url()) {
+               $select = "<a href=\"". $this->cfg->web_path ."/tag/205/". $start_with ."\"";
+            }
+            else {
+               $select = "<a href=\"". $this->cfg->web_path ."/index.php?mode=showpi&nbsp;tags=". $current_tags ."&nbsp;begin_with=". $begin_with ."\"";
+            }
+            $select.= " onclick=\"showPhotoIndex(". $start_with ."); return false;\"";
+
                if($style != "")
                   $select.= $style;
             $select.= ">". $i ."</a>&nbsp;";
@@ -1320,9 +1499,7 @@ class PHPFSPOT {
          if($last_page > 1)
             $this->tmpl->assign('page_selector', $page_select);
       }
-
       
-      $current_tags = $this->getCurrentTags();
       $extern_link = "index.php?mode=showpi";
       $rss_link = "index.php?mode=rss";
       if($current_tags != "") {
@@ -1353,6 +1530,7 @@ class PHPFSPOT {
       $this->tmpl->assign('img_name', $img_name);
       $this->tmpl->assign('img_fullname', $img_fullname);
       $this->tmpl->assign('img_title', $img_title);
+      $this->tmpl->assign('img_rating', $img_rating);
       $this->tmpl->assign('thumbs', $thumbs);
       $this->tmpl->assign('selected_tags', $this->getSelectedTags('img'));
 
@@ -1417,23 +1595,25 @@ class PHPFSPOT {
             $flip_hori = false;
             $flip_vert = false;
 
-            switch($meta['Orientation']) {
-               case 1: /* top, left */
-                  /* nothing to do */ break;
-               case 2: /* top, right */
-                  $rotate = 0; $flip_hori = true; break;
-               case 3: /* bottom, left */
-                  $rotate = 180; break;
-               case 4: /* bottom, right */
-                  $flip_vert = true; break;
-               case 5: /* left side, top */
-                  $rotate = 90; $flip_vert = true; break;
-               case 6: /* right side, top */
-                  $rotate = 90; break;
-               case 7: /* left side, bottom */
-                  $rotate = 270; $flip_vert = true; break;
-               case 8: /* right side, bottom */
-                  $rotate = 270; break;
+            if(isset($meta['Orientation'])) {
+               switch($meta['Orientation']) {
+                  case 1: /* top, left */
+                     /* nothing to do */ break;
+                  case 2: /* top, right */
+                     $rotate = 0; $flip_hori = true; break;
+                  case 3: /* bottom, left */
+                     $rotate = 180; break;
+                  case 4: /* bottom, right */
+                     $flip_vert = true; break;
+                  case 5: /* left side, top */
+                     $rotate = 90; $flip_vert = true; break;
+                  case 6: /* right side, top */
+                     $rotate = 90; break;
+                  case 7: /* left side, bottom */
+                     $rotate = 270; $flip_vert = true; break;
+                  case 8: /* right side, bottom */
+                     $rotate = 270; break;
+               }
             }
 
             $src_img = @imagecreatefromjpeg($orig_image);
@@ -1828,32 +2008,54 @@ class PHPFSPOT {
     */
    public function startSearch()
    {
-      if(isset($_POST['from']) && $this->isValidDate($_POST['from'])) {
-         $from = $_POST['from'];
+      /* date search */
+      if(isset($_POST['date_from']) && $this->isValidDate($_POST['date_from'])) {
+         $date_from = $_POST['date_from'];
       }
-      if(isset($_POST['to']) && $this->isValidDate($_POST['to'])) {
-         $to = $_POST['to'];
+      if(isset($_POST['date_to']) && $this->isValidDate($_POST['date_to'])) {
+         $date_to = $_POST['date_to'];
       }
 
+      /* tag-name search */
       if(isset($_POST['for_tag']) && is_string($_POST['for_tag'])) {
          $searchfor_tag = $_POST['for_tag'];
          $_SESSION['searchfor_tag'] = $_POST['for_tag'];
       }
+      else {
+         unset($_SESSION['searchfor_tag']);
+      }
 
+      /* file-name search */
       if(isset($_POST['for_name']) && is_string($_POST['for_name'])) {
-         $searchfor_name = $_POST['for_name'];
          $_SESSION['searchfor_name'] = $_POST['for_name'];
       }
+      else {
+         unset($_SESSION['searchfor_name']);
+      }
+
+      /* rate-search */
+      if(isset($_POST['rate_from']) && is_numeric($_POST['rate_from'])) {
+
+         $_SESSION['rate_from'] = $_POST['rate_from'];
+
+         if(isset($_POST['rate_to']) && is_numeric($_POST['rate_to'])) {
+            $_SESSION['rate_to'] = $_POST['rate_to'];
+         }
+      }
+      else {
+         /* delete any previously set value */
+         unset($_SESSION['rate_to'], $_SESSION['rate_from']);
+      }
 
       $this->get_tags();
 
-      if(isset($from) && !empty($from))
-         $_SESSION['from_date'] = strtotime($from ." 00:00:00");
+      if(isset($date_from) && !empty($date_from))
+         $_SESSION['from_date'] = strtotime($date_from ." 00:00:00");
       else
          unset($_SESSION['from_date']);
 
-      if(isset($to) && !empty($to))
-         $_SESSION['to_date'] = strtotime($to ." 23:59:59");
+      if(isset($date_to) && !empty($date_to))
+         $_SESSION['to_date'] = strtotime($date_to ." 23:59:59");
       else
          unset($_SESSION['to_date']);
 
@@ -2111,7 +2313,7 @@ class PHPFSPOT {
 
    private function _debug($text)
    {
-      if($this->fromcmd) {
+      if(isset($this->fromcmd)) {
          print $text;
       }
 
@@ -2163,32 +2365,31 @@ class PHPFSPOT {
    } // _error()
 
    /**
-    * output calendard input fields
+    * get calendar input-text fields
+    *
+    * this function returns a text-field used for the data selection.
+    * Either it will be filled with the current date or, if available,
+    * filled with the date user entered previously.
+    *
     * @param string $mode
     * @return string
     */
-   private function get_calendar($mode)
+   private function get_date_text_field($mode)
    {
-      $year = isset($_SESSION[$mode .'_date']) ? date("Y", $_SESSION[$mode .'_date']) : date("Y");
-      $month = isset($_SESSION[$mode .'_date']) ? date("m", $_SESSION[$mode .'_date']) : date("m");
-      $day = isset($_SESSION[$mode .'_date']) ? date("d", $_SESSION[$mode .'_date']) : date("d");
+      $date = isset($_SESSION[$mode .'_date']) ? date("Y", $_SESSION[$mode .'_date']) : date("Y");
+      $date.= "-";
+      $date.= isset($_SESSION[$mode .'_date']) ? date("m", $_SESSION[$mode .'_date']) : date("m");
+      $date.= "-";
+      $date.= isset($_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\"";
-      $output.= " />\n";
-      $output.= "<input type=\"text\" size=\"1\" id=\"". $mode ."month\" value=\"". $month ."\"";
-      if(!isset($_SESSION[$mode .'_date']))
-         $output.= " disabled=\"disabled\"";
-      $output.= " />\n";
-      $output.= "<input type=\"text\" size=\"1\" id=\"". $mode ."day\" value=\"". $day ."\"";
+      $output = "<input type=\"text\" size=\"15\" id=\"date_". $mode ."\" value=\"". $date ."\"";
       if(!isset($_SESSION[$mode .'_date']))
          $output.= " disabled=\"disabled\"";
       $output.= " />\n";
 
       return $output;
 
-   } // get_calendar()
+   } // get_date_text_field()
 
    /**
     * output calendar matrix
@@ -2369,7 +2570,7 @@ class PHPFSPOT {
          $orig_path = $this->translate_path($this->parse_uri($details['uri'], 'fullpath'));
 
          /* get EXIF information if JPEG */
-         if($details['mime'] == "image/jpeg") {
+         if(isset($details['mime']) && $details['mime'] == "image/jpeg") {
             $meta = $this->get_meta_informations($orig_path);
          }
 
@@ -2399,7 +2600,10 @@ class PHPFSPOT {
 
  
    /**
-    * return all selected tags as one string
+    * get all selected tags
+    *
+    * This function will return all selected tags as one string, seperated
+    * by a comma.
     * @return array
     */
    private function getCurrentTags()
@@ -2437,7 +2641,6 @@ class PHPFSPOT {
    public function whatToDo()
    {
       if(isset($_SESSION['current_photo']) && $_SESSION['start_action'] == 'showp') {
-         return "show_photo";
       }
       elseif(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
          return "showpi_tags";
@@ -2446,8 +2649,6 @@ class PHPFSPOT {
          return "showpi";
       }
 
-      return "nothing special";
-
    } // whatToDo()
 
    /**
@@ -2523,6 +2724,12 @@ class PHPFSPOT {
          case 'tags_desc':
             return " ORDER BY t.name DESC ,p.time ASC";
             break;
+         case 'rate_asc':
+            return " ORDER BY t.name ASC, p.rating ASC";
+            break;
+         case 'rate_desc':
+            return " ORDER BY t.name DESC, p.rating DESC";
+            break;
       }
 
    } // get_sort_order()
@@ -2702,7 +2909,9 @@ class PHPFSPOT {
     */
    private function ts2str($timestamp)
    {
-      return strftime("%Y-%m-%d", $timestamp);
+      if(!empty($timestamp) && is_numeric($timestamp))
+         return strftime("%Y-%m-%d", $timestamp);
+
    } // ts2str()
 
    /**
@@ -2771,15 +2980,7 @@ class PHPFSPOT {
     */
    private function get_phpfspot_url()
    {
-      if($this->cfg->web_path == "/")
-         $web_path = "";
-      /* remove trailing slash */
-      elseif(preg_match('/\/$/', $this->cfg->web_path))
-         $web_path = preg_replace('/\/$/', '', $this->cfg->web_path);
-      else
-         $web_path = $this->cfg->web_path;
-
-      return $this->get_web_protocol() ."://". $this->get_server_name() . $web_path;
+      return $this->get_web_protocol() ."://". $this->get_server_name() . $this->cfg->web_path;
 
    } // get_phpfspot_url()
 
@@ -2973,9 +3174,11 @@ class PHPFSPOT {
 
       }
 
-      /* check for pending slash on web_path */
-      if(!preg_match("/\/$/", $this->cfg->web_path))
-         $this->cfg->web_path.= "/";
+      /* remove trailing slash, if set */
+      if($this->cfg->web_path == "/")
+         $this->cfg->web_path = "";
+      elseif(preg_match('/\/$/', $this->cfg->web_path))
+         $this->cfg->web_path = preg_replace('/\/$/', '', $this->cfg->web_path);
 
       return $this->runtime_error;
 
@@ -3092,19 +3295,24 @@ class PHPFSPOT {
       
    } // get_tag_name()
 
-
+   /**
+    * parse user friendly url which got rewritten by the websever
+    * @param string $request_uri
+    * @return string
+    */
    private function parse_user_friendly_url($request_uri)
    {
       if(preg_match('/\/photoview\/|\/photo\/|\/tag\//', $request_uri)) {
 
-         unset($_SESSION['start_action']);
-         unset($_SESSION['selected_tags']);
-
          $options = explode('/', $request_uri);
 
          switch($options[1]) {
             case 'photoview':
                if(is_numeric($options[2])) {
+                  $this->session_cleanup();
+                  //unset($_SESSION['start_action']);
+                  //unset($_SESSION['selected_tags']);
+                  $_GET['mode'] = 'showp';
                   return $this->showPhoto($options[2]);
                }
                break;
@@ -3121,10 +3329,11 @@ class PHPFSPOT {
                break;
             case 'tag':
                if(is_numeric($options[2])) {
-                  $_GET['mode'] = 'showpi';
-                  $_SESSION['selected_tags'] = Array($options[2]);
-                  $this->tmpl->assign('preset_selected_tags', $this->getSelectedTags());
+                  $this->session_cleanup();
                   $_GET['tags'] = $options[2];
+                  $_SESSION['selected_tags'] = Array($options[2]);
+                  if(isset($options[3]) && is_numeric($options[3]))
+                     $_SESSION['begin_with'] = $options[3];
                   return $this->showPhotoIndex();
                }
                break;
@@ -3149,6 +3358,22 @@ class PHPFSPOT {
 
    } // is_user_friendly_url()
 
+   /**
+    * session cleanup
+    *
+    * this function will cleanup user's session information
+    */
+   private function session_cleanup()
+   {
+      unset($_SESSION['begin_with']);
+      $this->resetDateSearch();
+      $this->resetPhotoView();
+      $this->resetTagSearch();
+      $this->resetNameSearch();
+      $this->resetDateSearch();
+      $this->resetTags();
+
+   } // session_cleanup()
 
 } // class PHPFSPOT