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.1";
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 ."'
258 foreach($this->cfg->show_tags as $tag) {
259 $query_str.= "'". $tag ."',";
261 $query_str = substr($query_str, 0, strlen($query_str)-1);
266 WHERE p.id='". $idx ."'
270 $result = $this->db->db_query($query_str);
271 return $this->db->db_fetch_object($result);
273 } // get_photo_details
276 * returns aligned photo names
278 * this function returns aligned (length) names for
279 * an specific photo. If the length of the name exceeds
280 * $limit the name will be shrinked (...)
282 public function getPhotoName($idx, $limit = 0)
284 if($details = $this->get_photo_details($idx)) {
285 $name = $this->shrink_text($details['name'], $limit);
292 * shrink text according provided limit
294 * If the length of the name exceeds $limit the
295 * text will be shortend and some content in between
296 * will be replaced with "..."
298 private function shrink_text($text, $limit)
300 if($limit != 0 && strlen($text) > $limit) {
301 $text = substr($text, 0, $limit-5) ."...". substr($text, -($limit-5));
309 * translate f-spoth photo path
311 * as the full-qualified path recorded in the f-spot database
312 * is usally not the same as on the webserver, this function
313 * will replace the path with that one specified in the cfg
315 public function translate_path($path, $width = 0)
317 return str_replace($this->cfg->path_replace_from, $this->cfg->path_replace_to, $path);
322 * control HTML ouput for a single photo
324 * this function provides all the necessary information
325 * for the single photo template.
327 public function showPhoto($photo)
329 /* get all photos from the current photo selection */
330 $all_photos = $this->getPhotoSelection();
331 $count = count($all_photos);
333 for($i = 0; $i < $count; $i++) {
335 // $get_next will be set, when the photo which has to
336 // be displayed has been found - this means that the
337 // next available is in fact the NEXT image (for the
339 if(isset($get_next)) {
340 $next_img = $all_photos[$i];
344 /* the next photo is our NEXT photo */
345 if($all_photos[$i] == $photo) {
349 $previous_img = $all_photos[$i];
352 if($photo == $all_photos[$i]) {
357 $details = $this->get_photo_details($photo);
364 $orig_path = $this->translate_path($details['directory_path']) ."/". $details['name'];
365 $thumb_path = $this->get_thumb_path($this->cfg->photo_width, $photo);
367 if(!file_exists($orig_path)) {
368 $this->_error("Photo ". $orig_path ." does not exist!<br />\n");
371 if(!is_readable($orig_path)) {
372 $this->_error("Photo ". $orig_path ." is not readable for user ". $this->getuid() ."<br />\n");
375 /* If the thumbnail doesn't exist yet, try to create it */
376 if(!file_exists($thumb_path)) {
377 $this->gen_thumb($photo, true);
378 $thumb_path = $this->get_thumb_path($this->cfg->photo_width, $photo);
381 /* get f-spot database meta information */
382 $meta = $this->get_meta_informations($orig_path);
384 /* If EXIF data are available, use them */
385 if(isset($meta['ExifImageWidth'])) {
386 $meta_res = $meta['ExifImageWidth'] ."x". $meta['ExifImageLength'];
388 $info = getimagesize($orig_path);
389 $meta_res = $info[0] ."x". $info[1];
392 $meta_date = isset($meta['FileDateTime']) ? strftime("%a %x %X", $meta['FileDateTime']) : "n/a";
393 $meta_make = isset($meta['Make']) ? $meta['Make'] ." / ". $meta['Model'] : "n/a";
394 $meta_size = isset($meta['FileSize']) ? round($meta['FileSize']/1024, 1) ."kbyte" : "n/a";
396 $extern_link = "index.php?mode=showp&id=". $photo;
397 $current_tags = $this->getCurrentTags();
398 if($current_tags != "") {
399 $extern_link.= "&tags=". $current_tags;
401 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
402 $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
405 $this->tmpl->assign('extern_link', $extern_link);
407 if(file_exists($thumb_path)) {
409 $info = getimagesize($thumb_path);
411 $this->tmpl->assign('description', $details['description']);
412 $this->tmpl->assign('image_name', $details['name']);
414 $this->tmpl->assign('width', $info[0]);
415 $this->tmpl->assign('height', $info[1]);
416 $this->tmpl->assign('ExifMadeOn', $meta_date);
417 $this->tmpl->assign('ExifMadeWith', $meta_make);
418 $this->tmpl->assign('ExifOrigResolution', $meta_res);
419 $this->tmpl->assign('ExifFileSize', $meta_size);
421 $this->tmpl->assign('image_url', 'phpfspot_img.php?idx='. $photo ."&width=". $this->cfg->photo_width);
422 $this->tmpl->assign('image_url_full', 'phpfspot_img.php?idx='. $photo);
424 $this->tmpl->assign('tags', $this->get_photo_tags($photo));
425 $this->tmpl->assign('current', $current);
428 $this->_error("Can't open file ". $thumb_path ."\n");
433 $this->tmpl->assign('previous_url', "javascript:showImage(". $previous_img .");");
434 $this->tmpl->assign('prev_img', $previous_img);
438 $this->tmpl->assign('next_url', "javascript:showImage(". $next_img .");");
439 $this->tmpl->assign('next_img', $next_img);
441 $this->tmpl->assign('mini_width', $this->cfg->mini_width);
442 $this->tmpl->assign('photo_number', $i);
443 $this->tmpl->assign('photo_count', count($all_photos));
445 $this->tmpl->show("single_photo.tpl");
450 * all available tags and tag cloud
452 * this function outputs all available tags (time ordered)
453 * and in addition output them as tag cloud (tags which have
454 * many photos will appears more then others)
456 public function getAvailableTags()
460 $result = $this->db->db_query("
461 SELECT tag_id as id, count(tag_id) as quantity
471 while($row = $this->db->db_fetch_object($result)) {
472 $tags[$row['id']] = $row['quantity'];
475 // change these font sizes if you will
476 $max_size = 125; // max font size in %
477 $min_size = 75; // min font size in %
479 // get the largest and smallest array values
480 $max_qty = max(array_values($tags));
481 $min_qty = min(array_values($tags));
483 // find the range of values
484 $spread = $max_qty - $min_qty;
485 if (0 == $spread) { // we don't want to divide by zero
489 // determine the font-size increment
490 // this is the increase per tag quantity (times used)
491 $step = ($max_size - $min_size)/($spread);
493 // loop through our tag array
494 foreach ($tags as $key => $value) {
496 if(isset($_SESSION['selected_tags']) && in_array($key, $_SESSION['selected_tags']))
499 // calculate CSS font-size
500 // find the $value in excess of $min_qty
501 // multiply by the font-size increment ($size)
502 // and add the $min_size set above
503 $size = $min_size + (($value - $min_qty) * $step);
504 // uncomment if you want sizes in whole %:
507 if(isset($this->tags[$key])) {
508 $output.= "<a href=\"javascript:Tags('add', ". $key .");\" class=\"tag\" style=\"font-size: ". $size ."%;\">". $this->tags[$key] ."</a>, ";
513 $output = substr($output, 0, strlen($output)-2);
516 } // getAvailableTags()
519 * output all selected tags
521 * this function output all tags which have been selected
522 * by the user. the selected tags are stored in the
523 * session-variable $_SESSION['selected_tags']
525 public function getSelectedTags()
528 foreach($this->avail_tags as $tag)
530 // return all selected tags
531 if(isset($_SESSION['selected_tags']) && in_array($tag, $_SESSION['selected_tags'])) {
532 $output.= "<a href=\"javascript:Tags('del', ". $tag .");\" class=\"tag\">". $this->tags[$tag] ."</a>, ";
536 $output = substr($output, 0, strlen($output)-2);
539 } // getSelectedTags()
542 * add tag to users session variable
544 * this function will add the specified to users current
545 * tag selection. if a date search has been made before
546 * it will be now cleared
548 public function addTag($tag)
550 if(!isset($_SESSION['selected_tags']))
551 $_SESSION['selected_tags'] = Array();
553 if(!in_array($tag, $_SESSION['selected_tags']))
554 array_push($_SESSION['selected_tags'], $tag);
559 * remove tag to users session variable
561 * this function removes the specified tag from
562 * users current tag selection
564 public function delTag($tag)
566 if(isset($_SESSION['selected_tags'])) {
567 $key = array_search($tag, $_SESSION['selected_tags']);
568 unset($_SESSION['selected_tags'][$key]);
569 sort($_SESSION['selected_tags']);
575 * reset tag selection
577 * if there is any tag selection, it will be
580 public function resetTags()
582 if(isset($_SESSION['selected_tags']))
583 unset($_SESSION['selected_tags']);
590 * if a specific photo was requested (external link)
591 * unset the session variable now
593 public function resetPhotoView()
595 if(isset($_SESSION['current_photo']))
596 unset($_SESSION['current_photo']);
598 } // resetPhotoView();
603 * if any tag search has taken place, reset
606 public function resetTagSearch()
608 if(isset($_SESSION['searchfor']))
609 unset($_SESSION['searchfor']);
611 } // resetTagSearch()
616 * if any date search has taken place, reset
619 public function resetDateSearch()
621 if(isset($_SESSION['from_date']))
622 unset($_SESSION['from_date']);
623 if(isset($_SESSION['to_date']))
624 unset($_SESSION['to_date']);
626 } // resetDateSearch();
629 * return all photo according selection
631 * this function returns all photos based on
632 * the tag-selection, tag- or date-search.
633 * the tag-search also has to take care of AND
634 * and OR conjunctions
636 public function getPhotoSelection()
638 $matched_photos = Array();
640 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
641 $from_date = $_SESSION['from_date'];
642 $to_date = $_SESSION['to_date'];
643 $additional_where_cond = "
644 p.time>='". $from_date ."'
646 p.time<='". $to_date ."'
650 if(isset($_SESSION['sort_order'])) {
651 $order_str = $this->get_sort_order();
654 /* return a search result */
655 if(isset($_SESSION['searchfor']) && $_SESSION['searchfor'] != '') {
657 SELECT DISTINCT photo_id
663 WHERE t.name LIKE '%". $_SESSION['searchfor'] ."%'";
665 if(isset($additional_where_cond))
666 $query_str.= "AND ". $additional_where_cond ." ";
668 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
669 $query_str.= "AND t.name IN (";
670 foreach($this->cfg->show_tags as $tag) {
671 $query_str.= "'". $tag ."',";
673 $query_str = substr($query_str, 0, strlen($query_str)-1) . ")";
676 if(isset($order_str))
677 $query_str.= $order_str;
679 $result = $this->db->db_query($query_str);
680 while($row = $this->db->db_fetch_object($result)) {
681 array_push($matched_photos, $row['photo_id']);
683 return $matched_photos;
686 /* return according the selected tags */
687 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
689 foreach($_SESSION['selected_tags'] as $tag)
690 $selected.= $tag .",";
691 $selected = substr($selected, 0, strlen($selected)-1);
693 if($_SESSION['tag_condition'] == 'or') {
695 SELECT DISTINCT pt.photo_id
701 WHERE pt.tag_id IN (". $selected .")
703 if(isset($additional_where_cond))
704 $query_str.= "AND ". $additional_where_cond ." ";
706 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
707 $query_str.= "AND t.name IN (";
708 foreach($this->cfg->show_tags as $tag) {
709 $query_str.= "'". $tag ."',";
711 $query_str = substr($query_str, 0, strlen($query_str)-1) . ")";
714 if(isset($order_str))
715 $query_str.= $order_str;
717 elseif($_SESSION['tag_condition'] == 'and') {
719 if(count($_SESSION['selected_tags']) >= 32) {
720 print "A SQLite limit of 32 tables within a JOIN SELECT avoids to<br />\n";
721 print "evaluate your tag selection. Please remove some tags from your selection.\n";
725 /* Join together a table looking like
727 pt1.photo_id pt1.tag_id pt2.photo_id pt2.tag_id ...
729 so the query can quickly return all images matching the
730 selected tags in an AND condition
735 SELECT DISTINCT pt1.photo_id
739 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
746 for($i = 0; $i < count($_SESSION['selected_tags']); $i++) {
748 INNER JOIN photo_tags pt". ($i+2) ."
749 ON pt1.photo_id=pt". ($i+2) .".photo_id
756 $query_str.= "WHERE pt1.tag_id=". $_SESSION['selected_tags'][0];
757 for($i = 1; $i < count($_SESSION['selected_tags']); $i++) {
759 AND pt". ($i+1) .".tag_id=". $_SESSION['selected_tags'][$i] ."
762 if(isset($additional_where_cond))
763 $query_str.= "AND ". $additional_where_cond;
765 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
766 $query_str.= "AND t.name IN (";
767 foreach($this->cfg->show_tags as $tag) {
768 $query_str.= "'". $tag ."',";
770 $query_str = substr($query_str, 0, strlen($query_str)-1) . ")";
773 if(isset($order_str))
774 $query_str.= $order_str;
778 $result = $this->db->db_query($query_str);
779 while($row = $this->db->db_fetch_object($result)) {
780 array_push($matched_photos, $row['photo_id']);
782 return $matched_photos;
785 /* return all available photos */
787 SELECT DISTINCT photo_id
794 if(isset($additional_where_cond))
795 $query_str.= "WHERE ". $additional_where_cond ." ";
797 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
798 $query_str.= "AND t.name IN (";
799 foreach($this->cfg->show_tags as $tag) {
800 $query_str.= "'". $tag ."',";
802 $query_str = substr($query_str, 0, strlen($query_str)-1) . ")";
805 if(isset($order_str))
806 $query_str.= $order_str;
808 $result = $this->db->db_query($query_str);
809 while($row = $this->db->db_fetch_object($result)) {
810 array_push($matched_photos, $row['photo_id']);
812 return $matched_photos;
814 } // getPhotoSelection()
817 * control HTML ouput for photo index
819 * this function provides all the necessary information
820 * for the photo index template.
822 public function showPhotoIndex()
824 $photos = $this->getPhotoSelection();
826 $count = count($photos);
828 if(isset($_SESSION['begin_with']) && $_SESSION['begin_with'] != "")
829 $anchor = $_SESSION['begin_with'];
831 if(!isset($this->cfg->rows_per_page) || $this->cfg->rows_per_page == 0) {
837 elseif($this->cfg->rows_per_page > 0) {
839 if(!$_SESSION['begin_with'] || $_SESSION['begin_with'] == 0)
843 $begin_with = $_SESSION['begin_with'];
845 // verify $begin_with - perhaps the thumbs-per-rows or
846 // rows-per-page variables have changed or the jump back
847 // from a photo wasn't exact - so calculate the real new
849 $multiplicator = $this->cfg->rows_per_page * $this->cfg->thumbs_per_row;
850 for($i = 0; $i <= $count; $i+=$multiplicator) {
851 if($begin_with >= $i && $begin_with < $i+$multiplicator) {
858 $end_with = $begin_with + ($this->cfg->rows_per_page * $this->cfg->thumbs_per_row);
864 $images[$rows] = Array();
865 $img_height[$rows] = Array();
866 $img_width[$rows] = Array();
867 $img_id[$rows] = Array();
868 $img_name[$rows] = Array();
869 $img_title = Array();
871 for($i = $begin_with; $i < $end_with; $i++) {
873 $images[$rows][$cols] = $photos[$i];
874 $img_id[$rows][$cols] = $i;
875 $img_name[$rows][$cols] = htmlspecialchars($this->getPhotoName($photos[$i], 15));
876 $img_title[$rows][$cols] = "Click to view photo ". htmlspecialchars($this->getPhotoName($photos[$i], 0));
878 $thumb_path = $this->get_thumb_path($this->cfg->thumb_width, $photos[$i]);
880 if(file_exists($thumb_path)) {
881 $info = getimagesize($thumb_path);
882 $img_width[$rows][$cols] = $info[0];
883 $img_height[$rows][$cols] = $info[1];
886 if($cols == $this->cfg->thumbs_per_row-1) {
889 $images[$rows] = Array();
890 $img_width[$rows] = Array();
891 $img_height[$rows] = Array();
898 // +1 for for smarty's selection iteration
901 if(isset($_SESSION['searchfor']) && $_SESSION['searchfor'] != '')
902 $this->tmpl->assign('searchfor', $_SESSION['searchfor']);
904 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
905 $this->tmpl->assign('from_date', $this->ts2str($_SESSION['from_date']));
906 $this->tmpl->assign('to_date', $this->ts2str($_SESSION['to_date']));
909 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
910 $this->tmpl->assign('tag_result', 1);
913 /* do we have to display the page selector ? */
914 if($this->cfg->rows_per_page != 0) {
916 /* calculate the page switchers */
917 $previous_start = $begin_with - ($this->cfg->rows_per_page * $this->cfg->thumbs_per_row);
918 $next_start = $begin_with + ($this->cfg->rows_per_page * $this->cfg->thumbs_per_row);
921 $this->tmpl->assign("previous_url", "javascript:showPhotoIndex(". $previous_start .");");
922 if($end_with < $count)
923 $this->tmpl->assign("next_url", "javascript:showPhotoIndex(". $next_start .");");
925 $photo_per_page = $this->cfg->rows_per_page * $this->cfg->thumbs_per_row;
926 $last_page = ceil($count / $photo_per_page);
928 /* get the current selected page */
929 if($begin_with == 0) {
933 for($i = $begin_with; $i >= 0; $i-=$photo_per_page) {
940 for($i = 1; $i <= $last_page; $i++) {
942 if($current_page == $i)
943 $style = "style=\"font-size: 125%; text-decoration: underline;\"";
944 elseif($current_page-1 == $i || $current_page+1 == $i)
945 $style = "style=\"font-size: 105%;\"";
946 elseif(($current_page-5 >= $i) && ($i != 1) ||
947 ($current_page+5 <= $i) && ($i != $last_page))
948 $style = "style=\"font-size: 75%;\"";
952 $select = "<a href=\"javascript:showPhotoIndex(". (($i*$photo_per_page)-$photo_per_page) .");\"";
955 $select.= ">". $i ."</a> ";
957 // until 9 pages we show the selector from 1-9
958 if($last_page <= 9) {
959 $page_select.= $select;
962 if($i == 1 /* first page */ ||
963 $i == $last_page /* last page */ ||
964 $i == $current_page /* current page */ ||
965 $i == ceil($last_page * 0.25) /* first quater */ ||
966 $i == ceil($last_page * 0.5) /* half */ ||
967 $i == ceil($last_page * 0.75) /* third quater */ ||
968 (in_array($i, array(1,2,3,4,5,6)) && $current_page <= 4) /* the first 6 */ ||
969 (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 */ ||
970 $i == $current_page-3 || $i == $current_page-2 || $i == $current_page-1 /* three before */ ||
971 $i == $current_page+3 || $i == $current_page+2 || $i == $current_page+1 /* three after */) {
973 $page_select.= $select;
981 $page_select.= "......... ";
986 /* only show the page selector if we have more then one page */
988 $this->tmpl->assign('page_selector', $page_select);
992 $current_tags = $this->getCurrentTags();
993 $extern_link = "index.php?mode=showpi";
994 $rss_link = "index.php?mode=rss";
995 if($current_tags != "") {
996 $extern_link.= "&tags=". $current_tags;
997 $rss_link.= "&tags=". $current_tags;
999 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1000 $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
1001 $rss_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
1004 $export_link = "index.php?mode=export";
1005 $slideshow_link = "index.php?mode=slideshow";
1007 $this->tmpl->assign('extern_link', $extern_link);
1008 $this->tmpl->assign('slideshow_link', $slideshow_link);
1009 $this->tmpl->assign('export_link', $export_link);
1010 $this->tmpl->assign('rss_link', $rss_link);
1011 $this->tmpl->assign('count', $count);
1012 $this->tmpl->assign('width', $this->cfg->thumb_width);
1013 $this->tmpl->assign('images', $images);
1014 $this->tmpl->assign('img_width', $img_width);
1015 $this->tmpl->assign('img_height', $img_height);
1016 $this->tmpl->assign('img_id', $img_id);
1017 $this->tmpl->assign('img_name', $img_name);
1018 $this->tmpl->assign('img_title', $img_title);
1019 $this->tmpl->assign('rows', $rows);
1020 $this->tmpl->assign('columns', $this->cfg->thumbs_per_row);
1022 $this->tmpl->show("photo_index.tpl");
1025 print "<script language=\"JavaScript\">self.location.hash = '#image". $anchor ."';</script>\n";
1027 } // showPhotoIndex()
1030 * show credit template
1032 public function showCredits()
1034 $this->tmpl->assign('version', $this->cfg->version);
1035 $this->tmpl->assign('product', $this->cfg->product);
1036 $this->tmpl->show("credits.tpl");
1041 * create_thumbnails for the requested width
1043 * this function creates image thumbnails of $orig_image
1044 * stored as $thumb_image. It will check if the image is
1045 * in a supported format, if necessary rotate the image
1046 * (based on EXIF orientation meta headers) and re-sizing.
1048 public function create_thumbnail($orig_image, $thumb_image, $width)
1050 if(!file_exists($orig_image)) {
1054 $details = getimagesize($orig_image);
1056 /* check if original photo is a support image type */
1057 if(!$this->checkifImageSupported($details['mime']))
1060 $meta = $this->get_meta_informations($orig_image);
1065 switch($meta['Orientation']) {
1067 case 1: /* top, left */
1068 $rotate = 0; $flip = false; break;
1069 case 2: /* top, right */
1070 $rotate = 0; $flip = true; break;
1071 case 3: /* bottom, left */
1072 $rotate = 180; $flip = false; break;
1073 case 4: /* bottom, right */
1074 $rotate = 180; $flip = true; break;
1075 case 5: /* left side, top */
1076 $rotate = 90; $flip = true; break;
1077 case 6: /* right side, top */
1078 $rotate = 90; $flip = false; break;
1079 case 7: /* left side, bottom */
1080 $rotate = 270; $flip = true; break;
1081 case 8: /* right side, bottom */
1082 $rotate = 270; $flip = false; break;
1085 $src_img = @imagecreatefromjpeg($orig_image);
1088 print "Can't load image from ". $orig_image ."\n";
1092 /* grabs the height and width */
1093 $cur_width = imagesx($src_img);
1094 $cur_height = imagesy($src_img);
1096 // If requested width is more then the actual image width,
1097 // do not generate a thumbnail, instead safe the original
1098 // as thumbnail but with lower quality
1100 if($width >= $cur_width) {
1101 $result = imagejpeg($src_img, $thumb_image, 75);
1102 imagedestroy($src_img);
1106 // If the image will be rotate because EXIF orientation said so
1107 // 'virtually rotate' the image for further calculations
1108 if($rotate == 90 || $rotate == 270) {
1110 $cur_width = $cur_height;
1114 /* calculates aspect ratio */
1115 $aspect_ratio = $cur_height / $cur_width;
1118 if($aspect_ratio < 1) {
1120 $new_h = abs($new_w * $aspect_ratio);
1122 /* 'virtually' rotate the image and calculate it's ratio */
1123 $tmp_w = $cur_height;
1124 $tmp_h = $cur_width;
1125 /* now get the ratio from the 'rotated' image */
1126 $tmp_ratio = $tmp_h/$tmp_w;
1127 /* now calculate the new dimensions */
1129 $tmp_h = abs($tmp_w * $tmp_ratio);
1131 // now that we know, how high they photo should be, if it
1132 // gets rotated, use this high to scale the image
1134 $new_w = abs($new_h / $aspect_ratio);
1136 // If the image will be rotate because EXIF orientation said so
1137 // now 'virtually rotate' back the image for the image manipulation
1138 if($rotate == 90 || $rotate == 270) {
1145 /* creates new image of that size */
1146 $dst_img = imagecreatetruecolor($new_w, $new_h);
1148 imagefill($dst_img, 0, 0, ImageColorAllocate($dst_img, 255, 255, 255));
1150 /* copies resized portion of original image into new image */
1151 imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $new_w, $new_h, imagesx($src_img), imagesy($src_img));
1153 /* needs the image to be flipped horizontal? */
1157 for($x = 0; $x < $new_w; $x++) {
1158 imagecopy($dst_img, $image, $x, 0, $w - $x - 1, 0, 1, $h);
1163 $this->_debug("(ROTATE)");
1164 $dst_img = $this->rotateImage($dst_img, $rotate);
1167 /* write down new generated file */
1168 $result = imagejpeg($dst_img, $thumb_image, 75);
1170 /* free your mind */
1171 imagedestroy($dst_img);
1172 imagedestroy($src_img);
1174 if($result === false) {
1175 print "Can't write thumbnail ". $thumb_image ."\n";
1181 } // create_thumbnail()
1184 * return all exif meta data from the file
1186 public function get_meta_informations($file)
1188 return exif_read_data($file);
1190 } // get_meta_informations()
1193 * create phpfspot own sqlite database
1195 * this function creates phpfspots own sqlite database
1196 * if it does not exist yet. this own is used to store
1197 * some necessary informations (md5 sum's, ...).
1199 public function check_config_table()
1201 // if the config table doesn't exist yet, create it
1202 if(!$this->cfg_db->db_check_table_exists("images")) {
1203 $this->cfg_db->db_exec("
1204 CREATE TABLE images (
1205 img_idx int primary key,
1211 } // check_config_table
1214 * Generates a thumbnail from photo idx
1216 * This function will generate JPEG thumbnails from provided F-Spot photo
1219 * 1. Check if all thumbnail generations (width) are already in place and
1221 * 2. Check if the md5sum of the original file has changed
1222 * 3. Generate the thumbnails if needed
1224 public function gen_thumb($idx = 0, $force = 0)
1228 $resolutions = Array(
1229 $this->cfg->thumb_width,
1230 $this->cfg->photo_width,
1231 $this->cfg->mini_width,
1234 /* get details from F-Spot's database */
1235 $details = $this->get_photo_details($idx);
1237 /* calculate file MD5 sum */
1238 $full_path = $this->translate_path($details['directory_path']) ."/". $details['name'];
1240 if(!file_exists($full_path)) {
1241 $this->_error("File ". $full_path ." does not exist\n");
1245 if(!is_readable($full_path)) {
1246 $this->_error("File ". $full_path ." is not readable for ". $this->getuid() ."\n");
1250 $file_md5 = md5_file($full_path);
1252 $this->_debug("Image [". $idx ."] ". $this->shrink_text($details['name'], 20) ." Thumbnails:");
1254 foreach($resolutions as $resolution) {
1256 $thumb_sub_path = substr($file_md5, 0, 2);
1257 $thumb_path = $this->cfg->thumb_path ."/". $thumb_sub_path ."/". $resolution ."_". $file_md5;
1259 if(!file_exists(dirname($thumb_path))) {
1260 mkdir(dirname($thumb_path), 0755);
1263 /* if the thumbnail file doesn't exist, create it */
1264 if(!file_exists($thumb_path)) {
1266 $this->_debug(" ". $resolution ."px");
1267 if(!$this->create_thumbnail($full_path, $thumb_path, $resolution))
1270 /* if the file hasn't changed there is no need to regen the thumb */
1271 elseif($file_md5 != $this->getMD5($idx) || $force) {
1273 $this->_debug(" ". $resolution ."px");
1274 if(!$this->create_thumbnail($full_path, $thumb_path, $resolution))
1280 /* set the new/changed MD5 sum for the current photo */
1282 $this->setMD5($idx, $file_md5);
1285 $this->_debug("\n");
1290 * returns stored md5 sum for a specific photo
1292 * this function queries the phpfspot database for a
1293 * stored MD5 checksum of the specified photo
1295 public function getMD5($idx)
1297 $result = $this->cfg_db->db_query("
1300 WHERE img_idx='". $idx ."'
1306 $img = $this->cfg_db->db_fetch_object($result);
1307 return $img['img_md5'];
1312 * set MD5 sum for the specific photo
1314 private function setMD5($idx, $md5)
1316 $result = $this->cfg_db->db_exec("
1317 REPLACE INTO images (img_idx, img_md5)
1318 VALUES ('". $idx ."', '". $md5 ."')
1324 * store current tag condition
1326 * this function stores the current tag condition
1327 * (AND or OR) in the users session variables
1329 public function setTagCondition($mode)
1331 $_SESSION['tag_condition'] = $mode;
1333 } // setTagCondition()
1336 * invoke tag & date search
1338 * this function will return all matching tags and store
1339 * them in the session variable selected_tags. furthermore
1340 * it also handles the date search.
1341 * getPhotoSelection() will then only return the matching
1344 public function startSearch($searchfor, $sort_order, $from = 0, $to = 0)
1346 $_SESSION['searchfor'] = $searchfor;
1347 $_SESSION['sort_order'] = $sort_order;
1349 $_SESSION['from_date'] = strtotime($from);
1351 unset($_SESSION['from_date']);
1353 $_SESSION['to_date'] = strtotime($to);
1355 unset($_SESSION['to_date']);
1357 if($searchfor != "") {
1358 /* new search, reset the current selected tags */
1359 $_SESSION['selected_tags'] = Array();
1360 foreach($this->avail_tags as $tag) {
1361 if(preg_match('/'. $searchfor .'/i', $this->tags[$tag]))
1362 array_push($_SESSION['selected_tags'], $tag);
1371 * this function rotates the image according the
1374 private function rotateImage($img, $degrees)
1376 if(function_exists("imagerotate")) {
1377 $img = imagerotate($img, $degrees, 0);
1379 function imagerotate($src_img, $angle)
1381 $src_x = imagesx($src_img);
1382 $src_y = imagesy($src_img);
1383 if ($angle == 180) {
1387 elseif ($src_x <= $src_y) {
1391 elseif ($src_x >= $src_y) {
1396 $rotate=imagecreatetruecolor($dest_x,$dest_y);
1397 imagealphablending($rotate, false);
1402 for ($y = 0; $y < ($src_y); $y++) {
1403 for ($x = 0; $x < ($src_x); $x++) {
1404 $color = imagecolorat($src_img, $x, $y);
1405 imagesetpixel($rotate, $dest_x - $y - 1, $x, $color);
1411 for ($y = 0; $y < ($src_y); $y++) {
1412 for ($x = 0; $x < ($src_x); $x++) {
1413 $color = imagecolorat($src_img, $x, $y);
1414 imagesetpixel($rotate, $y, $dest_y - $x - 1, $color);
1420 for ($y = 0; $y < ($src_y); $y++) {
1421 for ($x = 0; $x < ($src_x); $x++) {
1422 $color = imagecolorat($src_img, $x, $y);
1423 imagesetpixel($rotate, $dest_x - $x - 1, $dest_y - $y - 1, $color);
1437 $img = imagerotate($img, $degrees);
1446 * return all assigned tags for the specified photo
1448 private function get_photo_tags($idx)
1450 $result = $this->db->db_query("
1453 INNER JOIN photo_tags pt
1455 WHERE pt.photo_id='". $idx ."'
1460 while($row = $this->db->db_fetch_object($result))
1461 $tags[$row['id']] = $row['name'];
1465 } // get_photo_tags()
1468 * create on-the-fly images with text within
1470 public function showTextImage($txt, $color=000000, $space=4, $font=4, $w=300)
1472 if (strlen($color) != 6)
1475 $int = hexdec($color);
1476 $h = imagefontheight($font);
1477 $fw = imagefontwidth($font);
1478 $txt = explode("\n", wordwrap($txt, ($w / $fw), "\n"));
1479 $lines = count($txt);
1480 $im = imagecreate($w, (($h * $lines) + ($lines * $space)));
1481 $bg = imagecolorallocate($im, 255, 255, 255);
1482 $color = imagecolorallocate($im, 0xFF & ($int >> 0x10), 0xFF & ($int >> 0x8), 0xFF & $int);
1485 foreach ($txt as $text) {
1486 $x = (($w - ($fw * strlen($text))) / 2);
1487 imagestring($im, $font, $x, $y, $text, $color);
1488 $y += ($h + $space);
1491 Header("Content-type: image/png");
1494 } // showTextImage()
1497 * check if all requirements are met
1499 private function checkRequirements()
1501 if(!function_exists("imagecreatefromjpeg")) {
1502 print "PHP GD library extension is missing<br />\n";
1506 if($this->cfg->db_access == "native" && !function_exists("sqlite3_open")) {
1507 print "PHP SQLite3 library extension is missing<br />\n";
1511 /* Check for HTML_AJAX PEAR package, lent from Horde project */
1512 ini_set('track_errors', 1);
1513 @include_once 'HTML/AJAX/Server.php';
1514 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
1515 print "PEAR HTML_AJAX package is missing<br />\n";
1518 @include_once 'Calendar/Calendar.php';
1519 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
1520 print "PEAR Calendar package is missing<br />\n";
1523 ini_restore('track_errors');
1530 } // checkRequirements()
1532 private function _debug($text)
1534 if($this->fromcmd) {
1541 * check if specified MIME type is supported
1543 public function checkifImageSupported($mime)
1545 if(in_array($mime, Array("image/jpeg")))
1550 } // checkifImageSupported()
1552 public function _error($text)
1554 switch($this->cfg->logging) {
1556 print "<img src=\"resources/green_info.png\" alt=\"warning\" />\n";
1563 error_log($text, 3, $his->cfg->log_file);
1570 * output calendard input fields
1572 private function get_calendar($mode)
1574 $year = $_SESSION[$mode .'_date'] ? date("Y", $_SESSION[$mode .'_date']) : date("Y");
1575 $month = $_SESSION[$mode .'_date'] ? date("m", $_SESSION[$mode .'_date']) : date("m");
1576 $day = $_SESSION[$mode .'_date'] ? date("d", $_SESSION[$mode .'_date']) : date("d");
1578 $output = "<input type=\"text\" size=\"3\" id=\"". $mode ."year\" value=\"". $year ."\"";
1579 if(!isset($_SESSION[$mode .'_date'])) $output.= " disabled=\"disabled\"";
1581 $output.= "<input type=\"text\" size=\"1\" id=\"". $mode ."month\" value=\"". $month ."\"";
1582 if(!isset($_SESSION[$mode .'_date'])) $output.= " disabled=\"disabled\"";
1584 $output.= "<input type=\"text\" size=\"1\" id=\"". $mode ."day\" value=\"". $day ."\"";
1585 if(!isset($_SESSION[$mode .'_date'])) $output.= " disabled=\"disabled\"";
1592 * output calendar matrix
1594 public function get_calendar_matrix($year = 0, $month = 0, $day = 0)
1596 if (!isset($year)) $year = date('Y');
1597 if (!isset($month)) $month = date('m');
1598 if (!isset($day)) $day = date('d');
1603 require_once CALENDAR_ROOT.'Month/Weekdays.php';
1604 require_once CALENDAR_ROOT.'Day.php';
1607 $month = new Calendar_Month_Weekdays($year,$month);
1610 $prevStamp = $month->prevMonth(true);
1611 $prev = "javascript:setMonth(". date('Y',$prevStamp) .", ". date('n',$prevStamp) .", ". date('j',$prevStamp) .");";
1612 $nextStamp = $month->nextMonth(true);
1613 $next = "javascript:setMonth(". date('Y',$nextStamp) .", ". date('n',$nextStamp) .", ". date('j',$nextStamp) .");";
1615 $selectedDays = array (
1616 new Calendar_Day($year,$month,$day),
1617 new Calendar_Day($year,12,25),
1620 // Build the days in the month
1621 $month->build($selectedDays);
1623 $this->tmpl->assign('current_month', date('F Y',$month->getTimeStamp()));
1624 $this->tmpl->assign('prev_month', $prev);
1625 $this->tmpl->assign('next_month', $next);
1627 while ( $day = $month->fetch() ) {
1629 if(!isset($matrix[$rows]))
1630 $matrix[$rows] = Array();
1634 $dayStamp = $day->thisDay(true);
1635 $link = "javascript:setCalendarDate(". date('Y',$dayStamp) .", ". date('n',$dayStamp).", ". date('j',$dayStamp) .");";
1637 // isFirst() to find start of week
1638 if ( $day->isFirst() )
1641 if ( $day->isSelected() ) {
1642 $string.= "<td class=\"selected\">".$day->thisDay()."</td>\n";
1643 } else if ( $day->isEmpty() ) {
1644 $string.= "<td> </td>\n";
1646 $string.= "<td><a class=\"calendar\" href=\"".$link."\">".$day->thisDay()."</a></td>\n";
1649 // isLast() to find end of week
1650 if ( $day->isLast() )
1651 $string.= "</tr>\n";
1653 $matrix[$rows][$cols] = $string;
1663 $this->tmpl->assign('matrix', $matrix);
1664 $this->tmpl->assign('rows', $rows);
1665 $this->tmpl->show("calendar.tpl");
1667 } // get_calendar_matrix()
1670 * output export page
1672 public function getExport($mode)
1674 $pictures = $this->getPhotoSelection();
1675 $current_tags = $this->getCurrentTags();
1677 foreach($pictures as $picture) {
1679 $orig_url = $this->get_phpfspot_url() ."index.php?mode=showp&id=". $picture;
1680 if($current_tags != "") {
1681 $orig_url.= "&tags=". $current_tags;
1683 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1684 $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
1687 $thumb_url = $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
1692 // <a href="%pictureurl%"><img src="%thumbnailurl%" ></a>
1693 print htmlspecialchars("<a href=\"". $orig_url ."\"><img src=\"". $thumb_url ."\" /></a>") ."<br />\n";
1697 // "[%pictureurl% %thumbnailurl%]"
1698 print htmlspecialchars("[".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
1701 case 'MoinMoinList':
1702 // " * [%pictureurl% %thumbnailurl%]"
1703 print " " . htmlspecialchars("* [".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
1714 public function getRSSFeed()
1716 Header("Content-type: text/xml; charset=utf-8");
1717 print "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
1720 xmlns:media="http://search.yahoo.com/mrss/"
1721 xmlns:dc="http://purl.org/dc/elements/1.1/"
1724 <title>phpfspot</title>
1725 <description>phpfspot RSS feed</description>
1726 <link><?php print htmlspecialchars($this->get_phpfspot_url()); ?></link>
1727 <pubDate><?php print strftime("%a, %d %b %Y %T %z"); ?></pubDate>
1728 <generator>phpfspot</generator>
1731 $pictures = $this->getPhotoSelection();
1732 $current_tags = $this->getCurrentTags();
1734 foreach($pictures as $picture) {
1736 $orig_url = $this->get_phpfspot_url() ."index.php?mode=showp&id=". $picture;
1737 if($current_tags != "") {
1738 $orig_url.= "&tags=". $current_tags;
1740 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1741 $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
1744 $details = $this->get_photo_details($picture);
1746 $thumb_url = $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
1747 $thumb_html = htmlspecialchars("
1748 <a href=\"". $orig_url ."\"><img src=\"". $thumb_url ."\" /></a>
1750 ". $details['description']);
1752 $orig_path = $this->translate_path($details['directory_path']) ."/". $details['name'];
1753 $meta = $this->get_meta_informations($orig_path);
1754 $meta_date = isset($meta['FileDateTime']) ? $meta['FileDateTime'] : filemtime($orig_path);
1758 <title><?php print htmlspecialchars($details['name']); ?></title>
1759 <link><?php print htmlspecialchars($orig_url); ?></link>
1760 <guid><?php print htmlspecialchars($orig_url); ?></guid>
1761 <dc:date.Taken><?php print strftime("%Y-%m-%dT%H:%M:%S+00:00", $meta_date); ?></dc:date.Taken>
1763 <?php print $thumb_html; ?>
1765 <pubDate><?php print strftime("%a, %d %b %Y %T %z", $meta_date); ?></pubDate>
1780 * return all selected tags as one string
1782 private function getCurrentTags()
1785 if($_SESSION['selected_tags'] != "") {
1786 foreach($_SESSION['selected_tags'] as $tag)
1787 $current_tags.= $tag .",";
1788 $current_tags = substr($current_tags, 0, strlen($current_tags)-1);
1790 return $current_tags;
1792 } // getCurrentTags()
1795 * return the current photo
1797 public function getCurrentPhoto()
1799 if(isset($_SESSION['current_photo'])) {
1800 print $_SESSION['current_photo'];
1802 } // getCurrentPhoto()
1805 * tells the client browser what to do
1807 * this function is getting called via AJAX by the
1808 * client browsers. it will tell them what they have
1809 * to do next. This is necessary for directly jumping
1810 * into photo index or single photo view when the are
1811 * requested with specific URLs
1813 public function whatToDo()
1815 if(isset($_SESSION['current_photo']) && $_SESSION['start_action'] == 'showp') {
1816 return "show_photo";
1818 elseif(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
1819 return "showpi_tags";
1821 elseif(isset($_SESSION['start_action']) && $_SESSION['start_action'] == 'showpi') {
1825 return "nothing special";
1830 * return the current process-user
1832 private function getuid()
1834 if($uid = posix_getuid()) {
1835 if($user = posix_getpwuid($uid)) {
1836 return $user['name'];
1845 * returns a select-dropdown box to select photo index sort parameters
1847 private function get_sort_field()
1849 $output = "<select name=\"sort_order\">";
1850 foreach(array('date_asc', 'date_desc', 'name_asc', 'name_desc') as $sort_order) {
1851 $output.= "<option value=\"". $sort_order ."\"";
1852 if($sort_order == $_SESSION['sort_order']) {
1853 $output.= " selected=\"selected\"";
1855 $output.= ">". $sort_order ."</option>";
1857 $output.= "</select>";
1860 } // get_sort_field()
1863 * returns the currently selected sort order
1865 private function get_sort_order()
1867 switch($_SESSION['sort_order']) {
1869 return " ORDER BY p.time ASC";
1872 return " ORDER BY p.time DESC";
1875 return " ORDER BY p.name ASC";
1878 return " ORDER BY p.name DESC";
1882 } // get_sort_order()
1885 * return the next to be shown slide show image
1887 * this function returns the URL of the next image
1888 * in the slideshow sequence.
1890 public function getNextSlideShowImage()
1892 $all_photos = $this->getPhotoSelection();
1894 if(!isset($_SESSION['slideshow_img']) || $_SESSION['slideshow_img'] == count($all_photos)-1)
1895 $_SESSION['slideshow_img'] = 0;
1897 $_SESSION['slideshow_img']++;
1899 return $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $all_photos[$_SESSION['slideshow_img']] ."&width=". $this->cfg->photo_width;
1901 } // getNextSlideShowImage()
1904 * return the previous to be shown slide show image
1906 * this function returns the URL of the previous image
1907 * in the slideshow sequence.
1909 public function getPrevSlideShowImage()
1911 $all_photos = $this->getPhotoSelection();
1913 if(!isset($_SESSION['slideshow_img']) || $_SESSION['slideshow_img'] == 0)
1914 $_SESSION['slideshow_img'] = 0;
1916 $_SESSION['slideshow_img']--;
1918 return $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $all_photos[$_SESSION['slideshow_img']] ."&width=". $this->cfg->photo_width;
1920 } // getPrevSlideShowImage()
1922 public function resetSlideShow()
1924 if(isset($_SESSION['slideshow_img']))
1925 unset($_SESSION['slideshow_img']);
1926 } // resetSlideShow()
1931 * this function will get all photos from the fspot
1932 * database and randomly return ONE entry
1934 * saddly there is yet no sqlite3 function which returns
1935 * the bulk result in array, so we have to fill up our
1938 public function get_random_photo()
1942 $result = $this->db->db_query("
1947 while($row = $this->db->db_fetch_object($result)) {
1948 array_push($all, $row['id']);
1951 return $all[array_rand($all)];
1953 } // get_random_photo()
1956 * validates provided date
1958 * this function validates if the provided date
1959 * contains a valid date and will return true
1962 public function isValidDate($date_str)
1964 $timestamp = strtotime($date_str);
1966 if(is_numeric($timestamp))
1974 * timestamp to string conversion
1976 private function ts2str($timestamp)
1978 return strftime("%Y-%m-%d", $timestamp);
1981 private function extractTags($tags_str)
1983 $not_validated = split(',', $_GET['tags']);
1984 $validated = array();
1986 foreach($not_validated as $tag) {
1987 if(is_numeric($tag))
1988 array_push($validated, $tag);
1996 * returns the full path to a thumbnail
1998 public function get_thumb_path($width, $photo)
2000 $sub_path = substr($this->getMD5($photo), 0, 2);
2001 return $this->cfg->thumb_path
2007 . $this->getMD5($photo);
2009 } // get_thumb_path()
2012 * returns server's virtual host name
2014 private function get_server_name()
2016 return $_SERVER['SERVER_NAME'];
2017 } // get_server_name()
2020 * returns type of webprotocol which is
2023 private function get_web_protocol()
2025 if(!isset($_SERVER['HTTPS']))
2029 } // get_web_protocol()
2032 * return url to this phpfspot installation
2034 private function get_phpfspot_url()
2036 return $this->get_web_protocol() ."://". $this->get_server_name() . $this->cfg->web_path;
2037 } // get_phpfspot_url()
2040 * check file exists and is readable
2042 * returns true, if everything is ok, otherwise false
2043 * if $silent is not set, this function will output and
2046 private function check_readable($file, $silent = null)
2048 if(!file_exists($file)) {
2050 print "File \"". $file ."\" does not exist.\n";
2054 if(!is_readable($file)) {
2056 print "File \"". $file ."\" is not reachable for user ". $this->getuid() ."\n";
2062 } // check_readable()