3 /***************************************************************************
5 * Copyright (c) by Andreas Unterkircher, unki@netshadow.at
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 ***************************************************************************/
24 require_once "phpfspot_cfg.php";
25 require_once "phpfspot_db.php";
40 * this function will be called on class construct
41 * and will check requirements, loads configuration,
42 * open databases and start the user session
44 public function __construct()
46 $this->cfg = new PHPFSPOT_CFG;
48 /* set application name and version information */
49 $this->cfg->product = "phpfspot";
50 $this->cfg->version = "1.2";
52 /* Check necessary requirements */
53 if(!$this->checkRequirements()) {
57 $this->db = new PHPFSPOT_DB($this, $this->cfg->fspot_db);
58 if(!is_writeable($this->cfg->fspot_db)) {
59 print $this->cfg->fspot_db ." is not writeable for user ". $this->getuid() ."\n";
63 $this->dbver = $this->getFspotDBVersion();
65 if(!is_writeable(dirname($this->cfg->phpfspot_db))) {
66 print dirname($this->cfg->phpfspot_db) .": directory is not writeable for user ". $this->getuid() ."\n";
70 if(!is_writeable($this->cfg->base_path ."/templates_c")) {
71 print $this->cfg->base_path ."/templates_c: directory is not writeable for user ". $this->getuid() ."\n";
75 $this->cfg_db = new PHPFSPOT_DB($this, $this->cfg->phpfspot_db);
76 if(!is_writeable($this->cfg->phpfspot_db)) {
77 print $this->cfg->phpfspot_db ." is not writeable for user ". $this->getuid() ."\n";
81 $this->check_config_table();
83 /* include Smarty template engine */
84 if(!$this->check_readable($this->cfg->smarty_path .'/libs/Smarty.class.php')) {
87 require $this->cfg->smarty_path .'/libs/Smarty.class.php';
88 /* overload Smarty class if our own template handler */
89 require_once "phpfspot_tmpl.php";
90 $this->tmpl = new PHPFSPOT_TMPL($this);
92 /* check if all necessary indices exist */
93 $this->checkDbIndices();
95 /* if session is not yet started, do it now */
96 if(session_id() == "")
99 if(!isset($_SESSION['tag_condition']))
100 $_SESSION['tag_condition'] = 'or';
102 if(!isset($_SESSION['sort_order']))
103 $_SESSION['sort_order'] = 'date_asc';
105 if(!isset($_SESSION['searchfor']))
106 $_SESSION['searchfor'] = '';
108 // if begin_with is still set but rows_per_page is now 0, unset it
109 if(isset($_SESSION['begin_with']) && $this->cfg->rows_per_page == 0)
110 unset($_SESSION['begin_with']);
114 public function __destruct()
120 * show - generate html output
122 * this function can be called after the constructor has
123 * prepared everyhing. it will load the index.tpl smarty
124 * template. if necessary it will registere pre-selects
125 * (photo index, photo, tag search, date search) into
128 public function show()
130 $this->tmpl->assign('searchfor', $_SESSION['searchfor']);
131 $this->tmpl->assign('page_title', $this->cfg->page_title);
132 $this->tmpl->assign('current_condition', $_SESSION['tag_condition']);
133 $this->tmpl->assign('template_path', 'themes/'. $this->cfg->theme_name);
135 if(isset($_GET['mode'])) {
137 $_SESSION['start_action'] = $_GET['mode'];
139 switch($_GET['mode']) {
141 if(isset($_GET['tags'])) {
142 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
144 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
145 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
147 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
148 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
152 if(isset($_GET['tags'])) {
153 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
154 $_SESSION['start_action'] = 'showp';
156 if(isset($_GET['id']) && is_numeric($_GET['id'])) {
157 $_SESSION['current_photo'] = $_GET['id'];
158 $_SESSION['start_action'] = 'showp';
160 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
161 $_SESSION['from_date'] = strtotime($_GET['from_date']);
163 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
164 $_SESSION['to_date'] = strtotime($_GET['to_date']);
168 $this->tmpl->show("export.tpl");
172 $this->tmpl->show("slideshow.tpl");
176 if(isset($_GET['tags'])) {
177 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
179 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
180 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
182 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
183 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
191 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date']))
192 $this->tmpl->assign('date_search_enabled', true);
194 $this->tmpl->assign('from_date', $this->get_calendar('from'));
195 $this->tmpl->assign('to_date', $this->get_calendar('to'));
196 $this->tmpl->assign('sort_field', $this->get_sort_field());
197 $this->tmpl->assign('content_page', 'welcome.tpl');
198 $this->tmpl->show("index.tpl");
203 * get_tags - grab all tags of f-spot's database
205 * this function will get all available tags from
206 * the f-spot database and store them within two
207 * arrays within this class for later usage. in
208 * fact, if the user requests (hide_tags) it will
209 * opt-out some of them.
211 * this function is getting called once by show()
213 private function get_tags()
215 $this->avail_tags = Array();
218 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
221 DISTINCT t1.id as id, t1.name as name
224 INNER JOIN photo_tags
225 pt2 ON pt1.photo_id=pt2.photo_id
231 t2.name IN ('".implode("','",$this->cfg->show_tags)."')
233 t1.sort_priority ASC";
235 $result = $this->db->db_query($query_str);
239 $result = $this->db->db_query("
242 ORDER BY sort_priority ASC
246 while($row = $this->db->db_fetch_object($result)) {
248 $tag_id = $row['id'];
249 $tag_name = $row['name'];
251 /* if the user has specified to ignore this tag in phpfspot's
252 configuration, ignore it here so it does not get added to
255 if(in_array($row['name'], $this->cfg->hide_tags))
258 /* if you include the following if-clause and the user has specified
259 to only show certain tags which are specified in phpfspot's
260 configuration, ignore all others so they will not be added to the
262 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags) &&
263 !in_array($row['name'], $this->cfg->show_tags))
267 $this->tags[$tag_id] = $tag_name;
268 $this->avail_tags[$count] = $tag_id;
276 * extract all photo details
278 * retrieve all available details from f-spot's
279 * database and return them as object
281 public function get_photo_details($idx)
283 if($this->dbver < 9) {
285 SELECT p.id, p.name, p.time, p.directory_path, p.description
291 SELECT p.id, p.uri, p.time, p.description
296 /* if show_tags is set, only return details for photos which
297 are specified to be shown
299 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
301 INNER JOIN photo_tags pt
305 WHERE p.id='". $idx ."'
306 AND t.name IN ('".implode("','",$this->cfg->show_tags)."')";
310 WHERE p.id='". $idx ."'
314 if($result = $this->db->db_query($query_str)) {
316 $row = $this->db->db_fetch_object($result);
318 if($this->dbver < 9) {
319 $row['uri'] = "file://". $row['directory_path'] ."/". $row['name'];
328 } // get_photo_details
331 * returns aligned photo names
333 * this function returns aligned (length) names for
334 * an specific photo. If the length of the name exceeds
335 * $limit the name will be shrinked (...)
337 public function getPhotoName($idx, $limit = 0)
339 if($details = $this->get_photo_details($idx)) {
340 if($long_name = $this->parse_uri($details['uri'], 'filename')) {
341 $name = $this->shrink_text($long_name, $limit);
351 * shrink text according provided limit
353 * If the length of the name exceeds $limit the
354 * text will be shortend and some content in between
355 * will be replaced with "..."
357 private function shrink_text($text, $limit)
359 if($limit != 0 && strlen($text) > $limit) {
360 $text = substr($text, 0, $limit-5) ."...". substr($text, -($limit-5));
368 * translate f-spoth photo path
370 * as the full-qualified path recorded in the f-spot database
371 * is usally not the same as on the webserver, this function
372 * will replace the path with that one specified in the cfg
374 public function translate_path($path, $width = 0)
376 return str_replace($this->cfg->path_replace_from, $this->cfg->path_replace_to, $path);
381 * control HTML ouput for a single photo
383 * this function provides all the necessary information
384 * for the single photo template.
386 public function showPhoto($photo)
388 /* get all photos from the current photo selection */
389 $all_photos = $this->getPhotoSelection();
390 $count = count($all_photos);
392 for($i = 0; $i < $count; $i++) {
394 // $get_next will be set, when the photo which has to
395 // be displayed has been found - this means that the
396 // next available is in fact the NEXT image (for the
398 if(isset($get_next)) {
399 $next_img = $all_photos[$i];
403 /* the next photo is our NEXT photo */
404 if($all_photos[$i] == $photo) {
408 $previous_img = $all_photos[$i];
411 if($photo == $all_photos[$i]) {
416 $details = $this->get_photo_details($photo);
423 $orig_path = $this->translate_path($this->parse_uri($details['uri'], 'fullpath'));
424 $thumb_path = $this->get_thumb_path($this->cfg->photo_width, $photo);
426 if(!file_exists($orig_path)) {
427 $this->_error("Photo ". $orig_path ." does not exist!<br />\n");
430 if(!is_readable($orig_path)) {
431 $this->_error("Photo ". $orig_path ." is not readable for user ". $this->getuid() ."<br />\n");
434 /* If the thumbnail doesn't exist yet, try to create it */
435 if(!file_exists($thumb_path)) {
436 $this->gen_thumb($photo, true);
437 $thumb_path = $this->get_thumb_path($this->cfg->photo_width, $photo);
440 /* get f-spot database meta information */
441 $meta = $this->get_meta_informations($orig_path);
443 /* If EXIF data are available, use them */
444 if(isset($meta['ExifImageWidth'])) {
445 $meta_res = $meta['ExifImageWidth'] ."x". $meta['ExifImageLength'];
447 $info = getimagesize($orig_path);
448 $meta_res = $info[0] ."x". $info[1];
451 $meta_date = isset($meta['FileDateTime']) ? strftime("%a %x %X", $meta['FileDateTime']) : "n/a";
452 $meta_make = isset($meta['Make']) ? $meta['Make'] ." / ". $meta['Model'] : "n/a";
453 $meta_size = isset($meta['FileSize']) ? round($meta['FileSize']/1024, 1) ."kbyte" : "n/a";
455 $extern_link = "index.php?mode=showp&id=". $photo;
456 $current_tags = $this->getCurrentTags();
457 if($current_tags != "") {
458 $extern_link.= "&tags=". $current_tags;
460 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
461 $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
464 $this->tmpl->assign('extern_link', $extern_link);
466 if(file_exists($thumb_path)) {
468 $info = getimagesize($thumb_path);
470 $this->tmpl->assign('description', $details['description']);
471 $this->tmpl->assign('image_name', $this->parse_uri($details['uri'], 'filename'));
473 $this->tmpl->assign('width', $info[0]);
474 $this->tmpl->assign('height', $info[1]);
475 $this->tmpl->assign('ExifMadeOn', $meta_date);
476 $this->tmpl->assign('ExifMadeWith', $meta_make);
477 $this->tmpl->assign('ExifOrigResolution', $meta_res);
478 $this->tmpl->assign('ExifFileSize', $meta_size);
480 $this->tmpl->assign('image_url', 'phpfspot_img.php?idx='. $photo ."&width=". $this->cfg->photo_width);
481 $this->tmpl->assign('image_url_full', 'phpfspot_img.php?idx='. $photo);
483 $this->tmpl->assign('tags', $this->get_photo_tags($photo));
484 $this->tmpl->assign('current', $current);
487 $this->_error("Can't open file ". $thumb_path ."\n");
492 $this->tmpl->assign('previous_url', "javascript:showImage(". $previous_img .");");
493 $this->tmpl->assign('prev_img', $previous_img);
497 $this->tmpl->assign('next_url', "javascript:showImage(". $next_img .");");
498 $this->tmpl->assign('next_img', $next_img);
500 $this->tmpl->assign('mini_width', $this->cfg->mini_width);
501 $this->tmpl->assign('photo_number', $i);
502 $this->tmpl->assign('photo_count', count($all_photos));
504 $this->tmpl->show("single_photo.tpl");
509 * all available tags and tag cloud
511 * this function outputs all available tags (time ordered)
512 * and in addition output them as tag cloud (tags which have
513 * many photos will appears more then others)
515 public function getAvailableTags()
521 $result = $this->db->db_query("
522 SELECT tag_id as id, count(tag_id) as quantity
532 while($row = $this->db->db_fetch_object($result)) {
533 $tags[$row['id']] = $row['quantity'];
536 // change these font sizes if you will
537 $max_size = 125; // max font size in %
538 $min_size = 75; // min font size in %
540 // get the largest and smallest array values
541 $max_qty = max(array_values($tags));
542 $min_qty = min(array_values($tags));
544 // find the range of values
545 $spread = $max_qty - $min_qty;
546 if (0 == $spread) { // we don't want to divide by zero
550 // determine the font-size increment
551 // this is the increase per tag quantity (times used)
552 $step = ($max_size - $min_size)/($spread);
554 // loop through our tag array
555 foreach ($tags as $key => $value) {
557 if(isset($_SESSION['selected_tags']) && in_array($key, $_SESSION['selected_tags']))
560 // calculate CSS font-size
561 // find the $value in excess of $min_qty
562 // multiply by the font-size increment ($size)
563 // and add the $min_size set above
564 $size = $min_size + (($value - $min_qty) * $step);
565 // uncomment if you want sizes in whole %:
568 if(isset($this->tags[$key])) {
569 $output.= "<a href=\"javascript:Tags('add', ". $key .");\" class=\"tag\" style=\"font-size: ". $size ."%;\">". $this->tags[$key] ."</a>, ";
574 $output = substr($output, 0, strlen($output)-2);
577 } // getAvailableTags()
580 * output all selected tags
582 * this function output all tags which have been selected
583 * by the user. the selected tags are stored in the
584 * session-variable $_SESSION['selected_tags']
586 public function getSelectedTags()
591 foreach($this->avail_tags as $tag)
593 // return all selected tags
594 if(isset($_SESSION['selected_tags']) && in_array($tag, $_SESSION['selected_tags'])) {
595 $output.= "<a href=\"javascript:Tags('del', ". $tag .");\" class=\"tag\">". $this->tags[$tag] ."</a>, ";
599 $output = substr($output, 0, strlen($output)-2);
602 } // getSelectedTags()
605 * add tag to users session variable
607 * this function will add the specified to users current
608 * tag selection. if a date search has been made before
609 * it will be now cleared
611 public function addTag($tag)
613 if(!isset($_SESSION['selected_tags']))
614 $_SESSION['selected_tags'] = Array();
616 if(!in_array($tag, $_SESSION['selected_tags']))
617 array_push($_SESSION['selected_tags'], $tag);
622 * remove tag to users session variable
624 * this function removes the specified tag from
625 * users current tag selection
627 public function delTag($tag)
629 if(isset($_SESSION['selected_tags'])) {
630 $key = array_search($tag, $_SESSION['selected_tags']);
631 unset($_SESSION['selected_tags'][$key]);
632 sort($_SESSION['selected_tags']);
638 * reset tag selection
640 * if there is any tag selection, it will be
643 public function resetTags()
645 if(isset($_SESSION['selected_tags']))
646 unset($_SESSION['selected_tags']);
653 * if a specific photo was requested (external link)
654 * unset the session variable now
656 public function resetPhotoView()
658 if(isset($_SESSION['current_photo']))
659 unset($_SESSION['current_photo']);
661 } // resetPhotoView();
666 * if any tag search has taken place, reset
669 public function resetTagSearch()
671 if(isset($_SESSION['searchfor']))
672 unset($_SESSION['searchfor']);
674 } // resetTagSearch()
679 * if any date search has taken place, reset
682 public function resetDateSearch()
684 if(isset($_SESSION['from_date']))
685 unset($_SESSION['from_date']);
686 if(isset($_SESSION['to_date']))
687 unset($_SESSION['to_date']);
689 } // resetDateSearch();
692 * return all photo according selection
694 * this function returns all photos based on
695 * the tag-selection, tag- or date-search.
696 * the tag-search also has to take care of AND
697 * and OR conjunctions
699 public function getPhotoSelection()
701 $matched_photos = Array();
703 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
704 $from_date = $_SESSION['from_date'];
705 $to_date = $_SESSION['to_date'];
706 $additional_where_cond = "
707 p.time>='". $from_date ."'
709 p.time<='". $to_date ."'
713 if(isset($_SESSION['sort_order'])) {
714 $order_str = $this->get_sort_order();
717 /* return a search result */
718 if(isset($_SESSION['searchfor']) && $_SESSION['searchfor'] != '') {
720 SELECT DISTINCT pt1.photo_id
722 INNER JOIN photo_tags pt2
723 ON pt1.photo_id=pt2.photo_id
730 WHERE t1.name LIKE '%". $_SESSION['searchfor'] ."%' ";
732 if(isset($additional_where_cond))
733 $query_str.= "AND ". $additional_where_cond ." ";
735 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
736 $query_str.= "AND t2.name IN ('".implode("','",$this->cfg->show_tags)."')";
739 if(isset($order_str))
740 $query_str.= $order_str;
742 $result = $this->db->db_query($query_str);
743 while($row = $this->db->db_fetch_object($result)) {
744 array_push($matched_photos, $row['photo_id']);
746 return $matched_photos;
749 /* return according the selected tags */
750 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
752 foreach($_SESSION['selected_tags'] as $tag)
753 $selected.= $tag .",";
754 $selected = substr($selected, 0, strlen($selected)-1);
756 /* photo has to match at least on of the selected tags */
757 if($_SESSION['tag_condition'] == 'or') {
759 SELECT DISTINCT pt1.photo_id
761 INNER JOIN photo_tags pt2
762 ON pt1.photo_id=pt2.photo_id
767 WHERE pt1.tag_id IN (". $selected .")
769 if(isset($additional_where_cond))
770 $query_str.= "AND ". $additional_where_cond ." ";
772 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
773 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags)."')";
776 if(isset($order_str))
777 $query_str.= $order_str;
779 /* photo has to match all selected tags */
780 elseif($_SESSION['tag_condition'] == 'and') {
782 if(count($_SESSION['selected_tags']) >= 32) {
783 print "A SQLite limit of 32 tables within a JOIN SELECT avoids to<br />\n";
784 print "evaluate your tag selection. Please remove some tags from your selection.\n";
788 /* Join together a table looking like
790 pt1.photo_id pt1.tag_id pt2.photo_id pt2.tag_id ...
792 so the query can quickly return all images matching the
793 selected tags in an AND condition
798 SELECT DISTINCT pt1.photo_id
802 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
809 for($i = 0; $i < count($_SESSION['selected_tags']); $i++) {
811 INNER JOIN photo_tags pt". ($i+2) ."
812 ON pt1.photo_id=pt". ($i+2) .".photo_id
819 $query_str.= "WHERE pt2.tag_id=". $_SESSION['selected_tags'][0]." ";
820 for($i = 1; $i < count($_SESSION['selected_tags']); $i++) {
822 AND pt". ($i+2) .".tag_id=". $_SESSION['selected_tags'][$i] ."
825 if(isset($additional_where_cond))
826 $query_str.= "AND ". $additional_where_cond;
828 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
829 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags). "')";
832 if(isset($order_str))
833 $query_str.= $order_str;
837 $result = $this->db->db_query($query_str);
838 while($row = $this->db->db_fetch_object($result)) {
839 array_push($matched_photos, $row['photo_id']);
841 return $matched_photos;
844 /* return all available photos */
846 SELECT DISTINCT photo_id
853 if(isset($additional_where_cond))
854 $query_str.= "WHERE ". $additional_where_cond ." ";
856 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
857 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags). "')";
860 if(isset($order_str))
861 $query_str.= $order_str;
863 $result = $this->db->db_query($query_str);
864 while($row = $this->db->db_fetch_object($result)) {
865 array_push($matched_photos, $row['photo_id']);
867 return $matched_photos;
869 } // getPhotoSelection()
872 * control HTML ouput for photo index
874 * this function provides all the necessary information
875 * for the photo index template.
877 public function showPhotoIndex()
879 $photos = $this->getPhotoSelection();
881 $count = count($photos);
883 if(isset($_SESSION['begin_with']) && $_SESSION['begin_with'] != "")
884 $anchor = $_SESSION['begin_with'];
886 if(!isset($this->cfg->rows_per_page) || $this->cfg->rows_per_page == 0) {
892 elseif($this->cfg->rows_per_page > 0) {
894 if(!$_SESSION['begin_with'] || $_SESSION['begin_with'] == 0)
898 $begin_with = $_SESSION['begin_with'];
900 // verify $begin_with - perhaps the thumbs-per-rows or
901 // rows-per-page variables have changed or the jump back
902 // from a photo wasn't exact - so calculate the real new
904 $multiplicator = $this->cfg->rows_per_page * $this->cfg->thumbs_per_row;
905 for($i = 0; $i <= $count; $i+=$multiplicator) {
906 if($begin_with >= $i && $begin_with < $i+$multiplicator) {
913 $end_with = $begin_with + ($this->cfg->rows_per_page * $this->cfg->thumbs_per_row);
919 $images[$rows] = Array();
920 $img_height[$rows] = Array();
921 $img_width[$rows] = Array();
922 $img_id[$rows] = Array();
923 $img_name[$rows] = Array();
924 $img_title = Array();
926 for($i = $begin_with; $i < $end_with; $i++) {
928 $images[$rows][$cols] = $photos[$i];
929 $img_id[$rows][$cols] = $i;
930 $img_name[$rows][$cols] = htmlspecialchars($this->getPhotoName($photos[$i], 15));
931 $img_title[$rows][$cols] = "Click to view photo ". htmlspecialchars($this->getPhotoName($photos[$i], 0));
933 $thumb_path = $this->get_thumb_path($this->cfg->thumb_width, $photos[$i]);
935 if(file_exists($thumb_path)) {
936 $info = getimagesize($thumb_path);
937 $img_width[$rows][$cols] = $info[0];
938 $img_height[$rows][$cols] = $info[1];
941 if($cols == $this->cfg->thumbs_per_row-1) {
944 $images[$rows] = Array();
945 $img_width[$rows] = Array();
946 $img_height[$rows] = Array();
953 // +1 for for smarty's selection iteration
956 if(isset($_SESSION['searchfor']) && $_SESSION['searchfor'] != '')
957 $this->tmpl->assign('searchfor', $_SESSION['searchfor']);
959 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
960 $this->tmpl->assign('from_date', $this->ts2str($_SESSION['from_date']));
961 $this->tmpl->assign('to_date', $this->ts2str($_SESSION['to_date']));
964 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
965 $this->tmpl->assign('tag_result', 1);
968 /* do we have to display the page selector ? */
969 if($this->cfg->rows_per_page != 0) {
971 /* calculate the page switchers */
972 $previous_start = $begin_with - ($this->cfg->rows_per_page * $this->cfg->thumbs_per_row);
973 $next_start = $begin_with + ($this->cfg->rows_per_page * $this->cfg->thumbs_per_row);
976 $this->tmpl->assign("previous_url", "javascript:showPhotoIndex(". $previous_start .");");
977 if($end_with < $count)
978 $this->tmpl->assign("next_url", "javascript:showPhotoIndex(". $next_start .");");
980 $photo_per_page = $this->cfg->rows_per_page * $this->cfg->thumbs_per_row;
981 $last_page = ceil($count / $photo_per_page);
983 /* get the current selected page */
984 if($begin_with == 0) {
988 for($i = $begin_with; $i >= 0; $i-=$photo_per_page) {
995 for($i = 1; $i <= $last_page; $i++) {
997 if($current_page == $i)
998 $style = "style=\"font-size: 125%; text-decoration: underline;\"";
999 elseif($current_page-1 == $i || $current_page+1 == $i)
1000 $style = "style=\"font-size: 105%;\"";
1001 elseif(($current_page-5 >= $i) && ($i != 1) ||
1002 ($current_page+5 <= $i) && ($i != $last_page))
1003 $style = "style=\"font-size: 75%;\"";
1007 $select = "<a href=\"javascript:showPhotoIndex(". (($i*$photo_per_page)-$photo_per_page) .");\"";
1010 $select.= ">". $i ."</a> ";
1012 // until 9 pages we show the selector from 1-9
1013 if($last_page <= 9) {
1014 $page_select.= $select;
1017 if($i == 1 /* first page */ ||
1018 $i == $last_page /* last page */ ||
1019 $i == $current_page /* current page */ ||
1020 $i == ceil($last_page * 0.25) /* first quater */ ||
1021 $i == ceil($last_page * 0.5) /* half */ ||
1022 $i == ceil($last_page * 0.75) /* third quater */ ||
1023 (in_array($i, array(1,2,3,4,5,6)) && $current_page <= 4) /* the first 6 */ ||
1024 (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 */ ||
1025 $i == $current_page-3 || $i == $current_page-2 || $i == $current_page-1 /* three before */ ||
1026 $i == $current_page+3 || $i == $current_page+2 || $i == $current_page+1 /* three after */) {
1028 $page_select.= $select;
1036 $page_select.= "......... ";
1041 /* only show the page selector if we have more then one page */
1043 $this->tmpl->assign('page_selector', $page_select);
1047 $current_tags = $this->getCurrentTags();
1048 $extern_link = "index.php?mode=showpi";
1049 $rss_link = "index.php?mode=rss";
1050 if($current_tags != "") {
1051 $extern_link.= "&tags=". $current_tags;
1052 $rss_link.= "&tags=". $current_tags;
1054 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1055 $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
1056 $rss_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
1059 $export_link = "index.php?mode=export";
1060 $slideshow_link = "index.php?mode=slideshow";
1062 $this->tmpl->assign('extern_link', $extern_link);
1063 $this->tmpl->assign('slideshow_link', $slideshow_link);
1064 $this->tmpl->assign('export_link', $export_link);
1065 $this->tmpl->assign('rss_link', $rss_link);
1066 $this->tmpl->assign('count', $count);
1067 $this->tmpl->assign('width', $this->cfg->thumb_width);
1068 $this->tmpl->assign('images', $images);
1069 $this->tmpl->assign('img_width', $img_width);
1070 $this->tmpl->assign('img_height', $img_height);
1071 $this->tmpl->assign('img_id', $img_id);
1072 $this->tmpl->assign('img_name', $img_name);
1073 $this->tmpl->assign('img_title', $img_title);
1074 $this->tmpl->assign('rows', $rows);
1075 $this->tmpl->assign('columns', $this->cfg->thumbs_per_row);
1077 $this->tmpl->show("photo_index.tpl");
1080 print "<script language=\"JavaScript\">self.location.hash = '#image". $anchor ."';</script>\n";
1082 } // showPhotoIndex()
1085 * show credit template
1087 public function showCredits()
1089 $this->tmpl->assign('version', $this->cfg->version);
1090 $this->tmpl->assign('product', $this->cfg->product);
1091 $this->tmpl->assign('db_version', $this->dbver);
1092 $this->tmpl->show("credits.tpl");
1097 * create_thumbnails for the requested width
1099 * this function creates image thumbnails of $orig_image
1100 * stored as $thumb_image. It will check if the image is
1101 * in a supported format, if necessary rotate the image
1102 * (based on EXIF orientation meta headers) and re-sizing.
1104 public function create_thumbnail($orig_image, $thumb_image, $width)
1106 if(!file_exists($orig_image)) {
1110 $details = getimagesize($orig_image);
1112 /* check if original photo is a support image type */
1113 if(!$this->checkifImageSupported($details['mime']))
1116 $meta = $this->get_meta_informations($orig_image);
1121 switch($meta['Orientation']) {
1123 case 1: /* top, left */
1124 $rotate = 0; $flip = false; break;
1125 case 2: /* top, right */
1126 $rotate = 0; $flip = true; break;
1127 case 3: /* bottom, left */
1128 $rotate = 180; $flip = false; break;
1129 case 4: /* bottom, right */
1130 $rotate = 180; $flip = true; break;
1131 case 5: /* left side, top */
1132 $rotate = 90; $flip = true; break;
1133 case 6: /* right side, top */
1134 $rotate = 90; $flip = false; break;
1135 case 7: /* left side, bottom */
1136 $rotate = 270; $flip = true; break;
1137 case 8: /* right side, bottom */
1138 $rotate = 270; $flip = false; break;
1141 $src_img = @imagecreatefromjpeg($orig_image);
1144 print "Can't load image from ". $orig_image ."\n";
1148 /* grabs the height and width */
1149 $cur_width = imagesx($src_img);
1150 $cur_height = imagesy($src_img);
1152 // If requested width is more then the actual image width,
1153 // do not generate a thumbnail, instead safe the original
1154 // as thumbnail but with lower quality
1156 if($width >= $cur_width) {
1157 $result = imagejpeg($src_img, $thumb_image, 75);
1158 imagedestroy($src_img);
1162 // If the image will be rotate because EXIF orientation said so
1163 // 'virtually rotate' the image for further calculations
1164 if($rotate == 90 || $rotate == 270) {
1166 $cur_width = $cur_height;
1170 /* calculates aspect ratio */
1171 $aspect_ratio = $cur_height / $cur_width;
1174 if($aspect_ratio < 1) {
1176 $new_h = abs($new_w * $aspect_ratio);
1178 /* 'virtually' rotate the image and calculate it's ratio */
1179 $tmp_w = $cur_height;
1180 $tmp_h = $cur_width;
1181 /* now get the ratio from the 'rotated' image */
1182 $tmp_ratio = $tmp_h/$tmp_w;
1183 /* now calculate the new dimensions */
1185 $tmp_h = abs($tmp_w * $tmp_ratio);
1187 // now that we know, how high they photo should be, if it
1188 // gets rotated, use this high to scale the image
1190 $new_w = abs($new_h / $aspect_ratio);
1192 // If the image will be rotate because EXIF orientation said so
1193 // now 'virtually rotate' back the image for the image manipulation
1194 if($rotate == 90 || $rotate == 270) {
1201 /* creates new image of that size */
1202 $dst_img = imagecreatetruecolor($new_w, $new_h);
1204 imagefill($dst_img, 0, 0, ImageColorAllocate($dst_img, 255, 255, 255));
1206 /* copies resized portion of original image into new image */
1207 imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $new_w, $new_h, imagesx($src_img), imagesy($src_img));
1209 /* needs the image to be flipped horizontal? */
1213 for($x = 0; $x < $new_w; $x++) {
1214 imagecopy($dst_img, $image, $x, 0, $w - $x - 1, 0, 1, $h);
1219 $this->_debug("(ROTATE)");
1220 $dst_img = $this->rotateImage($dst_img, $rotate);
1223 /* write down new generated file */
1224 $result = imagejpeg($dst_img, $thumb_image, 75);
1226 /* free your mind */
1227 imagedestroy($dst_img);
1228 imagedestroy($src_img);
1230 if($result === false) {
1231 print "Can't write thumbnail ". $thumb_image ."\n";
1237 } // create_thumbnail()
1240 * return all exif meta data from the file
1242 public function get_meta_informations($file)
1244 return exif_read_data($file);
1246 } // get_meta_informations()
1249 * create phpfspot own sqlite database
1251 * this function creates phpfspots own sqlite database
1252 * if it does not exist yet. this own is used to store
1253 * some necessary informations (md5 sum's, ...).
1255 public function check_config_table()
1257 // if the config table doesn't exist yet, create it
1258 if(!$this->cfg_db->db_check_table_exists("images")) {
1259 $this->cfg_db->db_exec("
1260 CREATE TABLE images (
1261 img_idx int primary key,
1267 } // check_config_table
1270 * Generates a thumbnail from photo idx
1272 * This function will generate JPEG thumbnails from provided F-Spot photo
1275 * 1. Check if all thumbnail generations (width) are already in place and
1277 * 2. Check if the md5sum of the original file has changed
1278 * 3. Generate the thumbnails if needed
1280 public function gen_thumb($idx = 0, $force = 0)
1284 $resolutions = Array(
1285 $this->cfg->thumb_width,
1286 $this->cfg->photo_width,
1287 $this->cfg->mini_width,
1290 /* get details from F-Spot's database */
1291 $details = $this->get_photo_details($idx);
1293 /* calculate file MD5 sum */
1294 $full_path = $this->translate_path($this->parse_uri($details['uri'], 'fullpath'));
1296 if(!file_exists($full_path)) {
1297 $this->_error("File ". $full_path ." does not exist\n");
1301 if(!is_readable($full_path)) {
1302 $this->_error("File ". $full_path ." is not readable for ". $this->getuid() ."\n");
1306 $file_md5 = md5_file($full_path);
1308 $this->_debug("Image [". $idx ."] ". $this->shrink_text($this->parse_uri($details['uri'], 'filename'), 20) ." Thumbnails:");
1312 foreach($resolutions as $resolution) {
1314 $thumb_sub_path = substr($file_md5, 0, 2);
1315 $thumb_path = $this->cfg->thumb_path ."/". $thumb_sub_path ."/". $resolution ."_". $file_md5;
1317 if(!file_exists(dirname($thumb_path))) {
1318 mkdir(dirname($thumb_path), 0755);
1321 /* if the thumbnail file doesn't exist, create it */
1322 if(!file_exists($thumb_path)) {
1324 $this->_debug(" ". $resolution ."px");
1325 if(!$this->create_thumbnail($full_path, $thumb_path, $resolution))
1330 /* if the file hasn't changed there is no need to regen the thumb */
1331 elseif($file_md5 != $this->getMD5($idx) || $force) {
1333 $this->_debug(" ". $resolution ."px");
1334 if(!$this->create_thumbnail($full_path, $thumb_path, $resolution))
1342 $this->_debug(" already exist");
1345 /* set the new/changed MD5 sum for the current photo */
1347 $this->setMD5($idx, $file_md5);
1350 $this->_debug("\n");
1355 * returns stored md5 sum for a specific photo
1357 * this function queries the phpfspot database for a
1358 * stored MD5 checksum of the specified photo
1360 public function getMD5($idx)
1362 $result = $this->cfg_db->db_query("
1365 WHERE img_idx='". $idx ."'
1371 $img = $this->cfg_db->db_fetch_object($result);
1372 return $img['img_md5'];
1377 * set MD5 sum for the specific photo
1379 private function setMD5($idx, $md5)
1381 $result = $this->cfg_db->db_exec("
1382 REPLACE INTO images (img_idx, img_md5)
1383 VALUES ('". $idx ."', '". $md5 ."')
1389 * store current tag condition
1391 * this function stores the current tag condition
1392 * (AND or OR) in the users session variables
1394 public function setTagCondition($mode)
1396 $_SESSION['tag_condition'] = $mode;
1398 } // setTagCondition()
1401 * invoke tag & date search
1403 * this function will return all matching tags and store
1404 * them in the session variable selected_tags. furthermore
1405 * it also handles the date search.
1406 * getPhotoSelection() will then only return the matching
1409 public function startSearch($searchfor, $sort_order, $from = 0, $to = 0)
1413 $_SESSION['searchfor'] = $searchfor;
1414 $_SESSION['sort_order'] = $sort_order;
1416 $_SESSION['from_date'] = strtotime($from);
1418 unset($_SESSION['from_date']);
1420 $_SESSION['to_date'] = strtotime($to);
1422 unset($_SESSION['to_date']);
1424 if($searchfor != "") {
1425 /* new search, reset the current selected tags */
1426 $_SESSION['selected_tags'] = Array();
1427 foreach($this->avail_tags as $tag) {
1428 if(preg_match('/'. $searchfor .'/i', $this->tags[$tag]))
1429 array_push($_SESSION['selected_tags'], $tag);
1438 * this function rotates the image according the
1441 private function rotateImage($img, $degrees)
1443 if(function_exists("imagerotate")) {
1444 $img = imagerotate($img, $degrees, 0);
1446 function imagerotate($src_img, $angle)
1448 $src_x = imagesx($src_img);
1449 $src_y = imagesy($src_img);
1450 if ($angle == 180) {
1454 elseif ($src_x <= $src_y) {
1458 elseif ($src_x >= $src_y) {
1463 $rotate=imagecreatetruecolor($dest_x,$dest_y);
1464 imagealphablending($rotate, false);
1469 for ($y = 0; $y < ($src_y); $y++) {
1470 for ($x = 0; $x < ($src_x); $x++) {
1471 $color = imagecolorat($src_img, $x, $y);
1472 imagesetpixel($rotate, $dest_x - $y - 1, $x, $color);
1478 for ($y = 0; $y < ($src_y); $y++) {
1479 for ($x = 0; $x < ($src_x); $x++) {
1480 $color = imagecolorat($src_img, $x, $y);
1481 imagesetpixel($rotate, $y, $dest_y - $x - 1, $color);
1487 for ($y = 0; $y < ($src_y); $y++) {
1488 for ($x = 0; $x < ($src_x); $x++) {
1489 $color = imagecolorat($src_img, $x, $y);
1490 imagesetpixel($rotate, $dest_x - $x - 1, $dest_y - $y - 1, $color);
1504 $img = imagerotate($img, $degrees);
1513 * return all assigned tags for the specified photo
1515 private function get_photo_tags($idx)
1517 $result = $this->db->db_query("
1520 INNER JOIN photo_tags pt
1522 WHERE pt.photo_id='". $idx ."'
1527 while($row = $this->db->db_fetch_object($result))
1528 $tags[$row['id']] = $row['name'];
1532 } // get_photo_tags()
1535 * create on-the-fly images with text within
1537 public function showTextImage($txt, $color=000000, $space=4, $font=4, $w=300)
1539 if (strlen($color) != 6)
1542 $int = hexdec($color);
1543 $h = imagefontheight($font);
1544 $fw = imagefontwidth($font);
1545 $txt = explode("\n", wordwrap($txt, ($w / $fw), "\n"));
1546 $lines = count($txt);
1547 $im = imagecreate($w, (($h * $lines) + ($lines * $space)));
1548 $bg = imagecolorallocate($im, 255, 255, 255);
1549 $color = imagecolorallocate($im, 0xFF & ($int >> 0x10), 0xFF & ($int >> 0x8), 0xFF & $int);
1552 foreach ($txt as $text) {
1553 $x = (($w - ($fw * strlen($text))) / 2);
1554 imagestring($im, $font, $x, $y, $text, $color);
1555 $y += ($h + $space);
1558 Header("Content-type: image/png");
1561 } // showTextImage()
1564 * check if all requirements are met
1566 private function checkRequirements()
1568 if(!function_exists("imagecreatefromjpeg")) {
1569 print "PHP GD library extension is missing<br />\n";
1573 if($this->cfg->db_access == "native" && !function_exists("sqlite3_open")) {
1574 print "PHP SQLite3 library extension is missing<br />\n";
1578 /* Check for HTML_AJAX PEAR package, lent from Horde project */
1579 ini_set('track_errors', 1);
1580 @include_once 'HTML/AJAX/Server.php';
1581 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
1582 print "PEAR HTML_AJAX package is missing<br />\n";
1585 @include_once 'Calendar/Calendar.php';
1586 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
1587 print "PEAR Calendar package is missing<br />\n";
1590 ini_restore('track_errors');
1597 } // checkRequirements()
1599 private function _debug($text)
1601 if($this->fromcmd) {
1608 * check if specified MIME type is supported
1610 public function checkifImageSupported($mime)
1612 if(in_array($mime, Array("image/jpeg")))
1617 } // checkifImageSupported()
1619 public function _error($text)
1621 switch($this->cfg->logging) {
1623 print "<img src=\"resources/green_info.png\" alt=\"warning\" />\n";
1630 error_log($text, 3, $his->cfg->log_file);
1637 * output calendard input fields
1639 private function get_calendar($mode)
1641 $year = isset($_SESSION[$mode .'_date']) ? date("Y", $_SESSION[$mode .'_date']) : date("Y");
1642 $month = isset($_SESSION[$mode .'_date']) ? date("m", $_SESSION[$mode .'_date']) : date("m");
1643 $day = isset($_SESSION[$mode .'_date']) ? date("d", $_SESSION[$mode .'_date']) : date("d");
1645 $output = "<input type=\"text\" size=\"3\" id=\"". $mode ."year\" value=\"". $year ."\"";
1646 if(!isset($_SESSION[$mode .'_date']))
1647 $output.= " disabled=\"disabled\"";
1649 $output.= "<input type=\"text\" size=\"1\" id=\"". $mode ."month\" value=\"". $month ."\"";
1650 if(!isset($_SESSION[$mode .'_date']))
1651 $output.= " disabled=\"disabled\"";
1653 $output.= "<input type=\"text\" size=\"1\" id=\"". $mode ."day\" value=\"". $day ."\"";
1654 if(!isset($_SESSION[$mode .'_date']))
1655 $output.= " disabled=\"disabled\"";
1663 * output calendar matrix
1665 public function get_calendar_matrix($year = 0, $month = 0, $day = 0)
1667 if (!isset($year)) $year = date('Y');
1668 if (!isset($month)) $month = date('m');
1669 if (!isset($day)) $day = date('d');
1674 require_once CALENDAR_ROOT.'Month/Weekdays.php';
1675 require_once CALENDAR_ROOT.'Day.php';
1678 $month = new Calendar_Month_Weekdays($year,$month);
1681 $prevStamp = $month->prevMonth(true);
1682 $prev = "javascript:setMonth(". date('Y',$prevStamp) .", ". date('n',$prevStamp) .", ". date('j',$prevStamp) .");";
1683 $nextStamp = $month->nextMonth(true);
1684 $next = "javascript:setMonth(". date('Y',$nextStamp) .", ". date('n',$nextStamp) .", ". date('j',$nextStamp) .");";
1686 $selectedDays = array (
1687 new Calendar_Day($year,$month,$day),
1688 new Calendar_Day($year,12,25),
1691 // Build the days in the month
1692 $month->build($selectedDays);
1694 $this->tmpl->assign('current_month', date('F Y',$month->getTimeStamp()));
1695 $this->tmpl->assign('prev_month', $prev);
1696 $this->tmpl->assign('next_month', $next);
1698 while ( $day = $month->fetch() ) {
1700 if(!isset($matrix[$rows]))
1701 $matrix[$rows] = Array();
1705 $dayStamp = $day->thisDay(true);
1706 $link = "javascript:setCalendarDate(". date('Y',$dayStamp) .", ". date('n',$dayStamp).", ". date('j',$dayStamp) .");";
1708 // isFirst() to find start of week
1709 if ( $day->isFirst() )
1712 if ( $day->isSelected() ) {
1713 $string.= "<td class=\"selected\">".$day->thisDay()."</td>\n";
1714 } else if ( $day->isEmpty() ) {
1715 $string.= "<td> </td>\n";
1717 $string.= "<td><a class=\"calendar\" href=\"".$link."\">".$day->thisDay()."</a></td>\n";
1720 // isLast() to find end of week
1721 if ( $day->isLast() )
1722 $string.= "</tr>\n";
1724 $matrix[$rows][$cols] = $string;
1734 $this->tmpl->assign('matrix', $matrix);
1735 $this->tmpl->assign('rows', $rows);
1736 $this->tmpl->show("calendar.tpl");
1738 } // get_calendar_matrix()
1741 * output export page
1743 public function getExport($mode)
1745 $pictures = $this->getPhotoSelection();
1746 $current_tags = $this->getCurrentTags();
1748 foreach($pictures as $picture) {
1750 $orig_url = $this->get_phpfspot_url() ."index.php?mode=showp&id=". $picture;
1751 if($current_tags != "") {
1752 $orig_url.= "&tags=". $current_tags;
1754 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1755 $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
1758 $thumb_url = $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
1763 // <a href="%pictureurl%"><img src="%thumbnailurl%" ></a>
1764 print htmlspecialchars("<a href=\"". $orig_url ."\"><img src=\"". $thumb_url ."\" /></a>") ."<br />\n";
1768 // "[%pictureurl% %thumbnailurl%]"
1769 print htmlspecialchars("[".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
1772 case 'MoinMoinList':
1773 // " * [%pictureurl% %thumbnailurl%]"
1774 print " " . htmlspecialchars("* [".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
1785 public function getRSSFeed()
1787 Header("Content-type: text/xml; charset=utf-8");
1788 print "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
1791 xmlns:media="http://search.yahoo.com/mrss/"
1792 xmlns:dc="http://purl.org/dc/elements/1.1/"
1795 <title>phpfspot</title>
1796 <description>phpfspot RSS feed</description>
1797 <link><?php print htmlspecialchars($this->get_phpfspot_url()); ?></link>
1798 <pubDate><?php print strftime("%a, %d %b %Y %T %z"); ?></pubDate>
1799 <generator>phpfspot</generator>
1802 $pictures = $this->getPhotoSelection();
1803 $current_tags = $this->getCurrentTags();
1805 foreach($pictures as $picture) {
1807 $orig_url = $this->get_phpfspot_url() ."index.php?mode=showp&id=". $picture;
1808 if($current_tags != "") {
1809 $orig_url.= "&tags=". $current_tags;
1811 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1812 $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
1815 $details = $this->get_photo_details($picture);
1817 $thumb_url = $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
1818 $thumb_html = htmlspecialchars("
1819 <a href=\"". $orig_url ."\"><img src=\"". $thumb_url ."\" /></a>
1821 ". $details['description']);
1823 $orig_path = $this->translate_path($this->parse_uri($details['uri'], 'fullpath'));
1824 $meta = $this->get_meta_informations($orig_path);
1825 $meta_date = isset($meta['FileDateTime']) ? $meta['FileDateTime'] : filemtime($orig_path);
1829 <title><?php print htmlspecialchars($this->parse_uri($details['uri'], 'filename')); ?></title>
1830 <link><?php print htmlspecialchars($orig_url); ?></link>
1831 <guid><?php print htmlspecialchars($orig_url); ?></guid>
1832 <dc:date.Taken><?php print strftime("%Y-%m-%dT%H:%M:%S+00:00", $meta_date); ?></dc:date.Taken>
1834 <?php print $thumb_html; ?>
1836 <pubDate><?php print strftime("%a, %d %b %Y %T %z", $meta_date); ?></pubDate>
1851 * return all selected tags as one string
1853 private function getCurrentTags()
1856 if($_SESSION['selected_tags'] != "") {
1857 foreach($_SESSION['selected_tags'] as $tag)
1858 $current_tags.= $tag .",";
1859 $current_tags = substr($current_tags, 0, strlen($current_tags)-1);
1861 return $current_tags;
1863 } // getCurrentTags()
1866 * return the current photo
1868 public function getCurrentPhoto()
1870 if(isset($_SESSION['current_photo'])) {
1871 print $_SESSION['current_photo'];
1873 } // getCurrentPhoto()
1876 * tells the client browser what to do
1878 * this function is getting called via AJAX by the
1879 * client browsers. it will tell them what they have
1880 * to do next. This is necessary for directly jumping
1881 * into photo index or single photo view when the are
1882 * requested with specific URLs
1884 public function whatToDo()
1886 if(isset($_SESSION['current_photo']) && $_SESSION['start_action'] == 'showp') {
1887 return "show_photo";
1889 elseif(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
1890 return "showpi_tags";
1892 elseif(isset($_SESSION['start_action']) && $_SESSION['start_action'] == 'showpi') {
1896 return "nothing special";
1901 * return the current process-user
1903 private function getuid()
1905 if($uid = posix_getuid()) {
1906 if($user = posix_getpwuid($uid)) {
1907 return $user['name'];
1916 * returns a select-dropdown box to select photo index sort parameters
1918 private function get_sort_field()
1920 $output = "<select name=\"sort_order\">";
1921 foreach(array('date_asc', 'date_desc', 'name_asc', 'name_desc') as $sort_order) {
1922 $output.= "<option value=\"". $sort_order ."\"";
1923 if($sort_order == $_SESSION['sort_order']) {
1924 $output.= " selected=\"selected\"";
1926 $output.= ">". $sort_order ."</option>";
1928 $output.= "</select>";
1931 } // get_sort_field()
1934 * returns the currently selected sort order
1936 private function get_sort_order()
1938 switch($_SESSION['sort_order']) {
1940 return " ORDER BY p.time ASC";
1943 return " ORDER BY p.time DESC";
1946 return " ORDER BY p.name ASC";
1949 return " ORDER BY p.name DESC";
1953 } // get_sort_order()
1956 * return the next to be shown slide show image
1958 * this function returns the URL of the next image
1959 * in the slideshow sequence.
1961 public function getNextSlideShowImage()
1963 $all_photos = $this->getPhotoSelection();
1965 if(!isset($_SESSION['slideshow_img']) || $_SESSION['slideshow_img'] == count($all_photos)-1)
1966 $_SESSION['slideshow_img'] = 0;
1968 $_SESSION['slideshow_img']++;
1970 return $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $all_photos[$_SESSION['slideshow_img']] ."&width=". $this->cfg->photo_width;
1972 } // getNextSlideShowImage()
1975 * return the previous to be shown slide show image
1977 * this function returns the URL of the previous image
1978 * in the slideshow sequence.
1980 public function getPrevSlideShowImage()
1982 $all_photos = $this->getPhotoSelection();
1984 if(!isset($_SESSION['slideshow_img']) || $_SESSION['slideshow_img'] == 0)
1985 $_SESSION['slideshow_img'] = 0;
1987 $_SESSION['slideshow_img']--;
1989 return $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $all_photos[$_SESSION['slideshow_img']] ."&width=". $this->cfg->photo_width;
1991 } // getPrevSlideShowImage()
1993 public function resetSlideShow()
1995 if(isset($_SESSION['slideshow_img']))
1996 unset($_SESSION['slideshow_img']);
1997 } // resetSlideShow()
2002 * this function will get all photos from the fspot
2003 * database and randomly return ONE entry
2005 * saddly there is yet no sqlite3 function which returns
2006 * the bulk result in array, so we have to fill up our
2009 public function get_random_photo()
2013 $result = $this->db->db_query("
2018 while($row = $this->db->db_fetch_object($result)) {
2019 array_push($all, $row['id']);
2022 return $all[array_rand($all)];
2024 } // get_random_photo()
2027 * validates provided date
2029 * this function validates if the provided date
2030 * contains a valid date and will return true
2033 public function isValidDate($date_str)
2035 $timestamp = strtotime($date_str);
2037 if(is_numeric($timestamp))
2045 * timestamp to string conversion
2047 private function ts2str($timestamp)
2049 return strftime("%Y-%m-%d", $timestamp);
2052 private function extractTags($tags_str)
2054 $not_validated = split(',', $_GET['tags']);
2055 $validated = array();
2057 foreach($not_validated as $tag) {
2058 if(is_numeric($tag))
2059 array_push($validated, $tag);
2067 * returns the full path to a thumbnail
2069 public function get_thumb_path($width, $photo)
2071 $md5 = $this->getMD5($photo);
2072 $sub_path = substr($md5, 0, 2);
2073 return $this->cfg->thumb_path
2081 } // get_thumb_path()
2084 * returns server's virtual host name
2086 private function get_server_name()
2088 return $_SERVER['SERVER_NAME'];
2089 } // get_server_name()
2092 * returns type of webprotocol which is
2095 private function get_web_protocol()
2097 if(!isset($_SERVER['HTTPS']))
2101 } // get_web_protocol()
2104 * return url to this phpfspot installation
2106 private function get_phpfspot_url()
2108 return $this->get_web_protocol() ."://". $this->get_server_name() . $this->cfg->web_path;
2109 } // get_phpfspot_url()
2112 * check file exists and is readable
2114 * returns true, if everything is ok, otherwise false
2115 * if $silent is not set, this function will output and
2118 private function check_readable($file, $silent = null)
2120 if(!file_exists($file)) {
2122 print "File \"". $file ."\" does not exist.\n";
2126 if(!is_readable($file)) {
2128 print "File \"". $file ."\" is not reachable for user ". $this->getuid() ."\n";
2134 } // check_readable()
2137 * check if all needed indices are present
2139 * this function checks, if some needed indices are already
2140 * present, or if not, create them on the fly. they are
2141 * necessary to speed up some queries like that one look for
2142 * all tags, when show_tags is specified in the configuration.
2144 private function checkDbIndices()
2146 $result = $this->db->db_exec("
2147 CREATE INDEX IF NOT EXISTS
2154 } // checkDbIndices()
2157 * retrive F-Spot database version
2159 * this function will return the F-Spot database version number
2160 * It is stored within the sqlite3 database in the table meta
2162 public function getFspotDBVersion()
2164 if($result = $this->db->db_fetchSingleRow("
2165 SELECT data as version
2168 name LIKE 'F-Spot Database Version'
2170 return $result['version'];
2174 } // getFspotDBVersion()
2177 * parse the provided URI and will returned the
2180 public function parse_uri($uri, $mode)
2182 if(($components = parse_url($uri)) !== false) {
2186 return basename($components['path']);
2189 return dirname($components['path']);
2192 return $components['path'];