3 /***************************************************************************
5 * Copyright (c) by Andreas Unterkircher, unki@netshadow.at
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 ***************************************************************************/
24 require_once "phpfspot_cfg.php";
25 require_once "phpfspot_db.php";
39 * this function will be called on class construct
40 * and will check requirements, loads configuration,
41 * open databases and start the user session
43 public function __construct()
45 $this->cfg = new PHPFSPOT_CFG;
47 /* set application name and version information */
48 $this->cfg->product = "phpfspot";
49 $this->cfg->version = "1.2";
51 /* Check necessary requirements */
52 if(!$this->checkRequirements()) {
56 $this->db = new PHPFSPOT_DB($this, $this->cfg->fspot_db);
58 if(!is_writeable(dirname($this->cfg->phpfspot_db))) {
59 print dirname($this->cfg->phpfspot_db) .": directory is not writeable!";
63 $this->cfg_db = new PHPFSPOT_DB($this, $this->cfg->phpfspot_db);
64 if(!is_writeable($this->cfg->phpfspot_db)) {
65 print $this->cfg->phpfspot_db ." is not writeable for user ". $this->getuid() ."\n";
68 $this->check_config_table();
70 /* include Smarty template engine */
71 if(!$this->check_readable($this->cfg->smarty_path .'/libs/Smarty.class.php')) {
74 require $this->cfg->smarty_path .'/libs/Smarty.class.php';
75 /* overload Smarty class if our own template handler */
76 require_once "phpfspot_tmpl.php";
77 $this->tmpl = new PHPFSPOT_TMPL($this);
83 if(!isset($_SESSION['tag_condition']))
84 $_SESSION['tag_condition'] = 'or';
86 if(!isset($_SESSION['sort_order']))
87 $_SESSION['sort_order'] = 'date_asc';
89 if(!isset($_SESSION['searchfor']))
90 $_SESSION['searchfor'] = '';
92 // if begin_with is still set but rows_per_page is now 0, unset it
93 if(isset($_SESSION['begin_with']) && $this->cfg->rows_per_page == 0)
94 unset($_SESSION['begin_with']);
98 public function __destruct()
104 * show - generate html output
106 * this function can be called after the constructor has
107 * prepared everyhing. it will load the index.tpl smarty
108 * template. if necessary it will registere pre-selects
109 * (photo index, photo, tag search, date search) into
112 public function show()
114 $this->tmpl->assign('searchfor', $_SESSION['searchfor']);
115 $this->tmpl->assign('page_title', $this->cfg->page_title);
116 $this->tmpl->assign('current_condition', $_SESSION['tag_condition']);
117 $this->tmpl->assign('template_path', 'themes/'. $this->cfg->theme_name);
119 $_SESSION['start_action'] = $_GET['mode'];
121 switch($_GET['mode']) {
123 if(isset($_GET['tags'])) {
124 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
126 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
127 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
129 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
130 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
134 if(isset($_GET['tags'])) {
135 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
136 $_SESSION['start_action'] = 'showp';
138 if(isset($_GET['id']) && is_numeric($_GET['id'])) {
139 $_SESSION['current_photo'] = $_GET['id'];
140 $_SESSION['start_action'] = 'showp';
142 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
143 $_SESSION['from_date'] = strtotime($_GET['from_date']);
145 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
146 $_SESSION['to_date'] = strtotime($_GET['to_date']);
150 $this->tmpl->show("export.tpl");
154 $this->tmpl->show("slideshow.tpl");
158 if(isset($_GET['tags'])) {
159 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
161 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
162 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
164 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
165 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
172 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date']))
173 $this->tmpl->assign('date_search_enabled', true);
175 $this->tmpl->assign('from_date', $this->get_calendar('from'));
176 $this->tmpl->assign('to_date', $this->get_calendar('to'));
177 $this->tmpl->assign('sort_field', $this->get_sort_field());
178 $this->tmpl->assign('content_page', 'welcome.tpl');
179 $this->tmpl->show("index.tpl");
184 * get_tags - grab all tags of f-spot's database
186 * this function will get all available tags from
187 * the f-spot database and store them within two
188 * arrays within this class for later usage. in
189 * fact, if the user requests (hide_tags) it will
190 * opt-out some of them.
192 * this function is getting called once by show()
194 private function get_tags()
196 $this->avail_tags = Array();
199 $result = $this->db->db_query("
202 ORDER BY sort_priority ASC
205 while($row = $this->db->db_fetch_object($result)) {
207 $tag_id = $row['id'];
208 $tag_name = $row['name'];
210 /* if the user has specified to ignore this tag in phpfspot's
211 configuration, ignore it here so it does not get added to
214 if(in_array($row['name'], $this->cfg->hide_tags))
217 /* if the user has specified to only show certain tags which
218 are specified in phpfspot's configuration, ignore all others
219 so they will not be added to the tag list.
221 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags) &&
222 !in_array($row['name'], $this->cfg->show_tags))
225 $this->tags[$tag_id] = $tag_name;
226 $this->avail_tags[$count] = $tag_id;
234 * extract all photo details
236 * retrieve all available details from f-spot's
237 * database and return them as object
239 public function get_photo_details($idx)
242 SELECT p.id, p.name, p.time, p.directory_path, p.description
246 /* if show_tags is set, only return details for photos which
247 are specified to be shown
249 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
251 INNER JOIN photo_tags pt
255 WHERE p.id='". $idx ."'
256 AND t.name IN ('".implode("','",$this->cfg->show_tags)."')";
260 WHERE p.id='". $idx ."'
264 $result = $this->db->db_query($query_str);
265 return $this->db->db_fetch_object($result);
267 } // get_photo_details
270 * returns aligned photo names
272 * this function returns aligned (length) names for
273 * an specific photo. If the length of the name exceeds
274 * $limit the name will be shrinked (...)
276 public function getPhotoName($idx, $limit = 0)
278 if($details = $this->get_photo_details($idx)) {
279 $name = $this->shrink_text($details['name'], $limit);
286 * shrink text according provided limit
288 * If the length of the name exceeds $limit the
289 * text will be shortend and some content in between
290 * will be replaced with "..."
292 private function shrink_text($text, $limit)
294 if($limit != 0 && strlen($text) > $limit) {
295 $text = substr($text, 0, $limit-5) ."...". substr($text, -($limit-5));
303 * translate f-spoth photo path
305 * as the full-qualified path recorded in the f-spot database
306 * is usally not the same as on the webserver, this function
307 * will replace the path with that one specified in the cfg
309 public function translate_path($path, $width = 0)
311 return str_replace($this->cfg->path_replace_from, $this->cfg->path_replace_to, $path);
316 * control HTML ouput for a single photo
318 * this function provides all the necessary information
319 * for the single photo template.
321 public function showPhoto($photo)
323 /* get all photos from the current photo selection */
324 $all_photos = $this->getPhotoSelection();
325 $count = count($all_photos);
327 for($i = 0; $i < $count; $i++) {
329 // $get_next will be set, when the photo which has to
330 // be displayed has been found - this means that the
331 // next available is in fact the NEXT image (for the
333 if(isset($get_next)) {
334 $next_img = $all_photos[$i];
338 /* the next photo is our NEXT photo */
339 if($all_photos[$i] == $photo) {
343 $previous_img = $all_photos[$i];
346 if($photo == $all_photos[$i]) {
351 $details = $this->get_photo_details($photo);
358 $orig_path = $this->translate_path($details['directory_path']) ."/". $details['name'];
359 $thumb_path = $this->get_thumb_path($this->cfg->photo_width, $photo);
361 if(!file_exists($orig_path)) {
362 $this->_error("Photo ". $orig_path ." does not exist!<br />\n");
365 if(!is_readable($orig_path)) {
366 $this->_error("Photo ". $orig_path ." is not readable for user ". $this->getuid() ."<br />\n");
369 /* If the thumbnail doesn't exist yet, try to create it */
370 if(!file_exists($thumb_path)) {
371 $this->gen_thumb($photo, true);
372 $thumb_path = $this->get_thumb_path($this->cfg->photo_width, $photo);
375 /* get f-spot database meta information */
376 $meta = $this->get_meta_informations($orig_path);
378 /* If EXIF data are available, use them */
379 if(isset($meta['ExifImageWidth'])) {
380 $meta_res = $meta['ExifImageWidth'] ."x". $meta['ExifImageLength'];
382 $info = getimagesize($orig_path);
383 $meta_res = $info[0] ."x". $info[1];
386 $meta_date = isset($meta['FileDateTime']) ? strftime("%a %x %X", $meta['FileDateTime']) : "n/a";
387 $meta_make = isset($meta['Make']) ? $meta['Make'] ." / ". $meta['Model'] : "n/a";
388 $meta_size = isset($meta['FileSize']) ? round($meta['FileSize']/1024, 1) ."kbyte" : "n/a";
390 $extern_link = "index.php?mode=showp&id=". $photo;
391 $current_tags = $this->getCurrentTags();
392 if($current_tags != "") {
393 $extern_link.= "&tags=". $current_tags;
395 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
396 $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
399 $this->tmpl->assign('extern_link', $extern_link);
401 if(file_exists($thumb_path)) {
403 $info = getimagesize($thumb_path);
405 $this->tmpl->assign('description', $details['description']);
406 $this->tmpl->assign('image_name', $details['name']);
408 $this->tmpl->assign('width', $info[0]);
409 $this->tmpl->assign('height', $info[1]);
410 $this->tmpl->assign('ExifMadeOn', $meta_date);
411 $this->tmpl->assign('ExifMadeWith', $meta_make);
412 $this->tmpl->assign('ExifOrigResolution', $meta_res);
413 $this->tmpl->assign('ExifFileSize', $meta_size);
415 $this->tmpl->assign('image_url', 'phpfspot_img.php?idx='. $photo ."&width=". $this->cfg->photo_width);
416 $this->tmpl->assign('image_url_full', 'phpfspot_img.php?idx='. $photo);
418 $this->tmpl->assign('tags', $this->get_photo_tags($photo));
419 $this->tmpl->assign('current', $current);
422 $this->_error("Can't open file ". $thumb_path ."\n");
427 $this->tmpl->assign('previous_url', "javascript:showImage(". $previous_img .");");
428 $this->tmpl->assign('prev_img', $previous_img);
432 $this->tmpl->assign('next_url', "javascript:showImage(". $next_img .");");
433 $this->tmpl->assign('next_img', $next_img);
435 $this->tmpl->assign('mini_width', $this->cfg->mini_width);
436 $this->tmpl->assign('photo_number', $i);
437 $this->tmpl->assign('photo_count', count($all_photos));
439 $this->tmpl->show("single_photo.tpl");
444 * all available tags and tag cloud
446 * this function outputs all available tags (time ordered)
447 * and in addition output them as tag cloud (tags which have
448 * many photos will appears more then others)
450 public function getAvailableTags()
454 $result = $this->db->db_query("
455 SELECT tag_id as id, count(tag_id) as quantity
465 while($row = $this->db->db_fetch_object($result)) {
466 $tags[$row['id']] = $row['quantity'];
469 // change these font sizes if you will
470 $max_size = 125; // max font size in %
471 $min_size = 75; // min font size in %
473 // get the largest and smallest array values
474 $max_qty = max(array_values($tags));
475 $min_qty = min(array_values($tags));
477 // find the range of values
478 $spread = $max_qty - $min_qty;
479 if (0 == $spread) { // we don't want to divide by zero
483 // determine the font-size increment
484 // this is the increase per tag quantity (times used)
485 $step = ($max_size - $min_size)/($spread);
487 // loop through our tag array
488 foreach ($tags as $key => $value) {
490 if(isset($_SESSION['selected_tags']) && in_array($key, $_SESSION['selected_tags']))
493 // calculate CSS font-size
494 // find the $value in excess of $min_qty
495 // multiply by the font-size increment ($size)
496 // and add the $min_size set above
497 $size = $min_size + (($value - $min_qty) * $step);
498 // uncomment if you want sizes in whole %:
501 if(isset($this->tags[$key])) {
502 $output.= "<a href=\"javascript:Tags('add', ". $key .");\" class=\"tag\" style=\"font-size: ". $size ."%;\">". $this->tags[$key] ."</a>, ";
507 $output = substr($output, 0, strlen($output)-2);
510 } // getAvailableTags()
513 * output all selected tags
515 * this function output all tags which have been selected
516 * by the user. the selected tags are stored in the
517 * session-variable $_SESSION['selected_tags']
519 public function getSelectedTags()
522 foreach($this->avail_tags as $tag)
524 // return all selected tags
525 if(isset($_SESSION['selected_tags']) && in_array($tag, $_SESSION['selected_tags'])) {
526 $output.= "<a href=\"javascript:Tags('del', ". $tag .");\" class=\"tag\">". $this->tags[$tag] ."</a>, ";
530 $output = substr($output, 0, strlen($output)-2);
533 } // getSelectedTags()
536 * add tag to users session variable
538 * this function will add the specified to users current
539 * tag selection. if a date search has been made before
540 * it will be now cleared
542 public function addTag($tag)
544 if(!isset($_SESSION['selected_tags']))
545 $_SESSION['selected_tags'] = Array();
547 if(!in_array($tag, $_SESSION['selected_tags']))
548 array_push($_SESSION['selected_tags'], $tag);
553 * remove tag to users session variable
555 * this function removes the specified tag from
556 * users current tag selection
558 public function delTag($tag)
560 if(isset($_SESSION['selected_tags'])) {
561 $key = array_search($tag, $_SESSION['selected_tags']);
562 unset($_SESSION['selected_tags'][$key]);
563 sort($_SESSION['selected_tags']);
569 * reset tag selection
571 * if there is any tag selection, it will be
574 public function resetTags()
576 if(isset($_SESSION['selected_tags']))
577 unset($_SESSION['selected_tags']);
584 * if a specific photo was requested (external link)
585 * unset the session variable now
587 public function resetPhotoView()
589 if(isset($_SESSION['current_photo']))
590 unset($_SESSION['current_photo']);
592 } // resetPhotoView();
597 * if any tag search has taken place, reset
600 public function resetTagSearch()
602 if(isset($_SESSION['searchfor']))
603 unset($_SESSION['searchfor']);
605 } // resetTagSearch()
610 * if any date search has taken place, reset
613 public function resetDateSearch()
615 if(isset($_SESSION['from_date']))
616 unset($_SESSION['from_date']);
617 if(isset($_SESSION['to_date']))
618 unset($_SESSION['to_date']);
620 } // resetDateSearch();
623 * return all photo according selection
625 * this function returns all photos based on
626 * the tag-selection, tag- or date-search.
627 * the tag-search also has to take care of AND
628 * and OR conjunctions
630 public function getPhotoSelection()
632 $matched_photos = Array();
634 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
635 $from_date = $_SESSION['from_date'];
636 $to_date = $_SESSION['to_date'];
637 $additional_where_cond = "
638 p.time>='". $from_date ."'
640 p.time<='". $to_date ."'
644 if(isset($_SESSION['sort_order'])) {
645 $order_str = $this->get_sort_order();
648 /* return a search result */
649 if(isset($_SESSION['searchfor']) && $_SESSION['searchfor'] != '') {
651 SELECT DISTINCT photo_id
657 WHERE t.name LIKE '%". $_SESSION['searchfor'] ."%'";
659 if(isset($additional_where_cond))
660 $query_str.= "AND ". $additional_where_cond ." ";
662 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
663 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags)."')";
666 if(isset($order_str))
667 $query_str.= $order_str;
669 $result = $this->db->db_query($query_str);
670 while($row = $this->db->db_fetch_object($result)) {
671 array_push($matched_photos, $row['photo_id']);
673 return $matched_photos;
676 /* return according the selected tags */
677 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
679 foreach($_SESSION['selected_tags'] as $tag)
680 $selected.= $tag .",";
681 $selected = substr($selected, 0, strlen($selected)-1);
683 if($_SESSION['tag_condition'] == 'or') {
685 SELECT DISTINCT pt.photo_id
691 WHERE pt.tag_id IN (". $selected .")
693 if(isset($additional_where_cond))
694 $query_str.= "AND ". $additional_where_cond ." ";
696 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
697 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags)."')";
700 if(isset($order_str))
701 $query_str.= $order_str;
703 elseif($_SESSION['tag_condition'] == 'and') {
705 if(count($_SESSION['selected_tags']) >= 32) {
706 print "A SQLite limit of 32 tables within a JOIN SELECT avoids to<br />\n";
707 print "evaluate your tag selection. Please remove some tags from your selection.\n";
711 /* Join together a table looking like
713 pt1.photo_id pt1.tag_id pt2.photo_id pt2.tag_id ...
715 so the query can quickly return all images matching the
716 selected tags in an AND condition
721 SELECT DISTINCT pt1.photo_id
725 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
732 for($i = 0; $i < count($_SESSION['selected_tags']); $i++) {
734 INNER JOIN photo_tags pt". ($i+2) ."
735 ON pt1.photo_id=pt". ($i+2) .".photo_id
742 $query_str.= "WHERE pt1.tag_id=". $_SESSION['selected_tags'][0];
743 for($i = 1; $i < count($_SESSION['selected_tags']); $i++) {
745 AND pt". ($i+1) .".tag_id=". $_SESSION['selected_tags'][$i] ."
748 if(isset($additional_where_cond))
749 $query_str.= "AND ". $additional_where_cond;
751 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
752 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags). "')";
755 if(isset($order_str))
756 $query_str.= $order_str;
760 $result = $this->db->db_query($query_str);
761 while($row = $this->db->db_fetch_object($result)) {
762 array_push($matched_photos, $row['photo_id']);
764 return $matched_photos;
767 /* return all available photos */
769 SELECT DISTINCT photo_id
776 if(isset($additional_where_cond))
777 $query_str.= "WHERE ". $additional_where_cond ." ";
779 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
780 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags). "')";
783 if(isset($order_str))
784 $query_str.= $order_str;
786 $result = $this->db->db_query($query_str);
787 while($row = $this->db->db_fetch_object($result)) {
788 array_push($matched_photos, $row['photo_id']);
790 return $matched_photos;
792 } // getPhotoSelection()
795 * control HTML ouput for photo index
797 * this function provides all the necessary information
798 * for the photo index template.
800 public function showPhotoIndex()
802 $photos = $this->getPhotoSelection();
804 $count = count($photos);
806 if(isset($_SESSION['begin_with']) && $_SESSION['begin_with'] != "")
807 $anchor = $_SESSION['begin_with'];
809 if(!isset($this->cfg->rows_per_page) || $this->cfg->rows_per_page == 0) {
815 elseif($this->cfg->rows_per_page > 0) {
817 if(!$_SESSION['begin_with'] || $_SESSION['begin_with'] == 0)
821 $begin_with = $_SESSION['begin_with'];
823 // verify $begin_with - perhaps the thumbs-per-rows or
824 // rows-per-page variables have changed or the jump back
825 // from a photo wasn't exact - so calculate the real new
827 $multiplicator = $this->cfg->rows_per_page * $this->cfg->thumbs_per_row;
828 for($i = 0; $i <= $count; $i+=$multiplicator) {
829 if($begin_with >= $i && $begin_with < $i+$multiplicator) {
836 $end_with = $begin_with + ($this->cfg->rows_per_page * $this->cfg->thumbs_per_row);
842 $images[$rows] = Array();
843 $img_height[$rows] = Array();
844 $img_width[$rows] = Array();
845 $img_id[$rows] = Array();
846 $img_name[$rows] = Array();
847 $img_title = Array();
849 for($i = $begin_with; $i < $end_with; $i++) {
851 $images[$rows][$cols] = $photos[$i];
852 $img_id[$rows][$cols] = $i;
853 $img_name[$rows][$cols] = htmlspecialchars($this->getPhotoName($photos[$i], 15));
854 $img_title[$rows][$cols] = "Click to view photo ". htmlspecialchars($this->getPhotoName($photos[$i], 0));
856 $thumb_path = $this->get_thumb_path($this->cfg->thumb_width, $photos[$i]);
858 if(file_exists($thumb_path)) {
859 $info = getimagesize($thumb_path);
860 $img_width[$rows][$cols] = $info[0];
861 $img_height[$rows][$cols] = $info[1];
864 if($cols == $this->cfg->thumbs_per_row-1) {
867 $images[$rows] = Array();
868 $img_width[$rows] = Array();
869 $img_height[$rows] = Array();
876 // +1 for for smarty's selection iteration
879 if(isset($_SESSION['searchfor']) && $_SESSION['searchfor'] != '')
880 $this->tmpl->assign('searchfor', $_SESSION['searchfor']);
882 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
883 $this->tmpl->assign('from_date', $this->ts2str($_SESSION['from_date']));
884 $this->tmpl->assign('to_date', $this->ts2str($_SESSION['to_date']));
887 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
888 $this->tmpl->assign('tag_result', 1);
891 /* do we have to display the page selector ? */
892 if($this->cfg->rows_per_page != 0) {
894 /* calculate the page switchers */
895 $previous_start = $begin_with - ($this->cfg->rows_per_page * $this->cfg->thumbs_per_row);
896 $next_start = $begin_with + ($this->cfg->rows_per_page * $this->cfg->thumbs_per_row);
899 $this->tmpl->assign("previous_url", "javascript:showPhotoIndex(". $previous_start .");");
900 if($end_with < $count)
901 $this->tmpl->assign("next_url", "javascript:showPhotoIndex(". $next_start .");");
903 $photo_per_page = $this->cfg->rows_per_page * $this->cfg->thumbs_per_row;
904 $last_page = ceil($count / $photo_per_page);
906 /* get the current selected page */
907 if($begin_with == 0) {
911 for($i = $begin_with; $i >= 0; $i-=$photo_per_page) {
918 for($i = 1; $i <= $last_page; $i++) {
920 if($current_page == $i)
921 $style = "style=\"font-size: 125%; text-decoration: underline;\"";
922 elseif($current_page-1 == $i || $current_page+1 == $i)
923 $style = "style=\"font-size: 105%;\"";
924 elseif(($current_page-5 >= $i) && ($i != 1) ||
925 ($current_page+5 <= $i) && ($i != $last_page))
926 $style = "style=\"font-size: 75%;\"";
930 $select = "<a href=\"javascript:showPhotoIndex(". (($i*$photo_per_page)-$photo_per_page) .");\"";
933 $select.= ">". $i ."</a> ";
935 // until 9 pages we show the selector from 1-9
936 if($last_page <= 9) {
937 $page_select.= $select;
940 if($i == 1 /* first page */ ||
941 $i == $last_page /* last page */ ||
942 $i == $current_page /* current page */ ||
943 $i == ceil($last_page * 0.25) /* first quater */ ||
944 $i == ceil($last_page * 0.5) /* half */ ||
945 $i == ceil($last_page * 0.75) /* third quater */ ||
946 (in_array($i, array(1,2,3,4,5,6)) && $current_page <= 4) /* the first 6 */ ||
947 (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 */ ||
948 $i == $current_page-3 || $i == $current_page-2 || $i == $current_page-1 /* three before */ ||
949 $i == $current_page+3 || $i == $current_page+2 || $i == $current_page+1 /* three after */) {
951 $page_select.= $select;
959 $page_select.= "......... ";
964 /* only show the page selector if we have more then one page */
966 $this->tmpl->assign('page_selector', $page_select);
970 $current_tags = $this->getCurrentTags();
971 $extern_link = "index.php?mode=showpi";
972 $rss_link = "index.php?mode=rss";
973 if($current_tags != "") {
974 $extern_link.= "&tags=". $current_tags;
975 $rss_link.= "&tags=". $current_tags;
977 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
978 $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
979 $rss_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
982 $export_link = "index.php?mode=export";
983 $slideshow_link = "index.php?mode=slideshow";
985 $this->tmpl->assign('extern_link', $extern_link);
986 $this->tmpl->assign('slideshow_link', $slideshow_link);
987 $this->tmpl->assign('export_link', $export_link);
988 $this->tmpl->assign('rss_link', $rss_link);
989 $this->tmpl->assign('count', $count);
990 $this->tmpl->assign('width', $this->cfg->thumb_width);
991 $this->tmpl->assign('images', $images);
992 $this->tmpl->assign('img_width', $img_width);
993 $this->tmpl->assign('img_height', $img_height);
994 $this->tmpl->assign('img_id', $img_id);
995 $this->tmpl->assign('img_name', $img_name);
996 $this->tmpl->assign('img_title', $img_title);
997 $this->tmpl->assign('rows', $rows);
998 $this->tmpl->assign('columns', $this->cfg->thumbs_per_row);
1000 $this->tmpl->show("photo_index.tpl");
1003 print "<script language=\"JavaScript\">self.location.hash = '#image". $anchor ."';</script>\n";
1005 } // showPhotoIndex()
1008 * show credit template
1010 public function showCredits()
1012 $this->tmpl->assign('version', $this->cfg->version);
1013 $this->tmpl->assign('product', $this->cfg->product);
1014 $this->tmpl->show("credits.tpl");
1019 * create_thumbnails for the requested width
1021 * this function creates image thumbnails of $orig_image
1022 * stored as $thumb_image. It will check if the image is
1023 * in a supported format, if necessary rotate the image
1024 * (based on EXIF orientation meta headers) and re-sizing.
1026 public function create_thumbnail($orig_image, $thumb_image, $width)
1028 if(!file_exists($orig_image)) {
1032 $details = getimagesize($orig_image);
1034 /* check if original photo is a support image type */
1035 if(!$this->checkifImageSupported($details['mime']))
1038 $meta = $this->get_meta_informations($orig_image);
1043 switch($meta['Orientation']) {
1045 case 1: /* top, left */
1046 $rotate = 0; $flip = false; break;
1047 case 2: /* top, right */
1048 $rotate = 0; $flip = true; break;
1049 case 3: /* bottom, left */
1050 $rotate = 180; $flip = false; break;
1051 case 4: /* bottom, right */
1052 $rotate = 180; $flip = true; break;
1053 case 5: /* left side, top */
1054 $rotate = 90; $flip = true; break;
1055 case 6: /* right side, top */
1056 $rotate = 90; $flip = false; break;
1057 case 7: /* left side, bottom */
1058 $rotate = 270; $flip = true; break;
1059 case 8: /* right side, bottom */
1060 $rotate = 270; $flip = false; break;
1063 $src_img = @imagecreatefromjpeg($orig_image);
1066 print "Can't load image from ". $orig_image ."\n";
1070 /* grabs the height and width */
1071 $cur_width = imagesx($src_img);
1072 $cur_height = imagesy($src_img);
1074 // If requested width is more then the actual image width,
1075 // do not generate a thumbnail, instead safe the original
1076 // as thumbnail but with lower quality
1078 if($width >= $cur_width) {
1079 $result = imagejpeg($src_img, $thumb_image, 75);
1080 imagedestroy($src_img);
1084 // If the image will be rotate because EXIF orientation said so
1085 // 'virtually rotate' the image for further calculations
1086 if($rotate == 90 || $rotate == 270) {
1088 $cur_width = $cur_height;
1092 /* calculates aspect ratio */
1093 $aspect_ratio = $cur_height / $cur_width;
1096 if($aspect_ratio < 1) {
1098 $new_h = abs($new_w * $aspect_ratio);
1100 /* 'virtually' rotate the image and calculate it's ratio */
1101 $tmp_w = $cur_height;
1102 $tmp_h = $cur_width;
1103 /* now get the ratio from the 'rotated' image */
1104 $tmp_ratio = $tmp_h/$tmp_w;
1105 /* now calculate the new dimensions */
1107 $tmp_h = abs($tmp_w * $tmp_ratio);
1109 // now that we know, how high they photo should be, if it
1110 // gets rotated, use this high to scale the image
1112 $new_w = abs($new_h / $aspect_ratio);
1114 // If the image will be rotate because EXIF orientation said so
1115 // now 'virtually rotate' back the image for the image manipulation
1116 if($rotate == 90 || $rotate == 270) {
1123 /* creates new image of that size */
1124 $dst_img = imagecreatetruecolor($new_w, $new_h);
1126 imagefill($dst_img, 0, 0, ImageColorAllocate($dst_img, 255, 255, 255));
1128 /* copies resized portion of original image into new image */
1129 imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $new_w, $new_h, imagesx($src_img), imagesy($src_img));
1131 /* needs the image to be flipped horizontal? */
1135 for($x = 0; $x < $new_w; $x++) {
1136 imagecopy($dst_img, $image, $x, 0, $w - $x - 1, 0, 1, $h);
1141 $this->_debug("(ROTATE)");
1142 $dst_img = $this->rotateImage($dst_img, $rotate);
1145 /* write down new generated file */
1146 $result = imagejpeg($dst_img, $thumb_image, 75);
1148 /* free your mind */
1149 imagedestroy($dst_img);
1150 imagedestroy($src_img);
1152 if($result === false) {
1153 print "Can't write thumbnail ". $thumb_image ."\n";
1159 } // create_thumbnail()
1162 * return all exif meta data from the file
1164 public function get_meta_informations($file)
1166 return exif_read_data($file);
1168 } // get_meta_informations()
1171 * create phpfspot own sqlite database
1173 * this function creates phpfspots own sqlite database
1174 * if it does not exist yet. this own is used to store
1175 * some necessary informations (md5 sum's, ...).
1177 public function check_config_table()
1179 // if the config table doesn't exist yet, create it
1180 if(!$this->cfg_db->db_check_table_exists("images")) {
1181 $this->cfg_db->db_exec("
1182 CREATE TABLE images (
1183 img_idx int primary key,
1189 } // check_config_table
1192 * Generates a thumbnail from photo idx
1194 * This function will generate JPEG thumbnails from provided F-Spot photo
1197 * 1. Check if all thumbnail generations (width) are already in place and
1199 * 2. Check if the md5sum of the original file has changed
1200 * 3. Generate the thumbnails if needed
1202 public function gen_thumb($idx = 0, $force = 0)
1206 $resolutions = Array(
1207 $this->cfg->thumb_width,
1208 $this->cfg->photo_width,
1209 $this->cfg->mini_width,
1212 /* get details from F-Spot's database */
1213 $details = $this->get_photo_details($idx);
1215 /* calculate file MD5 sum */
1216 $full_path = $this->translate_path($details['directory_path']) ."/". $details['name'];
1218 if(!file_exists($full_path)) {
1219 $this->_error("File ". $full_path ." does not exist\n");
1223 if(!is_readable($full_path)) {
1224 $this->_error("File ". $full_path ." is not readable for ". $this->getuid() ."\n");
1228 $file_md5 = md5_file($full_path);
1230 $this->_debug("Image [". $idx ."] ". $this->shrink_text($details['name'], 20) ." Thumbnails:");
1232 foreach($resolutions as $resolution) {
1234 $thumb_sub_path = substr($file_md5, 0, 2);
1235 $thumb_path = $this->cfg->thumb_path ."/". $thumb_sub_path ."/". $resolution ."_". $file_md5;
1237 if(!file_exists(dirname($thumb_path))) {
1238 mkdir(dirname($thumb_path), 0755);
1241 /* if the thumbnail file doesn't exist, create it */
1242 if(!file_exists($thumb_path)) {
1244 $this->_debug(" ". $resolution ."px");
1245 if(!$this->create_thumbnail($full_path, $thumb_path, $resolution))
1248 /* if the file hasn't changed there is no need to regen the thumb */
1249 elseif($file_md5 != $this->getMD5($idx) || $force) {
1251 $this->_debug(" ". $resolution ."px");
1252 if(!$this->create_thumbnail($full_path, $thumb_path, $resolution))
1258 /* set the new/changed MD5 sum for the current photo */
1260 $this->setMD5($idx, $file_md5);
1263 $this->_debug("\n");
1268 * returns stored md5 sum for a specific photo
1270 * this function queries the phpfspot database for a
1271 * stored MD5 checksum of the specified photo
1273 public function getMD5($idx)
1275 $result = $this->cfg_db->db_query("
1278 WHERE img_idx='". $idx ."'
1284 $img = $this->cfg_db->db_fetch_object($result);
1285 return $img['img_md5'];
1290 * set MD5 sum for the specific photo
1292 private function setMD5($idx, $md5)
1294 $result = $this->cfg_db->db_exec("
1295 REPLACE INTO images (img_idx, img_md5)
1296 VALUES ('". $idx ."', '". $md5 ."')
1302 * store current tag condition
1304 * this function stores the current tag condition
1305 * (AND or OR) in the users session variables
1307 public function setTagCondition($mode)
1309 $_SESSION['tag_condition'] = $mode;
1311 } // setTagCondition()
1314 * invoke tag & date search
1316 * this function will return all matching tags and store
1317 * them in the session variable selected_tags. furthermore
1318 * it also handles the date search.
1319 * getPhotoSelection() will then only return the matching
1322 public function startSearch($searchfor, $sort_order, $from = 0, $to = 0)
1324 $_SESSION['searchfor'] = $searchfor;
1325 $_SESSION['sort_order'] = $sort_order;
1327 $_SESSION['from_date'] = strtotime($from);
1329 unset($_SESSION['from_date']);
1331 $_SESSION['to_date'] = strtotime($to);
1333 unset($_SESSION['to_date']);
1335 if($searchfor != "") {
1336 /* new search, reset the current selected tags */
1337 $_SESSION['selected_tags'] = Array();
1338 foreach($this->avail_tags as $tag) {
1339 if(preg_match('/'. $searchfor .'/i', $this->tags[$tag]))
1340 array_push($_SESSION['selected_tags'], $tag);
1349 * this function rotates the image according the
1352 private function rotateImage($img, $degrees)
1354 if(function_exists("imagerotate")) {
1355 $img = imagerotate($img, $degrees, 0);
1357 function imagerotate($src_img, $angle)
1359 $src_x = imagesx($src_img);
1360 $src_y = imagesy($src_img);
1361 if ($angle == 180) {
1365 elseif ($src_x <= $src_y) {
1369 elseif ($src_x >= $src_y) {
1374 $rotate=imagecreatetruecolor($dest_x,$dest_y);
1375 imagealphablending($rotate, false);
1380 for ($y = 0; $y < ($src_y); $y++) {
1381 for ($x = 0; $x < ($src_x); $x++) {
1382 $color = imagecolorat($src_img, $x, $y);
1383 imagesetpixel($rotate, $dest_x - $y - 1, $x, $color);
1389 for ($y = 0; $y < ($src_y); $y++) {
1390 for ($x = 0; $x < ($src_x); $x++) {
1391 $color = imagecolorat($src_img, $x, $y);
1392 imagesetpixel($rotate, $y, $dest_y - $x - 1, $color);
1398 for ($y = 0; $y < ($src_y); $y++) {
1399 for ($x = 0; $x < ($src_x); $x++) {
1400 $color = imagecolorat($src_img, $x, $y);
1401 imagesetpixel($rotate, $dest_x - $x - 1, $dest_y - $y - 1, $color);
1415 $img = imagerotate($img, $degrees);
1424 * return all assigned tags for the specified photo
1426 private function get_photo_tags($idx)
1428 $result = $this->db->db_query("
1431 INNER JOIN photo_tags pt
1433 WHERE pt.photo_id='". $idx ."'
1438 while($row = $this->db->db_fetch_object($result))
1439 $tags[$row['id']] = $row['name'];
1443 } // get_photo_tags()
1446 * create on-the-fly images with text within
1448 public function showTextImage($txt, $color=000000, $space=4, $font=4, $w=300)
1450 if (strlen($color) != 6)
1453 $int = hexdec($color);
1454 $h = imagefontheight($font);
1455 $fw = imagefontwidth($font);
1456 $txt = explode("\n", wordwrap($txt, ($w / $fw), "\n"));
1457 $lines = count($txt);
1458 $im = imagecreate($w, (($h * $lines) + ($lines * $space)));
1459 $bg = imagecolorallocate($im, 255, 255, 255);
1460 $color = imagecolorallocate($im, 0xFF & ($int >> 0x10), 0xFF & ($int >> 0x8), 0xFF & $int);
1463 foreach ($txt as $text) {
1464 $x = (($w - ($fw * strlen($text))) / 2);
1465 imagestring($im, $font, $x, $y, $text, $color);
1466 $y += ($h + $space);
1469 Header("Content-type: image/png");
1472 } // showTextImage()
1475 * check if all requirements are met
1477 private function checkRequirements()
1479 if(!function_exists("imagecreatefromjpeg")) {
1480 print "PHP GD library extension is missing<br />\n";
1484 if($this->cfg->db_access == "native" && !function_exists("sqlite3_open")) {
1485 print "PHP SQLite3 library extension is missing<br />\n";
1489 /* Check for HTML_AJAX PEAR package, lent from Horde project */
1490 ini_set('track_errors', 1);
1491 @include_once 'HTML/AJAX/Server.php';
1492 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
1493 print "PEAR HTML_AJAX package is missing<br />\n";
1496 @include_once 'Calendar/Calendar.php';
1497 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
1498 print "PEAR Calendar package is missing<br />\n";
1501 ini_restore('track_errors');
1508 } // checkRequirements()
1510 private function _debug($text)
1512 if($this->fromcmd) {
1519 * check if specified MIME type is supported
1521 public function checkifImageSupported($mime)
1523 if(in_array($mime, Array("image/jpeg")))
1528 } // checkifImageSupported()
1530 public function _error($text)
1532 switch($this->cfg->logging) {
1534 print "<img src=\"resources/green_info.png\" alt=\"warning\" />\n";
1541 error_log($text, 3, $his->cfg->log_file);
1548 * output calendard input fields
1550 private function get_calendar($mode)
1552 $year = $_SESSION[$mode .'_date'] ? date("Y", $_SESSION[$mode .'_date']) : date("Y");
1553 $month = $_SESSION[$mode .'_date'] ? date("m", $_SESSION[$mode .'_date']) : date("m");
1554 $day = $_SESSION[$mode .'_date'] ? date("d", $_SESSION[$mode .'_date']) : date("d");
1556 $output = "<input type=\"text\" size=\"3\" id=\"". $mode ."year\" value=\"". $year ."\"";
1557 if(!isset($_SESSION[$mode .'_date'])) $output.= " disabled=\"disabled\"";
1559 $output.= "<input type=\"text\" size=\"1\" id=\"". $mode ."month\" value=\"". $month ."\"";
1560 if(!isset($_SESSION[$mode .'_date'])) $output.= " disabled=\"disabled\"";
1562 $output.= "<input type=\"text\" size=\"1\" id=\"". $mode ."day\" value=\"". $day ."\"";
1563 if(!isset($_SESSION[$mode .'_date'])) $output.= " disabled=\"disabled\"";
1570 * output calendar matrix
1572 public function get_calendar_matrix($year = 0, $month = 0, $day = 0)
1574 if (!isset($year)) $year = date('Y');
1575 if (!isset($month)) $month = date('m');
1576 if (!isset($day)) $day = date('d');
1581 require_once CALENDAR_ROOT.'Month/Weekdays.php';
1582 require_once CALENDAR_ROOT.'Day.php';
1585 $month = new Calendar_Month_Weekdays($year,$month);
1588 $prevStamp = $month->prevMonth(true);
1589 $prev = "javascript:setMonth(". date('Y',$prevStamp) .", ". date('n',$prevStamp) .", ". date('j',$prevStamp) .");";
1590 $nextStamp = $month->nextMonth(true);
1591 $next = "javascript:setMonth(". date('Y',$nextStamp) .", ". date('n',$nextStamp) .", ". date('j',$nextStamp) .");";
1593 $selectedDays = array (
1594 new Calendar_Day($year,$month,$day),
1595 new Calendar_Day($year,12,25),
1598 // Build the days in the month
1599 $month->build($selectedDays);
1601 $this->tmpl->assign('current_month', date('F Y',$month->getTimeStamp()));
1602 $this->tmpl->assign('prev_month', $prev);
1603 $this->tmpl->assign('next_month', $next);
1605 while ( $day = $month->fetch() ) {
1607 if(!isset($matrix[$rows]))
1608 $matrix[$rows] = Array();
1612 $dayStamp = $day->thisDay(true);
1613 $link = "javascript:setCalendarDate(". date('Y',$dayStamp) .", ". date('n',$dayStamp).", ". date('j',$dayStamp) .");";
1615 // isFirst() to find start of week
1616 if ( $day->isFirst() )
1619 if ( $day->isSelected() ) {
1620 $string.= "<td class=\"selected\">".$day->thisDay()."</td>\n";
1621 } else if ( $day->isEmpty() ) {
1622 $string.= "<td> </td>\n";
1624 $string.= "<td><a class=\"calendar\" href=\"".$link."\">".$day->thisDay()."</a></td>\n";
1627 // isLast() to find end of week
1628 if ( $day->isLast() )
1629 $string.= "</tr>\n";
1631 $matrix[$rows][$cols] = $string;
1641 $this->tmpl->assign('matrix', $matrix);
1642 $this->tmpl->assign('rows', $rows);
1643 $this->tmpl->show("calendar.tpl");
1645 } // get_calendar_matrix()
1648 * output export page
1650 public function getExport($mode)
1652 $pictures = $this->getPhotoSelection();
1653 $current_tags = $this->getCurrentTags();
1655 foreach($pictures as $picture) {
1657 $orig_url = $this->get_phpfspot_url() ."index.php?mode=showp&id=". $picture;
1658 if($current_tags != "") {
1659 $orig_url.= "&tags=". $current_tags;
1661 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1662 $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
1665 $thumb_url = $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
1670 // <a href="%pictureurl%"><img src="%thumbnailurl%" ></a>
1671 print htmlspecialchars("<a href=\"". $orig_url ."\"><img src=\"". $thumb_url ."\" /></a>") ."<br />\n";
1675 // "[%pictureurl% %thumbnailurl%]"
1676 print htmlspecialchars("[".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
1679 case 'MoinMoinList':
1680 // " * [%pictureurl% %thumbnailurl%]"
1681 print " " . htmlspecialchars("* [".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
1692 public function getRSSFeed()
1694 Header("Content-type: text/xml; charset=utf-8");
1695 print "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
1698 xmlns:media="http://search.yahoo.com/mrss/"
1699 xmlns:dc="http://purl.org/dc/elements/1.1/"
1702 <title>phpfspot</title>
1703 <description>phpfspot RSS feed</description>
1704 <link><?php print htmlspecialchars($this->get_phpfspot_url()); ?></link>
1705 <pubDate><?php print strftime("%a, %d %b %Y %T %z"); ?></pubDate>
1706 <generator>phpfspot</generator>
1709 $pictures = $this->getPhotoSelection();
1710 $current_tags = $this->getCurrentTags();
1712 foreach($pictures as $picture) {
1714 $orig_url = $this->get_phpfspot_url() ."index.php?mode=showp&id=". $picture;
1715 if($current_tags != "") {
1716 $orig_url.= "&tags=". $current_tags;
1718 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1719 $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
1722 $details = $this->get_photo_details($picture);
1724 $thumb_url = $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
1725 $thumb_html = htmlspecialchars("
1726 <a href=\"". $orig_url ."\"><img src=\"". $thumb_url ."\" /></a>
1728 ". $details['description']);
1730 $orig_path = $this->translate_path($details['directory_path']) ."/". $details['name'];
1731 $meta = $this->get_meta_informations($orig_path);
1732 $meta_date = isset($meta['FileDateTime']) ? $meta['FileDateTime'] : filemtime($orig_path);
1736 <title><?php print htmlspecialchars($details['name']); ?></title>
1737 <link><?php print htmlspecialchars($orig_url); ?></link>
1738 <guid><?php print htmlspecialchars($orig_url); ?></guid>
1739 <dc:date.Taken><?php print strftime("%Y-%m-%dT%H:%M:%S+00:00", $meta_date); ?></dc:date.Taken>
1741 <?php print $thumb_html; ?>
1743 <pubDate><?php print strftime("%a, %d %b %Y %T %z", $meta_date); ?></pubDate>
1758 * return all selected tags as one string
1760 private function getCurrentTags()
1763 if($_SESSION['selected_tags'] != "") {
1764 foreach($_SESSION['selected_tags'] as $tag)
1765 $current_tags.= $tag .",";
1766 $current_tags = substr($current_tags, 0, strlen($current_tags)-1);
1768 return $current_tags;
1770 } // getCurrentTags()
1773 * return the current photo
1775 public function getCurrentPhoto()
1777 if(isset($_SESSION['current_photo'])) {
1778 print $_SESSION['current_photo'];
1780 } // getCurrentPhoto()
1783 * tells the client browser what to do
1785 * this function is getting called via AJAX by the
1786 * client browsers. it will tell them what they have
1787 * to do next. This is necessary for directly jumping
1788 * into photo index or single photo view when the are
1789 * requested with specific URLs
1791 public function whatToDo()
1793 if(isset($_SESSION['current_photo']) && $_SESSION['start_action'] == 'showp') {
1794 return "show_photo";
1796 elseif(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
1797 return "showpi_tags";
1799 elseif(isset($_SESSION['start_action']) && $_SESSION['start_action'] == 'showpi') {
1803 return "nothing special";
1808 * return the current process-user
1810 private function getuid()
1812 if($uid = posix_getuid()) {
1813 if($user = posix_getpwuid($uid)) {
1814 return $user['name'];
1823 * returns a select-dropdown box to select photo index sort parameters
1825 private function get_sort_field()
1827 $output = "<select name=\"sort_order\">";
1828 foreach(array('date_asc', 'date_desc', 'name_asc', 'name_desc') as $sort_order) {
1829 $output.= "<option value=\"". $sort_order ."\"";
1830 if($sort_order == $_SESSION['sort_order']) {
1831 $output.= " selected=\"selected\"";
1833 $output.= ">". $sort_order ."</option>";
1835 $output.= "</select>";
1838 } // get_sort_field()
1841 * returns the currently selected sort order
1843 private function get_sort_order()
1845 switch($_SESSION['sort_order']) {
1847 return " ORDER BY p.time ASC";
1850 return " ORDER BY p.time DESC";
1853 return " ORDER BY p.name ASC";
1856 return " ORDER BY p.name DESC";
1860 } // get_sort_order()
1863 * return the next to be shown slide show image
1865 * this function returns the URL of the next image
1866 * in the slideshow sequence.
1868 public function getNextSlideShowImage()
1870 $all_photos = $this->getPhotoSelection();
1872 if(!isset($_SESSION['slideshow_img']) || $_SESSION['slideshow_img'] == count($all_photos)-1)
1873 $_SESSION['slideshow_img'] = 0;
1875 $_SESSION['slideshow_img']++;
1877 return $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $all_photos[$_SESSION['slideshow_img']] ."&width=". $this->cfg->photo_width;
1879 } // getNextSlideShowImage()
1882 * return the previous to be shown slide show image
1884 * this function returns the URL of the previous image
1885 * in the slideshow sequence.
1887 public function getPrevSlideShowImage()
1889 $all_photos = $this->getPhotoSelection();
1891 if(!isset($_SESSION['slideshow_img']) || $_SESSION['slideshow_img'] == 0)
1892 $_SESSION['slideshow_img'] = 0;
1894 $_SESSION['slideshow_img']--;
1896 return $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $all_photos[$_SESSION['slideshow_img']] ."&width=". $this->cfg->photo_width;
1898 } // getPrevSlideShowImage()
1900 public function resetSlideShow()
1902 if(isset($_SESSION['slideshow_img']))
1903 unset($_SESSION['slideshow_img']);
1904 } // resetSlideShow()
1909 * this function will get all photos from the fspot
1910 * database and randomly return ONE entry
1912 * saddly there is yet no sqlite3 function which returns
1913 * the bulk result in array, so we have to fill up our
1916 public function get_random_photo()
1920 $result = $this->db->db_query("
1925 while($row = $this->db->db_fetch_object($result)) {
1926 array_push($all, $row['id']);
1929 return $all[array_rand($all)];
1931 } // get_random_photo()
1934 * validates provided date
1936 * this function validates if the provided date
1937 * contains a valid date and will return true
1940 public function isValidDate($date_str)
1942 $timestamp = strtotime($date_str);
1944 if(is_numeric($timestamp))
1952 * timestamp to string conversion
1954 private function ts2str($timestamp)
1956 return strftime("%Y-%m-%d", $timestamp);
1959 private function extractTags($tags_str)
1961 $not_validated = split(',', $_GET['tags']);
1962 $validated = array();
1964 foreach($not_validated as $tag) {
1965 if(is_numeric($tag))
1966 array_push($validated, $tag);
1974 * returns the full path to a thumbnail
1976 public function get_thumb_path($width, $photo)
1978 $md5 = $this->getMD5($photo);
1979 $sub_path = substr($md5, 0, 2);
1980 return $this->cfg->thumb_path
1988 } // get_thumb_path()
1991 * returns server's virtual host name
1993 private function get_server_name()
1995 return $_SERVER['SERVER_NAME'];
1996 } // get_server_name()
1999 * returns type of webprotocol which is
2002 private function get_web_protocol()
2004 if(!isset($_SERVER['HTTPS']))
2008 } // get_web_protocol()
2011 * return url to this phpfspot installation
2013 private function get_phpfspot_url()
2015 return $this->get_web_protocol() ."://". $this->get_server_name() . $this->cfg->web_path;
2016 } // get_phpfspot_url()
2019 * check file exists and is readable
2021 * returns true, if everything is ok, otherwise false
2022 * if $silent is not set, this function will output and
2025 private function check_readable($file, $silent = null)
2027 if(!file_exists($file)) {
2029 print "File \"". $file ."\" does not exist.\n";
2033 if(!is_readable($file)) {
2035 print "File \"". $file ."\" is not reachable for user ". $this->getuid() ."\n";
2041 } // check_readable()