3 /***************************************************************************
5 * phpfspot, presents your F-Spot photo collection in Web browsers.
7 * Copyright (c) by Andreas Unterkircher
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 ***************************************************************************/
25 require_once "phpfspot_cfg.php";
26 require_once "phpfspot_db.php";
31 * this class contains the most functions which will to the major
39 * phpfspot configuration
47 * SQLite database handle to f-spot database
55 * SQLite database handle to phpfspot database
63 * Smarty template engine
64 * @link http://smarty.php.net smarty.php.net
65 * @see PHPFSPOT_TMPL()
79 * list of available, not-selected, tags
86 * true if runtime error occued
90 private $runtime_error = false;
93 * F-Spot database version
100 * class constructor ($cfg, $db, $cfg_db, $tmpl, $db_ver)
102 * this function will be called on class construct
103 * and will check requirements, loads configuration,
104 * open databases and start the user session
106 public function __construct()
109 * register PHPFSPOT class global
111 * @global PHPFSPOT $GLOBALS['phpfspot']
114 $GLOBALS['phpfspot'] =& $this;
116 $this->cfg = new PHPFSPOT_CFG;
118 /* verify config settings */
119 if($this->check_config_options()) {
123 /* set application name and version information */
124 $this->cfg->product = "phpfspot";
125 $this->cfg->version = "1.5";
127 $this->sort_orders= array(
128 'date_asc' => 'Date ↑',
129 'date_desc' => 'Date ↓',
130 'name_asc' => 'Name ↑',
131 'name_desc' => 'Name ↓',
132 'tags_asc' => 'Tags ↑',
133 'tags_desc' => 'Tags ↓',
136 /* Check necessary requirements */
137 if(!$this->check_requirements()) {
141 /******* Opening F-Spot's sqlite database *********/
143 /* Check if database file is writeable */
144 if(!is_writeable($this->cfg->fspot_db)) {
145 print $this->cfg->fspot_db ." is not writeable for user ". $this->getuid() ."\n";
149 /* open the database */
150 $this->db = new PHPFSPOT_DB($this, $this->cfg->fspot_db);
152 /* change sqlite temp directory, if requested */
153 if(isset($this->cfg->sqlite_temp_dir)) {
156 temp_store_directory = '". $this->cfg->sqlite_temp_dir ."'
160 $this->dbver = $this->getFspotDBVersion();
162 if(!is_writeable($this->cfg->base_path ."/templates_c")) {
163 print $this->cfg->base_path ."/templates_c: directory is not writeable for user ". $this->getuid() ."\n";
167 if(!is_writeable($this->cfg->thumb_path)) {
168 print $this->cfg->thumb_path .": directory is not writeable for user ". $this->getuid() ."\n";
172 /******* Opening phpfspot's sqlite database *********/
174 /* Check if directory where the database file is stored is writeable */
175 if(!is_writeable(dirname($this->cfg->phpfspot_db))) {
176 print dirname($this->cfg->phpfspot_db) .": directory is not writeable for user ". $this->getuid() ."\n";
180 /* Check if database file is writeable */
181 if(!is_writeable($this->cfg->phpfspot_db)) {
182 print $this->cfg->phpfspot_db ." is not writeable for user ". $this->getuid() ."\n";
186 /* open the database */
187 $this->cfg_db = new PHPFSPOT_DB($this, $this->cfg->phpfspot_db);
189 /* change sqlite temp directory, if requested */
190 if(isset($this->cfg->sqlite_temp_dir)) {
191 $this->cfg_db->db_exec("
193 temp_store_directory = '". $this->cfg->sqlite_temp_dir ."'
197 /* Check if some tables need to be created */
198 $this->check_config_table();
200 /* overload Smarty class with our own template handler */
201 require_once "phpfspot_tmpl.php";
202 $this->tmpl = new PHPFSPOT_TMPL();
204 $this->tmpl->assign('web_path', $this->cfg->web_path);
206 /* check if all necessary indices exist */
207 $this->checkDbIndices();
209 /* if session is not yet started, do it now */
210 if(session_id() == "")
213 if(!isset($_SESSION['tag_condition']))
214 $_SESSION['tag_condition'] = 'or';
216 if(!isset($_SESSION['sort_order']))
217 $_SESSION['sort_order'] = 'date_desc';
219 if(!isset($_SESSION['searchfor_tag']))
220 $_SESSION['searchfor_tag'] = '';
222 // if begin_with is still set but thumbs_per_page is now 0, unset it
223 if(isset($_SESSION['begin_with']) && $this->cfg->thumbs_per_page == 0)
224 unset($_SESSION['begin_with']);
228 public function __destruct()
234 * show - generate html output
236 * this function can be called after the constructor has
237 * prepared everyhing. it will load the index.tpl smarty
238 * template. if necessary it will registere pre-selects
239 * (photo index, photo, tag search, date search) into
242 public function show()
244 $this->tmpl->assign('searchfor_tag', $_SESSION['searchfor_tag']);
245 $this->tmpl->assign('page_title', $this->cfg->page_title);
246 $this->tmpl->assign('current_condition', $_SESSION['tag_condition']);
247 $this->tmpl->assign('template_path', 'themes/'. $this->cfg->theme_name);
250 if($this->is_user_friendly_url()) {
251 $content = $this->parse_user_friendly_url($_SERVER['REQUEST_URI']);
254 if(isset($_GET['mode'])) {
256 $_SESSION['start_action'] = $_GET['mode'];
258 switch($_GET['mode']) {
260 if(isset($_GET['tags'])) {
261 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
263 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
264 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
266 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
267 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
271 if(isset($_GET['tags'])) {
272 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
273 $_SESSION['start_action'] = 'showp';
275 if(isset($_GET['id']) && is_numeric($_GET['id'])) {
276 $_SESSION['current_photo'] = $_GET['id'];
277 $_SESSION['start_action'] = 'showp';
279 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
280 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
282 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
283 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
287 $this->tmpl->show("export.tpl");
291 $this->tmpl->show("slideshow.tpl");
295 if(isset($_GET['tags'])) {
296 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
298 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
299 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
301 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
302 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
310 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date']))
311 $this->tmpl->assign('date_search_enabled', true);
313 $this->tmpl->register_function("sort_select_list", array(&$this, "smarty_sort_select_list"), false);
314 $this->tmpl->assign('search_from_date', $this->get_calendar('from'));
315 $this->tmpl->assign('search_to_date', $this->get_calendar('to'));
317 $this->tmpl->assign('preset_selected_tags', $this->getSelectedTags());
318 $this->tmpl->assign('preset_available_tags', $this->getAvailableTags());
320 if(!isset($content)) {
321 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags']))
322 $this->tmpl->assign('initial_content', $this->showPhotoIndex());
324 $this->tmpl->assign('initial_content', $this->tmpl->fetch('welcome.tpl'));
327 $this->tmpl->assign('initial_content', $content);
329 $this->tmpl->show("index.tpl");
334 * get_tags - grab all tags of f-spot's database
336 * this function will get all available tags from
337 * the f-spot database and store them within two
338 * arrays within this class for later usage. in
339 * fact, if the user requests (hide_tags) it will
340 * opt-out some of them.
342 * this function is getting called once by show()
344 private function get_tags()
346 $this->avail_tags = Array();
349 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
352 DISTINCT t1.id as id, t1.name as name
355 INNER JOIN photo_tags
356 pt2 ON pt1.photo_id=pt2.photo_id
362 t2.name IN ('".implode("','",$this->cfg->show_tags)."')
364 t1.sort_priority ASC";
366 $result = $this->db->db_query($query_str);
370 $result = $this->db->db_query("
373 ORDER BY sort_priority ASC
377 while($row = $this->db->db_fetch_object($result)) {
379 $tag_id = $row['id'];
380 $tag_name = $row['name'];
382 /* if the user has specified to ignore this tag in phpfspot's
383 configuration, ignore it here so it does not get added to
386 if(in_array($row['name'], $this->cfg->hide_tags))
389 /* if you include the following if-clause and the user has specified
390 to only show certain tags which are specified in phpfspot's
391 configuration, ignore all others so they will not be added to the
393 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags) &&
394 !in_array($row['name'], $this->cfg->show_tags))
398 $this->tags[$tag_id] = $tag_name;
399 $this->avail_tags[$count] = $tag_id;
407 * extract all photo details
409 * retrieve all available details from f-spot's
410 * database and return them as object
411 * @param integer $idx
412 * @return object|null
414 public function get_photo_details($idx)
416 if($this->dbver < 9) {
418 SELECT p.id, p.name, p.time, p.directory_path, p.description
424 SELECT p.id, p.uri, p.time, p.description
429 /* if show_tags is set, only return details for photos which
430 are specified to be shown
432 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
434 INNER JOIN photo_tags pt
438 WHERE p.id='". $idx ."'
439 AND t.name IN ('".implode("','",$this->cfg->show_tags)."')";
443 WHERE p.id='". $idx ."'
447 if($result = $this->db->db_query($query_str)) {
449 $row = $this->db->db_fetch_object($result);
451 if($this->dbver < 9) {
452 $row['uri'] = "file://". $row['directory_path'] ."/". $row['name'];
461 } // get_photo_details
464 * returns aligned photo names
466 * this function returns aligned (length) names for
467 * an specific photo. If the length of the name exceeds
468 * $limit the name will be shrinked (...)
469 * @param integer $idx
470 * @param integer $limit
471 * @return string|null
473 public function getPhotoName($idx, $limit = 0)
475 if($details = $this->get_photo_details($idx)) {
476 if($long_name = $this->parse_uri($details['uri'], 'filename')) {
477 $name = $this->shrink_text($long_name, $limit);
487 * shrink text according provided limit
489 * If the length of the name exceeds $limit the
490 * text will be shortend and some content in between
491 * will be replaced with "..."
493 * @param integer $limit
496 private function shrink_text($text, $limit)
498 if($limit != 0 && strlen($text) > $limit) {
499 $text = substr($text, 0, $limit-5) ."...". substr($text, -($limit-5));
507 * translate f-spoth photo path
509 * as the full-qualified path recorded in the f-spot database
510 * is usally not the same as on the webserver, this function
511 * will replace the path with that one specified in the cfg
512 * @param string $path
515 public function translate_path($path)
517 return str_replace($this->cfg->path_replace_from, $this->cfg->path_replace_to, $path);
522 * control HTML ouput for a single photo
524 * this function provides all the necessary information
525 * for the single photo template.
526 * @param integer photo
528 public function showPhoto($photo)
530 /* get all photos from the current photo selection */
531 $all_photos = $this->getPhotoSelection();
532 $count = count($all_photos);
534 for($i = 0; $i < $count; $i++) {
536 // $get_next will be set, when the photo which has to
537 // be displayed has been found - this means that the
538 // next available is in fact the NEXT image (for the
540 if(isset($get_next)) {
541 $next_img = $all_photos[$i];
545 /* the next photo is our NEXT photo */
546 if($all_photos[$i] == $photo) {
550 $previous_img = $all_photos[$i];
553 if($photo == $all_photos[$i]) {
558 $details = $this->get_photo_details($photo);
565 $orig_path = $this->translate_path($this->parse_uri($details['uri'], 'fullpath'));
566 $thumb_path = $this->get_thumb_path($this->cfg->photo_width, $photo);
568 if(!file_exists($orig_path)) {
569 $this->_error("Photo ". $orig_path ." does not exist!<br />\n");
573 if(!is_readable($orig_path)) {
574 $this->_error("Photo ". $orig_path ." is not readable for user ". $this->getuid() ."<br />\n");
578 /* If the thumbnail doesn't exist yet, try to create it */
579 if(!file_exists($thumb_path)) {
580 $this->gen_thumb($photo, true);
581 $thumb_path = $this->get_thumb_path($this->cfg->photo_width, $photo);
584 /* get mime-type, height and width from the original photo */
585 $info = getimagesize($orig_path);
587 /* get EXIF information if JPEG */
588 if($info['mime'] == "image/jpeg") {
589 $meta = $this->get_meta_informations($orig_path);
592 /* If EXIF data are available, use them */
593 if(isset($meta['ExifImageWidth'])) {
594 $meta_res = $meta['ExifImageWidth'] ."x". $meta['ExifImageLength'];
596 $meta_res = $info[0] ."x". $info[1];
599 $meta_date = isset($meta['FileDateTime']) ? strftime("%a %x %X", $meta['FileDateTime']) : "n/a";
600 $meta_make = isset($meta['Make']) ? $meta['Make'] ." / ". $meta['Model'] : "n/a";
601 $meta_size = isset($meta['FileSize']) ? round($meta['FileSize']/1024, 1) ."kbyte" : "n/a";
603 $extern_link = "index.php?mode=showp&id=". $photo;
604 $current_tags = $this->getCurrentTags();
605 if($current_tags != "") {
606 $extern_link.= "&tags=". $current_tags;
608 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
609 $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
612 $this->tmpl->assign('extern_link', $extern_link);
614 if(!file_exists($thumb_path)) {
615 $this->_error("Can't open file ". $thumb_path ."\n");
619 $info_thumb = getimagesize($thumb_path);
621 $this->tmpl->assign('description', $details['description']);
622 $this->tmpl->assign('image_name', $this->parse_uri($details['uri'], 'filename'));
624 $this->tmpl->assign('width', $info_thumb[0]);
625 $this->tmpl->assign('height', $info_thumb[1]);
626 $this->tmpl->assign('ExifMadeOn', $meta_date);
627 $this->tmpl->assign('ExifMadeWith', $meta_make);
628 $this->tmpl->assign('ExifOrigResolution', $meta_res);
629 $this->tmpl->assign('ExifFileSize', $meta_size);
631 if($this->is_user_friendly_url()) {
632 $this->tmpl->assign('image_url', '/photo/'. $photo ."/". $this->cfg->photo_width);
633 $this->tmpl->assign('image_url_full', '/photo/'. $photo);
636 $this->tmpl->assign('image_url', 'phpfspot_img.php?idx='. $photo ."&width=". $this->cfg->photo_width);
637 $this->tmpl->assign('image_url_full', 'phpfspot_img.php?idx='. $photo);
640 $this->tmpl->assign('image_filename', $this->parse_uri($details['uri'], 'filename'));
642 $this->tmpl->assign('tags', $this->get_photo_tags($photo));
643 $this->tmpl->assign('current_page', $this->getCurrentPage($current, $count));
644 $this->tmpl->assign('current_img', $photo);
647 $this->tmpl->assign('previous_url', "javascript:showImage(". $previous_img .");");
648 $this->tmpl->assign('prev_img', $previous_img);
652 $this->tmpl->assign('next_url', "javascript:showImage(". $next_img .");");
653 $this->tmpl->assign('next_img', $next_img);
655 $this->tmpl->assign('mini_width', $this->cfg->mini_width);
656 $this->tmpl->assign('photo_width', $this->cfg->photo_width);
657 $this->tmpl->assign('photo_number', $i);
658 $this->tmpl->assign('photo_count', count($all_photos));
660 return $this->tmpl->fetch("single_photo.tpl");
665 * all available tags and tag cloud
667 * this function outputs all available tags (time ordered)
668 * and in addition output them as tag cloud (tags which have
669 * many photos will appears more then others)
671 public function getAvailableTags()
673 /* retrive tags from database */
678 $result = $this->db->db_query("
679 SELECT tag_id as id, count(tag_id) as quantity
689 while($row = $this->db->db_fetch_object($result)) {
690 $tags[$row['id']] = $row['quantity'];
693 // change these font sizes if you will
694 $max_size = 125; // max font size in %
695 $min_size = 75; // min font size in %
698 $max_sat = hexdec('cc');
699 $min_sat = hexdec('44');
701 // get the largest and smallest array values
702 $max_qty = max(array_values($tags));
703 $min_qty = min(array_values($tags));
705 // find the range of values
706 $spread = $max_qty - $min_qty;
707 if (0 == $spread) { // we don't want to divide by zero
711 // determine the font-size increment
712 // this is the increase per tag quantity (times used)
713 $step = ($max_size - $min_size)/($spread);
714 $step_sat = ($max_sat - $min_sat)/($spread);
716 // loop through our tag array
717 foreach ($tags as $key => $value) {
719 if(isset($_SESSION['selected_tags']) && in_array($key, $_SESSION['selected_tags']))
722 // calculate CSS font-size
723 // find the $value in excess of $min_qty
724 // multiply by the font-size increment ($size)
725 // and add the $min_size set above
726 $size = $min_size + (($value - $min_qty) * $step);
727 // uncomment if you want sizes in whole %:
730 $color = $min_sat + ($value - $min_qty) * $step_sat;
736 if(isset($this->tags[$key])) {
737 if($this->is_user_friendly_url())
738 $output.= "<a href=\"". $this->cfg->web_path ."/tag/". $key ."\" onclick=\"Tags('add', ". $key ."); return false;\" class=\"tag\" style=\"font-size: ". $size ."%; color: #". $r.$g.$b .";\">". $this->tags[$key] ."</a>, ";
740 $output.= "<a href=\"". $this->cfg->web_path ."/index.php?mode=showpi\" onclick=\"Tags('add', ". $key ."); return false;\" class=\"tag\" style=\"font-size: ". $size ."%; color: #". $r.$g.$b .";\">". $this->tags[$key] ."</a>, ";
744 $output = substr($output, 0, strlen($output)-2);
747 } // getAvailableTags()
750 * output all selected tags
752 * this function output all tags which have been selected
753 * by the user. the selected tags are stored in the
754 * session-variable $_SESSION['selected_tags']
757 public function getSelectedTags($type = 'link')
759 /* retrive tags from database */
764 foreach($this->avail_tags as $tag)
766 // return all selected tags
767 if(isset($_SESSION['selected_tags']) && in_array($tag, $_SESSION['selected_tags'])) {
772 $output.= "<a href=\"javascript:Tags('del', ". $tag .");\" class=\"tag\">". $this->tags[$tag] ."</a>, ";
776 <div style=\"display: table-cell;\">
777 <div style=\"display: table-row; text-align: center;\">
778 <a href=\"javascript:Tags('del', ". $tag .");\" title=\"". $this->tags[$tag] ."\">
779 <img src=\"". $this->cfg->web_path ."/phpfspot_img.php?tagidx=". $tag ."\" />
782 <div style=\"display: table-row; text-align: center;\">
783 <a href=\"javascript:Tags('del', ". $tag .");\" title=\"". $this->tags[$tag] ."\">
784 <img src=\"". $this->cfg->web_path ."/resources/underbar.png\" />
795 $output = substr($output, 0, strlen($output)-2);
799 return "no tags selected";
802 } // getSelectedTags()
805 * add tag to users session variable
807 * this function will add the specified to users current
808 * tag selection. if a date search has been made before
809 * it will be now cleared
812 public function addTag($tag)
814 if(!isset($_SESSION['selected_tags']))
815 $_SESSION['selected_tags'] = Array();
817 if(isset($_SESSION['searchfor_tag']))
818 unset($_SESSION['searchfor_tag']);
820 // has the user requested to hide this tag, and still someone,
821 // somehow tries to add it, don't allow this.
822 if(!isset($this->cfg->hide_tags) &&
823 in_array($this->get_tag_name($tag), $this->cfg->hide_tags))
826 if(!in_array($tag, $_SESSION['selected_tags']))
827 array_push($_SESSION['selected_tags'], $tag);
834 * remove tag to users session variable
836 * this function removes the specified tag from
837 * users current tag selection
841 public function delTag($tag)
843 if(isset($_SESSION['searchfor_tag']))
844 unset($_SESSION['searchfor_tag']);
846 if(isset($_SESSION['selected_tags'])) {
847 $key = array_search($tag, $_SESSION['selected_tags']);
848 unset($_SESSION['selected_tags'][$key]);
849 sort($_SESSION['selected_tags']);
857 * reset tag selection
859 * if there is any tag selection, it will be
862 public function resetTags()
864 if(isset($_SESSION['selected_tags']))
865 unset($_SESSION['selected_tags']);
870 * returns the value for the autocomplet tag-search
873 public function get_xml_tag_list()
875 if(!isset($_GET['search']) || !is_string($_GET['search']))
876 $_GET['search'] = '';
881 /* retrive tags from database */
884 $matched_tags = Array();
886 header("Content-Type: text/xml");
888 $string = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n";
889 $string.= "<results>\n";
891 foreach($this->avail_tags as $tag)
893 if(!empty($_GET['search']) &&
894 preg_match("/". $_GET['search'] ."/i", $this->tags[$tag]) &&
895 count($matched_tags) < $length) {
897 $count = $this->get_num_photos($tag);
900 $string.= " <rs id=\"". $i ."\" info=\"". $count ." photo\">". $this->tags[$tag] ."</rs>\n";
903 $string.= " <rs id=\"". $i ."\" info=\"". $count ." photos\">". $this->tags[$tag] ."</rs>\n";
909 /* if we have collected enough items, break out */
910 if(count($matched_tags) >= $length)
914 $string.= "</results>\n";
918 } // get_xml_tag_list()
924 * if a specific photo was requested (external link)
925 * unset the session variable now
927 public function resetPhotoView()
929 if(isset($_SESSION['current_photo']))
930 unset($_SESSION['current_photo']);
932 } // resetPhotoView();
937 * if any tag search has taken place, reset it now
939 public function resetTagSearch()
941 if(isset($_SESSION['searchfor_tag']))
942 unset($_SESSION['searchfor_tag']);
944 } // resetTagSearch()
949 * if any name search has taken place, reset it now
951 public function resetNameSearch()
953 if(isset($_SESSION['searchfor_name']))
954 unset($_SESSION['searchfor_name']);
956 } // resetNameSearch()
961 * if any date search has taken place, reset
964 public function resetDateSearch()
966 if(isset($_SESSION['from_date']))
967 unset($_SESSION['from_date']);
968 if(isset($_SESSION['to_date']))
969 unset($_SESSION['to_date']);
971 } // resetDateSearch();
974 * return all photo according selection
976 * this function returns all photos based on
977 * the tag-selection, tag- or date-search.
978 * the tag-search also has to take care of AND
979 * and OR conjunctions
982 public function getPhotoSelection()
984 $matched_photos = Array();
985 $additional_where_cond = "";
987 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
988 $from_date = $_SESSION['from_date'];
989 $to_date = $_SESSION['to_date'];
990 $additional_where_cond.= "
991 p.time>='". $from_date ."'
993 p.time<='". $to_date ."'
997 if(isset($_SESSION['searchfor_name'])) {
998 if($this->dbver < 9) {
999 $additional_where_cond.= "
1001 p.name LIKE '%". $_SESSION['searchfor_name'] ."%'
1003 p.description LIKE '%". $_SESSION['searchfor_name'] ."%'
1008 $additional_where_cond.= "
1010 basename(p.uri) LIKE '%". $_SESSION['searchfor_name'] ."%'
1012 p.description LIKE '%". $_SESSION['searchfor_name'] ."%'
1018 if(isset($_SESSION['sort_order'])) {
1019 $order_str = $this->get_sort_order();
1022 /* return a search result */
1023 if(isset($_SESSION['searchfor_tag']) && $_SESSION['searchfor_tag'] != '') {
1025 SELECT DISTINCT pt1.photo_id
1027 INNER JOIN photo_tags pt2
1028 ON pt1.photo_id=pt2.photo_id
1032 ON pt1.photo_id=p.id
1035 WHERE t.name LIKE '%". $_SESSION['searchfor_tag'] ."%' ";
1037 if(isset($additional_where_cond) && !empty($additional_where_cond))
1038 $query_str.= "AND ". $additional_where_cond ." ";
1040 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1041 $query_str.= "AND t2.name IN ('".implode("','",$this->cfg->show_tags)."')";
1044 if(isset($order_str))
1045 $query_str.= $order_str;
1047 $result = $this->db->db_query($query_str);
1048 while($row = $this->db->db_fetch_object($result)) {
1049 array_push($matched_photos, $row['photo_id']);
1051 return $matched_photos;
1054 /* return according the selected tags */
1055 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
1057 foreach($_SESSION['selected_tags'] as $tag)
1058 $selected.= $tag .",";
1059 $selected = substr($selected, 0, strlen($selected)-1);
1061 /* photo has to match at least on of the selected tags */
1062 if($_SESSION['tag_condition'] == 'or') {
1064 SELECT DISTINCT pt1.photo_id
1066 INNER JOIN photo_tags pt2
1067 ON pt1.photo_id=pt2.photo_id
1071 ON pt1.photo_id=p.id
1072 WHERE pt1.tag_id IN (". $selected .")
1074 if(isset($additional_where_cond) && !empty($additional_where_cond))
1075 $query_str.= "AND ". $additional_where_cond ." ";
1077 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1078 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags)."')";
1081 if(isset($order_str))
1082 $query_str.= $order_str;
1084 /* photo has to match all selected tags */
1085 elseif($_SESSION['tag_condition'] == 'and') {
1087 if(count($_SESSION['selected_tags']) >= 32) {
1088 print "A SQLite limit of 32 tables within a JOIN SELECT avoids to<br />\n";
1089 print "evaluate your tag selection. Please remove some tags from your selection.\n";
1093 /* Join together a table looking like
1095 pt1.photo_id pt1.tag_id pt2.photo_id pt2.tag_id ...
1097 so the query can quickly return all images matching the
1098 selected tags in an AND condition
1103 SELECT DISTINCT pt1.photo_id
1107 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1114 for($i = 0; $i < count($_SESSION['selected_tags']); $i++) {
1116 INNER JOIN photo_tags pt". ($i+2) ."
1117 ON pt1.photo_id=pt". ($i+2) .".photo_id
1122 ON pt1.photo_id=p.id
1124 $query_str.= "WHERE pt2.tag_id=". $_SESSION['selected_tags'][0]." ";
1125 for($i = 1; $i < count($_SESSION['selected_tags']); $i++) {
1127 AND pt". ($i+2) .".tag_id=". $_SESSION['selected_tags'][$i] ."
1130 if(isset($additional_where_cond) && !empty($additional_where_cond))
1131 $query_str.= "AND ". $additional_where_cond;
1133 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1134 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags). "')";
1137 if(isset($order_str))
1138 $query_str.= $order_str;
1142 $result = $this->db->db_query($query_str);
1143 while($row = $this->db->db_fetch_object($result)) {
1144 array_push($matched_photos, $row['photo_id']);
1146 return $matched_photos;
1149 /* return all available photos */
1151 SELECT DISTINCT p.id
1153 LEFT JOIN photo_tags pt
1159 if(isset($additional_where_cond) && !empty($additional_where_cond))
1160 $query_str.= "WHERE ". $additional_where_cond ." ";
1162 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1163 if(isset($additional_where_cond) && !empty($additional_where_cond))
1164 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags). "')";
1166 $query_str.= "WHERE t.name IN ('".implode("','",$this->cfg->show_tags). "')";
1169 if(isset($order_str))
1170 $query_str.= $order_str;
1172 $result = $this->db->db_query($query_str);
1173 while($row = $this->db->db_fetch_object($result)) {
1174 array_push($matched_photos, $row['id']);
1176 return $matched_photos;
1178 } // getPhotoSelection()
1181 * control HTML ouput for photo index
1183 * this function provides all the necessary information
1184 * for the photo index template.
1187 public function showPhotoIndex()
1189 $photos = $this->getPhotoSelection();
1191 $count = count($photos);
1193 /* if all thumbnails should be shown on one page */
1194 if(!isset($this->cfg->thumbs_per_page) || $this->cfg->thumbs_per_page == 0) {
1198 /* thumbnails should be splitted up in several pages */
1199 elseif($this->cfg->thumbs_per_page > 0) {
1201 if(!isset($_SESSION['begin_with']) || $_SESSION['begin_with'] == 0) {
1205 $begin_with = $_SESSION['begin_with'];
1208 $end_with = $begin_with + $this->cfg->thumbs_per_page;
1212 $images[$thumbs] = Array();
1213 $img_height[$thumbs] = Array();
1214 $img_width[$thumbs] = Array();
1215 $img_id[$thumbs] = Array();
1216 $img_name[$thumbs] = Array();
1217 $img_fullname[$thumbs] = Array();
1218 $img_title = Array();
1220 for($i = $begin_with; $i < $end_with; $i++) {
1222 if(isset($photos[$i])) {
1224 $images[$thumbs] = $photos[$i];
1225 $img_id[$thumbs] = $i;
1226 $img_name[$thumbs] = htmlspecialchars($this->getPhotoName($photos[$i], 15));
1227 $img_fullname[$thumbs] = htmlspecialchars($this->getPhotoName($photos[$i], 0));
1228 $img_title[$thumbs] = "Click to view photo ". htmlspecialchars($this->getPhotoName($photos[$i], 0));
1230 $thumb_path = $this->get_thumb_path($this->cfg->thumb_width, $photos[$i]);
1232 if(file_exists($thumb_path)) {
1233 $info = getimagesize($thumb_path);
1234 $img_width[$thumbs] = $info[0];
1235 $img_height[$thumbs] = $info[1];
1241 // +1 for for smarty's selection iteration
1244 if(isset($_SESSION['searchfor_tag']) && $_SESSION['searchfor_tag'] != '')
1245 $this->tmpl->assign('searchfor_tag', $_SESSION['searchfor_tag']);
1247 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1248 $this->tmpl->assign('from_date', $this->ts2str($_SESSION['from_date']));
1249 $this->tmpl->assign('to_date', $this->ts2str($_SESSION['to_date']));
1252 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
1253 $this->tmpl->assign('tag_result', 1);
1256 /* do we have to display the page selector ? */
1257 if($this->cfg->thumbs_per_page != 0) {
1261 /* calculate the page switchers */
1262 $previous_start = $begin_with - $this->cfg->thumbs_per_page;
1263 $next_start = $begin_with + $this->cfg->thumbs_per_page;
1265 if($begin_with != 0)
1266 $this->tmpl->assign("previous_url", "javascript:showPhotoIndex(". $previous_start .");");
1267 if($end_with < $count)
1268 $this->tmpl->assign("next_url", "javascript:showPhotoIndex(". $next_start .");");
1270 $photo_per_page = $this->cfg->thumbs_per_page;
1271 $last_page = ceil($count / $photo_per_page);
1273 /* get the current selected page */
1274 if($begin_with == 0) {
1278 for($i = $begin_with; $i >= 0; $i-=$photo_per_page) {
1285 for($i = 1; $i <= $last_page; $i++) {
1287 if($current_page == $i)
1288 $style = "style=\"font-size: 125%; text-decoration: underline;\"";
1289 elseif($current_page-1 == $i || $current_page+1 == $i)
1290 $style = "style=\"font-size: 105%;\"";
1291 elseif(($current_page-5 >= $i) && ($i != 1) ||
1292 ($current_page+5 <= $i) && ($i != $last_page))
1293 $style = "style=\"font-size: 75%;\"";
1297 $start_with = ($i*$photo_per_page)-$photo_per_page;
1299 if($this->is_user_friendly_url()) {
1300 $select = "<a href=\"". $this->cfg->web_path ."/tag/205/". $start_with ."\"";
1303 $select = "<a href=\"". $this->cfg->web_path ."/index.php?mode=showpi tags=". $current_tags ." begin_with=". $begin_with ."\"";
1305 $select.= " onclick=\"showPhotoIndex(". $start_with ."); return false;\"";
1309 $select.= ">". $i ."</a> ";
1311 // until 9 pages we show the selector from 1-9
1312 if($last_page <= 9) {
1313 $page_select.= $select;
1316 if($i == 1 /* first page */ ||
1317 $i == $last_page /* last page */ ||
1318 $i == $current_page /* current page */ ||
1319 $i == ceil($last_page * 0.25) /* first quater */ ||
1320 $i == ceil($last_page * 0.5) /* half */ ||
1321 $i == ceil($last_page * 0.75) /* third quater */ ||
1322 (in_array($i, array(1,2,3,4,5,6)) && $current_page <= 4) /* the first 6 */ ||
1323 (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 */ ||
1324 $i == $current_page-3 || $i == $current_page-2 || $i == $current_page-1 /* three before */ ||
1325 $i == $current_page+3 || $i == $current_page+2 || $i == $current_page+1 /* three after */) {
1327 $page_select.= $select;
1335 $page_select.= "......... ";
1340 /* only show the page selector if we have more then one page */
1342 $this->tmpl->assign('page_selector', $page_select);
1345 $current_tags = $this->getCurrentTags();
1346 $extern_link = "index.php?mode=showpi";
1347 $rss_link = "index.php?mode=rss";
1348 if($current_tags != "") {
1349 $extern_link.= "&tags=". $current_tags;
1350 $rss_link.= "&tags=". $current_tags;
1352 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1353 $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
1354 $rss_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
1357 $export_link = "index.php?mode=export";
1358 $slideshow_link = "index.php?mode=slideshow";
1360 $this->tmpl->assign('extern_link', $extern_link);
1361 $this->tmpl->assign('slideshow_link', $slideshow_link);
1362 $this->tmpl->assign('export_link', $export_link);
1363 $this->tmpl->assign('rss_link', $rss_link);
1364 $this->tmpl->assign('count', $count);
1365 $this->tmpl->assign('width', $this->cfg->thumb_width);
1366 $this->tmpl->assign('preview_width', $this->cfg->photo_width);
1367 $this->tmpl->assign('thumb_container_width', $this->cfg->thumb_width);
1368 $this->tmpl->assign('thumb_container_height', $this->cfg->thumb_height+20);
1369 $this->tmpl->assign('images', $images);
1370 $this->tmpl->assign('img_width', $img_width);
1371 $this->tmpl->assign('img_height', $img_height);
1372 $this->tmpl->assign('img_id', $img_id);
1373 $this->tmpl->assign('img_name', $img_name);
1374 $this->tmpl->assign('img_fullname', $img_fullname);
1375 $this->tmpl->assign('img_title', $img_title);
1376 $this->tmpl->assign('thumbs', $thumbs);
1377 $this->tmpl->assign('selected_tags', $this->getSelectedTags('img'));
1379 $result = $this->tmpl->fetch("photo_index.tpl");
1381 /* if we are returning to photo index from an photo-view,
1382 scroll the window to the last shown photo-thumbnail.
1383 after this, unset the last_photo session variable.
1385 if(isset($_SESSION['last_photo'])) {
1386 $result.= "<script language=\"JavaScript\">moveToThumb(". $_SESSION['last_photo'] .");</script>\n";
1387 unset($_SESSION['last_photo']);
1392 } // showPhotoIndex()
1395 * show credit template
1397 public function showCredits()
1399 $this->tmpl->assign('version', $this->cfg->version);
1400 $this->tmpl->assign('product', $this->cfg->product);
1401 $this->tmpl->assign('db_version', $this->dbver);
1402 $this->tmpl->show("credits.tpl");
1407 * create thumbnails for the requested width
1409 * this function creates image thumbnails of $orig_image
1410 * stored as $thumb_image. It will check if the image is
1411 * in a supported format, if necessary rotate the image
1412 * (based on EXIF orientation meta headers) and re-sizing.
1413 * @param string $orig_image
1414 * @param string $thumb_image
1415 * @param integer $width
1418 public function create_thumbnail($orig_image, $thumb_image, $width)
1420 if(!file_exists($orig_image)) {
1424 $mime = $this->get_mime_info($orig_image);
1426 /* check if original photo is a support image type */
1427 if(!$this->checkifImageSupported($mime))
1434 $meta = $this->get_meta_informations($orig_image);
1440 switch($meta['Orientation']) {
1441 case 1: /* top, left */
1442 /* nothing to do */ break;
1443 case 2: /* top, right */
1444 $rotate = 0; $flip_hori = true; break;
1445 case 3: /* bottom, left */
1446 $rotate = 180; break;
1447 case 4: /* bottom, right */
1448 $flip_vert = true; break;
1449 case 5: /* left side, top */
1450 $rotate = 90; $flip_vert = true; break;
1451 case 6: /* right side, top */
1452 $rotate = 90; break;
1453 case 7: /* left side, bottom */
1454 $rotate = 270; $flip_vert = true; break;
1455 case 8: /* right side, bottom */
1456 $rotate = 270; break;
1459 $src_img = @imagecreatefromjpeg($orig_image);
1465 $src_img = @imagecreatefrompng($orig_image);
1469 case 'image/x-portable-pixmap':
1471 $src_img = new Imagick($orig_image);
1472 $handler = "imagick";
1477 if(!isset($src_img) || empty($src_img)) {
1478 print "Can't load image from ". $orig_image ."\n";
1486 /* grabs the height and width */
1487 $cur_width = imagesx($src_img);
1488 $cur_height = imagesy($src_img);
1490 // If requested width is more then the actual image width,
1491 // do not generate a thumbnail, instead safe the original
1492 // as thumbnail but with lower quality. But if the image
1493 // is to heigh too, then we still have to resize it.
1494 if($width >= $cur_width && $cur_height < $this->cfg->thumb_height) {
1495 $result = imagejpeg($src_img, $thumb_image, 75);
1496 imagedestroy($src_img);
1503 $cur_width = $src_img->getImageWidth();
1504 $cur_height = $src_img->getImageHeight();
1506 // If requested width is more then the actual image width,
1507 // do not generate a thumbnail, instead safe the original
1508 // as thumbnail but with lower quality. But if the image
1509 // is to heigh too, then we still have to resize it.
1510 if($width >= $cur_width && $cur_height < $this->cfg->thumb_height) {
1511 $src_img->setCompressionQuality(75);
1512 $src_img->setImageFormat('jpeg');
1513 $src_img->writeImage($thumb_image);
1515 $src_img->destroy();
1522 // If the image will be rotate because EXIF orientation said so
1523 // 'virtually rotate' the image for further calculations
1524 if($rotate == 90 || $rotate == 270) {
1526 $cur_width = $cur_height;
1530 /* calculates aspect ratio */
1531 $aspect_ratio = $cur_height / $cur_width;
1534 if($aspect_ratio < 1) {
1536 $new_h = abs($new_w * $aspect_ratio);
1538 /* 'virtually' rotate the image and calculate it's ratio */
1539 $tmp_w = $cur_height;
1540 $tmp_h = $cur_width;
1541 /* now get the ratio from the 'rotated' image */
1542 $tmp_ratio = $tmp_h/$tmp_w;
1543 /* now calculate the new dimensions */
1545 $tmp_h = abs($tmp_w * $tmp_ratio);
1547 // now that we know, how high they photo should be, if it
1548 // gets rotated, use this high to scale the image
1550 $new_w = abs($new_h / $aspect_ratio);
1552 // If the image will be rotate because EXIF orientation said so
1553 // now 'virtually rotate' back the image for the image manipulation
1554 if($rotate == 90 || $rotate == 270) {
1565 /* creates new image of that size */
1566 $dst_img = imagecreatetruecolor($new_w, $new_h);
1568 imagefill($dst_img, 0, 0, ImageColorAllocate($dst_img, 255, 255, 255));
1570 /* copies resized portion of original image into new image */
1571 imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $new_w, $new_h, imagesx($src_img), imagesy($src_img));
1573 /* needs the image to be flipped horizontal? */
1575 $this->_debug("(FLIP)");
1576 $dst_img = $this->flipImage($dst_img, 'hori');
1578 /* needs the image to be flipped vertical? */
1580 $this->_debug("(FLIP)");
1581 $dst_img = $this->flipImage($dst_img, 'vert');
1585 $this->_debug("(ROTATE)");
1586 $dst_img = $this->rotateImage($dst_img, $rotate);
1589 /* write down new generated file */
1590 $result = imagejpeg($dst_img, $thumb_image, 75);
1592 /* free your mind */
1593 imagedestroy($dst_img);
1594 imagedestroy($src_img);
1596 if($result === false) {
1597 print "Can't write thumbnail ". $thumb_image ."\n";
1607 $src_img->resizeImage($new_w, $new_h, Imagick::FILTER_LANCZOS, 1);
1609 /* needs the image to be flipped horizontal? */
1611 $this->_debug("(FLIP)");
1612 $src_img->rotateImage(new ImagickPixel(), 90);
1613 $src_img->flipImage();
1614 $src_img->rotateImage(new ImagickPixel(), -90);
1616 /* needs the image to be flipped vertical? */
1618 $this->_debug("(FLIP)");
1619 $src_img->flipImage();
1623 $this->_debug("(ROTATE)");
1624 $src_img->rotateImage(new ImagickPixel(), $rotate);
1627 $src_img->setCompressionQuality(75);
1628 $src_img->setImageFormat('jpeg');
1630 if(!$src_img->writeImage($thumb_image)) {
1631 print "Can't write thumbnail ". $thumb_image ."\n";
1636 $src_img->destroy();
1643 } // create_thumbnail()
1646 * return all exif meta data from the file
1647 * @param string $file
1650 public function get_meta_informations($file)
1652 return exif_read_data($file);
1654 } // get_meta_informations()
1657 * create phpfspot own sqlite database
1659 * this function creates phpfspots own sqlite database
1660 * if it does not exist yet. this own is used to store
1661 * some necessary informations (md5 sum's, ...).
1663 public function check_config_table()
1665 // if the config table doesn't exist yet, create it
1666 if(!$this->cfg_db->db_check_table_exists("images")) {
1667 $this->cfg_db->db_exec("
1668 CREATE TABLE images (
1669 img_idx int primary key,
1675 } // check_config_table
1678 * Generates a thumbnail from photo idx
1680 * This function will generate JPEG thumbnails from provided F-Spot photo
1683 * 1. Check if all thumbnail generations (width) are already in place and
1685 * 2. Check if the md5sum of the original file has changed
1686 * 3. Generate the thumbnails if needed
1687 * @param integer $idx
1688 * @param integer $force
1689 * @param boolean $overwrite
1691 public function gen_thumb($idx = 0, $force = 0, $overwrite = false)
1695 $resolutions = Array(
1696 $this->cfg->thumb_width,
1697 $this->cfg->photo_width,
1698 $this->cfg->mini_width,
1702 /* get details from F-Spot's database */
1703 $details = $this->get_photo_details($idx);
1705 /* calculate file MD5 sum */
1706 $full_path = $this->translate_path($this->parse_uri($details['uri'], 'fullpath'));
1708 if(!file_exists($full_path)) {
1709 $this->_error("File ". $full_path ." does not exist\n");
1713 if(!is_readable($full_path)) {
1714 $this->_error("File ". $full_path ." is not readable for ". $this->getuid() ."\n");
1718 $this->_debug("Image [". $idx ."] ". $this->shrink_text($this->parse_uri($details['uri'], 'filename'), 20) ." Thumbnails:");
1720 /* If Nikon NEF format, we need to treat it another way */
1721 if(isset($this->cfg->dcraw_bin) &&
1722 file_exists($this->cfg->dcraw_bin) &&
1723 is_executable($this->cfg->dcraw_bin) &&
1724 preg_match('/\.nef$/i', $details['uri'])) {
1726 $ppm_path = preg_replace('/\.nef$/i', '.ppm', $full_path);
1728 /* if PPM file does not exist, let dcraw convert it from NEF */
1729 if(!file_exists($ppm_path)) {
1730 system($this->cfg->dcraw_bin ." -a ". $full_path);
1733 /* for now we handle the PPM instead of the NEF */
1734 $full_path = $ppm_path;
1738 $file_md5 = md5_file($full_path);
1741 foreach($resolutions as $resolution) {
1743 $generate_it = false;
1745 $thumb_sub_path = substr($file_md5, 0, 2);
1746 $thumb_path = $this->cfg->thumb_path ."/". $thumb_sub_path ."/". $resolution ."_". $file_md5;
1748 /* if thumbnail-subdirectory does not exist yet, create it */
1749 if(!file_exists(dirname($thumb_path))) {
1750 mkdir(dirname($thumb_path), 0755);
1753 /* if the thumbnail file doesn't exist, create it */
1754 if(!file_exists($thumb_path)) {
1755 $generate_it = true;
1757 /* if the file hasn't changed there is no need to regen the thumb */
1758 elseif($file_md5 != $this->getMD5($idx) || $force) {
1759 $generate_it = true;
1762 if($generate_it || $overwrite) {
1764 $this->_debug(" ". $resolution ."px");
1765 if(!$this->create_thumbnail($full_path, $thumb_path, $resolution))
1773 $this->_debug(" already exist");
1776 /* set the new/changed MD5 sum for the current photo */
1778 $this->setMD5($idx, $file_md5);
1781 $this->_debug("\n");
1786 * returns stored md5 sum for a specific photo
1788 * this function queries the phpfspot database for a
1789 * stored MD5 checksum of the specified photo
1790 * @param integer $idx
1791 * @return string|null
1793 public function getMD5($idx)
1795 $result = $this->cfg_db->db_query("
1798 WHERE img_idx='". $idx ."'
1804 $img = $this->cfg_db->db_fetch_object($result);
1805 return $img['img_md5'];
1810 * set MD5 sum for the specific photo
1811 * @param integer $idx
1812 * @param string $md5
1814 private function setMD5($idx, $md5)
1816 $result = $this->cfg_db->db_exec("
1817 REPLACE INTO images (img_idx, img_md5)
1818 VALUES ('". $idx ."', '". $md5 ."')
1824 * store current tag condition
1826 * this function stores the current tag condition
1827 * (AND or OR) in the users session variables
1828 * @param string $mode
1831 public function setTagCondition($mode)
1833 $_SESSION['tag_condition'] = $mode;
1837 } // setTagCondition()
1840 * invoke tag & date search
1842 * this function will return all matching tags and store
1843 * them in the session variable selected_tags. furthermore
1844 * it also handles the date search.
1845 * getPhotoSelection() will then only return the matching
1849 public function startSearch()
1851 if(isset($_POST['from']) && $this->isValidDate($_POST['from'])) {
1852 $from = $_POST['from'];
1854 if(isset($_POST['to']) && $this->isValidDate($_POST['to'])) {
1858 if(isset($_POST['for_tag']) && is_string($_POST['for_tag'])) {
1859 $searchfor_tag = $_POST['for_tag'];
1860 $_SESSION['searchfor_tag'] = $_POST['for_tag'];
1863 if(isset($_POST['for_name']) && is_string($_POST['for_name'])) {
1864 $searchfor_name = $_POST['for_name'];
1865 $_SESSION['searchfor_name'] = $_POST['for_name'];
1870 if(isset($from) && !empty($from))
1871 $_SESSION['from_date'] = strtotime($from ." 00:00:00");
1873 unset($_SESSION['from_date']);
1875 if(isset($to) && !empty($to))
1876 $_SESSION['to_date'] = strtotime($to ." 23:59:59");
1878 unset($_SESSION['to_date']);
1880 if(isset($searchfor_tag) && !empty($searchfor_tag)) {
1881 /* new search, reset the current selected tags */
1882 $_SESSION['selected_tags'] = Array();
1883 foreach($this->avail_tags as $tag) {
1884 if(preg_match('/'. $searchfor_tag .'/i', $this->tags[$tag]))
1885 array_push($_SESSION['selected_tags'], $tag);
1894 * updates sort order in session variable
1896 * this function is invoked by RPC and will sort the requested
1897 * sort order in the session variable.
1898 * @param string $sort_order
1901 public function updateSortOrder($order)
1903 if(isset($this->sort_orders[$order])) {
1904 $_SESSION['sort_order'] = $order;
1908 return "unkown error";
1910 } // updateSortOrder()
1915 * this function rotates the image according the
1917 * @param string $img
1918 * @param integer $degress
1921 private function rotateImage($img, $degrees)
1923 if(function_exists("imagerotate")) {
1924 $img = imagerotate($img, $degrees, 0);
1926 function imagerotate($src_img, $angle)
1928 $src_x = imagesx($src_img);
1929 $src_y = imagesy($src_img);
1930 if ($angle == 180) {
1934 elseif ($src_x <= $src_y) {
1938 elseif ($src_x >= $src_y) {
1943 $rotate=imagecreatetruecolor($dest_x,$dest_y);
1944 imagealphablending($rotate, false);
1949 for ($y = 0; $y < ($src_y); $y++) {
1950 for ($x = 0; $x < ($src_x); $x++) {
1951 $color = imagecolorat($src_img, $x, $y);
1952 imagesetpixel($rotate, $dest_x - $y - 1, $x, $color);
1958 for ($y = 0; $y < ($src_y); $y++) {
1959 for ($x = 0; $x < ($src_x); $x++) {
1960 $color = imagecolorat($src_img, $x, $y);
1961 imagesetpixel($rotate, $y, $dest_y - $x - 1, $color);
1967 for ($y = 0; $y < ($src_y); $y++) {
1968 for ($x = 0; $x < ($src_x); $x++) {
1969 $color = imagecolorat($src_img, $x, $y);
1970 imagesetpixel($rotate, $dest_x - $x - 1, $dest_y - $y - 1, $color);
1984 $img = imagerotate($img, $degrees);
1993 * returns flipped image
1995 * this function will return an either horizontal or
1996 * vertical flipped truecolor image.
1997 * @param string $image
1998 * @param string $mode
2001 private function flipImage($image, $mode)
2003 $w = imagesx($image);
2004 $h = imagesy($image);
2005 $flipped = imagecreatetruecolor($w, $h);
2009 for ($y = 0; $y < $h; $y++) {
2010 imagecopy($flipped, $image, 0, $y, 0, $h - $y - 1, $w, 1);
2014 for ($x = 0; $x < $w; $x++) {
2015 imagecopy($flipped, $image, $x, 0, $w - $x - 1, 0, 1, $h);
2025 * return all assigned tags for the specified photo
2026 * @param integer $idx
2029 private function get_photo_tags($idx)
2031 $result = $this->db->db_query("
2034 INNER JOIN photo_tags pt
2036 WHERE pt.photo_id='". $idx ."'
2041 while($row = $this->db->db_fetch_object($result)) {
2042 if(isset($this->cfg->hide_tags) && in_array($row['name'], $this->cfg->hide_tags))
2044 $tags[$row['id']] = $row['name'];
2049 } // get_photo_tags()
2052 * create on-the-fly images with text within
2053 * @param string $txt
2054 * @param string $color
2055 * @param integer $space
2056 * @param integer $font
2059 public function showTextImage($txt, $color=000000, $space=4, $font=4, $w=300)
2061 if (strlen($color) != 6)
2064 $int = hexdec($color);
2065 $h = imagefontheight($font);
2066 $fw = imagefontwidth($font);
2067 $txt = explode("\n", wordwrap($txt, ($w / $fw), "\n"));
2068 $lines = count($txt);
2069 $im = imagecreate($w, (($h * $lines) + ($lines * $space)));
2070 $bg = imagecolorallocate($im, 255, 255, 255);
2071 $color = imagecolorallocate($im, 0xFF & ($int >> 0x10), 0xFF & ($int >> 0x8), 0xFF & $int);
2074 foreach ($txt as $text) {
2075 $x = (($w - ($fw * strlen($text))) / 2);
2076 imagestring($im, $font, $x, $y, $text, $color);
2077 $y += ($h + $space);
2080 Header("Content-type: image/png");
2083 } // showTextImage()
2086 * check if all requirements are met
2089 private function check_requirements()
2091 if(!function_exists("imagecreatefromjpeg")) {
2092 print "PHP GD library extension is missing<br />\n";
2096 if($this->cfg->db_access == "native" && !function_exists("sqlite3_open")) {
2097 print "PHP SQLite3 library extension is missing<br />\n";
2101 /* Check for HTML_AJAX PEAR package, lent from Horde project */
2102 ini_set('track_errors', 1);
2103 @include_once 'HTML/AJAX/Server.php';
2104 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
2105 print "PEAR HTML_AJAX package is missing<br />\n";
2108 @include_once 'Calendar/Calendar.php';
2109 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
2110 print "PEAR Calendar package is missing<br />\n";
2113 @include_once 'Console/Getopt.php';
2114 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
2115 print "PEAR Console_Getopt package is missing<br />\n";
2118 @include_once $this->cfg->smarty_path .'/libs/Smarty.class.php';
2119 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
2120 print "Smarty template engine can not be found in ". $this->cfg->smarty_path ."/libs/Smarty.class.php<br />\n";
2123 ini_restore('track_errors');
2130 } // check_requirements()
2132 private function _debug($text)
2134 if($this->fromcmd) {
2141 * check if specified MIME type is supported
2142 * @param string $mime
2145 public function checkifImageSupported($mime)
2147 $supported_types = Array(
2150 "image/x-portable-pixmap",
2154 if(in_array($mime, $supported_types))
2159 } // checkifImageSupported()
2163 * @param string $text
2165 public function _error($text)
2167 switch($this->cfg->logging) {
2170 print "<img src=\"resources/green_info.png\" alt=\"warning\" />\n";
2171 print $text ."<br />\n";
2177 error_log($text, 3, $his->cfg->log_file);
2181 $this->runtime_error = true;
2186 * output calendard input fields
2187 * @param string $mode
2190 private function get_calendar($mode)
2192 $year = isset($_SESSION[$mode .'_date']) ? date("Y", $_SESSION[$mode .'_date']) : date("Y");
2193 $month = isset($_SESSION[$mode .'_date']) ? date("m", $_SESSION[$mode .'_date']) : date("m");
2194 $day = isset($_SESSION[$mode .'_date']) ? date("d", $_SESSION[$mode .'_date']) : date("d");
2196 $output = "<input type=\"text\" size=\"3\" id=\"". $mode ."year\" value=\"". $year ."\"";
2197 if(!isset($_SESSION[$mode .'_date']))
2198 $output.= " disabled=\"disabled\"";
2200 $output.= "<input type=\"text\" size=\"1\" id=\"". $mode ."month\" value=\"". $month ."\"";
2201 if(!isset($_SESSION[$mode .'_date']))
2202 $output.= " disabled=\"disabled\"";
2204 $output.= "<input type=\"text\" size=\"1\" id=\"". $mode ."day\" value=\"". $day ."\"";
2205 if(!isset($_SESSION[$mode .'_date']))
2206 $output.= " disabled=\"disabled\"";
2214 * output calendar matrix
2215 * @param integer $year
2216 * @param integer $month
2217 * @param integer $day
2219 public function get_calendar_matrix($year = 0, $month = 0, $day = 0)
2221 if (!isset($year)) $year = date('Y');
2222 if (!isset($month)) $month = date('m');
2223 if (!isset($day)) $day = date('d');
2228 require_once CALENDAR_ROOT.'Month/Weekdays.php';
2229 require_once CALENDAR_ROOT.'Day.php';
2232 $month = new Calendar_Month_Weekdays($year,$month);
2235 $prevStamp = $month->prevMonth(true);
2236 $prev = "javascript:setMonth(". date('Y',$prevStamp) .", ". date('n',$prevStamp) .", ". date('j',$prevStamp) .");";
2237 $nextStamp = $month->nextMonth(true);
2238 $next = "javascript:setMonth(". date('Y',$nextStamp) .", ". date('n',$nextStamp) .", ". date('j',$nextStamp) .");";
2240 $selectedDays = array (
2241 new Calendar_Day($year,$month,$day),
2242 new Calendar_Day($year,12,25),
2245 // Build the days in the month
2246 $month->build($selectedDays);
2248 $this->tmpl->assign('current_month', date('F Y',$month->getTimeStamp()));
2249 $this->tmpl->assign('prev_month', $prev);
2250 $this->tmpl->assign('next_month', $next);
2252 while ( $day = $month->fetch() ) {
2254 if(!isset($matrix[$rows]))
2255 $matrix[$rows] = Array();
2259 $dayStamp = $day->thisDay(true);
2260 $link = "javascript:setCalendarDate(". date('Y',$dayStamp) .", ". date('n',$dayStamp).", ". date('j',$dayStamp) .");";
2262 // isFirst() to find start of week
2263 if ( $day->isFirst() )
2266 if ( $day->isSelected() ) {
2267 $string.= "<td class=\"selected\">".$day->thisDay()."</td>\n";
2268 } else if ( $day->isEmpty() ) {
2269 $string.= "<td> </td>\n";
2271 $string.= "<td><a class=\"calendar\" href=\"".$link."\">".$day->thisDay()."</a></td>\n";
2274 // isLast() to find end of week
2275 if ( $day->isLast() )
2276 $string.= "</tr>\n";
2278 $matrix[$rows][$cols] = $string;
2288 $this->tmpl->assign('matrix', $matrix);
2289 $this->tmpl->assign('rows', $rows);
2290 $this->tmpl->show("calendar.tpl");
2292 } // get_calendar_matrix()
2295 * output export page
2296 * @param string $mode
2298 public function getExport($mode)
2300 $pictures = $this->getPhotoSelection();
2301 $current_tags = $this->getCurrentTags();
2303 foreach($pictures as $picture) {
2305 $orig_url = $this->get_phpfspot_url() ."/index.php?mode=showp&id=". $picture;
2306 if($current_tags != "") {
2307 $orig_url.= "&tags=". $current_tags;
2309 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
2310 $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
2313 if($this->is_user_friendly_url()) {
2314 $thumb_url = $this->get_phpfspot_url() ."/photo/". $picture ."/". $this->cfg->thumb_width;
2317 $thumb_url = $this->get_phpfspot_url() ."/phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
2323 // <a href="%pictureurl%"><img src="%thumbnailurl%" ></a>
2324 print htmlspecialchars("<a href=\"". $orig_url ."\"><img src=\"". $thumb_url ."\" /></a>") ."<br />\n";
2328 // "[%pictureurl% %thumbnailurl%]"
2329 print htmlspecialchars("[".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
2332 case 'MoinMoinList':
2333 // " * [%pictureurl% %thumbnailurl%]"
2334 print " " . htmlspecialchars("* [".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
2345 public function getRSSFeed()
2347 Header("Content-type: text/xml; charset=utf-8");
2348 print "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
2351 xmlns:media="http://search.yahoo.com/mrss/"
2352 xmlns:dc="http://purl.org/dc/elements/1.1/"
2355 <title>phpfspot</title>
2356 <description>phpfspot RSS feed</description>
2357 <link><?php print htmlspecialchars($this->get_phpfspot_url()); ?></link>
2358 <pubDate><?php print strftime("%a, %d %b %Y %T %z"); ?></pubDate>
2359 <generator>phpfspot</generator>
2362 $pictures = $this->getPhotoSelection();
2363 $current_tags = $this->getCurrentTags();
2365 foreach($pictures as $picture) {
2367 $orig_url = $this->get_phpfspot_url() ."/index.php?mode=showp&id=". $picture;
2368 if($current_tags != "") {
2369 $orig_url.= "&tags=". $current_tags;
2371 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
2372 $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
2375 $details = $this->get_photo_details($picture);
2377 if($this->is_user_friendly_url()) {
2378 $thumb_url = $this->get_phpfspot_url() ."/photo/". $picture ."/". $this->cfg->thumb_width;
2381 $thumb_url = $this->get_phpfspot_url() ."/phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
2384 $thumb_html = htmlspecialchars("
2385 <a href=\"". $orig_url ."\"><img src=\"". $thumb_url ."\" /></a>
2387 ". $details['description']);
2389 $orig_path = $this->translate_path($this->parse_uri($details['uri'], 'fullpath'));
2391 /* get EXIF information if JPEG */
2392 if($details['mime'] == "image/jpeg") {
2393 $meta = $this->get_meta_informations($orig_path);
2396 $meta_date = isset($meta['FileDateTime']) ? $meta['FileDateTime'] : filemtime($orig_path);
2400 <title><?php print htmlspecialchars($this->parse_uri($details['uri'], 'filename')); ?></title>
2401 <link><?php print htmlspecialchars($orig_url); ?></link>
2402 <guid><?php print htmlspecialchars($orig_url); ?></guid>
2403 <dc:date.Taken><?php print strftime("%Y-%m-%dT%H:%M:%S+00:00", $meta_date); ?></dc:date.Taken>
2405 <?php print $thumb_html; ?>
2407 <pubDate><?php print strftime("%a, %d %b %Y %T %z", $meta_date); ?></pubDate>
2422 * return all selected tags as one string
2425 private function getCurrentTags()
2428 if(isset($_SESSION['selected_tags']) && $_SESSION['selected_tags'] != "") {
2429 foreach($_SESSION['selected_tags'] as $tag)
2430 $current_tags.= $tag .",";
2431 $current_tags = substr($current_tags, 0, strlen($current_tags)-1);
2433 return $current_tags;
2435 } // getCurrentTags()
2438 * return the current photo
2440 public function getCurrentPhoto()
2442 if(isset($_SESSION['current_photo'])) {
2443 print $_SESSION['current_photo'];
2445 } // getCurrentPhoto()
2448 * tells the client browser what to do
2450 * this function is getting called via AJAX by the
2451 * client browsers. it will tell them what they have
2452 * to do next. This is necessary for directly jumping
2453 * into photo index or single photo view when the are
2454 * requested with specific URLs
2457 public function whatToDo()
2459 if(isset($_SESSION['current_photo']) && $_SESSION['start_action'] == 'showp') {
2461 elseif(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
2462 return "showpi_tags";
2464 elseif(isset($_SESSION['start_action']) && $_SESSION['start_action'] == 'showpi') {
2471 * return the current process-user
2474 private function getuid()
2476 if($uid = posix_getuid()) {
2477 if($user = posix_getpwuid($uid)) {
2478 return $user['name'];
2487 * returns a select-dropdown box to select photo index sort parameters
2488 * @param array $params
2489 * @param smarty $smarty
2492 public function smarty_sort_select_list($params, &$smarty)
2496 foreach($this->sort_orders as $key => $value) {
2497 $output.= "<option value=\"". $key ."\"";
2498 if($key == $_SESSION['sort_order']) {
2499 $output.= " selected=\"selected\"";
2501 $output.= ">". $value ."</option>";
2506 } // smarty_sort_select_list()
2509 * returns the currently selected sort order
2512 private function get_sort_order()
2514 switch($_SESSION['sort_order']) {
2516 return " ORDER BY p.time ASC";
2519 return " ORDER BY p.time DESC";
2522 if($this->dbver < 9) {
2523 return " ORDER BY p.name ASC";
2526 return " ORDER BY basename(p.uri) ASC";
2530 if($this->dbver < 9) {
2531 return " ORDER BY p.name DESC";
2534 return " ORDER BY basename(p.uri) DESC";
2538 return " ORDER BY t.name ASC ,p.time ASC";
2541 return " ORDER BY t.name DESC ,p.time ASC";
2545 } // get_sort_order()
2548 * return the next to be shown slide show image
2550 * this function returns the URL of the next image
2551 * in the slideshow sequence.
2554 public function getNextSlideShowImage()
2556 $all_photos = $this->getPhotoSelection();
2558 if(!isset($_SESSION['slideshow_img']) || $_SESSION['slideshow_img'] == count($all_photos)-1)
2559 $_SESSION['slideshow_img'] = 0;
2561 $_SESSION['slideshow_img']++;
2563 if($this->is_user_friendly_url()) {
2564 return $this->get_phpfspot_url() ."/photo/". $all_photos[$_SESSION['slideshow_img']] ."/". $this->cfg->photo_width;
2567 return $this->get_phpfspot_url() ."/phpfspot_img.php?idx=". $all_photos[$_SESSION['slideshow_img']] ."&width=". $this->cfg->photo_width;
2569 } // getNextSlideShowImage()
2572 * return the previous to be shown slide show image
2574 * this function returns the URL of the previous image
2575 * in the slideshow sequence.
2578 public function getPrevSlideShowImage()
2580 $all_photos = $this->getPhotoSelection();
2582 if(!isset($_SESSION['slideshow_img']) || $_SESSION['slideshow_img'] == 0)
2583 $_SESSION['slideshow_img'] = 0;
2585 $_SESSION['slideshow_img']--;
2587 if($this->is_user_friendly_url()) {
2588 return $this->get_phpfspot_url() ."/photo/". $all_photos[$_SESSION['slideshow_img']] ."/". $this->cfg->photo_width;
2591 return $this->get_phpfspot_url() ."/phpfspot_img.php?idx=". $all_photos[$_SESSION['slideshow_img']] ."&width=". $this->cfg->photo_width;
2593 } // getPrevSlideShowImage()
2595 public function resetSlideShow()
2597 if(isset($_SESSION['slideshow_img']))
2598 unset($_SESSION['slideshow_img']);
2600 } // resetSlideShow()
2605 * this function will get all photos from the fspot
2606 * database and randomly return ONE entry
2608 * saddly there is yet no sqlite3 function which returns
2609 * the bulk result in array, so we have to fill up our
2613 public function get_random_photo()
2622 /* if show_tags is set, only return details for photos which
2623 are specified to be shown
2625 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
2627 INNER JOIN photo_tags pt
2632 t.name IN ('".implode("','",$this->cfg->show_tags)."')";
2635 $result = $this->db->db_query($query_str);
2637 while($row = $this->db->db_fetch_object($result)) {
2638 array_push($all, $row['id']);
2641 return $all[array_rand($all)];
2643 } // get_random_photo()
2646 * get random photo tag photo
2648 * this function will get all photos tagged with the requested
2649 * tag from the fspot database and randomly return ONE entry
2651 * saddly there is yet no sqlite3 function which returns
2652 * the bulk result in array, so we have to fill up our
2656 public function get_random_tag_photo($tagidx)
2663 INNER JOIN photo_tags pt
2667 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
2675 pt.tag_id LIKE '". $tagidx ."'
2678 /*if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
2681 t.name IN ('".implode("','",$this->cfg->show_tags)."')
2685 $result = $this->db->db_query($query_str);
2687 while($row = $this->db->db_fetch_object($result)) {
2688 array_push($all, $row['id']);
2691 return $all[array_rand($all)];
2693 } // get_random_tag_photo()
2696 * validates provided date
2698 * this function validates if the provided date
2699 * contains a valid date and will return true
2701 * @param string $date_str
2704 public function isValidDate($date_str)
2706 $timestamp = strtotime($date_str);
2708 if(is_numeric($timestamp))
2716 * timestamp to string conversion
2717 * @param integer $timestamp
2720 private function ts2str($timestamp)
2722 if(!empty($timestamp) && is_numeric($timestamp))
2723 return strftime("%Y-%m-%d", $timestamp);
2728 * extract tag-names from $_GET['tags']
2729 * @param string $tags_str
2732 private function extractTags($tags_str)
2734 $not_validated = split(',', $tags_str);
2735 $validated = array();
2737 foreach($not_validated as $tag) {
2738 if(is_numeric($tag))
2739 array_push($validated, $tag);
2747 * returns the full path to a thumbnail
2748 * @param integer $width
2749 * @param integer $photo
2752 public function get_thumb_path($width, $photo)
2754 $md5 = $this->getMD5($photo);
2755 $sub_path = substr($md5, 0, 2);
2756 return $this->cfg->thumb_path
2764 } // get_thumb_path()
2767 * returns server's virtual host name
2770 private function get_server_name()
2772 return $_SERVER['SERVER_NAME'];
2773 } // get_server_name()
2776 * returns type of webprotocol which is currently used
2779 private function get_web_protocol()
2781 if(!isset($_SERVER['HTTPS']))
2785 } // get_web_protocol()
2788 * return url to this phpfspot installation
2791 private function get_phpfspot_url()
2793 return $this->get_web_protocol() ."://". $this->get_server_name() . $this->cfg->web_path;
2795 } // get_phpfspot_url()
2798 * returns the number of photos which are tagged with $tag_id
2799 * @param integer $tag_id
2802 public function get_num_photos($tag_id)
2804 if($result = $this->db->db_fetchSingleRow("
2805 SELECT count(*) as number
2808 tag_id LIKE '". $tag_id ."'")) {
2810 return $result['number'];
2816 } // get_num_photos()
2819 * check file exists and is readable
2821 * returns true, if everything is ok, otherwise false
2822 * if $silent is not set, this function will output and
2824 * @param string $file
2825 * @param boolean $silent
2828 private function check_readable($file, $silent = null)
2830 if(!file_exists($file)) {
2832 print "File \"". $file ."\" does not exist.\n";
2836 if(!is_readable($file)) {
2838 print "File \"". $file ."\" is not reachable for user ". $this->getuid() ."\n";
2844 } // check_readable()
2847 * check if all needed indices are present
2849 * this function checks, if some needed indices are already
2850 * present, or if not, create them on the fly. they are
2851 * necessary to speed up some queries like that one look for
2852 * all tags, when show_tags is specified in the configuration.
2854 private function checkDbIndices()
2856 $result = $this->db->db_exec("
2857 CREATE INDEX IF NOT EXISTS
2864 } // checkDbIndices()
2867 * retrive F-Spot database version
2869 * this function will return the F-Spot database version number
2870 * It is stored within the sqlite3 database in the table meta
2871 * @return string|null
2873 public function getFspotDBVersion()
2875 if($result = $this->db->db_fetchSingleRow("
2876 SELECT data as version
2879 name LIKE 'F-Spot Database Version'
2881 return $result['version'];
2885 } // getFspotDBVersion()
2888 * parse the provided URI and will returned the requested chunk
2889 * @param string $uri
2890 * @param string $mode
2893 public function parse_uri($uri, $mode)
2895 if(($components = parse_url($uri)) !== false) {
2899 return basename($components['path']);
2902 return dirname($components['path']);
2905 return $components['path'];
2915 * validate config options
2917 * this function checks if all necessary configuration options are
2918 * specified and set.
2921 private function check_config_options()
2923 if(!isset($this->cfg->page_title) || $this->cfg->page_title == "")
2924 $this->_error("Please set \$page_title in phpfspot_cfg");
2926 if(!isset($this->cfg->base_path) || $this->cfg->base_path == "")
2927 $this->_error("Please set \$base_path in phpfspot_cfg");
2929 if(!isset($this->cfg->web_path) || $this->cfg->web_path == "")
2930 $this->_error("Please set \$web_path in phpfspot_cfg");
2932 if(!isset($this->cfg->thumb_path) || $this->cfg->thumb_path == "")
2933 $this->_error("Please set \$thumb_path in phpfspot_cfg");
2935 if(!isset($this->cfg->smarty_path) || $this->cfg->smarty_path == "")
2936 $this->_error("Please set \$smarty_path in phpfspot_cfg");
2938 if(!isset($this->cfg->fspot_db) || $this->cfg->fspot_db == "")
2939 $this->_error("Please set \$fspot_db in phpfspot_cfg");
2941 if(!isset($this->cfg->db_access) || $this->cfg->db_access == "")
2942 $this->_error("Please set \$db_access in phpfspot_cfg");
2944 if(!isset($this->cfg->phpfspot_db) || $this->cfg->phpfspot_db == "")
2945 $this->_error("Please set \$phpfspot_db in phpfspot_cfg");
2947 if(!isset($this->cfg->thumb_width) || $this->cfg->thumb_width == "")
2948 $this->_error("Please set \$thumb_width in phpfspot_cfg");
2950 if(!isset($this->cfg->thumb_height) || $this->cfg->thumb_height == "")
2951 $this->_error("Please set \$thumb_height in phpfspot_cfg");
2953 if(!isset($this->cfg->photo_width) || $this->cfg->photo_width == "")
2954 $this->_error("Please set \$photo_width in phpfspot_cfg");
2956 if(!isset($this->cfg->mini_width) || $this->cfg->mini_width == "")
2957 $this->_error("Please set \$mini_width in phpfspot_cfg");
2959 if(!isset($this->cfg->thumbs_per_page))
2960 $this->_error("Please set \$thumbs_per_page in phpfspot_cfg");
2962 if(!isset($this->cfg->path_replace_from) || $this->cfg->path_replace_from == "")
2963 $this->_error("Please set \$path_replace_from in phpfspot_cfg");
2965 if(!isset($this->cfg->path_replace_to) || $this->cfg->path_replace_to == "")
2966 $this->_error("Please set \$path_replace_to in phpfspot_cfg");
2968 if(!isset($this->cfg->hide_tags))
2969 $this->_error("Please set \$hide_tags in phpfspot_cfg");
2971 if(!isset($this->cfg->theme_name))
2972 $this->_error("Please set \$theme_name in phpfspot_cfg");
2974 if(!isset($this->cfg->logging))
2975 $this->_error("Please set \$logging in phpfspot_cfg");
2977 if(isset($this->cfg->logging) && $this->cfg->logging == 'logfile') {
2979 if(!isset($this->cfg->log_file))
2980 $this->_error("Please set \$log_file because you set logging = log_file in phpfspot_cfg");
2982 if(!is_writeable($this->cfg->log_file))
2983 $this->_error("The specified \$log_file ". $log_file ." is not writeable!");
2987 /* remove trailing slash, if set */
2988 if($this->cfg->web_path == "/")
2989 $this->cfg->web_path = "";
2990 elseif(preg_match('/\/$/', $this->cfg->web_path))
2991 $this->cfg->web_path = preg_replace('/\/$/', '', $this->cfg->web_path);
2993 return $this->runtime_error;
2995 } // check_config_options()
2998 * cleanup phpfspot own database
3000 * When photos are getting delete from F-Spot, there will remain
3001 * remain some residues in phpfspot own database. This function
3002 * will try to wipe them out.
3004 public function cleanup_phpfspot_db()
3006 $to_delete = Array();
3008 $result = $this->cfg_db->db_query("
3011 ORDER BY img_idx ASC
3014 while($row = $this->cfg_db->db_fetch_object($result)) {
3015 if(!$this->db->db_fetchSingleRow("
3018 WHERE id='". $row['img_idx'] ."'")) {
3020 array_push($to_delete, $row['img_idx'], ',');
3024 print count($to_delete) ." unnecessary objects will be removed from phpfspot's database.\n";
3026 $this->cfg_db->db_exec("
3028 WHERE img_idx IN (". implode($to_delete) .")
3031 } // cleanup_phpfspot_db()
3034 * return first image of the page, the $current photo
3037 * this function is used to find out the first photo of the
3038 * current page, in which the $current photo lies. this is
3039 * used to display the correct photo, when calling showPhotoIndex()
3041 * @param integer $current
3042 * @param integer $max
3045 private function getCurrentPage($current, $max)
3047 if(isset($this->cfg->thumbs_per_page) && !empty($this->cfg->thumbs_per_page)) {
3048 for($page_start = 0; $page_start <= $max; $page_start+=$this->cfg->thumbs_per_page) {
3049 if($current >= $page_start && $current < ($page_start+$this->cfg->thumbs_per_page))
3055 } // getCurrentPage()
3060 * this function tries to find out the correct mime-type
3061 * for the provided file.
3062 * @param string $file
3065 public function get_mime_info($file)
3067 $details = getimagesize($file);
3069 /* if getimagesize() returns empty, try at least to find out the
3072 if(empty($details) && function_exists('mime_content_type')) {
3074 // mime_content_type is marked as deprecated in the documentation,
3075 // but is it really necessary to force users to install a PECL
3077 $details['mime'] = mime_content_type($file);
3080 return $details['mime'];
3082 } // get_mime_info()
3085 * return tag-name by tag-idx
3087 * this function returns the tag-name for the requested
3088 * tag specified by tag-idx.
3089 * @param integer $idx
3092 public function get_tag_name($idx)
3094 if($result = $this->db->db_fetchSingleRow("
3098 id LIKE '". $idx ."'")) {
3100 return $result['name'];
3109 * parse user friendly url which got rewritten by the websever
3110 * @param string $request_uri
3113 private function parse_user_friendly_url($request_uri)
3115 if(preg_match('/\/photoview\/|\/photo\/|\/tag\//', $request_uri)) {
3117 unset($_SESSION['start_action']);
3118 unset($_SESSION['selected_tags']);
3120 $options = explode('/', $request_uri);
3122 switch($options[1]) {
3124 if(is_numeric($options[2])) {
3125 $_GET['mode'] = 'showp';
3126 return $this->showPhoto($options[2]);
3130 if(is_numeric($options[2])) {
3131 require_once "phpfspot_img.php";
3132 $img = new PHPFSPOT_IMG;
3133 if(isset($options[3]) && is_numeric($options[3]))
3134 $img->showImg($options[2], $options[3]);
3136 $img->showImg($options[2]);
3141 if(is_numeric($options[2])) {
3142 $this->session_cleanup();
3143 $_GET['tags'] = $options[2];
3144 $_SESSION['selected_tags'] = Array($options[2]);
3145 if(isset($options[3]) && is_numeric($options[3]))
3146 $_SESSION['begin_with'] = $options[3];
3147 return $this->showPhotoIndex();
3153 } // parse_user_friendly_url()
3156 * check if user-friendly-urls are enabled
3158 * this function will return true, if the config option
3159 * $user_friendly_url has been set. Otherwise false.
3162 private function is_user_friendly_url()
3164 if(isset($this->cfg->user_friendly_url) && $this->cfg->user_friendly_url)
3169 } // is_user_friendly_url()
3174 * this function will cleanup user's session information
3176 private function session_cleanup()
3178 unset($_SESSION['begin_with']);
3179 $this->resetDateSearch();
3180 $this->resetPhotoView();
3181 $this->resetTagSearch();
3182 $this->resetNameSearch();
3183 $this->resetDateSearch();
3185 } // session_cleanup()