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";
40 * this function will be called on class construct
41 * and will check requirements, loads configuration,
42 * open databases and start the user session
44 public function __construct()
46 $this->cfg = new PHPFSPOT_CFG;
48 /* set application name and version information */
49 $this->cfg->product = "phpfspot";
50 $this->cfg->version = "1.2";
52 /* Check necessary requirements */
53 if(!$this->checkRequirements()) {
57 $this->db = new PHPFSPOT_DB($this, $this->cfg->fspot_db);
58 if(!is_writeable($this->cfg->fspot_db)) {
59 print $this->cfg->fspot_db ." is not writeable for user ". $this->getuid() ."\n";
63 $this->dbver = $this->getFspotDBVersion();
65 if(!is_writeable(dirname($this->cfg->phpfspot_db))) {
66 print dirname($this->cfg->phpfspot_db) .": directory is not writeable!";
70 $this->cfg_db = new PHPFSPOT_DB($this, $this->cfg->phpfspot_db);
71 if(!is_writeable($this->cfg->phpfspot_db)) {
72 print $this->cfg->phpfspot_db ." is not writeable for user ". $this->getuid() ."\n";
75 $this->check_config_table();
77 /* include Smarty template engine */
78 if(!$this->check_readable($this->cfg->smarty_path .'/libs/Smarty.class.php')) {
81 require $this->cfg->smarty_path .'/libs/Smarty.class.php';
82 /* overload Smarty class if our own template handler */
83 require_once "phpfspot_tmpl.php";
84 $this->tmpl = new PHPFSPOT_TMPL($this);
86 /* check if all necessary indices exist */
87 $this->checkDbIndices();
91 if(!isset($_SESSION['tag_condition']))
92 $_SESSION['tag_condition'] = 'or';
94 if(!isset($_SESSION['sort_order']))
95 $_SESSION['sort_order'] = 'date_asc';
97 if(!isset($_SESSION['searchfor']))
98 $_SESSION['searchfor'] = '';
100 // if begin_with is still set but rows_per_page is now 0, unset it
101 if(isset($_SESSION['begin_with']) && $this->cfg->rows_per_page == 0)
102 unset($_SESSION['begin_with']);
106 public function __destruct()
112 * show - generate html output
114 * this function can be called after the constructor has
115 * prepared everyhing. it will load the index.tpl smarty
116 * template. if necessary it will registere pre-selects
117 * (photo index, photo, tag search, date search) into
120 public function show()
122 $this->tmpl->assign('searchfor', $_SESSION['searchfor']);
123 $this->tmpl->assign('page_title', $this->cfg->page_title);
124 $this->tmpl->assign('current_condition', $_SESSION['tag_condition']);
125 $this->tmpl->assign('template_path', 'themes/'. $this->cfg->theme_name);
127 $_SESSION['start_action'] = $_GET['mode'];
129 switch($_GET['mode']) {
131 if(isset($_GET['tags'])) {
132 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
134 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
135 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
137 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
138 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
142 if(isset($_GET['tags'])) {
143 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
144 $_SESSION['start_action'] = 'showp';
146 if(isset($_GET['id']) && is_numeric($_GET['id'])) {
147 $_SESSION['current_photo'] = $_GET['id'];
148 $_SESSION['start_action'] = 'showp';
150 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
151 $_SESSION['from_date'] = strtotime($_GET['from_date']);
153 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
154 $_SESSION['to_date'] = strtotime($_GET['to_date']);
158 $this->tmpl->show("export.tpl");
162 $this->tmpl->show("slideshow.tpl");
166 if(isset($_GET['tags'])) {
167 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
169 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
170 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
172 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
173 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
180 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date']))
181 $this->tmpl->assign('date_search_enabled', true);
183 $this->tmpl->assign('from_date', $this->get_calendar('from'));
184 $this->tmpl->assign('to_date', $this->get_calendar('to'));
185 $this->tmpl->assign('sort_field', $this->get_sort_field());
186 $this->tmpl->assign('content_page', 'welcome.tpl');
187 $this->tmpl->show("index.tpl");
192 * get_tags - grab all tags of f-spot's database
194 * this function will get all available tags from
195 * the f-spot database and store them within two
196 * arrays within this class for later usage. in
197 * fact, if the user requests (hide_tags) it will
198 * opt-out some of them.
200 * this function is getting called once by show()
202 private function get_tags()
204 $this->avail_tags = Array();
207 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
210 DISTINCT t1.id as id, t1.name as name
213 INNER JOIN photo_tags
214 pt2 ON pt1.photo_id=pt2.photo_id
220 t2.name IN ('".implode("','",$this->cfg->show_tags)."')
222 t1.sort_priority ASC";
224 $result = $this->db->db_query($query_str);
228 $result = $this->db->db_query("
231 ORDER BY sort_priority ASC
235 while($row = $this->db->db_fetch_object($result)) {
237 $tag_id = $row['id'];
238 $tag_name = $row['name'];
240 /* if the user has specified to ignore this tag in phpfspot's
241 configuration, ignore it here so it does not get added to
244 if(in_array($row['name'], $this->cfg->hide_tags))
247 /* if you include the following if-clause and the user has specified
248 to only show certain tags which are specified in phpfspot's
249 configuration, ignore all others so they will not be added to the
251 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags) &&
252 !in_array($row['name'], $this->cfg->show_tags))
256 $this->tags[$tag_id] = $tag_name;
257 $this->avail_tags[$count] = $tag_id;
265 * extract all photo details
267 * retrieve all available details from f-spot's
268 * database and return them as object
270 public function get_photo_details($idx)
273 SELECT p.id, p.name, p.time, p.directory_path, p.description
277 /* if show_tags is set, only return details for photos which
278 are specified to be shown
280 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
282 INNER JOIN photo_tags pt
286 WHERE p.id='". $idx ."'
287 AND t.name IN ('".implode("','",$this->cfg->show_tags)."')";
291 WHERE p.id='". $idx ."'
295 $result = $this->db->db_query($query_str);
296 return $this->db->db_fetch_object($result);
298 } // get_photo_details
301 * returns aligned photo names
303 * this function returns aligned (length) names for
304 * an specific photo. If the length of the name exceeds
305 * $limit the name will be shrinked (...)
307 public function getPhotoName($idx, $limit = 0)
309 if($details = $this->get_photo_details($idx)) {
310 $name = $this->shrink_text($details['name'], $limit);
317 * shrink text according provided limit
319 * If the length of the name exceeds $limit the
320 * text will be shortend and some content in between
321 * will be replaced with "..."
323 private function shrink_text($text, $limit)
325 if($limit != 0 && strlen($text) > $limit) {
326 $text = substr($text, 0, $limit-5) ."...". substr($text, -($limit-5));
334 * translate f-spoth photo path
336 * as the full-qualified path recorded in the f-spot database
337 * is usally not the same as on the webserver, this function
338 * will replace the path with that one specified in the cfg
340 public function translate_path($path, $width = 0)
342 return str_replace($this->cfg->path_replace_from, $this->cfg->path_replace_to, $path);
347 * control HTML ouput for a single photo
349 * this function provides all the necessary information
350 * for the single photo template.
352 public function showPhoto($photo)
354 /* get all photos from the current photo selection */
355 $all_photos = $this->getPhotoSelection();
356 $count = count($all_photos);
358 for($i = 0; $i < $count; $i++) {
360 // $get_next will be set, when the photo which has to
361 // be displayed has been found - this means that the
362 // next available is in fact the NEXT image (for the
364 if(isset($get_next)) {
365 $next_img = $all_photos[$i];
369 /* the next photo is our NEXT photo */
370 if($all_photos[$i] == $photo) {
374 $previous_img = $all_photos[$i];
377 if($photo == $all_photos[$i]) {
382 $details = $this->get_photo_details($photo);
389 $orig_path = $this->translate_path($details['directory_path']) ."/". $details['name'];
390 $thumb_path = $this->get_thumb_path($this->cfg->photo_width, $photo);
392 if(!file_exists($orig_path)) {
393 $this->_error("Photo ". $orig_path ." does not exist!<br />\n");
396 if(!is_readable($orig_path)) {
397 $this->_error("Photo ". $orig_path ." is not readable for user ". $this->getuid() ."<br />\n");
400 /* If the thumbnail doesn't exist yet, try to create it */
401 if(!file_exists($thumb_path)) {
402 $this->gen_thumb($photo, true);
403 $thumb_path = $this->get_thumb_path($this->cfg->photo_width, $photo);
406 /* get f-spot database meta information */
407 $meta = $this->get_meta_informations($orig_path);
409 /* If EXIF data are available, use them */
410 if(isset($meta['ExifImageWidth'])) {
411 $meta_res = $meta['ExifImageWidth'] ."x". $meta['ExifImageLength'];
413 $info = getimagesize($orig_path);
414 $meta_res = $info[0] ."x". $info[1];
417 $meta_date = isset($meta['FileDateTime']) ? strftime("%a %x %X", $meta['FileDateTime']) : "n/a";
418 $meta_make = isset($meta['Make']) ? $meta['Make'] ." / ". $meta['Model'] : "n/a";
419 $meta_size = isset($meta['FileSize']) ? round($meta['FileSize']/1024, 1) ."kbyte" : "n/a";
421 $extern_link = "index.php?mode=showp&id=". $photo;
422 $current_tags = $this->getCurrentTags();
423 if($current_tags != "") {
424 $extern_link.= "&tags=". $current_tags;
426 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
427 $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
430 $this->tmpl->assign('extern_link', $extern_link);
432 if(file_exists($thumb_path)) {
434 $info = getimagesize($thumb_path);
436 $this->tmpl->assign('description', $details['description']);
437 $this->tmpl->assign('image_name', $details['name']);
439 $this->tmpl->assign('width', $info[0]);
440 $this->tmpl->assign('height', $info[1]);
441 $this->tmpl->assign('ExifMadeOn', $meta_date);
442 $this->tmpl->assign('ExifMadeWith', $meta_make);
443 $this->tmpl->assign('ExifOrigResolution', $meta_res);
444 $this->tmpl->assign('ExifFileSize', $meta_size);
446 $this->tmpl->assign('image_url', 'phpfspot_img.php?idx='. $photo ."&width=". $this->cfg->photo_width);
447 $this->tmpl->assign('image_url_full', 'phpfspot_img.php?idx='. $photo);
449 $this->tmpl->assign('tags', $this->get_photo_tags($photo));
450 $this->tmpl->assign('current', $current);
453 $this->_error("Can't open file ". $thumb_path ."\n");
458 $this->tmpl->assign('previous_url', "javascript:showImage(". $previous_img .");");
459 $this->tmpl->assign('prev_img', $previous_img);
463 $this->tmpl->assign('next_url', "javascript:showImage(". $next_img .");");
464 $this->tmpl->assign('next_img', $next_img);
466 $this->tmpl->assign('mini_width', $this->cfg->mini_width);
467 $this->tmpl->assign('photo_number', $i);
468 $this->tmpl->assign('photo_count', count($all_photos));
470 $this->tmpl->show("single_photo.tpl");
475 * all available tags and tag cloud
477 * this function outputs all available tags (time ordered)
478 * and in addition output them as tag cloud (tags which have
479 * many photos will appears more then others)
481 public function getAvailableTags()
487 $result = $this->db->db_query("
488 SELECT tag_id as id, count(tag_id) as quantity
498 while($row = $this->db->db_fetch_object($result)) {
499 $tags[$row['id']] = $row['quantity'];
502 // change these font sizes if you will
503 $max_size = 125; // max font size in %
504 $min_size = 75; // min font size in %
506 // get the largest and smallest array values
507 $max_qty = max(array_values($tags));
508 $min_qty = min(array_values($tags));
510 // find the range of values
511 $spread = $max_qty - $min_qty;
512 if (0 == $spread) { // we don't want to divide by zero
516 // determine the font-size increment
517 // this is the increase per tag quantity (times used)
518 $step = ($max_size - $min_size)/($spread);
520 // loop through our tag array
521 foreach ($tags as $key => $value) {
523 if(isset($_SESSION['selected_tags']) && in_array($key, $_SESSION['selected_tags']))
526 // calculate CSS font-size
527 // find the $value in excess of $min_qty
528 // multiply by the font-size increment ($size)
529 // and add the $min_size set above
530 $size = $min_size + (($value - $min_qty) * $step);
531 // uncomment if you want sizes in whole %:
534 if(isset($this->tags[$key])) {
535 $output.= "<a href=\"javascript:Tags('add', ". $key .");\" class=\"tag\" style=\"font-size: ". $size ."%;\">". $this->tags[$key] ."</a>, ";
540 $output = substr($output, 0, strlen($output)-2);
543 } // getAvailableTags()
546 * output all selected tags
548 * this function output all tags which have been selected
549 * by the user. the selected tags are stored in the
550 * session-variable $_SESSION['selected_tags']
552 public function getSelectedTags()
557 foreach($this->avail_tags as $tag)
559 // return all selected tags
560 if(isset($_SESSION['selected_tags']) && in_array($tag, $_SESSION['selected_tags'])) {
561 $output.= "<a href=\"javascript:Tags('del', ". $tag .");\" class=\"tag\">". $this->tags[$tag] ."</a>, ";
565 $output = substr($output, 0, strlen($output)-2);
568 } // getSelectedTags()
571 * add tag to users session variable
573 * this function will add the specified to users current
574 * tag selection. if a date search has been made before
575 * it will be now cleared
577 public function addTag($tag)
579 if(!isset($_SESSION['selected_tags']))
580 $_SESSION['selected_tags'] = Array();
582 if(!in_array($tag, $_SESSION['selected_tags']))
583 array_push($_SESSION['selected_tags'], $tag);
588 * remove tag to users session variable
590 * this function removes the specified tag from
591 * users current tag selection
593 public function delTag($tag)
595 if(isset($_SESSION['selected_tags'])) {
596 $key = array_search($tag, $_SESSION['selected_tags']);
597 unset($_SESSION['selected_tags'][$key]);
598 sort($_SESSION['selected_tags']);
604 * reset tag selection
606 * if there is any tag selection, it will be
609 public function resetTags()
611 if(isset($_SESSION['selected_tags']))
612 unset($_SESSION['selected_tags']);
619 * if a specific photo was requested (external link)
620 * unset the session variable now
622 public function resetPhotoView()
624 if(isset($_SESSION['current_photo']))
625 unset($_SESSION['current_photo']);
627 } // resetPhotoView();
632 * if any tag search has taken place, reset
635 public function resetTagSearch()
637 if(isset($_SESSION['searchfor']))
638 unset($_SESSION['searchfor']);
640 } // resetTagSearch()
645 * if any date search has taken place, reset
648 public function resetDateSearch()
650 if(isset($_SESSION['from_date']))
651 unset($_SESSION['from_date']);
652 if(isset($_SESSION['to_date']))
653 unset($_SESSION['to_date']);
655 } // resetDateSearch();
658 * return all photo according selection
660 * this function returns all photos based on
661 * the tag-selection, tag- or date-search.
662 * the tag-search also has to take care of AND
663 * and OR conjunctions
665 public function getPhotoSelection()
667 $matched_photos = Array();
669 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
670 $from_date = $_SESSION['from_date'];
671 $to_date = $_SESSION['to_date'];
672 $additional_where_cond = "
673 p.time>='". $from_date ."'
675 p.time<='". $to_date ."'
679 if(isset($_SESSION['sort_order'])) {
680 $order_str = $this->get_sort_order();
683 /* return a search result */
684 if(isset($_SESSION['searchfor']) && $_SESSION['searchfor'] != '') {
686 SELECT DISTINCT pt1.photo_id
688 INNER JOIN photo_tags pt2
689 ON pt1.photo_id=pt2.photo_id
696 WHERE t1.name LIKE '%". $_SESSION['searchfor'] ."%' ";
698 if(isset($additional_where_cond))
699 $query_str.= "AND ". $additional_where_cond ." ";
701 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
702 $query_str.= "AND t2.name IN ('".implode("','",$this->cfg->show_tags)."')";
705 if(isset($order_str))
706 $query_str.= $order_str;
708 $result = $this->db->db_query($query_str);
709 while($row = $this->db->db_fetch_object($result)) {
710 array_push($matched_photos, $row['photo_id']);
712 return $matched_photos;
715 /* return according the selected tags */
716 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
718 foreach($_SESSION['selected_tags'] as $tag)
719 $selected.= $tag .",";
720 $selected = substr($selected, 0, strlen($selected)-1);
722 /* photo has to match at least on of the selected tags */
723 if($_SESSION['tag_condition'] == 'or') {
725 SELECT DISTINCT pt1.photo_id
727 INNER JOIN photo_tags pt2
728 ON pt1.photo_id=pt2.photo_id
733 WHERE pt1.tag_id IN (". $selected .")
735 if(isset($additional_where_cond))
736 $query_str.= "AND ". $additional_where_cond ." ";
738 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
739 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags)."')";
742 if(isset($order_str))
743 $query_str.= $order_str;
745 /* photo has to match all selected tags */
746 elseif($_SESSION['tag_condition'] == 'and') {
748 if(count($_SESSION['selected_tags']) >= 32) {
749 print "A SQLite limit of 32 tables within a JOIN SELECT avoids to<br />\n";
750 print "evaluate your tag selection. Please remove some tags from your selection.\n";
754 /* Join together a table looking like
756 pt1.photo_id pt1.tag_id pt2.photo_id pt2.tag_id ...
758 so the query can quickly return all images matching the
759 selected tags in an AND condition
764 SELECT DISTINCT pt1.photo_id
768 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
775 for($i = 0; $i < count($_SESSION['selected_tags']); $i++) {
777 INNER JOIN photo_tags pt". ($i+2) ."
778 ON pt1.photo_id=pt". ($i+2) .".photo_id
785 $query_str.= "WHERE pt2.tag_id=". $_SESSION['selected_tags'][0]." ";
786 for($i = 1; $i < count($_SESSION['selected_tags']); $i++) {
788 AND pt". ($i+2) .".tag_id=". $_SESSION['selected_tags'][$i] ."
791 if(isset($additional_where_cond))
792 $query_str.= "AND ". $additional_where_cond;
794 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
795 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags). "')";
798 if(isset($order_str))
799 $query_str.= $order_str;
803 $result = $this->db->db_query($query_str);
804 while($row = $this->db->db_fetch_object($result)) {
805 array_push($matched_photos, $row['photo_id']);
807 return $matched_photos;
810 /* return all available photos */
812 SELECT DISTINCT photo_id
819 if(isset($additional_where_cond))
820 $query_str.= "WHERE ". $additional_where_cond ." ";
822 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
823 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags). "')";
826 if(isset($order_str))
827 $query_str.= $order_str;
829 $result = $this->db->db_query($query_str);
830 while($row = $this->db->db_fetch_object($result)) {
831 array_push($matched_photos, $row['photo_id']);
833 return $matched_photos;
835 } // getPhotoSelection()
838 * control HTML ouput for photo index
840 * this function provides all the necessary information
841 * for the photo index template.
843 public function showPhotoIndex()
845 $photos = $this->getPhotoSelection();
847 $count = count($photos);
849 if(isset($_SESSION['begin_with']) && $_SESSION['begin_with'] != "")
850 $anchor = $_SESSION['begin_with'];
852 if(!isset($this->cfg->rows_per_page) || $this->cfg->rows_per_page == 0) {
858 elseif($this->cfg->rows_per_page > 0) {
860 if(!$_SESSION['begin_with'] || $_SESSION['begin_with'] == 0)
864 $begin_with = $_SESSION['begin_with'];
866 // verify $begin_with - perhaps the thumbs-per-rows or
867 // rows-per-page variables have changed or the jump back
868 // from a photo wasn't exact - so calculate the real new
870 $multiplicator = $this->cfg->rows_per_page * $this->cfg->thumbs_per_row;
871 for($i = 0; $i <= $count; $i+=$multiplicator) {
872 if($begin_with >= $i && $begin_with < $i+$multiplicator) {
879 $end_with = $begin_with + ($this->cfg->rows_per_page * $this->cfg->thumbs_per_row);
885 $images[$rows] = Array();
886 $img_height[$rows] = Array();
887 $img_width[$rows] = Array();
888 $img_id[$rows] = Array();
889 $img_name[$rows] = Array();
890 $img_title = Array();
892 for($i = $begin_with; $i < $end_with; $i++) {
894 $images[$rows][$cols] = $photos[$i];
895 $img_id[$rows][$cols] = $i;
896 $img_name[$rows][$cols] = htmlspecialchars($this->getPhotoName($photos[$i], 15));
897 $img_title[$rows][$cols] = "Click to view photo ". htmlspecialchars($this->getPhotoName($photos[$i], 0));
899 $thumb_path = $this->get_thumb_path($this->cfg->thumb_width, $photos[$i]);
901 if(file_exists($thumb_path)) {
902 $info = getimagesize($thumb_path);
903 $img_width[$rows][$cols] = $info[0];
904 $img_height[$rows][$cols] = $info[1];
907 if($cols == $this->cfg->thumbs_per_row-1) {
910 $images[$rows] = Array();
911 $img_width[$rows] = Array();
912 $img_height[$rows] = Array();
919 // +1 for for smarty's selection iteration
922 if(isset($_SESSION['searchfor']) && $_SESSION['searchfor'] != '')
923 $this->tmpl->assign('searchfor', $_SESSION['searchfor']);
925 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
926 $this->tmpl->assign('from_date', $this->ts2str($_SESSION['from_date']));
927 $this->tmpl->assign('to_date', $this->ts2str($_SESSION['to_date']));
930 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
931 $this->tmpl->assign('tag_result', 1);
934 /* do we have to display the page selector ? */
935 if($this->cfg->rows_per_page != 0) {
937 /* calculate the page switchers */
938 $previous_start = $begin_with - ($this->cfg->rows_per_page * $this->cfg->thumbs_per_row);
939 $next_start = $begin_with + ($this->cfg->rows_per_page * $this->cfg->thumbs_per_row);
942 $this->tmpl->assign("previous_url", "javascript:showPhotoIndex(". $previous_start .");");
943 if($end_with < $count)
944 $this->tmpl->assign("next_url", "javascript:showPhotoIndex(". $next_start .");");
946 $photo_per_page = $this->cfg->rows_per_page * $this->cfg->thumbs_per_row;
947 $last_page = ceil($count / $photo_per_page);
949 /* get the current selected page */
950 if($begin_with == 0) {
954 for($i = $begin_with; $i >= 0; $i-=$photo_per_page) {
961 for($i = 1; $i <= $last_page; $i++) {
963 if($current_page == $i)
964 $style = "style=\"font-size: 125%; text-decoration: underline;\"";
965 elseif($current_page-1 == $i || $current_page+1 == $i)
966 $style = "style=\"font-size: 105%;\"";
967 elseif(($current_page-5 >= $i) && ($i != 1) ||
968 ($current_page+5 <= $i) && ($i != $last_page))
969 $style = "style=\"font-size: 75%;\"";
973 $select = "<a href=\"javascript:showPhotoIndex(". (($i*$photo_per_page)-$photo_per_page) .");\"";
976 $select.= ">". $i ."</a> ";
978 // until 9 pages we show the selector from 1-9
979 if($last_page <= 9) {
980 $page_select.= $select;
983 if($i == 1 /* first page */ ||
984 $i == $last_page /* last page */ ||
985 $i == $current_page /* current page */ ||
986 $i == ceil($last_page * 0.25) /* first quater */ ||
987 $i == ceil($last_page * 0.5) /* half */ ||
988 $i == ceil($last_page * 0.75) /* third quater */ ||
989 (in_array($i, array(1,2,3,4,5,6)) && $current_page <= 4) /* the first 6 */ ||
990 (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 */ ||
991 $i == $current_page-3 || $i == $current_page-2 || $i == $current_page-1 /* three before */ ||
992 $i == $current_page+3 || $i == $current_page+2 || $i == $current_page+1 /* three after */) {
994 $page_select.= $select;
1002 $page_select.= "......... ";
1007 /* only show the page selector if we have more then one page */
1009 $this->tmpl->assign('page_selector', $page_select);
1013 $current_tags = $this->getCurrentTags();
1014 $extern_link = "index.php?mode=showpi";
1015 $rss_link = "index.php?mode=rss";
1016 if($current_tags != "") {
1017 $extern_link.= "&tags=". $current_tags;
1018 $rss_link.= "&tags=". $current_tags;
1020 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1021 $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
1022 $rss_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
1025 $export_link = "index.php?mode=export";
1026 $slideshow_link = "index.php?mode=slideshow";
1028 $this->tmpl->assign('extern_link', $extern_link);
1029 $this->tmpl->assign('slideshow_link', $slideshow_link);
1030 $this->tmpl->assign('export_link', $export_link);
1031 $this->tmpl->assign('rss_link', $rss_link);
1032 $this->tmpl->assign('count', $count);
1033 $this->tmpl->assign('width', $this->cfg->thumb_width);
1034 $this->tmpl->assign('images', $images);
1035 $this->tmpl->assign('img_width', $img_width);
1036 $this->tmpl->assign('img_height', $img_height);
1037 $this->tmpl->assign('img_id', $img_id);
1038 $this->tmpl->assign('img_name', $img_name);
1039 $this->tmpl->assign('img_title', $img_title);
1040 $this->tmpl->assign('rows', $rows);
1041 $this->tmpl->assign('columns', $this->cfg->thumbs_per_row);
1043 $this->tmpl->show("photo_index.tpl");
1046 print "<script language=\"JavaScript\">self.location.hash = '#image". $anchor ."';</script>\n";
1048 } // showPhotoIndex()
1051 * show credit template
1053 public function showCredits()
1055 $this->tmpl->assign('version', $this->cfg->version);
1056 $this->tmpl->assign('product', $this->cfg->product);
1057 $this->tmpl->assign('db_version', $this->dbver);
1058 $this->tmpl->show("credits.tpl");
1063 * create_thumbnails for the requested width
1065 * this function creates image thumbnails of $orig_image
1066 * stored as $thumb_image. It will check if the image is
1067 * in a supported format, if necessary rotate the image
1068 * (based on EXIF orientation meta headers) and re-sizing.
1070 public function create_thumbnail($orig_image, $thumb_image, $width)
1072 if(!file_exists($orig_image)) {
1076 $details = getimagesize($orig_image);
1078 /* check if original photo is a support image type */
1079 if(!$this->checkifImageSupported($details['mime']))
1082 $meta = $this->get_meta_informations($orig_image);
1087 switch($meta['Orientation']) {
1089 case 1: /* top, left */
1090 $rotate = 0; $flip = false; break;
1091 case 2: /* top, right */
1092 $rotate = 0; $flip = true; break;
1093 case 3: /* bottom, left */
1094 $rotate = 180; $flip = false; break;
1095 case 4: /* bottom, right */
1096 $rotate = 180; $flip = true; break;
1097 case 5: /* left side, top */
1098 $rotate = 90; $flip = true; break;
1099 case 6: /* right side, top */
1100 $rotate = 90; $flip = false; break;
1101 case 7: /* left side, bottom */
1102 $rotate = 270; $flip = true; break;
1103 case 8: /* right side, bottom */
1104 $rotate = 270; $flip = false; break;
1107 $src_img = @imagecreatefromjpeg($orig_image);
1110 print "Can't load image from ". $orig_image ."\n";
1114 /* grabs the height and width */
1115 $cur_width = imagesx($src_img);
1116 $cur_height = imagesy($src_img);
1118 // If requested width is more then the actual image width,
1119 // do not generate a thumbnail, instead safe the original
1120 // as thumbnail but with lower quality
1122 if($width >= $cur_width) {
1123 $result = imagejpeg($src_img, $thumb_image, 75);
1124 imagedestroy($src_img);
1128 // If the image will be rotate because EXIF orientation said so
1129 // 'virtually rotate' the image for further calculations
1130 if($rotate == 90 || $rotate == 270) {
1132 $cur_width = $cur_height;
1136 /* calculates aspect ratio */
1137 $aspect_ratio = $cur_height / $cur_width;
1140 if($aspect_ratio < 1) {
1142 $new_h = abs($new_w * $aspect_ratio);
1144 /* 'virtually' rotate the image and calculate it's ratio */
1145 $tmp_w = $cur_height;
1146 $tmp_h = $cur_width;
1147 /* now get the ratio from the 'rotated' image */
1148 $tmp_ratio = $tmp_h/$tmp_w;
1149 /* now calculate the new dimensions */
1151 $tmp_h = abs($tmp_w * $tmp_ratio);
1153 // now that we know, how high they photo should be, if it
1154 // gets rotated, use this high to scale the image
1156 $new_w = abs($new_h / $aspect_ratio);
1158 // If the image will be rotate because EXIF orientation said so
1159 // now 'virtually rotate' back the image for the image manipulation
1160 if($rotate == 90 || $rotate == 270) {
1167 /* creates new image of that size */
1168 $dst_img = imagecreatetruecolor($new_w, $new_h);
1170 imagefill($dst_img, 0, 0, ImageColorAllocate($dst_img, 255, 255, 255));
1172 /* copies resized portion of original image into new image */
1173 imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $new_w, $new_h, imagesx($src_img), imagesy($src_img));
1175 /* needs the image to be flipped horizontal? */
1179 for($x = 0; $x < $new_w; $x++) {
1180 imagecopy($dst_img, $image, $x, 0, $w - $x - 1, 0, 1, $h);
1185 $this->_debug("(ROTATE)");
1186 $dst_img = $this->rotateImage($dst_img, $rotate);
1189 /* write down new generated file */
1190 $result = imagejpeg($dst_img, $thumb_image, 75);
1192 /* free your mind */
1193 imagedestroy($dst_img);
1194 imagedestroy($src_img);
1196 if($result === false) {
1197 print "Can't write thumbnail ". $thumb_image ."\n";
1203 } // create_thumbnail()
1206 * return all exif meta data from the file
1208 public function get_meta_informations($file)
1210 return exif_read_data($file);
1212 } // get_meta_informations()
1215 * create phpfspot own sqlite database
1217 * this function creates phpfspots own sqlite database
1218 * if it does not exist yet. this own is used to store
1219 * some necessary informations (md5 sum's, ...).
1221 public function check_config_table()
1223 // if the config table doesn't exist yet, create it
1224 if(!$this->cfg_db->db_check_table_exists("images")) {
1225 $this->cfg_db->db_exec("
1226 CREATE TABLE images (
1227 img_idx int primary key,
1233 } // check_config_table
1236 * Generates a thumbnail from photo idx
1238 * This function will generate JPEG thumbnails from provided F-Spot photo
1241 * 1. Check if all thumbnail generations (width) are already in place and
1243 * 2. Check if the md5sum of the original file has changed
1244 * 3. Generate the thumbnails if needed
1246 public function gen_thumb($idx = 0, $force = 0)
1250 $resolutions = Array(
1251 $this->cfg->thumb_width,
1252 $this->cfg->photo_width,
1253 $this->cfg->mini_width,
1256 /* get details from F-Spot's database */
1257 $details = $this->get_photo_details($idx);
1259 /* calculate file MD5 sum */
1260 $full_path = $this->translate_path($details['directory_path']) ."/". $details['name'];
1262 if(!file_exists($full_path)) {
1263 $this->_error("File ". $full_path ." does not exist\n");
1267 if(!is_readable($full_path)) {
1268 $this->_error("File ". $full_path ." is not readable for ". $this->getuid() ."\n");
1272 $file_md5 = md5_file($full_path);
1274 $this->_debug("Image [". $idx ."] ". $this->shrink_text($details['name'], 20) ." Thumbnails:");
1276 foreach($resolutions as $resolution) {
1278 $thumb_sub_path = substr($file_md5, 0, 2);
1279 $thumb_path = $this->cfg->thumb_path ."/". $thumb_sub_path ."/". $resolution ."_". $file_md5;
1281 if(!file_exists(dirname($thumb_path))) {
1282 mkdir(dirname($thumb_path), 0755);
1285 /* if the thumbnail file doesn't exist, create it */
1286 if(!file_exists($thumb_path)) {
1288 $this->_debug(" ". $resolution ."px");
1289 if(!$this->create_thumbnail($full_path, $thumb_path, $resolution))
1292 /* if the file hasn't changed there is no need to regen the thumb */
1293 elseif($file_md5 != $this->getMD5($idx) || $force) {
1295 $this->_debug(" ". $resolution ."px");
1296 if(!$this->create_thumbnail($full_path, $thumb_path, $resolution))
1302 /* set the new/changed MD5 sum for the current photo */
1304 $this->setMD5($idx, $file_md5);
1307 $this->_debug("\n");
1312 * returns stored md5 sum for a specific photo
1314 * this function queries the phpfspot database for a
1315 * stored MD5 checksum of the specified photo
1317 public function getMD5($idx)
1319 $result = $this->cfg_db->db_query("
1322 WHERE img_idx='". $idx ."'
1328 $img = $this->cfg_db->db_fetch_object($result);
1329 return $img['img_md5'];
1334 * set MD5 sum for the specific photo
1336 private function setMD5($idx, $md5)
1338 $result = $this->cfg_db->db_exec("
1339 REPLACE INTO images (img_idx, img_md5)
1340 VALUES ('". $idx ."', '". $md5 ."')
1346 * store current tag condition
1348 * this function stores the current tag condition
1349 * (AND or OR) in the users session variables
1351 public function setTagCondition($mode)
1353 $_SESSION['tag_condition'] = $mode;
1355 } // setTagCondition()
1358 * invoke tag & date search
1360 * this function will return all matching tags and store
1361 * them in the session variable selected_tags. furthermore
1362 * it also handles the date search.
1363 * getPhotoSelection() will then only return the matching
1366 public function startSearch($searchfor, $sort_order, $from = 0, $to = 0)
1370 $_SESSION['searchfor'] = $searchfor;
1371 $_SESSION['sort_order'] = $sort_order;
1373 $_SESSION['from_date'] = strtotime($from);
1375 unset($_SESSION['from_date']);
1377 $_SESSION['to_date'] = strtotime($to);
1379 unset($_SESSION['to_date']);
1381 if($searchfor != "") {
1382 /* new search, reset the current selected tags */
1383 $_SESSION['selected_tags'] = Array();
1384 foreach($this->avail_tags as $tag) {
1385 if(preg_match('/'. $searchfor .'/i', $this->tags[$tag]))
1386 array_push($_SESSION['selected_tags'], $tag);
1395 * this function rotates the image according the
1398 private function rotateImage($img, $degrees)
1400 if(function_exists("imagerotate")) {
1401 $img = imagerotate($img, $degrees, 0);
1403 function imagerotate($src_img, $angle)
1405 $src_x = imagesx($src_img);
1406 $src_y = imagesy($src_img);
1407 if ($angle == 180) {
1411 elseif ($src_x <= $src_y) {
1415 elseif ($src_x >= $src_y) {
1420 $rotate=imagecreatetruecolor($dest_x,$dest_y);
1421 imagealphablending($rotate, false);
1426 for ($y = 0; $y < ($src_y); $y++) {
1427 for ($x = 0; $x < ($src_x); $x++) {
1428 $color = imagecolorat($src_img, $x, $y);
1429 imagesetpixel($rotate, $dest_x - $y - 1, $x, $color);
1435 for ($y = 0; $y < ($src_y); $y++) {
1436 for ($x = 0; $x < ($src_x); $x++) {
1437 $color = imagecolorat($src_img, $x, $y);
1438 imagesetpixel($rotate, $y, $dest_y - $x - 1, $color);
1444 for ($y = 0; $y < ($src_y); $y++) {
1445 for ($x = 0; $x < ($src_x); $x++) {
1446 $color = imagecolorat($src_img, $x, $y);
1447 imagesetpixel($rotate, $dest_x - $x - 1, $dest_y - $y - 1, $color);
1461 $img = imagerotate($img, $degrees);
1470 * return all assigned tags for the specified photo
1472 private function get_photo_tags($idx)
1474 $result = $this->db->db_query("
1477 INNER JOIN photo_tags pt
1479 WHERE pt.photo_id='". $idx ."'
1484 while($row = $this->db->db_fetch_object($result))
1485 $tags[$row['id']] = $row['name'];
1489 } // get_photo_tags()
1492 * create on-the-fly images with text within
1494 public function showTextImage($txt, $color=000000, $space=4, $font=4, $w=300)
1496 if (strlen($color) != 6)
1499 $int = hexdec($color);
1500 $h = imagefontheight($font);
1501 $fw = imagefontwidth($font);
1502 $txt = explode("\n", wordwrap($txt, ($w / $fw), "\n"));
1503 $lines = count($txt);
1504 $im = imagecreate($w, (($h * $lines) + ($lines * $space)));
1505 $bg = imagecolorallocate($im, 255, 255, 255);
1506 $color = imagecolorallocate($im, 0xFF & ($int >> 0x10), 0xFF & ($int >> 0x8), 0xFF & $int);
1509 foreach ($txt as $text) {
1510 $x = (($w - ($fw * strlen($text))) / 2);
1511 imagestring($im, $font, $x, $y, $text, $color);
1512 $y += ($h + $space);
1515 Header("Content-type: image/png");
1518 } // showTextImage()
1521 * check if all requirements are met
1523 private function checkRequirements()
1525 if(!function_exists("imagecreatefromjpeg")) {
1526 print "PHP GD library extension is missing<br />\n";
1530 if($this->cfg->db_access == "native" && !function_exists("sqlite3_open")) {
1531 print "PHP SQLite3 library extension is missing<br />\n";
1535 /* Check for HTML_AJAX PEAR package, lent from Horde project */
1536 ini_set('track_errors', 1);
1537 @include_once 'HTML/AJAX/Server.php';
1538 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
1539 print "PEAR HTML_AJAX package is missing<br />\n";
1542 @include_once 'Calendar/Calendar.php';
1543 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
1544 print "PEAR Calendar package is missing<br />\n";
1547 ini_restore('track_errors');
1554 } // checkRequirements()
1556 private function _debug($text)
1558 if($this->fromcmd) {
1565 * check if specified MIME type is supported
1567 public function checkifImageSupported($mime)
1569 if(in_array($mime, Array("image/jpeg")))
1574 } // checkifImageSupported()
1576 public function _error($text)
1578 switch($this->cfg->logging) {
1580 print "<img src=\"resources/green_info.png\" alt=\"warning\" />\n";
1587 error_log($text, 3, $his->cfg->log_file);
1594 * output calendard input fields
1596 private function get_calendar($mode)
1598 $year = $_SESSION[$mode .'_date'] ? date("Y", $_SESSION[$mode .'_date']) : date("Y");
1599 $month = $_SESSION[$mode .'_date'] ? date("m", $_SESSION[$mode .'_date']) : date("m");
1600 $day = $_SESSION[$mode .'_date'] ? date("d", $_SESSION[$mode .'_date']) : date("d");
1602 $output = "<input type=\"text\" size=\"3\" id=\"". $mode ."year\" value=\"". $year ."\"";
1603 if(!isset($_SESSION[$mode .'_date'])) $output.= " disabled=\"disabled\"";
1605 $output.= "<input type=\"text\" size=\"1\" id=\"". $mode ."month\" value=\"". $month ."\"";
1606 if(!isset($_SESSION[$mode .'_date'])) $output.= " disabled=\"disabled\"";
1608 $output.= "<input type=\"text\" size=\"1\" id=\"". $mode ."day\" value=\"". $day ."\"";
1609 if(!isset($_SESSION[$mode .'_date'])) $output.= " disabled=\"disabled\"";
1616 * output calendar matrix
1618 public function get_calendar_matrix($year = 0, $month = 0, $day = 0)
1620 if (!isset($year)) $year = date('Y');
1621 if (!isset($month)) $month = date('m');
1622 if (!isset($day)) $day = date('d');
1627 require_once CALENDAR_ROOT.'Month/Weekdays.php';
1628 require_once CALENDAR_ROOT.'Day.php';
1631 $month = new Calendar_Month_Weekdays($year,$month);
1634 $prevStamp = $month->prevMonth(true);
1635 $prev = "javascript:setMonth(". date('Y',$prevStamp) .", ". date('n',$prevStamp) .", ". date('j',$prevStamp) .");";
1636 $nextStamp = $month->nextMonth(true);
1637 $next = "javascript:setMonth(". date('Y',$nextStamp) .", ". date('n',$nextStamp) .", ". date('j',$nextStamp) .");";
1639 $selectedDays = array (
1640 new Calendar_Day($year,$month,$day),
1641 new Calendar_Day($year,12,25),
1644 // Build the days in the month
1645 $month->build($selectedDays);
1647 $this->tmpl->assign('current_month', date('F Y',$month->getTimeStamp()));
1648 $this->tmpl->assign('prev_month', $prev);
1649 $this->tmpl->assign('next_month', $next);
1651 while ( $day = $month->fetch() ) {
1653 if(!isset($matrix[$rows]))
1654 $matrix[$rows] = Array();
1658 $dayStamp = $day->thisDay(true);
1659 $link = "javascript:setCalendarDate(". date('Y',$dayStamp) .", ". date('n',$dayStamp).", ". date('j',$dayStamp) .");";
1661 // isFirst() to find start of week
1662 if ( $day->isFirst() )
1665 if ( $day->isSelected() ) {
1666 $string.= "<td class=\"selected\">".$day->thisDay()."</td>\n";
1667 } else if ( $day->isEmpty() ) {
1668 $string.= "<td> </td>\n";
1670 $string.= "<td><a class=\"calendar\" href=\"".$link."\">".$day->thisDay()."</a></td>\n";
1673 // isLast() to find end of week
1674 if ( $day->isLast() )
1675 $string.= "</tr>\n";
1677 $matrix[$rows][$cols] = $string;
1687 $this->tmpl->assign('matrix', $matrix);
1688 $this->tmpl->assign('rows', $rows);
1689 $this->tmpl->show("calendar.tpl");
1691 } // get_calendar_matrix()
1694 * output export page
1696 public function getExport($mode)
1698 $pictures = $this->getPhotoSelection();
1699 $current_tags = $this->getCurrentTags();
1701 foreach($pictures as $picture) {
1703 $orig_url = $this->get_phpfspot_url() ."index.php?mode=showp&id=". $picture;
1704 if($current_tags != "") {
1705 $orig_url.= "&tags=". $current_tags;
1707 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1708 $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
1711 $thumb_url = $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
1716 // <a href="%pictureurl%"><img src="%thumbnailurl%" ></a>
1717 print htmlspecialchars("<a href=\"". $orig_url ."\"><img src=\"". $thumb_url ."\" /></a>") ."<br />\n";
1721 // "[%pictureurl% %thumbnailurl%]"
1722 print htmlspecialchars("[".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
1725 case 'MoinMoinList':
1726 // " * [%pictureurl% %thumbnailurl%]"
1727 print " " . htmlspecialchars("* [".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
1738 public function getRSSFeed()
1740 Header("Content-type: text/xml; charset=utf-8");
1741 print "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
1744 xmlns:media="http://search.yahoo.com/mrss/"
1745 xmlns:dc="http://purl.org/dc/elements/1.1/"
1748 <title>phpfspot</title>
1749 <description>phpfspot RSS feed</description>
1750 <link><?php print htmlspecialchars($this->get_phpfspot_url()); ?></link>
1751 <pubDate><?php print strftime("%a, %d %b %Y %T %z"); ?></pubDate>
1752 <generator>phpfspot</generator>
1755 $pictures = $this->getPhotoSelection();
1756 $current_tags = $this->getCurrentTags();
1758 foreach($pictures as $picture) {
1760 $orig_url = $this->get_phpfspot_url() ."index.php?mode=showp&id=". $picture;
1761 if($current_tags != "") {
1762 $orig_url.= "&tags=". $current_tags;
1764 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1765 $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
1768 $details = $this->get_photo_details($picture);
1770 $thumb_url = $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
1771 $thumb_html = htmlspecialchars("
1772 <a href=\"". $orig_url ."\"><img src=\"". $thumb_url ."\" /></a>
1774 ". $details['description']);
1776 $orig_path = $this->translate_path($details['directory_path']) ."/". $details['name'];
1777 $meta = $this->get_meta_informations($orig_path);
1778 $meta_date = isset($meta['FileDateTime']) ? $meta['FileDateTime'] : filemtime($orig_path);
1782 <title><?php print htmlspecialchars($details['name']); ?></title>
1783 <link><?php print htmlspecialchars($orig_url); ?></link>
1784 <guid><?php print htmlspecialchars($orig_url); ?></guid>
1785 <dc:date.Taken><?php print strftime("%Y-%m-%dT%H:%M:%S+00:00", $meta_date); ?></dc:date.Taken>
1787 <?php print $thumb_html; ?>
1789 <pubDate><?php print strftime("%a, %d %b %Y %T %z", $meta_date); ?></pubDate>
1804 * return all selected tags as one string
1806 private function getCurrentTags()
1809 if($_SESSION['selected_tags'] != "") {
1810 foreach($_SESSION['selected_tags'] as $tag)
1811 $current_tags.= $tag .",";
1812 $current_tags = substr($current_tags, 0, strlen($current_tags)-1);
1814 return $current_tags;
1816 } // getCurrentTags()
1819 * return the current photo
1821 public function getCurrentPhoto()
1823 if(isset($_SESSION['current_photo'])) {
1824 print $_SESSION['current_photo'];
1826 } // getCurrentPhoto()
1829 * tells the client browser what to do
1831 * this function is getting called via AJAX by the
1832 * client browsers. it will tell them what they have
1833 * to do next. This is necessary for directly jumping
1834 * into photo index or single photo view when the are
1835 * requested with specific URLs
1837 public function whatToDo()
1839 if(isset($_SESSION['current_photo']) && $_SESSION['start_action'] == 'showp') {
1840 return "show_photo";
1842 elseif(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
1843 return "showpi_tags";
1845 elseif(isset($_SESSION['start_action']) && $_SESSION['start_action'] == 'showpi') {
1849 return "nothing special";
1854 * return the current process-user
1856 private function getuid()
1858 if($uid = posix_getuid()) {
1859 if($user = posix_getpwuid($uid)) {
1860 return $user['name'];
1869 * returns a select-dropdown box to select photo index sort parameters
1871 private function get_sort_field()
1873 $output = "<select name=\"sort_order\">";
1874 foreach(array('date_asc', 'date_desc', 'name_asc', 'name_desc') as $sort_order) {
1875 $output.= "<option value=\"". $sort_order ."\"";
1876 if($sort_order == $_SESSION['sort_order']) {
1877 $output.= " selected=\"selected\"";
1879 $output.= ">". $sort_order ."</option>";
1881 $output.= "</select>";
1884 } // get_sort_field()
1887 * returns the currently selected sort order
1889 private function get_sort_order()
1891 switch($_SESSION['sort_order']) {
1893 return " ORDER BY p.time ASC";
1896 return " ORDER BY p.time DESC";
1899 return " ORDER BY p.name ASC";
1902 return " ORDER BY p.name DESC";
1906 } // get_sort_order()
1909 * return the next to be shown slide show image
1911 * this function returns the URL of the next image
1912 * in the slideshow sequence.
1914 public function getNextSlideShowImage()
1916 $all_photos = $this->getPhotoSelection();
1918 if(!isset($_SESSION['slideshow_img']) || $_SESSION['slideshow_img'] == count($all_photos)-1)
1919 $_SESSION['slideshow_img'] = 0;
1921 $_SESSION['slideshow_img']++;
1923 return $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $all_photos[$_SESSION['slideshow_img']] ."&width=". $this->cfg->photo_width;
1925 } // getNextSlideShowImage()
1928 * return the previous to be shown slide show image
1930 * this function returns the URL of the previous image
1931 * in the slideshow sequence.
1933 public function getPrevSlideShowImage()
1935 $all_photos = $this->getPhotoSelection();
1937 if(!isset($_SESSION['slideshow_img']) || $_SESSION['slideshow_img'] == 0)
1938 $_SESSION['slideshow_img'] = 0;
1940 $_SESSION['slideshow_img']--;
1942 return $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $all_photos[$_SESSION['slideshow_img']] ."&width=". $this->cfg->photo_width;
1944 } // getPrevSlideShowImage()
1946 public function resetSlideShow()
1948 if(isset($_SESSION['slideshow_img']))
1949 unset($_SESSION['slideshow_img']);
1950 } // resetSlideShow()
1955 * this function will get all photos from the fspot
1956 * database and randomly return ONE entry
1958 * saddly there is yet no sqlite3 function which returns
1959 * the bulk result in array, so we have to fill up our
1962 public function get_random_photo()
1966 $result = $this->db->db_query("
1971 while($row = $this->db->db_fetch_object($result)) {
1972 array_push($all, $row['id']);
1975 return $all[array_rand($all)];
1977 } // get_random_photo()
1980 * validates provided date
1982 * this function validates if the provided date
1983 * contains a valid date and will return true
1986 public function isValidDate($date_str)
1988 $timestamp = strtotime($date_str);
1990 if(is_numeric($timestamp))
1998 * timestamp to string conversion
2000 private function ts2str($timestamp)
2002 return strftime("%Y-%m-%d", $timestamp);
2005 private function extractTags($tags_str)
2007 $not_validated = split(',', $_GET['tags']);
2008 $validated = array();
2010 foreach($not_validated as $tag) {
2011 if(is_numeric($tag))
2012 array_push($validated, $tag);
2020 * returns the full path to a thumbnail
2022 public function get_thumb_path($width, $photo)
2024 $md5 = $this->getMD5($photo);
2025 $sub_path = substr($md5, 0, 2);
2026 return $this->cfg->thumb_path
2034 } // get_thumb_path()
2037 * returns server's virtual host name
2039 private function get_server_name()
2041 return $_SERVER['SERVER_NAME'];
2042 } // get_server_name()
2045 * returns type of webprotocol which is
2048 private function get_web_protocol()
2050 if(!isset($_SERVER['HTTPS']))
2054 } // get_web_protocol()
2057 * return url to this phpfspot installation
2059 private function get_phpfspot_url()
2061 return $this->get_web_protocol() ."://". $this->get_server_name() . $this->cfg->web_path;
2062 } // get_phpfspot_url()
2065 * check file exists and is readable
2067 * returns true, if everything is ok, otherwise false
2068 * if $silent is not set, this function will output and
2071 private function check_readable($file, $silent = null)
2073 if(!file_exists($file)) {
2075 print "File \"". $file ."\" does not exist.\n";
2079 if(!is_readable($file)) {
2081 print "File \"". $file ."\" is not reachable for user ". $this->getuid() ."\n";
2087 } // check_readable()
2090 * check if all needed indices are present
2092 * this function checks, if some needed indices are already
2093 * present, or if not, create them on the fly. they are
2094 * necessary to speed up some queries like that one look for
2095 * all tags, when show_tags is specified in the configuration.
2097 private function checkDbIndices()
2099 $result = $this->db->db_exec("
2100 CREATE INDEX IF NOT EXISTS
2107 } // checkDbIndices()
2110 * retrive F-Spot database version
2112 * this function will return the F-Spot database version number
2113 * It is stored within the sqlite3 database in the table meta
2115 public function getFspotDBVersion()
2117 if($result = $this->db->db_fetchSingleRow("
2118 SELECT data as version
2121 name LIKE 'F-Spot Database Version'
2123 return $result['version'];
2127 } // getFspotDBVersion()