3 /***************************************************************************
5 * Copyright (c) by Andreas Unterkircher, unki@netshadow.at
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 ***************************************************************************/
24 require_once "phpfspot_cfg.php";
25 require_once "phpfspot_db.php";
39 * this function will be called on class construct
40 * and will check requirements, loads configuration,
41 * open databases and start the user session
43 public function __construct()
45 $this->cfg = new PHPFSPOT_CFG;
47 /* set application name and version information */
48 $this->cfg->product = "phpfspot";
49 $this->cfg->version = "1.2";
51 /* Check necessary requirements */
52 if(!$this->checkRequirements()) {
56 $this->db = new PHPFSPOT_DB($this, $this->cfg->fspot_db);
58 if(!is_writeable(dirname($this->cfg->phpfspot_db))) {
59 print dirname($this->cfg->phpfspot_db) .": directory is not writeable!";
63 $this->cfg_db = new PHPFSPOT_DB($this, $this->cfg->phpfspot_db);
64 if(!is_writeable($this->cfg->phpfspot_db)) {
65 print $this->cfg->phpfspot_db ." is not writeable for user ". $this->getuid() ."\n";
68 $this->check_config_table();
70 /* include Smarty template engine */
71 if(!$this->check_readable($this->cfg->smarty_path .'/libs/Smarty.class.php')) {
74 require $this->cfg->smarty_path .'/libs/Smarty.class.php';
75 /* overload Smarty class if our own template handler */
76 require_once "phpfspot_tmpl.php";
77 $this->tmpl = new PHPFSPOT_TMPL($this);
79 /* check if all necessary indices exist */
80 $this->checkDbIndices();
84 if(!isset($_SESSION['tag_condition']))
85 $_SESSION['tag_condition'] = 'or';
87 if(!isset($_SESSION['sort_order']))
88 $_SESSION['sort_order'] = 'date_asc';
90 if(!isset($_SESSION['searchfor']))
91 $_SESSION['searchfor'] = '';
93 // if begin_with is still set but rows_per_page is now 0, unset it
94 if(isset($_SESSION['begin_with']) && $this->cfg->rows_per_page == 0)
95 unset($_SESSION['begin_with']);
99 public function __destruct()
105 * show - generate html output
107 * this function can be called after the constructor has
108 * prepared everyhing. it will load the index.tpl smarty
109 * template. if necessary it will registere pre-selects
110 * (photo index, photo, tag search, date search) into
113 public function show()
115 $this->tmpl->assign('searchfor', $_SESSION['searchfor']);
116 $this->tmpl->assign('page_title', $this->cfg->page_title);
117 $this->tmpl->assign('current_condition', $_SESSION['tag_condition']);
118 $this->tmpl->assign('template_path', 'themes/'. $this->cfg->theme_name);
120 $_SESSION['start_action'] = $_GET['mode'];
122 switch($_GET['mode']) {
124 if(isset($_GET['tags'])) {
125 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
127 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
128 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
130 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
131 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
135 if(isset($_GET['tags'])) {
136 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
137 $_SESSION['start_action'] = 'showp';
139 if(isset($_GET['id']) && is_numeric($_GET['id'])) {
140 $_SESSION['current_photo'] = $_GET['id'];
141 $_SESSION['start_action'] = 'showp';
143 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
144 $_SESSION['from_date'] = strtotime($_GET['from_date']);
146 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
147 $_SESSION['to_date'] = strtotime($_GET['to_date']);
151 $this->tmpl->show("export.tpl");
155 $this->tmpl->show("slideshow.tpl");
159 if(isset($_GET['tags'])) {
160 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
162 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
163 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
165 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
166 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
173 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date']))
174 $this->tmpl->assign('date_search_enabled', true);
176 $this->tmpl->assign('from_date', $this->get_calendar('from'));
177 $this->tmpl->assign('to_date', $this->get_calendar('to'));
178 $this->tmpl->assign('sort_field', $this->get_sort_field());
179 $this->tmpl->assign('content_page', 'welcome.tpl');
180 $this->tmpl->show("index.tpl");
185 * get_tags - grab all tags of f-spot's database
187 * this function will get all available tags from
188 * the f-spot database and store them within two
189 * arrays within this class for later usage. in
190 * fact, if the user requests (hide_tags) it will
191 * opt-out some of them.
193 * this function is getting called once by show()
195 private function get_tags()
197 $this->avail_tags = Array();
200 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
203 DISTINCT t1.id as id, t1.name as name
206 INNER JOIN photo_tags
207 pt2 ON pt1.photo_id=pt2.photo_id
213 t2.name IN ('".implode("','",$this->cfg->show_tags)."')
215 t1.sort_priority ASC";
217 $result = $this->db->db_query($query_str);
221 $result = $this->db->db_query("
224 ORDER BY sort_priority ASC
228 while($row = $this->db->db_fetch_object($result)) {
230 $tag_id = $row['id'];
231 $tag_name = $row['name'];
233 /* if the user has specified to ignore this tag in phpfspot's
234 configuration, ignore it here so it does not get added to
237 if(in_array($row['name'], $this->cfg->hide_tags))
240 /* if you include the following if-clause and the user has specified
241 to only show certain tags which are specified in phpfspot's
242 configuration, ignore all others so they will not be added to the
244 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags) &&
245 !in_array($row['name'], $this->cfg->show_tags))
249 $this->tags[$tag_id] = $tag_name;
250 $this->avail_tags[$count] = $tag_id;
258 * extract all photo details
260 * retrieve all available details from f-spot's
261 * database and return them as object
263 public function get_photo_details($idx)
266 SELECT p.id, p.name, p.time, p.directory_path, p.description
270 /* if show_tags is set, only return details for photos which
271 are specified to be shown
273 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
275 INNER JOIN photo_tags pt
279 WHERE p.id='". $idx ."'
280 AND t.name IN ('".implode("','",$this->cfg->show_tags)."')";
284 WHERE p.id='". $idx ."'
288 $result = $this->db->db_query($query_str);
289 return $this->db->db_fetch_object($result);
291 } // get_photo_details
294 * returns aligned photo names
296 * this function returns aligned (length) names for
297 * an specific photo. If the length of the name exceeds
298 * $limit the name will be shrinked (...)
300 public function getPhotoName($idx, $limit = 0)
302 if($details = $this->get_photo_details($idx)) {
303 $name = $this->shrink_text($details['name'], $limit);
310 * shrink text according provided limit
312 * If the length of the name exceeds $limit the
313 * text will be shortend and some content in between
314 * will be replaced with "..."
316 private function shrink_text($text, $limit)
318 if($limit != 0 && strlen($text) > $limit) {
319 $text = substr($text, 0, $limit-5) ."...". substr($text, -($limit-5));
327 * translate f-spoth photo path
329 * as the full-qualified path recorded in the f-spot database
330 * is usally not the same as on the webserver, this function
331 * will replace the path with that one specified in the cfg
333 public function translate_path($path, $width = 0)
335 return str_replace($this->cfg->path_replace_from, $this->cfg->path_replace_to, $path);
340 * control HTML ouput for a single photo
342 * this function provides all the necessary information
343 * for the single photo template.
345 public function showPhoto($photo)
347 /* get all photos from the current photo selection */
348 $all_photos = $this->getPhotoSelection();
349 $count = count($all_photos);
351 for($i = 0; $i < $count; $i++) {
353 // $get_next will be set, when the photo which has to
354 // be displayed has been found - this means that the
355 // next available is in fact the NEXT image (for the
357 if(isset($get_next)) {
358 $next_img = $all_photos[$i];
362 /* the next photo is our NEXT photo */
363 if($all_photos[$i] == $photo) {
367 $previous_img = $all_photos[$i];
370 if($photo == $all_photos[$i]) {
375 $details = $this->get_photo_details($photo);
382 $orig_path = $this->translate_path($details['directory_path']) ."/". $details['name'];
383 $thumb_path = $this->get_thumb_path($this->cfg->photo_width, $photo);
385 if(!file_exists($orig_path)) {
386 $this->_error("Photo ". $orig_path ." does not exist!<br />\n");
389 if(!is_readable($orig_path)) {
390 $this->_error("Photo ". $orig_path ." is not readable for user ". $this->getuid() ."<br />\n");
393 /* If the thumbnail doesn't exist yet, try to create it */
394 if(!file_exists($thumb_path)) {
395 $this->gen_thumb($photo, true);
396 $thumb_path = $this->get_thumb_path($this->cfg->photo_width, $photo);
399 /* get f-spot database meta information */
400 $meta = $this->get_meta_informations($orig_path);
402 /* If EXIF data are available, use them */
403 if(isset($meta['ExifImageWidth'])) {
404 $meta_res = $meta['ExifImageWidth'] ."x". $meta['ExifImageLength'];
406 $info = getimagesize($orig_path);
407 $meta_res = $info[0] ."x". $info[1];
410 $meta_date = isset($meta['FileDateTime']) ? strftime("%a %x %X", $meta['FileDateTime']) : "n/a";
411 $meta_make = isset($meta['Make']) ? $meta['Make'] ." / ". $meta['Model'] : "n/a";
412 $meta_size = isset($meta['FileSize']) ? round($meta['FileSize']/1024, 1) ."kbyte" : "n/a";
414 $extern_link = "index.php?mode=showp&id=". $photo;
415 $current_tags = $this->getCurrentTags();
416 if($current_tags != "") {
417 $extern_link.= "&tags=". $current_tags;
419 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
420 $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
423 $this->tmpl->assign('extern_link', $extern_link);
425 if(file_exists($thumb_path)) {
427 $info = getimagesize($thumb_path);
429 $this->tmpl->assign('description', $details['description']);
430 $this->tmpl->assign('image_name', $details['name']);
432 $this->tmpl->assign('width', $info[0]);
433 $this->tmpl->assign('height', $info[1]);
434 $this->tmpl->assign('ExifMadeOn', $meta_date);
435 $this->tmpl->assign('ExifMadeWith', $meta_make);
436 $this->tmpl->assign('ExifOrigResolution', $meta_res);
437 $this->tmpl->assign('ExifFileSize', $meta_size);
439 $this->tmpl->assign('image_url', 'phpfspot_img.php?idx='. $photo ."&width=". $this->cfg->photo_width);
440 $this->tmpl->assign('image_url_full', 'phpfspot_img.php?idx='. $photo);
442 $this->tmpl->assign('tags', $this->get_photo_tags($photo));
443 $this->tmpl->assign('current', $current);
446 $this->_error("Can't open file ". $thumb_path ."\n");
451 $this->tmpl->assign('previous_url', "javascript:showImage(". $previous_img .");");
452 $this->tmpl->assign('prev_img', $previous_img);
456 $this->tmpl->assign('next_url', "javascript:showImage(". $next_img .");");
457 $this->tmpl->assign('next_img', $next_img);
459 $this->tmpl->assign('mini_width', $this->cfg->mini_width);
460 $this->tmpl->assign('photo_number', $i);
461 $this->tmpl->assign('photo_count', count($all_photos));
463 $this->tmpl->show("single_photo.tpl");
468 * all available tags and tag cloud
470 * this function outputs all available tags (time ordered)
471 * and in addition output them as tag cloud (tags which have
472 * many photos will appears more then others)
474 public function getAvailableTags()
480 $result = $this->db->db_query("
481 SELECT tag_id as id, count(tag_id) as quantity
491 while($row = $this->db->db_fetch_object($result)) {
492 $tags[$row['id']] = $row['quantity'];
495 // change these font sizes if you will
496 $max_size = 125; // max font size in %
497 $min_size = 75; // min font size in %
499 // get the largest and smallest array values
500 $max_qty = max(array_values($tags));
501 $min_qty = min(array_values($tags));
503 // find the range of values
504 $spread = $max_qty - $min_qty;
505 if (0 == $spread) { // we don't want to divide by zero
509 // determine the font-size increment
510 // this is the increase per tag quantity (times used)
511 $step = ($max_size - $min_size)/($spread);
513 // loop through our tag array
514 foreach ($tags as $key => $value) {
516 if(isset($_SESSION['selected_tags']) && in_array($key, $_SESSION['selected_tags']))
519 // calculate CSS font-size
520 // find the $value in excess of $min_qty
521 // multiply by the font-size increment ($size)
522 // and add the $min_size set above
523 $size = $min_size + (($value - $min_qty) * $step);
524 // uncomment if you want sizes in whole %:
527 if(isset($this->tags[$key])) {
528 $output.= "<a href=\"javascript:Tags('add', ". $key .");\" class=\"tag\" style=\"font-size: ". $size ."%;\">". $this->tags[$key] ."</a>, ";
533 $output = substr($output, 0, strlen($output)-2);
536 } // getAvailableTags()
539 * output all selected tags
541 * this function output all tags which have been selected
542 * by the user. the selected tags are stored in the
543 * session-variable $_SESSION['selected_tags']
545 public function getSelectedTags()
550 foreach($this->avail_tags as $tag)
552 // return all selected tags
553 if(isset($_SESSION['selected_tags']) && in_array($tag, $_SESSION['selected_tags'])) {
554 $output.= "<a href=\"javascript:Tags('del', ". $tag .");\" class=\"tag\">". $this->tags[$tag] ."</a>, ";
558 $output = substr($output, 0, strlen($output)-2);
561 } // getSelectedTags()
564 * add tag to users session variable
566 * this function will add the specified to users current
567 * tag selection. if a date search has been made before
568 * it will be now cleared
570 public function addTag($tag)
572 if(!isset($_SESSION['selected_tags']))
573 $_SESSION['selected_tags'] = Array();
575 if(!in_array($tag, $_SESSION['selected_tags']))
576 array_push($_SESSION['selected_tags'], $tag);
581 * remove tag to users session variable
583 * this function removes the specified tag from
584 * users current tag selection
586 public function delTag($tag)
588 if(isset($_SESSION['selected_tags'])) {
589 $key = array_search($tag, $_SESSION['selected_tags']);
590 unset($_SESSION['selected_tags'][$key]);
591 sort($_SESSION['selected_tags']);
597 * reset tag selection
599 * if there is any tag selection, it will be
602 public function resetTags()
604 if(isset($_SESSION['selected_tags']))
605 unset($_SESSION['selected_tags']);
612 * if a specific photo was requested (external link)
613 * unset the session variable now
615 public function resetPhotoView()
617 if(isset($_SESSION['current_photo']))
618 unset($_SESSION['current_photo']);
620 } // resetPhotoView();
625 * if any tag search has taken place, reset
628 public function resetTagSearch()
630 if(isset($_SESSION['searchfor']))
631 unset($_SESSION['searchfor']);
633 } // resetTagSearch()
638 * if any date search has taken place, reset
641 public function resetDateSearch()
643 if(isset($_SESSION['from_date']))
644 unset($_SESSION['from_date']);
645 if(isset($_SESSION['to_date']))
646 unset($_SESSION['to_date']);
648 } // resetDateSearch();
651 * return all photo according selection
653 * this function returns all photos based on
654 * the tag-selection, tag- or date-search.
655 * the tag-search also has to take care of AND
656 * and OR conjunctions
658 public function getPhotoSelection()
660 $matched_photos = Array();
662 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
663 $from_date = $_SESSION['from_date'];
664 $to_date = $_SESSION['to_date'];
665 $additional_where_cond = "
666 p.time>='". $from_date ."'
668 p.time<='". $to_date ."'
672 if(isset($_SESSION['sort_order'])) {
673 $order_str = $this->get_sort_order();
676 /* return a search result */
677 if(isset($_SESSION['searchfor']) && $_SESSION['searchfor'] != '') {
679 SELECT DISTINCT pt1.photo_id
681 INNER JOIN photo_tags pt2
682 ON pt1.photo_id=pt2.photo_id
689 WHERE t1.name LIKE '%". $_SESSION['searchfor'] ."%' ";
691 if(isset($additional_where_cond))
692 $query_str.= "AND ". $additional_where_cond ." ";
694 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
695 $query_str.= "AND t2.name IN ('".implode("','",$this->cfg->show_tags)."')";
698 if(isset($order_str))
699 $query_str.= $order_str;
701 $result = $this->db->db_query($query_str);
702 while($row = $this->db->db_fetch_object($result)) {
703 array_push($matched_photos, $row['photo_id']);
705 return $matched_photos;
708 /* return according the selected tags */
709 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
711 foreach($_SESSION['selected_tags'] as $tag)
712 $selected.= $tag .",";
713 $selected = substr($selected, 0, strlen($selected)-1);
715 /* photo has to match at least on of the selected tags */
716 if($_SESSION['tag_condition'] == 'or') {
718 SELECT DISTINCT pt1.photo_id
720 INNER JOIN photo_tags pt2
721 ON pt1.photo_id=pt2.photo_id
726 WHERE pt1.tag_id IN (". $selected .")
728 if(isset($additional_where_cond))
729 $query_str.= "AND ". $additional_where_cond ." ";
731 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
732 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags)."')";
735 if(isset($order_str))
736 $query_str.= $order_str;
738 /* photo has to match all selected tags */
739 elseif($_SESSION['tag_condition'] == 'and') {
741 if(count($_SESSION['selected_tags']) >= 32) {
742 print "A SQLite limit of 32 tables within a JOIN SELECT avoids to<br />\n";
743 print "evaluate your tag selection. Please remove some tags from your selection.\n";
747 /* Join together a table looking like
749 pt1.photo_id pt1.tag_id pt2.photo_id pt2.tag_id ...
751 so the query can quickly return all images matching the
752 selected tags in an AND condition
757 SELECT DISTINCT pt1.photo_id
761 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
768 for($i = 0; $i < count($_SESSION['selected_tags']); $i++) {
770 INNER JOIN photo_tags pt". ($i+2) ."
771 ON pt1.photo_id=pt". ($i+2) .".photo_id
778 $query_str.= "WHERE pt2.tag_id=". $_SESSION['selected_tags'][0]." ";
779 for($i = 1; $i < count($_SESSION['selected_tags']); $i++) {
781 AND pt". ($i+2) .".tag_id=". $_SESSION['selected_tags'][$i] ."
784 if(isset($additional_where_cond))
785 $query_str.= "AND ". $additional_where_cond;
787 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
788 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags). "')";
791 if(isset($order_str))
792 $query_str.= $order_str;
796 $result = $this->db->db_query($query_str);
797 while($row = $this->db->db_fetch_object($result)) {
798 array_push($matched_photos, $row['photo_id']);
800 return $matched_photos;
803 /* return all available photos */
805 SELECT DISTINCT photo_id
812 if(isset($additional_where_cond))
813 $query_str.= "WHERE ". $additional_where_cond ." ";
815 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
816 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags). "')";
819 if(isset($order_str))
820 $query_str.= $order_str;
822 $result = $this->db->db_query($query_str);
823 while($row = $this->db->db_fetch_object($result)) {
824 array_push($matched_photos, $row['photo_id']);
826 return $matched_photos;
828 } // getPhotoSelection()
831 * control HTML ouput for photo index
833 * this function provides all the necessary information
834 * for the photo index template.
836 public function showPhotoIndex()
838 $photos = $this->getPhotoSelection();
840 $count = count($photos);
842 if(isset($_SESSION['begin_with']) && $_SESSION['begin_with'] != "")
843 $anchor = $_SESSION['begin_with'];
845 if(!isset($this->cfg->rows_per_page) || $this->cfg->rows_per_page == 0) {
851 elseif($this->cfg->rows_per_page > 0) {
853 if(!$_SESSION['begin_with'] || $_SESSION['begin_with'] == 0)
857 $begin_with = $_SESSION['begin_with'];
859 // verify $begin_with - perhaps the thumbs-per-rows or
860 // rows-per-page variables have changed or the jump back
861 // from a photo wasn't exact - so calculate the real new
863 $multiplicator = $this->cfg->rows_per_page * $this->cfg->thumbs_per_row;
864 for($i = 0; $i <= $count; $i+=$multiplicator) {
865 if($begin_with >= $i && $begin_with < $i+$multiplicator) {
872 $end_with = $begin_with + ($this->cfg->rows_per_page * $this->cfg->thumbs_per_row);
878 $images[$rows] = Array();
879 $img_height[$rows] = Array();
880 $img_width[$rows] = Array();
881 $img_id[$rows] = Array();
882 $img_name[$rows] = Array();
883 $img_title = Array();
885 for($i = $begin_with; $i < $end_with; $i++) {
887 $images[$rows][$cols] = $photos[$i];
888 $img_id[$rows][$cols] = $i;
889 $img_name[$rows][$cols] = htmlspecialchars($this->getPhotoName($photos[$i], 15));
890 $img_title[$rows][$cols] = "Click to view photo ". htmlspecialchars($this->getPhotoName($photos[$i], 0));
892 $thumb_path = $this->get_thumb_path($this->cfg->thumb_width, $photos[$i]);
894 if(file_exists($thumb_path)) {
895 $info = getimagesize($thumb_path);
896 $img_width[$rows][$cols] = $info[0];
897 $img_height[$rows][$cols] = $info[1];
900 if($cols == $this->cfg->thumbs_per_row-1) {
903 $images[$rows] = Array();
904 $img_width[$rows] = Array();
905 $img_height[$rows] = Array();
912 // +1 for for smarty's selection iteration
915 if(isset($_SESSION['searchfor']) && $_SESSION['searchfor'] != '')
916 $this->tmpl->assign('searchfor', $_SESSION['searchfor']);
918 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
919 $this->tmpl->assign('from_date', $this->ts2str($_SESSION['from_date']));
920 $this->tmpl->assign('to_date', $this->ts2str($_SESSION['to_date']));
923 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
924 $this->tmpl->assign('tag_result', 1);
927 /* do we have to display the page selector ? */
928 if($this->cfg->rows_per_page != 0) {
930 /* calculate the page switchers */
931 $previous_start = $begin_with - ($this->cfg->rows_per_page * $this->cfg->thumbs_per_row);
932 $next_start = $begin_with + ($this->cfg->rows_per_page * $this->cfg->thumbs_per_row);
935 $this->tmpl->assign("previous_url", "javascript:showPhotoIndex(". $previous_start .");");
936 if($end_with < $count)
937 $this->tmpl->assign("next_url", "javascript:showPhotoIndex(". $next_start .");");
939 $photo_per_page = $this->cfg->rows_per_page * $this->cfg->thumbs_per_row;
940 $last_page = ceil($count / $photo_per_page);
942 /* get the current selected page */
943 if($begin_with == 0) {
947 for($i = $begin_with; $i >= 0; $i-=$photo_per_page) {
954 for($i = 1; $i <= $last_page; $i++) {
956 if($current_page == $i)
957 $style = "style=\"font-size: 125%; text-decoration: underline;\"";
958 elseif($current_page-1 == $i || $current_page+1 == $i)
959 $style = "style=\"font-size: 105%;\"";
960 elseif(($current_page-5 >= $i) && ($i != 1) ||
961 ($current_page+5 <= $i) && ($i != $last_page))
962 $style = "style=\"font-size: 75%;\"";
966 $select = "<a href=\"javascript:showPhotoIndex(". (($i*$photo_per_page)-$photo_per_page) .");\"";
969 $select.= ">". $i ."</a> ";
971 // until 9 pages we show the selector from 1-9
972 if($last_page <= 9) {
973 $page_select.= $select;
976 if($i == 1 /* first page */ ||
977 $i == $last_page /* last page */ ||
978 $i == $current_page /* current page */ ||
979 $i == ceil($last_page * 0.25) /* first quater */ ||
980 $i == ceil($last_page * 0.5) /* half */ ||
981 $i == ceil($last_page * 0.75) /* third quater */ ||
982 (in_array($i, array(1,2,3,4,5,6)) && $current_page <= 4) /* the first 6 */ ||
983 (in_array($i, array($last_page, $last_page-1, $last_page-2, $last_page-3, $last_page-4, $last_page-5)) && $current_page >= $last_page-4) /* the last 6 */ ||
984 $i == $current_page-3 || $i == $current_page-2 || $i == $current_page-1 /* three before */ ||
985 $i == $current_page+3 || $i == $current_page+2 || $i == $current_page+1 /* three after */) {
987 $page_select.= $select;
995 $page_select.= "......... ";
1000 /* only show the page selector if we have more then one page */
1002 $this->tmpl->assign('page_selector', $page_select);
1006 $current_tags = $this->getCurrentTags();
1007 $extern_link = "index.php?mode=showpi";
1008 $rss_link = "index.php?mode=rss";
1009 if($current_tags != "") {
1010 $extern_link.= "&tags=". $current_tags;
1011 $rss_link.= "&tags=". $current_tags;
1013 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1014 $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
1015 $rss_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
1018 $export_link = "index.php?mode=export";
1019 $slideshow_link = "index.php?mode=slideshow";
1021 $this->tmpl->assign('extern_link', $extern_link);
1022 $this->tmpl->assign('slideshow_link', $slideshow_link);
1023 $this->tmpl->assign('export_link', $export_link);
1024 $this->tmpl->assign('rss_link', $rss_link);
1025 $this->tmpl->assign('count', $count);
1026 $this->tmpl->assign('width', $this->cfg->thumb_width);
1027 $this->tmpl->assign('images', $images);
1028 $this->tmpl->assign('img_width', $img_width);
1029 $this->tmpl->assign('img_height', $img_height);
1030 $this->tmpl->assign('img_id', $img_id);
1031 $this->tmpl->assign('img_name', $img_name);
1032 $this->tmpl->assign('img_title', $img_title);
1033 $this->tmpl->assign('rows', $rows);
1034 $this->tmpl->assign('columns', $this->cfg->thumbs_per_row);
1036 $this->tmpl->show("photo_index.tpl");
1039 print "<script language=\"JavaScript\">self.location.hash = '#image". $anchor ."';</script>\n";
1041 } // showPhotoIndex()
1044 * show credit template
1046 public function showCredits()
1048 $this->tmpl->assign('version', $this->cfg->version);
1049 $this->tmpl->assign('product', $this->cfg->product);
1050 $this->tmpl->show("credits.tpl");
1055 * create_thumbnails for the requested width
1057 * this function creates image thumbnails of $orig_image
1058 * stored as $thumb_image. It will check if the image is
1059 * in a supported format, if necessary rotate the image
1060 * (based on EXIF orientation meta headers) and re-sizing.
1062 public function create_thumbnail($orig_image, $thumb_image, $width)
1064 if(!file_exists($orig_image)) {
1068 $details = getimagesize($orig_image);
1070 /* check if original photo is a support image type */
1071 if(!$this->checkifImageSupported($details['mime']))
1074 $meta = $this->get_meta_informations($orig_image);
1079 switch($meta['Orientation']) {
1081 case 1: /* top, left */
1082 $rotate = 0; $flip = false; break;
1083 case 2: /* top, right */
1084 $rotate = 0; $flip = true; break;
1085 case 3: /* bottom, left */
1086 $rotate = 180; $flip = false; break;
1087 case 4: /* bottom, right */
1088 $rotate = 180; $flip = true; break;
1089 case 5: /* left side, top */
1090 $rotate = 90; $flip = true; break;
1091 case 6: /* right side, top */
1092 $rotate = 90; $flip = false; break;
1093 case 7: /* left side, bottom */
1094 $rotate = 270; $flip = true; break;
1095 case 8: /* right side, bottom */
1096 $rotate = 270; $flip = false; break;
1099 $src_img = @imagecreatefromjpeg($orig_image);
1102 print "Can't load image from ". $orig_image ."\n";
1106 /* grabs the height and width */
1107 $cur_width = imagesx($src_img);
1108 $cur_height = imagesy($src_img);
1110 // If requested width is more then the actual image width,
1111 // do not generate a thumbnail, instead safe the original
1112 // as thumbnail but with lower quality
1114 if($width >= $cur_width) {
1115 $result = imagejpeg($src_img, $thumb_image, 75);
1116 imagedestroy($src_img);
1120 // If the image will be rotate because EXIF orientation said so
1121 // 'virtually rotate' the image for further calculations
1122 if($rotate == 90 || $rotate == 270) {
1124 $cur_width = $cur_height;
1128 /* calculates aspect ratio */
1129 $aspect_ratio = $cur_height / $cur_width;
1132 if($aspect_ratio < 1) {
1134 $new_h = abs($new_w * $aspect_ratio);
1136 /* 'virtually' rotate the image and calculate it's ratio */
1137 $tmp_w = $cur_height;
1138 $tmp_h = $cur_width;
1139 /* now get the ratio from the 'rotated' image */
1140 $tmp_ratio = $tmp_h/$tmp_w;
1141 /* now calculate the new dimensions */
1143 $tmp_h = abs($tmp_w * $tmp_ratio);
1145 // now that we know, how high they photo should be, if it
1146 // gets rotated, use this high to scale the image
1148 $new_w = abs($new_h / $aspect_ratio);
1150 // If the image will be rotate because EXIF orientation said so
1151 // now 'virtually rotate' back the image for the image manipulation
1152 if($rotate == 90 || $rotate == 270) {
1159 /* creates new image of that size */
1160 $dst_img = imagecreatetruecolor($new_w, $new_h);
1162 imagefill($dst_img, 0, 0, ImageColorAllocate($dst_img, 255, 255, 255));
1164 /* copies resized portion of original image into new image */
1165 imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $new_w, $new_h, imagesx($src_img), imagesy($src_img));
1167 /* needs the image to be flipped horizontal? */
1171 for($x = 0; $x < $new_w; $x++) {
1172 imagecopy($dst_img, $image, $x, 0, $w - $x - 1, 0, 1, $h);
1177 $this->_debug("(ROTATE)");
1178 $dst_img = $this->rotateImage($dst_img, $rotate);
1181 /* write down new generated file */
1182 $result = imagejpeg($dst_img, $thumb_image, 75);
1184 /* free your mind */
1185 imagedestroy($dst_img);
1186 imagedestroy($src_img);
1188 if($result === false) {
1189 print "Can't write thumbnail ". $thumb_image ."\n";
1195 } // create_thumbnail()
1198 * return all exif meta data from the file
1200 public function get_meta_informations($file)
1202 return exif_read_data($file);
1204 } // get_meta_informations()
1207 * create phpfspot own sqlite database
1209 * this function creates phpfspots own sqlite database
1210 * if it does not exist yet. this own is used to store
1211 * some necessary informations (md5 sum's, ...).
1213 public function check_config_table()
1215 // if the config table doesn't exist yet, create it
1216 if(!$this->cfg_db->db_check_table_exists("images")) {
1217 $this->cfg_db->db_exec("
1218 CREATE TABLE images (
1219 img_idx int primary key,
1225 } // check_config_table
1228 * Generates a thumbnail from photo idx
1230 * This function will generate JPEG thumbnails from provided F-Spot photo
1233 * 1. Check if all thumbnail generations (width) are already in place and
1235 * 2. Check if the md5sum of the original file has changed
1236 * 3. Generate the thumbnails if needed
1238 public function gen_thumb($idx = 0, $force = 0)
1242 $resolutions = Array(
1243 $this->cfg->thumb_width,
1244 $this->cfg->photo_width,
1245 $this->cfg->mini_width,
1248 /* get details from F-Spot's database */
1249 $details = $this->get_photo_details($idx);
1251 /* calculate file MD5 sum */
1252 $full_path = $this->translate_path($details['directory_path']) ."/". $details['name'];
1254 if(!file_exists($full_path)) {
1255 $this->_error("File ". $full_path ." does not exist\n");
1259 if(!is_readable($full_path)) {
1260 $this->_error("File ". $full_path ." is not readable for ". $this->getuid() ."\n");
1264 $file_md5 = md5_file($full_path);
1266 $this->_debug("Image [". $idx ."] ". $this->shrink_text($details['name'], 20) ." Thumbnails:");
1268 foreach($resolutions as $resolution) {
1270 $thumb_sub_path = substr($file_md5, 0, 2);
1271 $thumb_path = $this->cfg->thumb_path ."/". $thumb_sub_path ."/". $resolution ."_". $file_md5;
1273 if(!file_exists(dirname($thumb_path))) {
1274 mkdir(dirname($thumb_path), 0755);
1277 /* if the thumbnail file doesn't exist, create it */
1278 if(!file_exists($thumb_path)) {
1280 $this->_debug(" ". $resolution ."px");
1281 if(!$this->create_thumbnail($full_path, $thumb_path, $resolution))
1284 /* if the file hasn't changed there is no need to regen the thumb */
1285 elseif($file_md5 != $this->getMD5($idx) || $force) {
1287 $this->_debug(" ". $resolution ."px");
1288 if(!$this->create_thumbnail($full_path, $thumb_path, $resolution))
1294 /* set the new/changed MD5 sum for the current photo */
1296 $this->setMD5($idx, $file_md5);
1299 $this->_debug("\n");
1304 * returns stored md5 sum for a specific photo
1306 * this function queries the phpfspot database for a
1307 * stored MD5 checksum of the specified photo
1309 public function getMD5($idx)
1311 $result = $this->cfg_db->db_query("
1314 WHERE img_idx='". $idx ."'
1320 $img = $this->cfg_db->db_fetch_object($result);
1321 return $img['img_md5'];
1326 * set MD5 sum for the specific photo
1328 private function setMD5($idx, $md5)
1330 $result = $this->cfg_db->db_exec("
1331 REPLACE INTO images (img_idx, img_md5)
1332 VALUES ('". $idx ."', '". $md5 ."')
1338 * store current tag condition
1340 * this function stores the current tag condition
1341 * (AND or OR) in the users session variables
1343 public function setTagCondition($mode)
1345 $_SESSION['tag_condition'] = $mode;
1347 } // setTagCondition()
1350 * invoke tag & date search
1352 * this function will return all matching tags and store
1353 * them in the session variable selected_tags. furthermore
1354 * it also handles the date search.
1355 * getPhotoSelection() will then only return the matching
1358 public function startSearch($searchfor, $sort_order, $from = 0, $to = 0)
1362 $_SESSION['searchfor'] = $searchfor;
1363 $_SESSION['sort_order'] = $sort_order;
1365 $_SESSION['from_date'] = strtotime($from);
1367 unset($_SESSION['from_date']);
1369 $_SESSION['to_date'] = strtotime($to);
1371 unset($_SESSION['to_date']);
1373 if($searchfor != "") {
1374 /* new search, reset the current selected tags */
1375 $_SESSION['selected_tags'] = Array();
1376 foreach($this->avail_tags as $tag) {
1377 if(preg_match('/'. $searchfor .'/i', $this->tags[$tag]))
1378 array_push($_SESSION['selected_tags'], $tag);
1387 * this function rotates the image according the
1390 private function rotateImage($img, $degrees)
1392 if(function_exists("imagerotate")) {
1393 $img = imagerotate($img, $degrees, 0);
1395 function imagerotate($src_img, $angle)
1397 $src_x = imagesx($src_img);
1398 $src_y = imagesy($src_img);
1399 if ($angle == 180) {
1403 elseif ($src_x <= $src_y) {
1407 elseif ($src_x >= $src_y) {
1412 $rotate=imagecreatetruecolor($dest_x,$dest_y);
1413 imagealphablending($rotate, false);
1418 for ($y = 0; $y < ($src_y); $y++) {
1419 for ($x = 0; $x < ($src_x); $x++) {
1420 $color = imagecolorat($src_img, $x, $y);
1421 imagesetpixel($rotate, $dest_x - $y - 1, $x, $color);
1427 for ($y = 0; $y < ($src_y); $y++) {
1428 for ($x = 0; $x < ($src_x); $x++) {
1429 $color = imagecolorat($src_img, $x, $y);
1430 imagesetpixel($rotate, $y, $dest_y - $x - 1, $color);
1436 for ($y = 0; $y < ($src_y); $y++) {
1437 for ($x = 0; $x < ($src_x); $x++) {
1438 $color = imagecolorat($src_img, $x, $y);
1439 imagesetpixel($rotate, $dest_x - $x - 1, $dest_y - $y - 1, $color);
1453 $img = imagerotate($img, $degrees);
1462 * return all assigned tags for the specified photo
1464 private function get_photo_tags($idx)
1466 $result = $this->db->db_query("
1469 INNER JOIN photo_tags pt
1471 WHERE pt.photo_id='". $idx ."'
1476 while($row = $this->db->db_fetch_object($result))
1477 $tags[$row['id']] = $row['name'];
1481 } // get_photo_tags()
1484 * create on-the-fly images with text within
1486 public function showTextImage($txt, $color=000000, $space=4, $font=4, $w=300)
1488 if (strlen($color) != 6)
1491 $int = hexdec($color);
1492 $h = imagefontheight($font);
1493 $fw = imagefontwidth($font);
1494 $txt = explode("\n", wordwrap($txt, ($w / $fw), "\n"));
1495 $lines = count($txt);
1496 $im = imagecreate($w, (($h * $lines) + ($lines * $space)));
1497 $bg = imagecolorallocate($im, 255, 255, 255);
1498 $color = imagecolorallocate($im, 0xFF & ($int >> 0x10), 0xFF & ($int >> 0x8), 0xFF & $int);
1501 foreach ($txt as $text) {
1502 $x = (($w - ($fw * strlen($text))) / 2);
1503 imagestring($im, $font, $x, $y, $text, $color);
1504 $y += ($h + $space);
1507 Header("Content-type: image/png");
1510 } // showTextImage()
1513 * check if all requirements are met
1515 private function checkRequirements()
1517 if(!function_exists("imagecreatefromjpeg")) {
1518 print "PHP GD library extension is missing<br />\n";
1522 if($this->cfg->db_access == "native" && !function_exists("sqlite3_open")) {
1523 print "PHP SQLite3 library extension is missing<br />\n";
1527 /* Check for HTML_AJAX PEAR package, lent from Horde project */
1528 ini_set('track_errors', 1);
1529 @include_once 'HTML/AJAX/Server.php';
1530 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
1531 print "PEAR HTML_AJAX package is missing<br />\n";
1534 @include_once 'Calendar/Calendar.php';
1535 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
1536 print "PEAR Calendar package is missing<br />\n";
1539 ini_restore('track_errors');
1546 } // checkRequirements()
1548 private function _debug($text)
1550 if($this->fromcmd) {
1557 * check if specified MIME type is supported
1559 public function checkifImageSupported($mime)
1561 if(in_array($mime, Array("image/jpeg")))
1566 } // checkifImageSupported()
1568 public function _error($text)
1570 switch($this->cfg->logging) {
1572 print "<img src=\"resources/green_info.png\" alt=\"warning\" />\n";
1579 error_log($text, 3, $his->cfg->log_file);
1586 * output calendard input fields
1588 private function get_calendar($mode)
1590 $year = $_SESSION[$mode .'_date'] ? date("Y", $_SESSION[$mode .'_date']) : date("Y");
1591 $month = $_SESSION[$mode .'_date'] ? date("m", $_SESSION[$mode .'_date']) : date("m");
1592 $day = $_SESSION[$mode .'_date'] ? date("d", $_SESSION[$mode .'_date']) : date("d");
1594 $output = "<input type=\"text\" size=\"3\" id=\"". $mode ."year\" value=\"". $year ."\"";
1595 if(!isset($_SESSION[$mode .'_date'])) $output.= " disabled=\"disabled\"";
1597 $output.= "<input type=\"text\" size=\"1\" id=\"". $mode ."month\" value=\"". $month ."\"";
1598 if(!isset($_SESSION[$mode .'_date'])) $output.= " disabled=\"disabled\"";
1600 $output.= "<input type=\"text\" size=\"1\" id=\"". $mode ."day\" value=\"". $day ."\"";
1601 if(!isset($_SESSION[$mode .'_date'])) $output.= " disabled=\"disabled\"";
1608 * output calendar matrix
1610 public function get_calendar_matrix($year = 0, $month = 0, $day = 0)
1612 if (!isset($year)) $year = date('Y');
1613 if (!isset($month)) $month = date('m');
1614 if (!isset($day)) $day = date('d');
1619 require_once CALENDAR_ROOT.'Month/Weekdays.php';
1620 require_once CALENDAR_ROOT.'Day.php';
1623 $month = new Calendar_Month_Weekdays($year,$month);
1626 $prevStamp = $month->prevMonth(true);
1627 $prev = "javascript:setMonth(". date('Y',$prevStamp) .", ". date('n',$prevStamp) .", ". date('j',$prevStamp) .");";
1628 $nextStamp = $month->nextMonth(true);
1629 $next = "javascript:setMonth(". date('Y',$nextStamp) .", ". date('n',$nextStamp) .", ". date('j',$nextStamp) .");";
1631 $selectedDays = array (
1632 new Calendar_Day($year,$month,$day),
1633 new Calendar_Day($year,12,25),
1636 // Build the days in the month
1637 $month->build($selectedDays);
1639 $this->tmpl->assign('current_month', date('F Y',$month->getTimeStamp()));
1640 $this->tmpl->assign('prev_month', $prev);
1641 $this->tmpl->assign('next_month', $next);
1643 while ( $day = $month->fetch() ) {
1645 if(!isset($matrix[$rows]))
1646 $matrix[$rows] = Array();
1650 $dayStamp = $day->thisDay(true);
1651 $link = "javascript:setCalendarDate(". date('Y',$dayStamp) .", ". date('n',$dayStamp).", ". date('j',$dayStamp) .");";
1653 // isFirst() to find start of week
1654 if ( $day->isFirst() )
1657 if ( $day->isSelected() ) {
1658 $string.= "<td class=\"selected\">".$day->thisDay()."</td>\n";
1659 } else if ( $day->isEmpty() ) {
1660 $string.= "<td> </td>\n";
1662 $string.= "<td><a class=\"calendar\" href=\"".$link."\">".$day->thisDay()."</a></td>\n";
1665 // isLast() to find end of week
1666 if ( $day->isLast() )
1667 $string.= "</tr>\n";
1669 $matrix[$rows][$cols] = $string;
1679 $this->tmpl->assign('matrix', $matrix);
1680 $this->tmpl->assign('rows', $rows);
1681 $this->tmpl->show("calendar.tpl");
1683 } // get_calendar_matrix()
1686 * output export page
1688 public function getExport($mode)
1690 $pictures = $this->getPhotoSelection();
1691 $current_tags = $this->getCurrentTags();
1693 foreach($pictures as $picture) {
1695 $orig_url = $this->get_phpfspot_url() ."index.php?mode=showp&id=". $picture;
1696 if($current_tags != "") {
1697 $orig_url.= "&tags=". $current_tags;
1699 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1700 $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
1703 $thumb_url = $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
1708 // <a href="%pictureurl%"><img src="%thumbnailurl%" ></a>
1709 print htmlspecialchars("<a href=\"". $orig_url ."\"><img src=\"". $thumb_url ."\" /></a>") ."<br />\n";
1713 // "[%pictureurl% %thumbnailurl%]"
1714 print htmlspecialchars("[".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
1717 case 'MoinMoinList':
1718 // " * [%pictureurl% %thumbnailurl%]"
1719 print " " . htmlspecialchars("* [".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
1730 public function getRSSFeed()
1732 Header("Content-type: text/xml; charset=utf-8");
1733 print "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
1736 xmlns:media="http://search.yahoo.com/mrss/"
1737 xmlns:dc="http://purl.org/dc/elements/1.1/"
1740 <title>phpfspot</title>
1741 <description>phpfspot RSS feed</description>
1742 <link><?php print htmlspecialchars($this->get_phpfspot_url()); ?></link>
1743 <pubDate><?php print strftime("%a, %d %b %Y %T %z"); ?></pubDate>
1744 <generator>phpfspot</generator>
1747 $pictures = $this->getPhotoSelection();
1748 $current_tags = $this->getCurrentTags();
1750 foreach($pictures as $picture) {
1752 $orig_url = $this->get_phpfspot_url() ."index.php?mode=showp&id=". $picture;
1753 if($current_tags != "") {
1754 $orig_url.= "&tags=". $current_tags;
1756 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1757 $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
1760 $details = $this->get_photo_details($picture);
1762 $thumb_url = $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
1763 $thumb_html = htmlspecialchars("
1764 <a href=\"". $orig_url ."\"><img src=\"". $thumb_url ."\" /></a>
1766 ". $details['description']);
1768 $orig_path = $this->translate_path($details['directory_path']) ."/". $details['name'];
1769 $meta = $this->get_meta_informations($orig_path);
1770 $meta_date = isset($meta['FileDateTime']) ? $meta['FileDateTime'] : filemtime($orig_path);
1774 <title><?php print htmlspecialchars($details['name']); ?></title>
1775 <link><?php print htmlspecialchars($orig_url); ?></link>
1776 <guid><?php print htmlspecialchars($orig_url); ?></guid>
1777 <dc:date.Taken><?php print strftime("%Y-%m-%dT%H:%M:%S+00:00", $meta_date); ?></dc:date.Taken>
1779 <?php print $thumb_html; ?>
1781 <pubDate><?php print strftime("%a, %d %b %Y %T %z", $meta_date); ?></pubDate>
1796 * return all selected tags as one string
1798 private function getCurrentTags()
1801 if($_SESSION['selected_tags'] != "") {
1802 foreach($_SESSION['selected_tags'] as $tag)
1803 $current_tags.= $tag .",";
1804 $current_tags = substr($current_tags, 0, strlen($current_tags)-1);
1806 return $current_tags;
1808 } // getCurrentTags()
1811 * return the current photo
1813 public function getCurrentPhoto()
1815 if(isset($_SESSION['current_photo'])) {
1816 print $_SESSION['current_photo'];
1818 } // getCurrentPhoto()
1821 * tells the client browser what to do
1823 * this function is getting called via AJAX by the
1824 * client browsers. it will tell them what they have
1825 * to do next. This is necessary for directly jumping
1826 * into photo index or single photo view when the are
1827 * requested with specific URLs
1829 public function whatToDo()
1831 if(isset($_SESSION['current_photo']) && $_SESSION['start_action'] == 'showp') {
1832 return "show_photo";
1834 elseif(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
1835 return "showpi_tags";
1837 elseif(isset($_SESSION['start_action']) && $_SESSION['start_action'] == 'showpi') {
1841 return "nothing special";
1846 * return the current process-user
1848 private function getuid()
1850 if($uid = posix_getuid()) {
1851 if($user = posix_getpwuid($uid)) {
1852 return $user['name'];
1861 * returns a select-dropdown box to select photo index sort parameters
1863 private function get_sort_field()
1865 $output = "<select name=\"sort_order\">";
1866 foreach(array('date_asc', 'date_desc', 'name_asc', 'name_desc') as $sort_order) {
1867 $output.= "<option value=\"". $sort_order ."\"";
1868 if($sort_order == $_SESSION['sort_order']) {
1869 $output.= " selected=\"selected\"";
1871 $output.= ">". $sort_order ."</option>";
1873 $output.= "</select>";
1876 } // get_sort_field()
1879 * returns the currently selected sort order
1881 private function get_sort_order()
1883 switch($_SESSION['sort_order']) {
1885 return " ORDER BY p.time ASC";
1888 return " ORDER BY p.time DESC";
1891 return " ORDER BY p.name ASC";
1894 return " ORDER BY p.name DESC";
1898 } // get_sort_order()
1901 * return the next to be shown slide show image
1903 * this function returns the URL of the next image
1904 * in the slideshow sequence.
1906 public function getNextSlideShowImage()
1908 $all_photos = $this->getPhotoSelection();
1910 if(!isset($_SESSION['slideshow_img']) || $_SESSION['slideshow_img'] == count($all_photos)-1)
1911 $_SESSION['slideshow_img'] = 0;
1913 $_SESSION['slideshow_img']++;
1915 return $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $all_photos[$_SESSION['slideshow_img']] ."&width=". $this->cfg->photo_width;
1917 } // getNextSlideShowImage()
1920 * return the previous to be shown slide show image
1922 * this function returns the URL of the previous image
1923 * in the slideshow sequence.
1925 public function getPrevSlideShowImage()
1927 $all_photos = $this->getPhotoSelection();
1929 if(!isset($_SESSION['slideshow_img']) || $_SESSION['slideshow_img'] == 0)
1930 $_SESSION['slideshow_img'] = 0;
1932 $_SESSION['slideshow_img']--;
1934 return $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $all_photos[$_SESSION['slideshow_img']] ."&width=". $this->cfg->photo_width;
1936 } // getPrevSlideShowImage()
1938 public function resetSlideShow()
1940 if(isset($_SESSION['slideshow_img']))
1941 unset($_SESSION['slideshow_img']);
1942 } // resetSlideShow()
1947 * this function will get all photos from the fspot
1948 * database and randomly return ONE entry
1950 * saddly there is yet no sqlite3 function which returns
1951 * the bulk result in array, so we have to fill up our
1954 public function get_random_photo()
1958 $result = $this->db->db_query("
1963 while($row = $this->db->db_fetch_object($result)) {
1964 array_push($all, $row['id']);
1967 return $all[array_rand($all)];
1969 } // get_random_photo()
1972 * validates provided date
1974 * this function validates if the provided date
1975 * contains a valid date and will return true
1978 public function isValidDate($date_str)
1980 $timestamp = strtotime($date_str);
1982 if(is_numeric($timestamp))
1990 * timestamp to string conversion
1992 private function ts2str($timestamp)
1994 return strftime("%Y-%m-%d", $timestamp);
1997 private function extractTags($tags_str)
1999 $not_validated = split(',', $_GET['tags']);
2000 $validated = array();
2002 foreach($not_validated as $tag) {
2003 if(is_numeric($tag))
2004 array_push($validated, $tag);
2012 * returns the full path to a thumbnail
2014 public function get_thumb_path($width, $photo)
2016 $md5 = $this->getMD5($photo);
2017 $sub_path = substr($md5, 0, 2);
2018 return $this->cfg->thumb_path
2026 } // get_thumb_path()
2029 * returns server's virtual host name
2031 private function get_server_name()
2033 return $_SERVER['SERVER_NAME'];
2034 } // get_server_name()
2037 * returns type of webprotocol which is
2040 private function get_web_protocol()
2042 if(!isset($_SERVER['HTTPS']))
2046 } // get_web_protocol()
2049 * return url to this phpfspot installation
2051 private function get_phpfspot_url()
2053 return $this->get_web_protocol() ."://". $this->get_server_name() . $this->cfg->web_path;
2054 } // get_phpfspot_url()
2057 * check file exists and is readable
2059 * returns true, if everything is ok, otherwise false
2060 * if $silent is not set, this function will output and
2063 private function check_readable($file, $silent = null)
2065 if(!file_exists($file)) {
2067 print "File \"". $file ."\" does not exist.\n";
2071 if(!is_readable($file)) {
2073 print "File \"". $file ."\" is not reachable for user ". $this->getuid() ."\n";
2079 } // check_readable()
2082 * check if all needed indices are present
2084 * this function checks, if some needed indices are already
2085 * present, or if not, create them on the fly. they are
2086 * necessary to speed up some queries like that one look for
2087 * all tags, when show_tags is specified in the configuration.
2089 private function checkDbIndices()
2091 $result = $this->db->db_exec("
2092 CREATE INDEX IF NOT EXISTS
2099 } // checkDbIndices()