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);
83 if(!isset($_SESSION['tag_condition']))
84 $_SESSION['tag_condition'] = 'or';
86 if(!isset($_SESSION['sort_order']))
87 $_SESSION['sort_order'] = 'date_asc';
89 if(!isset($_SESSION['searchfor']))
90 $_SESSION['searchfor'] = '';
92 // if begin_with is still set but rows_per_page is now 0, unset it
93 if(isset($_SESSION['begin_with']) && $this->cfg->rows_per_page == 0)
94 unset($_SESSION['begin_with']);
98 public function __destruct()
104 * show - generate html output
106 * this function can be called after the constructor has
107 * prepared everyhing. it will load the index.tpl smarty
108 * template. if necessary it will registere pre-selects
109 * (photo index, photo, tag search, date search) into
112 public function show()
114 $this->tmpl->assign('searchfor', $_SESSION['searchfor']);
115 $this->tmpl->assign('page_title', $this->cfg->page_title);
116 $this->tmpl->assign('current_condition', $_SESSION['tag_condition']);
117 $this->tmpl->assign('template_path', 'themes/'. $this->cfg->theme_name);
119 $_SESSION['start_action'] = $_GET['mode'];
121 switch($_GET['mode']) {
123 if(isset($_GET['tags'])) {
124 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
126 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
127 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
129 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
130 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
134 if(isset($_GET['tags'])) {
135 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
136 $_SESSION['start_action'] = 'showp';
138 if(isset($_GET['id']) && is_numeric($_GET['id'])) {
139 $_SESSION['current_photo'] = $_GET['id'];
140 $_SESSION['start_action'] = 'showp';
142 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
143 $_SESSION['from_date'] = strtotime($_GET['from_date']);
145 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
146 $_SESSION['to_date'] = strtotime($_GET['to_date']);
150 $this->tmpl->show("export.tpl");
154 $this->tmpl->show("slideshow.tpl");
158 if(isset($_GET['tags'])) {
159 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
161 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
162 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
164 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
165 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
172 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date']))
173 $this->tmpl->assign('date_search_enabled', true);
175 $this->tmpl->assign('from_date', $this->get_calendar('from'));
176 $this->tmpl->assign('to_date', $this->get_calendar('to'));
177 $this->tmpl->assign('sort_field', $this->get_sort_field());
178 $this->tmpl->assign('content_page', 'welcome.tpl');
179 $this->tmpl->show("index.tpl");
184 * get_tags - grab all tags of f-spot's database
186 * this function will get all available tags from
187 * the f-spot database and store them within two
188 * arrays within this class for later usage. in
189 * fact, if the user requests (hide_tags) it will
190 * opt-out some of them.
192 * this function is getting called once by show()
194 private function get_tags()
196 $this->avail_tags = Array();
199 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
202 DISTINCT t1.id,t1.name
205 INNER JOIN photo_tags
206 pt2 ON pt1.photo_id=pt2.photo_id
213 ".implode("','",$this->cfg->show_tags)."
216 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()
478 $result = $this->db->db_query("
479 SELECT tag_id as id, count(tag_id) as quantity
489 while($row = $this->db->db_fetch_object($result)) {
490 $tags[$row['id']] = $row['quantity'];
493 // change these font sizes if you will
494 $max_size = 125; // max font size in %
495 $min_size = 75; // min font size in %
497 // get the largest and smallest array values
498 $max_qty = max(array_values($tags));
499 $min_qty = min(array_values($tags));
501 // find the range of values
502 $spread = $max_qty - $min_qty;
503 if (0 == $spread) { // we don't want to divide by zero
507 // determine the font-size increment
508 // this is the increase per tag quantity (times used)
509 $step = ($max_size - $min_size)/($spread);
511 // loop through our tag array
512 foreach ($tags as $key => $value) {
514 if(isset($_SESSION['selected_tags']) && in_array($key, $_SESSION['selected_tags']))
517 // calculate CSS font-size
518 // find the $value in excess of $min_qty
519 // multiply by the font-size increment ($size)
520 // and add the $min_size set above
521 $size = $min_size + (($value - $min_qty) * $step);
522 // uncomment if you want sizes in whole %:
525 if(isset($this->tags[$key])) {
526 $output.= "<a href=\"javascript:Tags('add', ". $key .");\" class=\"tag\" style=\"font-size: ". $size ."%;\">". $this->tags[$key] ."</a>, ";
531 $output = substr($output, 0, strlen($output)-2);
534 } // getAvailableTags()
537 * output all selected tags
539 * this function output all tags which have been selected
540 * by the user. the selected tags are stored in the
541 * session-variable $_SESSION['selected_tags']
543 public function getSelectedTags()
546 foreach($this->avail_tags as $tag)
548 // return all selected tags
549 if(isset($_SESSION['selected_tags']) && in_array($tag, $_SESSION['selected_tags'])) {
550 $output.= "<a href=\"javascript:Tags('del', ". $tag .");\" class=\"tag\">". $this->tags[$tag] ."</a>, ";
554 $output = substr($output, 0, strlen($output)-2);
557 } // getSelectedTags()
560 * add tag to users session variable
562 * this function will add the specified to users current
563 * tag selection. if a date search has been made before
564 * it will be now cleared
566 public function addTag($tag)
568 if(!isset($_SESSION['selected_tags']))
569 $_SESSION['selected_tags'] = Array();
571 if(!in_array($tag, $_SESSION['selected_tags']))
572 array_push($_SESSION['selected_tags'], $tag);
577 * remove tag to users session variable
579 * this function removes the specified tag from
580 * users current tag selection
582 public function delTag($tag)
584 if(isset($_SESSION['selected_tags'])) {
585 $key = array_search($tag, $_SESSION['selected_tags']);
586 unset($_SESSION['selected_tags'][$key]);
587 sort($_SESSION['selected_tags']);
593 * reset tag selection
595 * if there is any tag selection, it will be
598 public function resetTags()
600 if(isset($_SESSION['selected_tags']))
601 unset($_SESSION['selected_tags']);
608 * if a specific photo was requested (external link)
609 * unset the session variable now
611 public function resetPhotoView()
613 if(isset($_SESSION['current_photo']))
614 unset($_SESSION['current_photo']);
616 } // resetPhotoView();
621 * if any tag search has taken place, reset
624 public function resetTagSearch()
626 if(isset($_SESSION['searchfor']))
627 unset($_SESSION['searchfor']);
629 } // resetTagSearch()
634 * if any date search has taken place, reset
637 public function resetDateSearch()
639 if(isset($_SESSION['from_date']))
640 unset($_SESSION['from_date']);
641 if(isset($_SESSION['to_date']))
642 unset($_SESSION['to_date']);
644 } // resetDateSearch();
647 * return all photo according selection
649 * this function returns all photos based on
650 * the tag-selection, tag- or date-search.
651 * the tag-search also has to take care of AND
652 * and OR conjunctions
654 public function getPhotoSelection()
656 $matched_photos = Array();
658 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
659 $from_date = $_SESSION['from_date'];
660 $to_date = $_SESSION['to_date'];
661 $additional_where_cond = "
662 p.time>='". $from_date ."'
664 p.time<='". $to_date ."'
668 if(isset($_SESSION['sort_order'])) {
669 $order_str = $this->get_sort_order();
672 /* return a search result */
673 if(isset($_SESSION['searchfor']) && $_SESSION['searchfor'] != '') {
675 SELECT DISTINCT photo_id
681 WHERE t.name LIKE '%". $_SESSION['searchfor'] ."%'";
683 if(isset($additional_where_cond))
684 $query_str.= "AND ". $additional_where_cond ." ";
686 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
687 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags)."')";
690 if(isset($order_str))
691 $query_str.= $order_str;
693 $result = $this->db->db_query($query_str);
694 while($row = $this->db->db_fetch_object($result)) {
695 array_push($matched_photos, $row['photo_id']);
697 return $matched_photos;
700 /* return according the selected tags */
701 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
703 foreach($_SESSION['selected_tags'] as $tag)
704 $selected.= $tag .",";
705 $selected = substr($selected, 0, strlen($selected)-1);
707 if($_SESSION['tag_condition'] == 'or') {
709 SELECT DISTINCT pt.photo_id
715 WHERE pt.tag_id IN (". $selected .")
717 if(isset($additional_where_cond))
718 $query_str.= "AND ". $additional_where_cond ." ";
720 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
721 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags)."')";
724 if(isset($order_str))
725 $query_str.= $order_str;
727 elseif($_SESSION['tag_condition'] == 'and') {
729 if(count($_SESSION['selected_tags']) >= 32) {
730 print "A SQLite limit of 32 tables within a JOIN SELECT avoids to<br />\n";
731 print "evaluate your tag selection. Please remove some tags from your selection.\n";
735 /* Join together a table looking like
737 pt1.photo_id pt1.tag_id pt2.photo_id pt2.tag_id ...
739 so the query can quickly return all images matching the
740 selected tags in an AND condition
745 SELECT DISTINCT pt1.photo_id
749 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
756 for($i = 0; $i < count($_SESSION['selected_tags']); $i++) {
758 INNER JOIN photo_tags pt". ($i+2) ."
759 ON pt1.photo_id=pt". ($i+2) .".photo_id
766 $query_str.= "WHERE pt2.tag_id=". $_SESSION['selected_tags'][0]." ";
767 for($i = 1; $i < count($_SESSION['selected_tags']); $i++) {
769 AND pt". ($i+2) .".tag_id=". $_SESSION['selected_tags'][$i] ."
772 if(isset($additional_where_cond))
773 $query_str.= "AND ". $additional_where_cond;
775 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
776 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags). "')";
779 if(isset($order_str))
780 $query_str.= $order_str;
784 $result = $this->db->db_query($query_str);
785 while($row = $this->db->db_fetch_object($result)) {
786 array_push($matched_photos, $row['photo_id']);
788 return $matched_photos;
791 /* return all available photos */
793 SELECT DISTINCT photo_id
800 if(isset($additional_where_cond))
801 $query_str.= "WHERE ". $additional_where_cond ." ";
803 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
804 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags). "')";
807 if(isset($order_str))
808 $query_str.= $order_str;
810 $result = $this->db->db_query($query_str);
811 while($row = $this->db->db_fetch_object($result)) {
812 array_push($matched_photos, $row['photo_id']);
814 return $matched_photos;
816 } // getPhotoSelection()
819 * control HTML ouput for photo index
821 * this function provides all the necessary information
822 * for the photo index template.
824 public function showPhotoIndex()
826 $photos = $this->getPhotoSelection();
828 $count = count($photos);
830 if(isset($_SESSION['begin_with']) && $_SESSION['begin_with'] != "")
831 $anchor = $_SESSION['begin_with'];
833 if(!isset($this->cfg->rows_per_page) || $this->cfg->rows_per_page == 0) {
839 elseif($this->cfg->rows_per_page > 0) {
841 if(!$_SESSION['begin_with'] || $_SESSION['begin_with'] == 0)
845 $begin_with = $_SESSION['begin_with'];
847 // verify $begin_with - perhaps the thumbs-per-rows or
848 // rows-per-page variables have changed or the jump back
849 // from a photo wasn't exact - so calculate the real new
851 $multiplicator = $this->cfg->rows_per_page * $this->cfg->thumbs_per_row;
852 for($i = 0; $i <= $count; $i+=$multiplicator) {
853 if($begin_with >= $i && $begin_with < $i+$multiplicator) {
860 $end_with = $begin_with + ($this->cfg->rows_per_page * $this->cfg->thumbs_per_row);
866 $images[$rows] = Array();
867 $img_height[$rows] = Array();
868 $img_width[$rows] = Array();
869 $img_id[$rows] = Array();
870 $img_name[$rows] = Array();
871 $img_title = Array();
873 for($i = $begin_with; $i < $end_with; $i++) {
875 $images[$rows][$cols] = $photos[$i];
876 $img_id[$rows][$cols] = $i;
877 $img_name[$rows][$cols] = htmlspecialchars($this->getPhotoName($photos[$i], 15));
878 $img_title[$rows][$cols] = "Click to view photo ". htmlspecialchars($this->getPhotoName($photos[$i], 0));
880 $thumb_path = $this->get_thumb_path($this->cfg->thumb_width, $photos[$i]);
882 if(file_exists($thumb_path)) {
883 $info = getimagesize($thumb_path);
884 $img_width[$rows][$cols] = $info[0];
885 $img_height[$rows][$cols] = $info[1];
888 if($cols == $this->cfg->thumbs_per_row-1) {
891 $images[$rows] = Array();
892 $img_width[$rows] = Array();
893 $img_height[$rows] = Array();
900 // +1 for for smarty's selection iteration
903 if(isset($_SESSION['searchfor']) && $_SESSION['searchfor'] != '')
904 $this->tmpl->assign('searchfor', $_SESSION['searchfor']);
906 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
907 $this->tmpl->assign('from_date', $this->ts2str($_SESSION['from_date']));
908 $this->tmpl->assign('to_date', $this->ts2str($_SESSION['to_date']));
911 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
912 $this->tmpl->assign('tag_result', 1);
915 /* do we have to display the page selector ? */
916 if($this->cfg->rows_per_page != 0) {
918 /* calculate the page switchers */
919 $previous_start = $begin_with - ($this->cfg->rows_per_page * $this->cfg->thumbs_per_row);
920 $next_start = $begin_with + ($this->cfg->rows_per_page * $this->cfg->thumbs_per_row);
923 $this->tmpl->assign("previous_url", "javascript:showPhotoIndex(". $previous_start .");");
924 if($end_with < $count)
925 $this->tmpl->assign("next_url", "javascript:showPhotoIndex(". $next_start .");");
927 $photo_per_page = $this->cfg->rows_per_page * $this->cfg->thumbs_per_row;
928 $last_page = ceil($count / $photo_per_page);
930 /* get the current selected page */
931 if($begin_with == 0) {
935 for($i = $begin_with; $i >= 0; $i-=$photo_per_page) {
942 for($i = 1; $i <= $last_page; $i++) {
944 if($current_page == $i)
945 $style = "style=\"font-size: 125%; text-decoration: underline;\"";
946 elseif($current_page-1 == $i || $current_page+1 == $i)
947 $style = "style=\"font-size: 105%;\"";
948 elseif(($current_page-5 >= $i) && ($i != 1) ||
949 ($current_page+5 <= $i) && ($i != $last_page))
950 $style = "style=\"font-size: 75%;\"";
954 $select = "<a href=\"javascript:showPhotoIndex(". (($i*$photo_per_page)-$photo_per_page) .");\"";
957 $select.= ">". $i ."</a> ";
959 // until 9 pages we show the selector from 1-9
960 if($last_page <= 9) {
961 $page_select.= $select;
964 if($i == 1 /* first page */ ||
965 $i == $last_page /* last page */ ||
966 $i == $current_page /* current page */ ||
967 $i == ceil($last_page * 0.25) /* first quater */ ||
968 $i == ceil($last_page * 0.5) /* half */ ||
969 $i == ceil($last_page * 0.75) /* third quater */ ||
970 (in_array($i, array(1,2,3,4,5,6)) && $current_page <= 4) /* the first 6 */ ||
971 (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 */ ||
972 $i == $current_page-3 || $i == $current_page-2 || $i == $current_page-1 /* three before */ ||
973 $i == $current_page+3 || $i == $current_page+2 || $i == $current_page+1 /* three after */) {
975 $page_select.= $select;
983 $page_select.= "......... ";
988 /* only show the page selector if we have more then one page */
990 $this->tmpl->assign('page_selector', $page_select);
994 $current_tags = $this->getCurrentTags();
995 $extern_link = "index.php?mode=showpi";
996 $rss_link = "index.php?mode=rss";
997 if($current_tags != "") {
998 $extern_link.= "&tags=". $current_tags;
999 $rss_link.= "&tags=". $current_tags;
1001 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1002 $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
1003 $rss_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
1006 $export_link = "index.php?mode=export";
1007 $slideshow_link = "index.php?mode=slideshow";
1009 $this->tmpl->assign('extern_link', $extern_link);
1010 $this->tmpl->assign('slideshow_link', $slideshow_link);
1011 $this->tmpl->assign('export_link', $export_link);
1012 $this->tmpl->assign('rss_link', $rss_link);
1013 $this->tmpl->assign('count', $count);
1014 $this->tmpl->assign('width', $this->cfg->thumb_width);
1015 $this->tmpl->assign('images', $images);
1016 $this->tmpl->assign('img_width', $img_width);
1017 $this->tmpl->assign('img_height', $img_height);
1018 $this->tmpl->assign('img_id', $img_id);
1019 $this->tmpl->assign('img_name', $img_name);
1020 $this->tmpl->assign('img_title', $img_title);
1021 $this->tmpl->assign('rows', $rows);
1022 $this->tmpl->assign('columns', $this->cfg->thumbs_per_row);
1024 $this->tmpl->show("photo_index.tpl");
1027 print "<script language=\"JavaScript\">self.location.hash = '#image". $anchor ."';</script>\n";
1029 } // showPhotoIndex()
1032 * show credit template
1034 public function showCredits()
1036 $this->tmpl->assign('version', $this->cfg->version);
1037 $this->tmpl->assign('product', $this->cfg->product);
1038 $this->tmpl->show("credits.tpl");
1043 * create_thumbnails for the requested width
1045 * this function creates image thumbnails of $orig_image
1046 * stored as $thumb_image. It will check if the image is
1047 * in a supported format, if necessary rotate the image
1048 * (based on EXIF orientation meta headers) and re-sizing.
1050 public function create_thumbnail($orig_image, $thumb_image, $width)
1052 if(!file_exists($orig_image)) {
1056 $details = getimagesize($orig_image);
1058 /* check if original photo is a support image type */
1059 if(!$this->checkifImageSupported($details['mime']))
1062 $meta = $this->get_meta_informations($orig_image);
1067 switch($meta['Orientation']) {
1069 case 1: /* top, left */
1070 $rotate = 0; $flip = false; break;
1071 case 2: /* top, right */
1072 $rotate = 0; $flip = true; break;
1073 case 3: /* bottom, left */
1074 $rotate = 180; $flip = false; break;
1075 case 4: /* bottom, right */
1076 $rotate = 180; $flip = true; break;
1077 case 5: /* left side, top */
1078 $rotate = 90; $flip = true; break;
1079 case 6: /* right side, top */
1080 $rotate = 90; $flip = false; break;
1081 case 7: /* left side, bottom */
1082 $rotate = 270; $flip = true; break;
1083 case 8: /* right side, bottom */
1084 $rotate = 270; $flip = false; break;
1087 $src_img = @imagecreatefromjpeg($orig_image);
1090 print "Can't load image from ". $orig_image ."\n";
1094 /* grabs the height and width */
1095 $cur_width = imagesx($src_img);
1096 $cur_height = imagesy($src_img);
1098 // If requested width is more then the actual image width,
1099 // do not generate a thumbnail, instead safe the original
1100 // as thumbnail but with lower quality
1102 if($width >= $cur_width) {
1103 $result = imagejpeg($src_img, $thumb_image, 75);
1104 imagedestroy($src_img);
1108 // If the image will be rotate because EXIF orientation said so
1109 // 'virtually rotate' the image for further calculations
1110 if($rotate == 90 || $rotate == 270) {
1112 $cur_width = $cur_height;
1116 /* calculates aspect ratio */
1117 $aspect_ratio = $cur_height / $cur_width;
1120 if($aspect_ratio < 1) {
1122 $new_h = abs($new_w * $aspect_ratio);
1124 /* 'virtually' rotate the image and calculate it's ratio */
1125 $tmp_w = $cur_height;
1126 $tmp_h = $cur_width;
1127 /* now get the ratio from the 'rotated' image */
1128 $tmp_ratio = $tmp_h/$tmp_w;
1129 /* now calculate the new dimensions */
1131 $tmp_h = abs($tmp_w * $tmp_ratio);
1133 // now that we know, how high they photo should be, if it
1134 // gets rotated, use this high to scale the image
1136 $new_w = abs($new_h / $aspect_ratio);
1138 // If the image will be rotate because EXIF orientation said so
1139 // now 'virtually rotate' back the image for the image manipulation
1140 if($rotate == 90 || $rotate == 270) {
1147 /* creates new image of that size */
1148 $dst_img = imagecreatetruecolor($new_w, $new_h);
1150 imagefill($dst_img, 0, 0, ImageColorAllocate($dst_img, 255, 255, 255));
1152 /* copies resized portion of original image into new image */
1153 imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $new_w, $new_h, imagesx($src_img), imagesy($src_img));
1155 /* needs the image to be flipped horizontal? */
1159 for($x = 0; $x < $new_w; $x++) {
1160 imagecopy($dst_img, $image, $x, 0, $w - $x - 1, 0, 1, $h);
1165 $this->_debug("(ROTATE)");
1166 $dst_img = $this->rotateImage($dst_img, $rotate);
1169 /* write down new generated file */
1170 $result = imagejpeg($dst_img, $thumb_image, 75);
1172 /* free your mind */
1173 imagedestroy($dst_img);
1174 imagedestroy($src_img);
1176 if($result === false) {
1177 print "Can't write thumbnail ". $thumb_image ."\n";
1183 } // create_thumbnail()
1186 * return all exif meta data from the file
1188 public function get_meta_informations($file)
1190 return exif_read_data($file);
1192 } // get_meta_informations()
1195 * create phpfspot own sqlite database
1197 * this function creates phpfspots own sqlite database
1198 * if it does not exist yet. this own is used to store
1199 * some necessary informations (md5 sum's, ...).
1201 public function check_config_table()
1203 // if the config table doesn't exist yet, create it
1204 if(!$this->cfg_db->db_check_table_exists("images")) {
1205 $this->cfg_db->db_exec("
1206 CREATE TABLE images (
1207 img_idx int primary key,
1213 } // check_config_table
1216 * Generates a thumbnail from photo idx
1218 * This function will generate JPEG thumbnails from provided F-Spot photo
1221 * 1. Check if all thumbnail generations (width) are already in place and
1223 * 2. Check if the md5sum of the original file has changed
1224 * 3. Generate the thumbnails if needed
1226 public function gen_thumb($idx = 0, $force = 0)
1230 $resolutions = Array(
1231 $this->cfg->thumb_width,
1232 $this->cfg->photo_width,
1233 $this->cfg->mini_width,
1236 /* get details from F-Spot's database */
1237 $details = $this->get_photo_details($idx);
1239 /* calculate file MD5 sum */
1240 $full_path = $this->translate_path($details['directory_path']) ."/". $details['name'];
1242 if(!file_exists($full_path)) {
1243 $this->_error("File ". $full_path ." does not exist\n");
1247 if(!is_readable($full_path)) {
1248 $this->_error("File ". $full_path ." is not readable for ". $this->getuid() ."\n");
1252 $file_md5 = md5_file($full_path);
1254 $this->_debug("Image [". $idx ."] ". $this->shrink_text($details['name'], 20) ." Thumbnails:");
1256 foreach($resolutions as $resolution) {
1258 $thumb_sub_path = substr($file_md5, 0, 2);
1259 $thumb_path = $this->cfg->thumb_path ."/". $thumb_sub_path ."/". $resolution ."_". $file_md5;
1261 if(!file_exists(dirname($thumb_path))) {
1262 mkdir(dirname($thumb_path), 0755);
1265 /* if the thumbnail file doesn't exist, create it */
1266 if(!file_exists($thumb_path)) {
1268 $this->_debug(" ". $resolution ."px");
1269 if(!$this->create_thumbnail($full_path, $thumb_path, $resolution))
1272 /* if the file hasn't changed there is no need to regen the thumb */
1273 elseif($file_md5 != $this->getMD5($idx) || $force) {
1275 $this->_debug(" ". $resolution ."px");
1276 if(!$this->create_thumbnail($full_path, $thumb_path, $resolution))
1282 /* set the new/changed MD5 sum for the current photo */
1284 $this->setMD5($idx, $file_md5);
1287 $this->_debug("\n");
1292 * returns stored md5 sum for a specific photo
1294 * this function queries the phpfspot database for a
1295 * stored MD5 checksum of the specified photo
1297 public function getMD5($idx)
1299 $result = $this->cfg_db->db_query("
1302 WHERE img_idx='". $idx ."'
1308 $img = $this->cfg_db->db_fetch_object($result);
1309 return $img['img_md5'];
1314 * set MD5 sum for the specific photo
1316 private function setMD5($idx, $md5)
1318 $result = $this->cfg_db->db_exec("
1319 REPLACE INTO images (img_idx, img_md5)
1320 VALUES ('". $idx ."', '". $md5 ."')
1326 * store current tag condition
1328 * this function stores the current tag condition
1329 * (AND or OR) in the users session variables
1331 public function setTagCondition($mode)
1333 $_SESSION['tag_condition'] = $mode;
1335 } // setTagCondition()
1338 * invoke tag & date search
1340 * this function will return all matching tags and store
1341 * them in the session variable selected_tags. furthermore
1342 * it also handles the date search.
1343 * getPhotoSelection() will then only return the matching
1346 public function startSearch($searchfor, $sort_order, $from = 0, $to = 0)
1348 $_SESSION['searchfor'] = $searchfor;
1349 $_SESSION['sort_order'] = $sort_order;
1351 $_SESSION['from_date'] = strtotime($from);
1353 unset($_SESSION['from_date']);
1355 $_SESSION['to_date'] = strtotime($to);
1357 unset($_SESSION['to_date']);
1359 if($searchfor != "") {
1360 /* new search, reset the current selected tags */
1361 $_SESSION['selected_tags'] = Array();
1362 foreach($this->avail_tags as $tag) {
1363 if(preg_match('/'. $searchfor .'/i', $this->tags[$tag]))
1364 array_push($_SESSION['selected_tags'], $tag);
1373 * this function rotates the image according the
1376 private function rotateImage($img, $degrees)
1378 if(function_exists("imagerotate")) {
1379 $img = imagerotate($img, $degrees, 0);
1381 function imagerotate($src_img, $angle)
1383 $src_x = imagesx($src_img);
1384 $src_y = imagesy($src_img);
1385 if ($angle == 180) {
1389 elseif ($src_x <= $src_y) {
1393 elseif ($src_x >= $src_y) {
1398 $rotate=imagecreatetruecolor($dest_x,$dest_y);
1399 imagealphablending($rotate, false);
1404 for ($y = 0; $y < ($src_y); $y++) {
1405 for ($x = 0; $x < ($src_x); $x++) {
1406 $color = imagecolorat($src_img, $x, $y);
1407 imagesetpixel($rotate, $dest_x - $y - 1, $x, $color);
1413 for ($y = 0; $y < ($src_y); $y++) {
1414 for ($x = 0; $x < ($src_x); $x++) {
1415 $color = imagecolorat($src_img, $x, $y);
1416 imagesetpixel($rotate, $y, $dest_y - $x - 1, $color);
1422 for ($y = 0; $y < ($src_y); $y++) {
1423 for ($x = 0; $x < ($src_x); $x++) {
1424 $color = imagecolorat($src_img, $x, $y);
1425 imagesetpixel($rotate, $dest_x - $x - 1, $dest_y - $y - 1, $color);
1439 $img = imagerotate($img, $degrees);
1448 * return all assigned tags for the specified photo
1450 private function get_photo_tags($idx)
1452 $result = $this->db->db_query("
1455 INNER JOIN photo_tags pt
1457 WHERE pt.photo_id='". $idx ."'
1462 while($row = $this->db->db_fetch_object($result))
1463 $tags[$row['id']] = $row['name'];
1467 } // get_photo_tags()
1470 * create on-the-fly images with text within
1472 public function showTextImage($txt, $color=000000, $space=4, $font=4, $w=300)
1474 if (strlen($color) != 6)
1477 $int = hexdec($color);
1478 $h = imagefontheight($font);
1479 $fw = imagefontwidth($font);
1480 $txt = explode("\n", wordwrap($txt, ($w / $fw), "\n"));
1481 $lines = count($txt);
1482 $im = imagecreate($w, (($h * $lines) + ($lines * $space)));
1483 $bg = imagecolorallocate($im, 255, 255, 255);
1484 $color = imagecolorallocate($im, 0xFF & ($int >> 0x10), 0xFF & ($int >> 0x8), 0xFF & $int);
1487 foreach ($txt as $text) {
1488 $x = (($w - ($fw * strlen($text))) / 2);
1489 imagestring($im, $font, $x, $y, $text, $color);
1490 $y += ($h + $space);
1493 Header("Content-type: image/png");
1496 } // showTextImage()
1499 * check if all requirements are met
1501 private function checkRequirements()
1503 if(!function_exists("imagecreatefromjpeg")) {
1504 print "PHP GD library extension is missing<br />\n";
1508 if($this->cfg->db_access == "native" && !function_exists("sqlite3_open")) {
1509 print "PHP SQLite3 library extension is missing<br />\n";
1513 /* Check for HTML_AJAX PEAR package, lent from Horde project */
1514 ini_set('track_errors', 1);
1515 @include_once 'HTML/AJAX/Server.php';
1516 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
1517 print "PEAR HTML_AJAX package is missing<br />\n";
1520 @include_once 'Calendar/Calendar.php';
1521 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
1522 print "PEAR Calendar package is missing<br />\n";
1525 ini_restore('track_errors');
1532 } // checkRequirements()
1534 private function _debug($text)
1536 if($this->fromcmd) {
1543 * check if specified MIME type is supported
1545 public function checkifImageSupported($mime)
1547 if(in_array($mime, Array("image/jpeg")))
1552 } // checkifImageSupported()
1554 public function _error($text)
1556 switch($this->cfg->logging) {
1558 print "<img src=\"resources/green_info.png\" alt=\"warning\" />\n";
1565 error_log($text, 3, $his->cfg->log_file);
1572 * output calendard input fields
1574 private function get_calendar($mode)
1576 $year = $_SESSION[$mode .'_date'] ? date("Y", $_SESSION[$mode .'_date']) : date("Y");
1577 $month = $_SESSION[$mode .'_date'] ? date("m", $_SESSION[$mode .'_date']) : date("m");
1578 $day = $_SESSION[$mode .'_date'] ? date("d", $_SESSION[$mode .'_date']) : date("d");
1580 $output = "<input type=\"text\" size=\"3\" id=\"". $mode ."year\" value=\"". $year ."\"";
1581 if(!isset($_SESSION[$mode .'_date'])) $output.= " disabled=\"disabled\"";
1583 $output.= "<input type=\"text\" size=\"1\" id=\"". $mode ."month\" value=\"". $month ."\"";
1584 if(!isset($_SESSION[$mode .'_date'])) $output.= " disabled=\"disabled\"";
1586 $output.= "<input type=\"text\" size=\"1\" id=\"". $mode ."day\" value=\"". $day ."\"";
1587 if(!isset($_SESSION[$mode .'_date'])) $output.= " disabled=\"disabled\"";
1594 * output calendar matrix
1596 public function get_calendar_matrix($year = 0, $month = 0, $day = 0)
1598 if (!isset($year)) $year = date('Y');
1599 if (!isset($month)) $month = date('m');
1600 if (!isset($day)) $day = date('d');
1605 require_once CALENDAR_ROOT.'Month/Weekdays.php';
1606 require_once CALENDAR_ROOT.'Day.php';
1609 $month = new Calendar_Month_Weekdays($year,$month);
1612 $prevStamp = $month->prevMonth(true);
1613 $prev = "javascript:setMonth(". date('Y',$prevStamp) .", ". date('n',$prevStamp) .", ". date('j',$prevStamp) .");";
1614 $nextStamp = $month->nextMonth(true);
1615 $next = "javascript:setMonth(". date('Y',$nextStamp) .", ". date('n',$nextStamp) .", ". date('j',$nextStamp) .");";
1617 $selectedDays = array (
1618 new Calendar_Day($year,$month,$day),
1619 new Calendar_Day($year,12,25),
1622 // Build the days in the month
1623 $month->build($selectedDays);
1625 $this->tmpl->assign('current_month', date('F Y',$month->getTimeStamp()));
1626 $this->tmpl->assign('prev_month', $prev);
1627 $this->tmpl->assign('next_month', $next);
1629 while ( $day = $month->fetch() ) {
1631 if(!isset($matrix[$rows]))
1632 $matrix[$rows] = Array();
1636 $dayStamp = $day->thisDay(true);
1637 $link = "javascript:setCalendarDate(". date('Y',$dayStamp) .", ". date('n',$dayStamp).", ". date('j',$dayStamp) .");";
1639 // isFirst() to find start of week
1640 if ( $day->isFirst() )
1643 if ( $day->isSelected() ) {
1644 $string.= "<td class=\"selected\">".$day->thisDay()."</td>\n";
1645 } else if ( $day->isEmpty() ) {
1646 $string.= "<td> </td>\n";
1648 $string.= "<td><a class=\"calendar\" href=\"".$link."\">".$day->thisDay()."</a></td>\n";
1651 // isLast() to find end of week
1652 if ( $day->isLast() )
1653 $string.= "</tr>\n";
1655 $matrix[$rows][$cols] = $string;
1665 $this->tmpl->assign('matrix', $matrix);
1666 $this->tmpl->assign('rows', $rows);
1667 $this->tmpl->show("calendar.tpl");
1669 } // get_calendar_matrix()
1672 * output export page
1674 public function getExport($mode)
1676 $pictures = $this->getPhotoSelection();
1677 $current_tags = $this->getCurrentTags();
1679 foreach($pictures as $picture) {
1681 $orig_url = $this->get_phpfspot_url() ."index.php?mode=showp&id=". $picture;
1682 if($current_tags != "") {
1683 $orig_url.= "&tags=". $current_tags;
1685 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1686 $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
1689 $thumb_url = $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
1694 // <a href="%pictureurl%"><img src="%thumbnailurl%" ></a>
1695 print htmlspecialchars("<a href=\"". $orig_url ."\"><img src=\"". $thumb_url ."\" /></a>") ."<br />\n";
1699 // "[%pictureurl% %thumbnailurl%]"
1700 print htmlspecialchars("[".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
1703 case 'MoinMoinList':
1704 // " * [%pictureurl% %thumbnailurl%]"
1705 print " " . htmlspecialchars("* [".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
1716 public function getRSSFeed()
1718 Header("Content-type: text/xml; charset=utf-8");
1719 print "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
1722 xmlns:media="http://search.yahoo.com/mrss/"
1723 xmlns:dc="http://purl.org/dc/elements/1.1/"
1726 <title>phpfspot</title>
1727 <description>phpfspot RSS feed</description>
1728 <link><?php print htmlspecialchars($this->get_phpfspot_url()); ?></link>
1729 <pubDate><?php print strftime("%a, %d %b %Y %T %z"); ?></pubDate>
1730 <generator>phpfspot</generator>
1733 $pictures = $this->getPhotoSelection();
1734 $current_tags = $this->getCurrentTags();
1736 foreach($pictures as $picture) {
1738 $orig_url = $this->get_phpfspot_url() ."index.php?mode=showp&id=". $picture;
1739 if($current_tags != "") {
1740 $orig_url.= "&tags=". $current_tags;
1742 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1743 $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
1746 $details = $this->get_photo_details($picture);
1748 $thumb_url = $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
1749 $thumb_html = htmlspecialchars("
1750 <a href=\"". $orig_url ."\"><img src=\"". $thumb_url ."\" /></a>
1752 ". $details['description']);
1754 $orig_path = $this->translate_path($details['directory_path']) ."/". $details['name'];
1755 $meta = $this->get_meta_informations($orig_path);
1756 $meta_date = isset($meta['FileDateTime']) ? $meta['FileDateTime'] : filemtime($orig_path);
1760 <title><?php print htmlspecialchars($details['name']); ?></title>
1761 <link><?php print htmlspecialchars($orig_url); ?></link>
1762 <guid><?php print htmlspecialchars($orig_url); ?></guid>
1763 <dc:date.Taken><?php print strftime("%Y-%m-%dT%H:%M:%S+00:00", $meta_date); ?></dc:date.Taken>
1765 <?php print $thumb_html; ?>
1767 <pubDate><?php print strftime("%a, %d %b %Y %T %z", $meta_date); ?></pubDate>
1782 * return all selected tags as one string
1784 private function getCurrentTags()
1787 if($_SESSION['selected_tags'] != "") {
1788 foreach($_SESSION['selected_tags'] as $tag)
1789 $current_tags.= $tag .",";
1790 $current_tags = substr($current_tags, 0, strlen($current_tags)-1);
1792 return $current_tags;
1794 } // getCurrentTags()
1797 * return the current photo
1799 public function getCurrentPhoto()
1801 if(isset($_SESSION['current_photo'])) {
1802 print $_SESSION['current_photo'];
1804 } // getCurrentPhoto()
1807 * tells the client browser what to do
1809 * this function is getting called via AJAX by the
1810 * client browsers. it will tell them what they have
1811 * to do next. This is necessary for directly jumping
1812 * into photo index or single photo view when the are
1813 * requested with specific URLs
1815 public function whatToDo()
1817 if(isset($_SESSION['current_photo']) && $_SESSION['start_action'] == 'showp') {
1818 return "show_photo";
1820 elseif(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
1821 return "showpi_tags";
1823 elseif(isset($_SESSION['start_action']) && $_SESSION['start_action'] == 'showpi') {
1827 return "nothing special";
1832 * return the current process-user
1834 private function getuid()
1836 if($uid = posix_getuid()) {
1837 if($user = posix_getpwuid($uid)) {
1838 return $user['name'];
1847 * returns a select-dropdown box to select photo index sort parameters
1849 private function get_sort_field()
1851 $output = "<select name=\"sort_order\">";
1852 foreach(array('date_asc', 'date_desc', 'name_asc', 'name_desc') as $sort_order) {
1853 $output.= "<option value=\"". $sort_order ."\"";
1854 if($sort_order == $_SESSION['sort_order']) {
1855 $output.= " selected=\"selected\"";
1857 $output.= ">". $sort_order ."</option>";
1859 $output.= "</select>";
1862 } // get_sort_field()
1865 * returns the currently selected sort order
1867 private function get_sort_order()
1869 switch($_SESSION['sort_order']) {
1871 return " ORDER BY p.time ASC";
1874 return " ORDER BY p.time DESC";
1877 return " ORDER BY p.name ASC";
1880 return " ORDER BY p.name DESC";
1884 } // get_sort_order()
1887 * return the next to be shown slide show image
1889 * this function returns the URL of the next image
1890 * in the slideshow sequence.
1892 public function getNextSlideShowImage()
1894 $all_photos = $this->getPhotoSelection();
1896 if(!isset($_SESSION['slideshow_img']) || $_SESSION['slideshow_img'] == count($all_photos)-1)
1897 $_SESSION['slideshow_img'] = 0;
1899 $_SESSION['slideshow_img']++;
1901 return $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $all_photos[$_SESSION['slideshow_img']] ."&width=". $this->cfg->photo_width;
1903 } // getNextSlideShowImage()
1906 * return the previous to be shown slide show image
1908 * this function returns the URL of the previous image
1909 * in the slideshow sequence.
1911 public function getPrevSlideShowImage()
1913 $all_photos = $this->getPhotoSelection();
1915 if(!isset($_SESSION['slideshow_img']) || $_SESSION['slideshow_img'] == 0)
1916 $_SESSION['slideshow_img'] = 0;
1918 $_SESSION['slideshow_img']--;
1920 return $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $all_photos[$_SESSION['slideshow_img']] ."&width=". $this->cfg->photo_width;
1922 } // getPrevSlideShowImage()
1924 public function resetSlideShow()
1926 if(isset($_SESSION['slideshow_img']))
1927 unset($_SESSION['slideshow_img']);
1928 } // resetSlideShow()
1933 * this function will get all photos from the fspot
1934 * database and randomly return ONE entry
1936 * saddly there is yet no sqlite3 function which returns
1937 * the bulk result in array, so we have to fill up our
1940 public function get_random_photo()
1944 $result = $this->db->db_query("
1949 while($row = $this->db->db_fetch_object($result)) {
1950 array_push($all, $row['id']);
1953 return $all[array_rand($all)];
1955 } // get_random_photo()
1958 * validates provided date
1960 * this function validates if the provided date
1961 * contains a valid date and will return true
1964 public function isValidDate($date_str)
1966 $timestamp = strtotime($date_str);
1968 if(is_numeric($timestamp))
1976 * timestamp to string conversion
1978 private function ts2str($timestamp)
1980 return strftime("%Y-%m-%d", $timestamp);
1983 private function extractTags($tags_str)
1985 $not_validated = split(',', $_GET['tags']);
1986 $validated = array();
1988 foreach($not_validated as $tag) {
1989 if(is_numeric($tag))
1990 array_push($validated, $tag);
1998 * returns the full path to a thumbnail
2000 public function get_thumb_path($width, $photo)
2002 $md5 = $this->getMD5($photo);
2003 $sub_path = substr($md5, 0, 2);
2004 return $this->cfg->thumb_path
2012 } // get_thumb_path()
2015 * returns server's virtual host name
2017 private function get_server_name()
2019 return $_SERVER['SERVER_NAME'];
2020 } // get_server_name()
2023 * returns type of webprotocol which is
2026 private function get_web_protocol()
2028 if(!isset($_SERVER['HTTPS']))
2032 } // get_web_protocol()
2035 * return url to this phpfspot installation
2037 private function get_phpfspot_url()
2039 return $this->get_web_protocol() ."://". $this->get_server_name() . $this->cfg->web_path;
2040 } // get_phpfspot_url()
2043 * check file exists and is readable
2045 * returns true, if everything is ok, otherwise false
2046 * if $silent is not set, this function will output and
2049 private function check_readable($file, $silent = null)
2051 if(!file_exists($file)) {
2053 print "File \"". $file ."\" does not exist.\n";
2057 if(!is_readable($file)) {
2059 print "File \"". $file ."\" is not reachable for user ". $this->getuid() ."\n";
2065 } // check_readable()