3 /***************************************************************************
5 * Copyright (c) by Andreas Unterkircher, unki@netshadow.at
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 ***************************************************************************/
24 require_once "phpfspot_cfg.php";
25 require_once "phpfspot_db.php";
39 * this function will be called on class construct
40 * and will check requirements, loads configuration,
41 * open databases and start the user session
43 public function __construct()
45 $this->cfg = new PHPFSPOT_CFG;
47 /* set application name and version information */
48 $this->cfg->product = "phpfspot";
49 $this->cfg->version = "1.2";
51 /* Check necessary requirements */
52 if(!$this->checkRequirements()) {
56 $this->db = new PHPFSPOT_DB($this, $this->cfg->fspot_db);
58 if(!is_writeable(dirname($this->cfg->phpfspot_db))) {
59 print dirname($this->cfg->phpfspot_db) .": directory is not writeable!";
63 $this->cfg_db = new PHPFSPOT_DB($this, $this->cfg->phpfspot_db);
64 if(!is_writeable($this->cfg->phpfspot_db)) {
65 print $this->cfg->phpfspot_db ." is not writeable for user ". $this->getuid() ."\n";
68 $this->check_config_table();
70 /* include Smarty template engine */
71 if(!$this->check_readable($this->cfg->smarty_path .'/libs/Smarty.class.php')) {
74 require $this->cfg->smarty_path .'/libs/Smarty.class.php';
75 /* overload Smarty class if our own template handler */
76 require_once "phpfspot_tmpl.php";
77 $this->tmpl = new PHPFSPOT_TMPL($this);
79 /* check if all necessary indices exist */
80 $this->checkDbIndices();
86 if(!isset($_SESSION['tag_condition']))
87 $_SESSION['tag_condition'] = 'or';
89 if(!isset($_SESSION['sort_order']))
90 $_SESSION['sort_order'] = 'date_asc';
92 if(!isset($_SESSION['searchfor']))
93 $_SESSION['searchfor'] = '';
95 // if begin_with is still set but rows_per_page is now 0, unset it
96 if(isset($_SESSION['begin_with']) && $this->cfg->rows_per_page == 0)
97 unset($_SESSION['begin_with']);
101 public function __destruct()
107 * show - generate html output
109 * this function can be called after the constructor has
110 * prepared everyhing. it will load the index.tpl smarty
111 * template. if necessary it will registere pre-selects
112 * (photo index, photo, tag search, date search) into
115 public function show()
117 $this->tmpl->assign('searchfor', $_SESSION['searchfor']);
118 $this->tmpl->assign('page_title', $this->cfg->page_title);
119 $this->tmpl->assign('current_condition', $_SESSION['tag_condition']);
120 $this->tmpl->assign('template_path', 'themes/'. $this->cfg->theme_name);
122 $_SESSION['start_action'] = $_GET['mode'];
124 switch($_GET['mode']) {
126 if(isset($_GET['tags'])) {
127 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
129 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
130 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
132 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
133 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
137 if(isset($_GET['tags'])) {
138 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
139 $_SESSION['start_action'] = 'showp';
141 if(isset($_GET['id']) && is_numeric($_GET['id'])) {
142 $_SESSION['current_photo'] = $_GET['id'];
143 $_SESSION['start_action'] = 'showp';
145 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
146 $_SESSION['from_date'] = strtotime($_GET['from_date']);
148 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
149 $_SESSION['to_date'] = strtotime($_GET['to_date']);
153 $this->tmpl->show("export.tpl");
157 $this->tmpl->show("slideshow.tpl");
161 if(isset($_GET['tags'])) {
162 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
164 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
165 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
167 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
168 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
175 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date']))
176 $this->tmpl->assign('date_search_enabled', true);
178 $this->tmpl->assign('from_date', $this->get_calendar('from'));
179 $this->tmpl->assign('to_date', $this->get_calendar('to'));
180 $this->tmpl->assign('sort_field', $this->get_sort_field());
181 $this->tmpl->assign('content_page', 'welcome.tpl');
182 $this->tmpl->show("index.tpl");
187 * get_tags - grab all tags of f-spot's database
189 * this function will get all available tags from
190 * the f-spot database and store them within two
191 * arrays within this class for later usage. in
192 * fact, if the user requests (hide_tags) it will
193 * opt-out some of them.
195 * this function is getting called once by show()
197 private function get_tags()
199 $this->avail_tags = Array();
202 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
205 DISTINCT t1.id as id, t1.name as name
208 INNER JOIN photo_tags
209 pt2 ON pt1.photo_id=pt2.photo_id
215 t2.name IN ('".implode("','",$this->cfg->show_tags)."')
217 t1.sort_priority ASC";
219 $result = $this->db->db_query($query_str);
223 $result = $this->db->db_query("
226 ORDER BY sort_priority ASC
230 while($row = $this->db->db_fetch_object($result)) {
232 $tag_id = $row['id'];
233 $tag_name = $row['name'];
235 /* if the user has specified to ignore this tag in phpfspot's
236 configuration, ignore it here so it does not get added to
239 if(in_array($row['name'], $this->cfg->hide_tags))
242 /* if you include the following if-clause and the user has specified
243 to only show certain tags which are specified in phpfspot's
244 configuration, ignore all others so they will not be added to the
246 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags) &&
247 !in_array($row['name'], $this->cfg->show_tags))
251 $this->tags[$tag_id] = $tag_name;
252 $this->avail_tags[$count] = $tag_id;
260 * extract all photo details
262 * retrieve all available details from f-spot's
263 * database and return them as object
265 public function get_photo_details($idx)
268 SELECT p.id, p.name, p.time, p.directory_path, p.description
272 /* if show_tags is set, only return details for photos which
273 are specified to be shown
275 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
277 INNER JOIN photo_tags pt
281 WHERE p.id='". $idx ."'
282 AND t.name IN ('".implode("','",$this->cfg->show_tags)."')";
286 WHERE p.id='". $idx ."'
290 $result = $this->db->db_query($query_str);
291 return $this->db->db_fetch_object($result);
293 } // get_photo_details
296 * returns aligned photo names
298 * this function returns aligned (length) names for
299 * an specific photo. If the length of the name exceeds
300 * $limit the name will be shrinked (...)
302 public function getPhotoName($idx, $limit = 0)
304 if($details = $this->get_photo_details($idx)) {
305 $name = $this->shrink_text($details['name'], $limit);
312 * shrink text according provided limit
314 * If the length of the name exceeds $limit the
315 * text will be shortend and some content in between
316 * will be replaced with "..."
318 private function shrink_text($text, $limit)
320 if($limit != 0 && strlen($text) > $limit) {
321 $text = substr($text, 0, $limit-5) ."...". substr($text, -($limit-5));
329 * translate f-spoth photo path
331 * as the full-qualified path recorded in the f-spot database
332 * is usally not the same as on the webserver, this function
333 * will replace the path with that one specified in the cfg
335 public function translate_path($path, $width = 0)
337 return str_replace($this->cfg->path_replace_from, $this->cfg->path_replace_to, $path);
342 * control HTML ouput for a single photo
344 * this function provides all the necessary information
345 * for the single photo template.
347 public function showPhoto($photo)
349 /* get all photos from the current photo selection */
350 $all_photos = $this->getPhotoSelection();
351 $count = count($all_photos);
353 for($i = 0; $i < $count; $i++) {
355 // $get_next will be set, when the photo which has to
356 // be displayed has been found - this means that the
357 // next available is in fact the NEXT image (for the
359 if(isset($get_next)) {
360 $next_img = $all_photos[$i];
364 /* the next photo is our NEXT photo */
365 if($all_photos[$i] == $photo) {
369 $previous_img = $all_photos[$i];
372 if($photo == $all_photos[$i]) {
377 $details = $this->get_photo_details($photo);
384 $orig_path = $this->translate_path($details['directory_path']) ."/". $details['name'];
385 $thumb_path = $this->get_thumb_path($this->cfg->photo_width, $photo);
387 if(!file_exists($orig_path)) {
388 $this->_error("Photo ". $orig_path ." does not exist!<br />\n");
391 if(!is_readable($orig_path)) {
392 $this->_error("Photo ". $orig_path ." is not readable for user ". $this->getuid() ."<br />\n");
395 /* If the thumbnail doesn't exist yet, try to create it */
396 if(!file_exists($thumb_path)) {
397 $this->gen_thumb($photo, true);
398 $thumb_path = $this->get_thumb_path($this->cfg->photo_width, $photo);
401 /* get f-spot database meta information */
402 $meta = $this->get_meta_informations($orig_path);
404 /* If EXIF data are available, use them */
405 if(isset($meta['ExifImageWidth'])) {
406 $meta_res = $meta['ExifImageWidth'] ."x". $meta['ExifImageLength'];
408 $info = getimagesize($orig_path);
409 $meta_res = $info[0] ."x". $info[1];
412 $meta_date = isset($meta['FileDateTime']) ? strftime("%a %x %X", $meta['FileDateTime']) : "n/a";
413 $meta_make = isset($meta['Make']) ? $meta['Make'] ." / ". $meta['Model'] : "n/a";
414 $meta_size = isset($meta['FileSize']) ? round($meta['FileSize']/1024, 1) ."kbyte" : "n/a";
416 $extern_link = "index.php?mode=showp&id=". $photo;
417 $current_tags = $this->getCurrentTags();
418 if($current_tags != "") {
419 $extern_link.= "&tags=". $current_tags;
421 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
422 $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
425 $this->tmpl->assign('extern_link', $extern_link);
427 if(file_exists($thumb_path)) {
429 $info = getimagesize($thumb_path);
431 $this->tmpl->assign('description', $details['description']);
432 $this->tmpl->assign('image_name', $details['name']);
434 $this->tmpl->assign('width', $info[0]);
435 $this->tmpl->assign('height', $info[1]);
436 $this->tmpl->assign('ExifMadeOn', $meta_date);
437 $this->tmpl->assign('ExifMadeWith', $meta_make);
438 $this->tmpl->assign('ExifOrigResolution', $meta_res);
439 $this->tmpl->assign('ExifFileSize', $meta_size);
441 $this->tmpl->assign('image_url', 'phpfspot_img.php?idx='. $photo ."&width=". $this->cfg->photo_width);
442 $this->tmpl->assign('image_url_full', 'phpfspot_img.php?idx='. $photo);
444 $this->tmpl->assign('tags', $this->get_photo_tags($photo));
445 $this->tmpl->assign('current', $current);
448 $this->_error("Can't open file ". $thumb_path ."\n");
453 $this->tmpl->assign('previous_url', "javascript:showImage(". $previous_img .");");
454 $this->tmpl->assign('prev_img', $previous_img);
458 $this->tmpl->assign('next_url', "javascript:showImage(". $next_img .");");
459 $this->tmpl->assign('next_img', $next_img);
461 $this->tmpl->assign('mini_width', $this->cfg->mini_width);
462 $this->tmpl->assign('photo_number', $i);
463 $this->tmpl->assign('photo_count', count($all_photos));
465 $this->tmpl->show("single_photo.tpl");
470 * all available tags and tag cloud
472 * this function outputs all available tags (time ordered)
473 * and in addition output them as tag cloud (tags which have
474 * many photos will appears more then others)
476 public function getAvailableTags()
480 $result = $this->db->db_query("
481 SELECT tag_id as id, count(tag_id) as quantity
491 while($row = $this->db->db_fetch_object($result)) {
492 $tags[$row['id']] = $row['quantity'];
495 // change these font sizes if you will
496 $max_size = 125; // max font size in %
497 $min_size = 75; // min font size in %
499 // get the largest and smallest array values
500 $max_qty = max(array_values($tags));
501 $min_qty = min(array_values($tags));
503 // find the range of values
504 $spread = $max_qty - $min_qty;
505 if (0 == $spread) { // we don't want to divide by zero
509 // determine the font-size increment
510 // this is the increase per tag quantity (times used)
511 $step = ($max_size - $min_size)/($spread);
513 // loop through our tag array
514 foreach ($tags as $key => $value) {
516 if(isset($_SESSION['selected_tags']) && in_array($key, $_SESSION['selected_tags']))
519 // calculate CSS font-size
520 // find the $value in excess of $min_qty
521 // multiply by the font-size increment ($size)
522 // and add the $min_size set above
523 $size = $min_size + (($value - $min_qty) * $step);
524 // uncomment if you want sizes in whole %:
527 if(isset($this->tags[$key])) {
528 $output.= "<a href=\"javascript:Tags('add', ". $key .");\" class=\"tag\" style=\"font-size: ". $size ."%;\">". $this->tags[$key] ."</a>, ";
533 $output = substr($output, 0, strlen($output)-2);
536 } // getAvailableTags()
539 * output all selected tags
541 * this function output all tags which have been selected
542 * by the user. the selected tags are stored in the
543 * session-variable $_SESSION['selected_tags']
545 public function getSelectedTags()
548 foreach($this->avail_tags as $tag)
550 // return all selected tags
551 if(isset($_SESSION['selected_tags']) && in_array($tag, $_SESSION['selected_tags'])) {
552 $output.= "<a href=\"javascript:Tags('del', ". $tag .");\" class=\"tag\">". $this->tags[$tag] ."</a>, ";
556 $output = substr($output, 0, strlen($output)-2);
559 } // getSelectedTags()
562 * add tag to users session variable
564 * this function will add the specified to users current
565 * tag selection. if a date search has been made before
566 * it will be now cleared
568 public function addTag($tag)
570 if(!isset($_SESSION['selected_tags']))
571 $_SESSION['selected_tags'] = Array();
573 if(!in_array($tag, $_SESSION['selected_tags']))
574 array_push($_SESSION['selected_tags'], $tag);
579 * remove tag to users session variable
581 * this function removes the specified tag from
582 * users current tag selection
584 public function delTag($tag)
586 if(isset($_SESSION['selected_tags'])) {
587 $key = array_search($tag, $_SESSION['selected_tags']);
588 unset($_SESSION['selected_tags'][$key]);
589 sort($_SESSION['selected_tags']);
595 * reset tag selection
597 * if there is any tag selection, it will be
600 public function resetTags()
602 if(isset($_SESSION['selected_tags']))
603 unset($_SESSION['selected_tags']);
610 * if a specific photo was requested (external link)
611 * unset the session variable now
613 public function resetPhotoView()
615 if(isset($_SESSION['current_photo']))
616 unset($_SESSION['current_photo']);
618 } // resetPhotoView();
623 * if any tag search has taken place, reset
626 public function resetTagSearch()
628 if(isset($_SESSION['searchfor']))
629 unset($_SESSION['searchfor']);
631 } // resetTagSearch()
636 * if any date search has taken place, reset
639 public function resetDateSearch()
641 if(isset($_SESSION['from_date']))
642 unset($_SESSION['from_date']);
643 if(isset($_SESSION['to_date']))
644 unset($_SESSION['to_date']);
646 } // resetDateSearch();
649 * return all photo according selection
651 * this function returns all photos based on
652 * the tag-selection, tag- or date-search.
653 * the tag-search also has to take care of AND
654 * and OR conjunctions
656 public function getPhotoSelection()
658 $matched_photos = Array();
660 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
661 $from_date = $_SESSION['from_date'];
662 $to_date = $_SESSION['to_date'];
663 $additional_where_cond = "
664 p.time>='". $from_date ."'
666 p.time<='". $to_date ."'
670 if(isset($_SESSION['sort_order'])) {
671 $order_str = $this->get_sort_order();
674 /* return a search result */
675 if(isset($_SESSION['searchfor']) && $_SESSION['searchfor'] != '') {
677 SELECT DISTINCT pt1.photo_id
679 INNER JOIN photo_tags pt2
680 ON pt1.photo_id=pt2.photo_id
687 WHERE t1.name LIKE '%". $_SESSION['searchfor'] ."%' ";
689 if(isset($additional_where_cond))
690 $query_str.= "AND ". $additional_where_cond ." ";
692 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
693 $query_str.= "AND t2.name IN ('".implode("','",$this->cfg->show_tags)."')";
696 if(isset($order_str))
697 $query_str.= $order_str;
699 $result = $this->db->db_query($query_str);
700 while($row = $this->db->db_fetch_object($result)) {
701 array_push($matched_photos, $row['photo_id']);
703 return $matched_photos;
706 /* return according the selected tags */
707 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
709 foreach($_SESSION['selected_tags'] as $tag)
710 $selected.= $tag .",";
711 $selected = substr($selected, 0, strlen($selected)-1);
713 /* photo has to match at least on of the selected tags */
714 if($_SESSION['tag_condition'] == 'or') {
716 SELECT DISTINCT pt1.photo_id
718 INNER JOIN photo_tags pt2
719 ON pt1.photo_id=pt2.photo_id
724 WHERE pt1.tag_id IN (". $selected .")
726 if(isset($additional_where_cond))
727 $query_str.= "AND ". $additional_where_cond ." ";
729 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
730 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags)."')";
733 if(isset($order_str))
734 $query_str.= $order_str;
736 /* photo has to match all selected tags */
737 elseif($_SESSION['tag_condition'] == 'and') {
739 if(count($_SESSION['selected_tags']) >= 32) {
740 print "A SQLite limit of 32 tables within a JOIN SELECT avoids to<br />\n";
741 print "evaluate your tag selection. Please remove some tags from your selection.\n";
745 /* Join together a table looking like
747 pt1.photo_id pt1.tag_id pt2.photo_id pt2.tag_id ...
749 so the query can quickly return all images matching the
750 selected tags in an AND condition
755 SELECT DISTINCT pt1.photo_id
759 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
766 for($i = 0; $i < count($_SESSION['selected_tags']); $i++) {
768 INNER JOIN photo_tags pt". ($i+2) ."
769 ON pt1.photo_id=pt". ($i+2) .".photo_id
776 $query_str.= "WHERE pt2.tag_id=". $_SESSION['selected_tags'][0]." ";
777 for($i = 1; $i < count($_SESSION['selected_tags']); $i++) {
779 AND pt". ($i+2) .".tag_id=". $_SESSION['selected_tags'][$i] ."
782 if(isset($additional_where_cond))
783 $query_str.= "AND ". $additional_where_cond;
785 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
786 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags). "')";
789 if(isset($order_str))
790 $query_str.= $order_str;
794 $result = $this->db->db_query($query_str);
795 while($row = $this->db->db_fetch_object($result)) {
796 array_push($matched_photos, $row['photo_id']);
798 return $matched_photos;
801 /* return all available photos */
803 SELECT DISTINCT photo_id
810 if(isset($additional_where_cond))
811 $query_str.= "WHERE ". $additional_where_cond ." ";
813 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
814 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags). "')";
817 if(isset($order_str))
818 $query_str.= $order_str;
820 $result = $this->db->db_query($query_str);
821 while($row = $this->db->db_fetch_object($result)) {
822 array_push($matched_photos, $row['photo_id']);
824 return $matched_photos;
826 } // getPhotoSelection()
829 * control HTML ouput for photo index
831 * this function provides all the necessary information
832 * for the photo index template.
834 public function showPhotoIndex()
836 $photos = $this->getPhotoSelection();
838 $count = count($photos);
840 if(isset($_SESSION['begin_with']) && $_SESSION['begin_with'] != "")
841 $anchor = $_SESSION['begin_with'];
843 if(!isset($this->cfg->rows_per_page) || $this->cfg->rows_per_page == 0) {
849 elseif($this->cfg->rows_per_page > 0) {
851 if(!$_SESSION['begin_with'] || $_SESSION['begin_with'] == 0)
855 $begin_with = $_SESSION['begin_with'];
857 // verify $begin_with - perhaps the thumbs-per-rows or
858 // rows-per-page variables have changed or the jump back
859 // from a photo wasn't exact - so calculate the real new
861 $multiplicator = $this->cfg->rows_per_page * $this->cfg->thumbs_per_row;
862 for($i = 0; $i <= $count; $i+=$multiplicator) {
863 if($begin_with >= $i && $begin_with < $i+$multiplicator) {
870 $end_with = $begin_with + ($this->cfg->rows_per_page * $this->cfg->thumbs_per_row);
876 $images[$rows] = Array();
877 $img_height[$rows] = Array();
878 $img_width[$rows] = Array();
879 $img_id[$rows] = Array();
880 $img_name[$rows] = Array();
881 $img_title = Array();
883 for($i = $begin_with; $i < $end_with; $i++) {
885 $images[$rows][$cols] = $photos[$i];
886 $img_id[$rows][$cols] = $i;
887 $img_name[$rows][$cols] = htmlspecialchars($this->getPhotoName($photos[$i], 15));
888 $img_title[$rows][$cols] = "Click to view photo ". htmlspecialchars($this->getPhotoName($photos[$i], 0));
890 $thumb_path = $this->get_thumb_path($this->cfg->thumb_width, $photos[$i]);
892 if(file_exists($thumb_path)) {
893 $info = getimagesize($thumb_path);
894 $img_width[$rows][$cols] = $info[0];
895 $img_height[$rows][$cols] = $info[1];
898 if($cols == $this->cfg->thumbs_per_row-1) {
901 $images[$rows] = Array();
902 $img_width[$rows] = Array();
903 $img_height[$rows] = Array();
910 // +1 for for smarty's selection iteration
913 if(isset($_SESSION['searchfor']) && $_SESSION['searchfor'] != '')
914 $this->tmpl->assign('searchfor', $_SESSION['searchfor']);
916 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
917 $this->tmpl->assign('from_date', $this->ts2str($_SESSION['from_date']));
918 $this->tmpl->assign('to_date', $this->ts2str($_SESSION['to_date']));
921 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
922 $this->tmpl->assign('tag_result', 1);
925 /* do we have to display the page selector ? */
926 if($this->cfg->rows_per_page != 0) {
928 /* calculate the page switchers */
929 $previous_start = $begin_with - ($this->cfg->rows_per_page * $this->cfg->thumbs_per_row);
930 $next_start = $begin_with + ($this->cfg->rows_per_page * $this->cfg->thumbs_per_row);
933 $this->tmpl->assign("previous_url", "javascript:showPhotoIndex(". $previous_start .");");
934 if($end_with < $count)
935 $this->tmpl->assign("next_url", "javascript:showPhotoIndex(". $next_start .");");
937 $photo_per_page = $this->cfg->rows_per_page * $this->cfg->thumbs_per_row;
938 $last_page = ceil($count / $photo_per_page);
940 /* get the current selected page */
941 if($begin_with == 0) {
945 for($i = $begin_with; $i >= 0; $i-=$photo_per_page) {
952 for($i = 1; $i <= $last_page; $i++) {
954 if($current_page == $i)
955 $style = "style=\"font-size: 125%; text-decoration: underline;\"";
956 elseif($current_page-1 == $i || $current_page+1 == $i)
957 $style = "style=\"font-size: 105%;\"";
958 elseif(($current_page-5 >= $i) && ($i != 1) ||
959 ($current_page+5 <= $i) && ($i != $last_page))
960 $style = "style=\"font-size: 75%;\"";
964 $select = "<a href=\"javascript:showPhotoIndex(". (($i*$photo_per_page)-$photo_per_page) .");\"";
967 $select.= ">". $i ."</a> ";
969 // until 9 pages we show the selector from 1-9
970 if($last_page <= 9) {
971 $page_select.= $select;
974 if($i == 1 /* first page */ ||
975 $i == $last_page /* last page */ ||
976 $i == $current_page /* current page */ ||
977 $i == ceil($last_page * 0.25) /* first quater */ ||
978 $i == ceil($last_page * 0.5) /* half */ ||
979 $i == ceil($last_page * 0.75) /* third quater */ ||
980 (in_array($i, array(1,2,3,4,5,6)) && $current_page <= 4) /* the first 6 */ ||
981 (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 */ ||
982 $i == $current_page-3 || $i == $current_page-2 || $i == $current_page-1 /* three before */ ||
983 $i == $current_page+3 || $i == $current_page+2 || $i == $current_page+1 /* three after */) {
985 $page_select.= $select;
993 $page_select.= "......... ";
998 /* only show the page selector if we have more then one page */
1000 $this->tmpl->assign('page_selector', $page_select);
1004 $current_tags = $this->getCurrentTags();
1005 $extern_link = "index.php?mode=showpi";
1006 $rss_link = "index.php?mode=rss";
1007 if($current_tags != "") {
1008 $extern_link.= "&tags=". $current_tags;
1009 $rss_link.= "&tags=". $current_tags;
1011 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1012 $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
1013 $rss_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
1016 $export_link = "index.php?mode=export";
1017 $slideshow_link = "index.php?mode=slideshow";
1019 $this->tmpl->assign('extern_link', $extern_link);
1020 $this->tmpl->assign('slideshow_link', $slideshow_link);
1021 $this->tmpl->assign('export_link', $export_link);
1022 $this->tmpl->assign('rss_link', $rss_link);
1023 $this->tmpl->assign('count', $count);
1024 $this->tmpl->assign('width', $this->cfg->thumb_width);
1025 $this->tmpl->assign('images', $images);
1026 $this->tmpl->assign('img_width', $img_width);
1027 $this->tmpl->assign('img_height', $img_height);
1028 $this->tmpl->assign('img_id', $img_id);
1029 $this->tmpl->assign('img_name', $img_name);
1030 $this->tmpl->assign('img_title', $img_title);
1031 $this->tmpl->assign('rows', $rows);
1032 $this->tmpl->assign('columns', $this->cfg->thumbs_per_row);
1034 $this->tmpl->show("photo_index.tpl");
1037 print "<script language=\"JavaScript\">self.location.hash = '#image". $anchor ."';</script>\n";
1039 } // showPhotoIndex()
1042 * show credit template
1044 public function showCredits()
1046 $this->tmpl->assign('version', $this->cfg->version);
1047 $this->tmpl->assign('product', $this->cfg->product);
1048 $this->tmpl->show("credits.tpl");
1053 * create_thumbnails for the requested width
1055 * this function creates image thumbnails of $orig_image
1056 * stored as $thumb_image. It will check if the image is
1057 * in a supported format, if necessary rotate the image
1058 * (based on EXIF orientation meta headers) and re-sizing.
1060 public function create_thumbnail($orig_image, $thumb_image, $width)
1062 if(!file_exists($orig_image)) {
1066 $details = getimagesize($orig_image);
1068 /* check if original photo is a support image type */
1069 if(!$this->checkifImageSupported($details['mime']))
1072 $meta = $this->get_meta_informations($orig_image);
1077 switch($meta['Orientation']) {
1079 case 1: /* top, left */
1080 $rotate = 0; $flip = false; break;
1081 case 2: /* top, right */
1082 $rotate = 0; $flip = true; break;
1083 case 3: /* bottom, left */
1084 $rotate = 180; $flip = false; break;
1085 case 4: /* bottom, right */
1086 $rotate = 180; $flip = true; break;
1087 case 5: /* left side, top */
1088 $rotate = 90; $flip = true; break;
1089 case 6: /* right side, top */
1090 $rotate = 90; $flip = false; break;
1091 case 7: /* left side, bottom */
1092 $rotate = 270; $flip = true; break;
1093 case 8: /* right side, bottom */
1094 $rotate = 270; $flip = false; break;
1097 $src_img = @imagecreatefromjpeg($orig_image);
1100 print "Can't load image from ". $orig_image ."\n";
1104 /* grabs the height and width */
1105 $cur_width = imagesx($src_img);
1106 $cur_height = imagesy($src_img);
1108 // If requested width is more then the actual image width,
1109 // do not generate a thumbnail, instead safe the original
1110 // as thumbnail but with lower quality
1112 if($width >= $cur_width) {
1113 $result = imagejpeg($src_img, $thumb_image, 75);
1114 imagedestroy($src_img);
1118 // If the image will be rotate because EXIF orientation said so
1119 // 'virtually rotate' the image for further calculations
1120 if($rotate == 90 || $rotate == 270) {
1122 $cur_width = $cur_height;
1126 /* calculates aspect ratio */
1127 $aspect_ratio = $cur_height / $cur_width;
1130 if($aspect_ratio < 1) {
1132 $new_h = abs($new_w * $aspect_ratio);
1134 /* 'virtually' rotate the image and calculate it's ratio */
1135 $tmp_w = $cur_height;
1136 $tmp_h = $cur_width;
1137 /* now get the ratio from the 'rotated' image */
1138 $tmp_ratio = $tmp_h/$tmp_w;
1139 /* now calculate the new dimensions */
1141 $tmp_h = abs($tmp_w * $tmp_ratio);
1143 // now that we know, how high they photo should be, if it
1144 // gets rotated, use this high to scale the image
1146 $new_w = abs($new_h / $aspect_ratio);
1148 // If the image will be rotate because EXIF orientation said so
1149 // now 'virtually rotate' back the image for the image manipulation
1150 if($rotate == 90 || $rotate == 270) {
1157 /* creates new image of that size */
1158 $dst_img = imagecreatetruecolor($new_w, $new_h);
1160 imagefill($dst_img, 0, 0, ImageColorAllocate($dst_img, 255, 255, 255));
1162 /* copies resized portion of original image into new image */
1163 imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $new_w, $new_h, imagesx($src_img), imagesy($src_img));
1165 /* needs the image to be flipped horizontal? */
1169 for($x = 0; $x < $new_w; $x++) {
1170 imagecopy($dst_img, $image, $x, 0, $w - $x - 1, 0, 1, $h);
1175 $this->_debug("(ROTATE)");
1176 $dst_img = $this->rotateImage($dst_img, $rotate);
1179 /* write down new generated file */
1180 $result = imagejpeg($dst_img, $thumb_image, 75);
1182 /* free your mind */
1183 imagedestroy($dst_img);
1184 imagedestroy($src_img);
1186 if($result === false) {
1187 print "Can't write thumbnail ". $thumb_image ."\n";
1193 } // create_thumbnail()
1196 * return all exif meta data from the file
1198 public function get_meta_informations($file)
1200 return exif_read_data($file);
1202 } // get_meta_informations()
1205 * create phpfspot own sqlite database
1207 * this function creates phpfspots own sqlite database
1208 * if it does not exist yet. this own is used to store
1209 * some necessary informations (md5 sum's, ...).
1211 public function check_config_table()
1213 // if the config table doesn't exist yet, create it
1214 if(!$this->cfg_db->db_check_table_exists("images")) {
1215 $this->cfg_db->db_exec("
1216 CREATE TABLE images (
1217 img_idx int primary key,
1223 } // check_config_table
1226 * Generates a thumbnail from photo idx
1228 * This function will generate JPEG thumbnails from provided F-Spot photo
1231 * 1. Check if all thumbnail generations (width) are already in place and
1233 * 2. Check if the md5sum of the original file has changed
1234 * 3. Generate the thumbnails if needed
1236 public function gen_thumb($idx = 0, $force = 0)
1240 $resolutions = Array(
1241 $this->cfg->thumb_width,
1242 $this->cfg->photo_width,
1243 $this->cfg->mini_width,
1246 /* get details from F-Spot's database */
1247 $details = $this->get_photo_details($idx);
1249 /* calculate file MD5 sum */
1250 $full_path = $this->translate_path($details['directory_path']) ."/". $details['name'];
1252 if(!file_exists($full_path)) {
1253 $this->_error("File ". $full_path ." does not exist\n");
1257 if(!is_readable($full_path)) {
1258 $this->_error("File ". $full_path ." is not readable for ". $this->getuid() ."\n");
1262 $file_md5 = md5_file($full_path);
1264 $this->_debug("Image [". $idx ."] ". $this->shrink_text($details['name'], 20) ." Thumbnails:");
1266 foreach($resolutions as $resolution) {
1268 $thumb_sub_path = substr($file_md5, 0, 2);
1269 $thumb_path = $this->cfg->thumb_path ."/". $thumb_sub_path ."/". $resolution ."_". $file_md5;
1271 if(!file_exists(dirname($thumb_path))) {
1272 mkdir(dirname($thumb_path), 0755);
1275 /* if the thumbnail file doesn't exist, create it */
1276 if(!file_exists($thumb_path)) {
1278 $this->_debug(" ". $resolution ."px");
1279 if(!$this->create_thumbnail($full_path, $thumb_path, $resolution))
1282 /* if the file hasn't changed there is no need to regen the thumb */
1283 elseif($file_md5 != $this->getMD5($idx) || $force) {
1285 $this->_debug(" ". $resolution ."px");
1286 if(!$this->create_thumbnail($full_path, $thumb_path, $resolution))
1292 /* set the new/changed MD5 sum for the current photo */
1294 $this->setMD5($idx, $file_md5);
1297 $this->_debug("\n");
1302 * returns stored md5 sum for a specific photo
1304 * this function queries the phpfspot database for a
1305 * stored MD5 checksum of the specified photo
1307 public function getMD5($idx)
1309 $result = $this->cfg_db->db_query("
1312 WHERE img_idx='". $idx ."'
1318 $img = $this->cfg_db->db_fetch_object($result);
1319 return $img['img_md5'];
1324 * set MD5 sum for the specific photo
1326 private function setMD5($idx, $md5)
1328 $result = $this->cfg_db->db_exec("
1329 REPLACE INTO images (img_idx, img_md5)
1330 VALUES ('". $idx ."', '". $md5 ."')
1336 * store current tag condition
1338 * this function stores the current tag condition
1339 * (AND or OR) in the users session variables
1341 public function setTagCondition($mode)
1343 $_SESSION['tag_condition'] = $mode;
1345 } // setTagCondition()
1348 * invoke tag & date search
1350 * this function will return all matching tags and store
1351 * them in the session variable selected_tags. furthermore
1352 * it also handles the date search.
1353 * getPhotoSelection() will then only return the matching
1356 public function startSearch($searchfor, $sort_order, $from = 0, $to = 0)
1358 $_SESSION['searchfor'] = $searchfor;
1359 $_SESSION['sort_order'] = $sort_order;
1361 $_SESSION['from_date'] = strtotime($from);
1363 unset($_SESSION['from_date']);
1365 $_SESSION['to_date'] = strtotime($to);
1367 unset($_SESSION['to_date']);
1369 if($searchfor != "") {
1370 /* new search, reset the current selected tags */
1371 $_SESSION['selected_tags'] = Array();
1372 foreach($this->avail_tags as $tag) {
1373 if(preg_match('/'. $searchfor .'/i', $this->tags[$tag]))
1374 array_push($_SESSION['selected_tags'], $tag);
1383 * this function rotates the image according the
1386 private function rotateImage($img, $degrees)
1388 if(function_exists("imagerotate")) {
1389 $img = imagerotate($img, $degrees, 0);
1391 function imagerotate($src_img, $angle)
1393 $src_x = imagesx($src_img);
1394 $src_y = imagesy($src_img);
1395 if ($angle == 180) {
1399 elseif ($src_x <= $src_y) {
1403 elseif ($src_x >= $src_y) {
1408 $rotate=imagecreatetruecolor($dest_x,$dest_y);
1409 imagealphablending($rotate, false);
1414 for ($y = 0; $y < ($src_y); $y++) {
1415 for ($x = 0; $x < ($src_x); $x++) {
1416 $color = imagecolorat($src_img, $x, $y);
1417 imagesetpixel($rotate, $dest_x - $y - 1, $x, $color);
1423 for ($y = 0; $y < ($src_y); $y++) {
1424 for ($x = 0; $x < ($src_x); $x++) {
1425 $color = imagecolorat($src_img, $x, $y);
1426 imagesetpixel($rotate, $y, $dest_y - $x - 1, $color);
1432 for ($y = 0; $y < ($src_y); $y++) {
1433 for ($x = 0; $x < ($src_x); $x++) {
1434 $color = imagecolorat($src_img, $x, $y);
1435 imagesetpixel($rotate, $dest_x - $x - 1, $dest_y - $y - 1, $color);
1449 $img = imagerotate($img, $degrees);
1458 * return all assigned tags for the specified photo
1460 private function get_photo_tags($idx)
1462 $result = $this->db->db_query("
1465 INNER JOIN photo_tags pt
1467 WHERE pt.photo_id='". $idx ."'
1472 while($row = $this->db->db_fetch_object($result))
1473 $tags[$row['id']] = $row['name'];
1477 } // get_photo_tags()
1480 * create on-the-fly images with text within
1482 public function showTextImage($txt, $color=000000, $space=4, $font=4, $w=300)
1484 if (strlen($color) != 6)
1487 $int = hexdec($color);
1488 $h = imagefontheight($font);
1489 $fw = imagefontwidth($font);
1490 $txt = explode("\n", wordwrap($txt, ($w / $fw), "\n"));
1491 $lines = count($txt);
1492 $im = imagecreate($w, (($h * $lines) + ($lines * $space)));
1493 $bg = imagecolorallocate($im, 255, 255, 255);
1494 $color = imagecolorallocate($im, 0xFF & ($int >> 0x10), 0xFF & ($int >> 0x8), 0xFF & $int);
1497 foreach ($txt as $text) {
1498 $x = (($w - ($fw * strlen($text))) / 2);
1499 imagestring($im, $font, $x, $y, $text, $color);
1500 $y += ($h + $space);
1503 Header("Content-type: image/png");
1506 } // showTextImage()
1509 * check if all requirements are met
1511 private function checkRequirements()
1513 if(!function_exists("imagecreatefromjpeg")) {
1514 print "PHP GD library extension is missing<br />\n";
1518 if($this->cfg->db_access == "native" && !function_exists("sqlite3_open")) {
1519 print "PHP SQLite3 library extension is missing<br />\n";
1523 /* Check for HTML_AJAX PEAR package, lent from Horde project */
1524 ini_set('track_errors', 1);
1525 @include_once 'HTML/AJAX/Server.php';
1526 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
1527 print "PEAR HTML_AJAX package is missing<br />\n";
1530 @include_once 'Calendar/Calendar.php';
1531 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
1532 print "PEAR Calendar package is missing<br />\n";
1535 ini_restore('track_errors');
1542 } // checkRequirements()
1544 private function _debug($text)
1546 if($this->fromcmd) {
1553 * check if specified MIME type is supported
1555 public function checkifImageSupported($mime)
1557 if(in_array($mime, Array("image/jpeg")))
1562 } // checkifImageSupported()
1564 public function _error($text)
1566 switch($this->cfg->logging) {
1568 print "<img src=\"resources/green_info.png\" alt=\"warning\" />\n";
1575 error_log($text, 3, $his->cfg->log_file);
1582 * output calendard input fields
1584 private function get_calendar($mode)
1586 $year = $_SESSION[$mode .'_date'] ? date("Y", $_SESSION[$mode .'_date']) : date("Y");
1587 $month = $_SESSION[$mode .'_date'] ? date("m", $_SESSION[$mode .'_date']) : date("m");
1588 $day = $_SESSION[$mode .'_date'] ? date("d", $_SESSION[$mode .'_date']) : date("d");
1590 $output = "<input type=\"text\" size=\"3\" id=\"". $mode ."year\" value=\"". $year ."\"";
1591 if(!isset($_SESSION[$mode .'_date'])) $output.= " disabled=\"disabled\"";
1593 $output.= "<input type=\"text\" size=\"1\" id=\"". $mode ."month\" value=\"". $month ."\"";
1594 if(!isset($_SESSION[$mode .'_date'])) $output.= " disabled=\"disabled\"";
1596 $output.= "<input type=\"text\" size=\"1\" id=\"". $mode ."day\" value=\"". $day ."\"";
1597 if(!isset($_SESSION[$mode .'_date'])) $output.= " disabled=\"disabled\"";
1604 * output calendar matrix
1606 public function get_calendar_matrix($year = 0, $month = 0, $day = 0)
1608 if (!isset($year)) $year = date('Y');
1609 if (!isset($month)) $month = date('m');
1610 if (!isset($day)) $day = date('d');
1615 require_once CALENDAR_ROOT.'Month/Weekdays.php';
1616 require_once CALENDAR_ROOT.'Day.php';
1619 $month = new Calendar_Month_Weekdays($year,$month);
1622 $prevStamp = $month->prevMonth(true);
1623 $prev = "javascript:setMonth(". date('Y',$prevStamp) .", ". date('n',$prevStamp) .", ". date('j',$prevStamp) .");";
1624 $nextStamp = $month->nextMonth(true);
1625 $next = "javascript:setMonth(". date('Y',$nextStamp) .", ". date('n',$nextStamp) .", ". date('j',$nextStamp) .");";
1627 $selectedDays = array (
1628 new Calendar_Day($year,$month,$day),
1629 new Calendar_Day($year,12,25),
1632 // Build the days in the month
1633 $month->build($selectedDays);
1635 $this->tmpl->assign('current_month', date('F Y',$month->getTimeStamp()));
1636 $this->tmpl->assign('prev_month', $prev);
1637 $this->tmpl->assign('next_month', $next);
1639 while ( $day = $month->fetch() ) {
1641 if(!isset($matrix[$rows]))
1642 $matrix[$rows] = Array();
1646 $dayStamp = $day->thisDay(true);
1647 $link = "javascript:setCalendarDate(". date('Y',$dayStamp) .", ". date('n',$dayStamp).", ". date('j',$dayStamp) .");";
1649 // isFirst() to find start of week
1650 if ( $day->isFirst() )
1653 if ( $day->isSelected() ) {
1654 $string.= "<td class=\"selected\">".$day->thisDay()."</td>\n";
1655 } else if ( $day->isEmpty() ) {
1656 $string.= "<td> </td>\n";
1658 $string.= "<td><a class=\"calendar\" href=\"".$link."\">".$day->thisDay()."</a></td>\n";
1661 // isLast() to find end of week
1662 if ( $day->isLast() )
1663 $string.= "</tr>\n";
1665 $matrix[$rows][$cols] = $string;
1675 $this->tmpl->assign('matrix', $matrix);
1676 $this->tmpl->assign('rows', $rows);
1677 $this->tmpl->show("calendar.tpl");
1679 } // get_calendar_matrix()
1682 * output export page
1684 public function getExport($mode)
1686 $pictures = $this->getPhotoSelection();
1687 $current_tags = $this->getCurrentTags();
1689 foreach($pictures as $picture) {
1691 $orig_url = $this->get_phpfspot_url() ."index.php?mode=showp&id=". $picture;
1692 if($current_tags != "") {
1693 $orig_url.= "&tags=". $current_tags;
1695 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1696 $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
1699 $thumb_url = $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
1704 // <a href="%pictureurl%"><img src="%thumbnailurl%" ></a>
1705 print htmlspecialchars("<a href=\"". $orig_url ."\"><img src=\"". $thumb_url ."\" /></a>") ."<br />\n";
1709 // "[%pictureurl% %thumbnailurl%]"
1710 print htmlspecialchars("[".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
1713 case 'MoinMoinList':
1714 // " * [%pictureurl% %thumbnailurl%]"
1715 print " " . htmlspecialchars("* [".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
1726 public function getRSSFeed()
1728 Header("Content-type: text/xml; charset=utf-8");
1729 print "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
1732 xmlns:media="http://search.yahoo.com/mrss/"
1733 xmlns:dc="http://purl.org/dc/elements/1.1/"
1736 <title>phpfspot</title>
1737 <description>phpfspot RSS feed</description>
1738 <link><?php print htmlspecialchars($this->get_phpfspot_url()); ?></link>
1739 <pubDate><?php print strftime("%a, %d %b %Y %T %z"); ?></pubDate>
1740 <generator>phpfspot</generator>
1743 $pictures = $this->getPhotoSelection();
1744 $current_tags = $this->getCurrentTags();
1746 foreach($pictures as $picture) {
1748 $orig_url = $this->get_phpfspot_url() ."index.php?mode=showp&id=". $picture;
1749 if($current_tags != "") {
1750 $orig_url.= "&tags=". $current_tags;
1752 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1753 $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
1756 $details = $this->get_photo_details($picture);
1758 $thumb_url = $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
1759 $thumb_html = htmlspecialchars("
1760 <a href=\"". $orig_url ."\"><img src=\"". $thumb_url ."\" /></a>
1762 ". $details['description']);
1764 $orig_path = $this->translate_path($details['directory_path']) ."/". $details['name'];
1765 $meta = $this->get_meta_informations($orig_path);
1766 $meta_date = isset($meta['FileDateTime']) ? $meta['FileDateTime'] : filemtime($orig_path);
1770 <title><?php print htmlspecialchars($details['name']); ?></title>
1771 <link><?php print htmlspecialchars($orig_url); ?></link>
1772 <guid><?php print htmlspecialchars($orig_url); ?></guid>
1773 <dc:date.Taken><?php print strftime("%Y-%m-%dT%H:%M:%S+00:00", $meta_date); ?></dc:date.Taken>
1775 <?php print $thumb_html; ?>
1777 <pubDate><?php print strftime("%a, %d %b %Y %T %z", $meta_date); ?></pubDate>
1792 * return all selected tags as one string
1794 private function getCurrentTags()
1797 if($_SESSION['selected_tags'] != "") {
1798 foreach($_SESSION['selected_tags'] as $tag)
1799 $current_tags.= $tag .",";
1800 $current_tags = substr($current_tags, 0, strlen($current_tags)-1);
1802 return $current_tags;
1804 } // getCurrentTags()
1807 * return the current photo
1809 public function getCurrentPhoto()
1811 if(isset($_SESSION['current_photo'])) {
1812 print $_SESSION['current_photo'];
1814 } // getCurrentPhoto()
1817 * tells the client browser what to do
1819 * this function is getting called via AJAX by the
1820 * client browsers. it will tell them what they have
1821 * to do next. This is necessary for directly jumping
1822 * into photo index or single photo view when the are
1823 * requested with specific URLs
1825 public function whatToDo()
1827 if(isset($_SESSION['current_photo']) && $_SESSION['start_action'] == 'showp') {
1828 return "show_photo";
1830 elseif(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
1831 return "showpi_tags";
1833 elseif(isset($_SESSION['start_action']) && $_SESSION['start_action'] == 'showpi') {
1837 return "nothing special";
1842 * return the current process-user
1844 private function getuid()
1846 if($uid = posix_getuid()) {
1847 if($user = posix_getpwuid($uid)) {
1848 return $user['name'];
1857 * returns a select-dropdown box to select photo index sort parameters
1859 private function get_sort_field()
1861 $output = "<select name=\"sort_order\">";
1862 foreach(array('date_asc', 'date_desc', 'name_asc', 'name_desc') as $sort_order) {
1863 $output.= "<option value=\"". $sort_order ."\"";
1864 if($sort_order == $_SESSION['sort_order']) {
1865 $output.= " selected=\"selected\"";
1867 $output.= ">". $sort_order ."</option>";
1869 $output.= "</select>";
1872 } // get_sort_field()
1875 * returns the currently selected sort order
1877 private function get_sort_order()
1879 switch($_SESSION['sort_order']) {
1881 return " ORDER BY p.time ASC";
1884 return " ORDER BY p.time DESC";
1887 return " ORDER BY p.name ASC";
1890 return " ORDER BY p.name DESC";
1894 } // get_sort_order()
1897 * return the next to be shown slide show image
1899 * this function returns the URL of the next image
1900 * in the slideshow sequence.
1902 public function getNextSlideShowImage()
1904 $all_photos = $this->getPhotoSelection();
1906 if(!isset($_SESSION['slideshow_img']) || $_SESSION['slideshow_img'] == count($all_photos)-1)
1907 $_SESSION['slideshow_img'] = 0;
1909 $_SESSION['slideshow_img']++;
1911 return $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $all_photos[$_SESSION['slideshow_img']] ."&width=". $this->cfg->photo_width;
1913 } // getNextSlideShowImage()
1916 * return the previous to be shown slide show image
1918 * this function returns the URL of the previous image
1919 * in the slideshow sequence.
1921 public function getPrevSlideShowImage()
1923 $all_photos = $this->getPhotoSelection();
1925 if(!isset($_SESSION['slideshow_img']) || $_SESSION['slideshow_img'] == 0)
1926 $_SESSION['slideshow_img'] = 0;
1928 $_SESSION['slideshow_img']--;
1930 return $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $all_photos[$_SESSION['slideshow_img']] ."&width=". $this->cfg->photo_width;
1932 } // getPrevSlideShowImage()
1934 public function resetSlideShow()
1936 if(isset($_SESSION['slideshow_img']))
1937 unset($_SESSION['slideshow_img']);
1938 } // resetSlideShow()
1943 * this function will get all photos from the fspot
1944 * database and randomly return ONE entry
1946 * saddly there is yet no sqlite3 function which returns
1947 * the bulk result in array, so we have to fill up our
1950 public function get_random_photo()
1954 $result = $this->db->db_query("
1959 while($row = $this->db->db_fetch_object($result)) {
1960 array_push($all, $row['id']);
1963 return $all[array_rand($all)];
1965 } // get_random_photo()
1968 * validates provided date
1970 * this function validates if the provided date
1971 * contains a valid date and will return true
1974 public function isValidDate($date_str)
1976 $timestamp = strtotime($date_str);
1978 if(is_numeric($timestamp))
1986 * timestamp to string conversion
1988 private function ts2str($timestamp)
1990 return strftime("%Y-%m-%d", $timestamp);
1993 private function extractTags($tags_str)
1995 $not_validated = split(',', $_GET['tags']);
1996 $validated = array();
1998 foreach($not_validated as $tag) {
1999 if(is_numeric($tag))
2000 array_push($validated, $tag);
2008 * returns the full path to a thumbnail
2010 public function get_thumb_path($width, $photo)
2012 $md5 = $this->getMD5($photo);
2013 $sub_path = substr($md5, 0, 2);
2014 return $this->cfg->thumb_path
2022 } // get_thumb_path()
2025 * returns server's virtual host name
2027 private function get_server_name()
2029 return $_SERVER['SERVER_NAME'];
2030 } // get_server_name()
2033 * returns type of webprotocol which is
2036 private function get_web_protocol()
2038 if(!isset($_SERVER['HTTPS']))
2042 } // get_web_protocol()
2045 * return url to this phpfspot installation
2047 private function get_phpfspot_url()
2049 return $this->get_web_protocol() ."://". $this->get_server_name() . $this->cfg->web_path;
2050 } // get_phpfspot_url()
2053 * check file exists and is readable
2055 * returns true, if everything is ok, otherwise false
2056 * if $silent is not set, this function will output and
2059 private function check_readable($file, $silent = null)
2061 if(!file_exists($file)) {
2063 print "File \"". $file ."\" does not exist.\n";
2067 if(!is_readable($file)) {
2069 print "File \"". $file ."\" is not reachable for user ". $this->getuid() ."\n";
2075 } // check_readable()
2078 * check if all needed indices are present
2080 * this function checks, if some needed indices are already
2081 * present, or if not, create them on the fly. they are
2082 * necessary to speed up some queries like that one look for
2083 * all tags, when show_tags is specified in the configuration.
2085 private function checkDbIndices()
2087 $result = $this->db->db_exec("
2088 CREATE INDEX IF NOT EXISTS
2095 } // checkDbIndices()