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']);
226 // if user-friendly-url's are enabled, set also a flag for the template handler
227 if($this->is_user_friendly_url()) {
228 $this->tmpl->assign('user_friendly_url', 'true');
233 public function __destruct()
239 * show - generate html output
241 * this function can be called after the constructor has
242 * prepared everyhing. it will load the index.tpl smarty
243 * template. if necessary it will registere pre-selects
244 * (photo index, photo, tag search, date search) into
247 public function show()
249 $this->tmpl->assign('searchfor_tag', $_SESSION['searchfor_tag']);
250 $this->tmpl->assign('page_title', $this->cfg->page_title);
251 $this->tmpl->assign('current_condition', $_SESSION['tag_condition']);
252 $this->tmpl->assign('template_path', 'themes/'. $this->cfg->theme_name);
255 if($this->is_user_friendly_url()) {
256 $content = $this->parse_user_friendly_url($_SERVER['REQUEST_URI']);
259 if(isset($_GET['mode'])) {
261 $_SESSION['start_action'] = $_GET['mode'];
263 switch($_GET['mode']) {
265 if(isset($_GET['tags'])) {
266 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
268 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
269 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
271 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
272 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
276 if(isset($_GET['tags'])) {
277 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
278 $_SESSION['start_action'] = 'showp';
280 if(isset($_GET['id']) && is_numeric($_GET['id'])) {
281 $_SESSION['current_photo'] = $_GET['id'];
282 $_SESSION['start_action'] = 'showp';
284 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
285 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
287 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
288 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
292 $this->tmpl->show("export.tpl");
296 $this->tmpl->show("slideshow.tpl");
300 if(isset($_GET['tags'])) {
301 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
303 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
304 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
306 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
307 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
315 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date']))
316 $this->tmpl->assign('date_search_enabled', true);
318 $this->tmpl->register_function("sort_select_list", array(&$this, "smarty_sort_select_list"), false);
319 $this->tmpl->assign('search_from_date', $this->get_calendar('from'));
320 $this->tmpl->assign('search_to_date', $this->get_calendar('to'));
322 $this->tmpl->assign('preset_selected_tags', $this->getSelectedTags());
323 $this->tmpl->assign('preset_available_tags', $this->getAvailableTags());
325 if(!isset($content)) {
326 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags']))
327 $this->tmpl->assign('initial_content', $this->showPhotoIndex());
329 $this->tmpl->assign('initial_content', $this->tmpl->fetch('welcome.tpl'));
332 $this->tmpl->assign('initial_content', $content);
334 $this->tmpl->show("index.tpl");
339 * get_tags - grab all tags of f-spot's database
341 * this function will get all available tags from
342 * the f-spot database and store them within two
343 * arrays within this class for later usage. in
344 * fact, if the user requests (hide_tags) it will
345 * opt-out some of them.
347 * this function is getting called once by show()
349 private function get_tags()
351 $this->avail_tags = Array();
354 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
357 DISTINCT t1.id as id, t1.name as name
360 INNER JOIN photo_tags
361 pt2 ON pt1.photo_id=pt2.photo_id
367 t2.name IN ('".implode("','",$this->cfg->show_tags)."')
369 t1.sort_priority ASC";
371 $result = $this->db->db_query($query_str);
375 $result = $this->db->db_query("
378 ORDER BY sort_priority ASC
382 while($row = $this->db->db_fetch_object($result)) {
384 $tag_id = $row['id'];
385 $tag_name = $row['name'];
387 /* if the user has specified to ignore this tag in phpfspot's
388 configuration, ignore it here so it does not get added to
391 if(in_array($row['name'], $this->cfg->hide_tags))
394 /* if you include the following if-clause and the user has specified
395 to only show certain tags which are specified in phpfspot's
396 configuration, ignore all others so they will not be added to the
398 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags) &&
399 !in_array($row['name'], $this->cfg->show_tags))
403 $this->tags[$tag_id] = $tag_name;
404 $this->avail_tags[$count] = $tag_id;
412 * extract all photo details
414 * retrieve all available details from f-spot's
415 * database and return them as object
416 * @param integer $idx
417 * @return object|null
419 public function get_photo_details($idx)
421 if($this->dbver < 9) {
423 SELECT p.id, p.name, p.time, p.directory_path, p.description
429 SELECT p.id, p.uri, p.time, p.description
434 /* if show_tags is set, only return details for photos which
435 are specified to be shown
437 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
439 INNER JOIN photo_tags pt
443 WHERE p.id='". $idx ."'
444 AND t.name IN ('".implode("','",$this->cfg->show_tags)."')";
448 WHERE p.id='". $idx ."'
452 if($result = $this->db->db_query($query_str)) {
454 $row = $this->db->db_fetch_object($result);
456 if($this->dbver < 9) {
457 $row['uri'] = "file://". $row['directory_path'] ."/". $row['name'];
466 } // get_photo_details
469 * returns aligned photo names
471 * this function returns aligned (length) names for
472 * an specific photo. If the length of the name exceeds
473 * $limit the name will be shrinked (...)
474 * @param integer $idx
475 * @param integer $limit
476 * @return string|null
478 public function getPhotoName($idx, $limit = 0)
480 if($details = $this->get_photo_details($idx)) {
481 if($long_name = $this->parse_uri($details['uri'], 'filename')) {
482 $name = $this->shrink_text($long_name, $limit);
492 * shrink text according provided limit
494 * If the length of the name exceeds $limit the
495 * text will be shortend and some content in between
496 * will be replaced with "..."
498 * @param integer $limit
501 private function shrink_text($text, $limit)
503 if($limit != 0 && strlen($text) > $limit) {
504 $text = substr($text, 0, $limit-5) ."...". substr($text, -($limit-5));
512 * translate f-spoth photo path
514 * as the full-qualified path recorded in the f-spot database
515 * is usally not the same as on the webserver, this function
516 * will replace the path with that one specified in the cfg
517 * @param string $path
520 public function translate_path($path)
522 return str_replace($this->cfg->path_replace_from, $this->cfg->path_replace_to, $path);
527 * control HTML ouput for a single photo
529 * this function provides all the necessary information
530 * for the single photo template.
531 * @param integer photo
533 public function showPhoto($photo)
535 /* get all photos from the current photo selection */
536 $all_photos = $this->getPhotoSelection();
537 $count = count($all_photos);
539 for($i = 0; $i < $count; $i++) {
541 // $get_next will be set, when the photo which has to
542 // be displayed has been found - this means that the
543 // next available is in fact the NEXT image (for the
545 if(isset($get_next)) {
546 $next_img = $all_photos[$i];
550 /* the next photo is our NEXT photo */
551 if($all_photos[$i] == $photo) {
555 $previous_img = $all_photos[$i];
558 if($photo == $all_photos[$i]) {
563 $details = $this->get_photo_details($photo);
570 $orig_path = $this->translate_path($this->parse_uri($details['uri'], 'fullpath'));
571 $thumb_path = $this->get_thumb_path($this->cfg->photo_width, $photo);
573 if(!file_exists($orig_path)) {
574 $this->_error("Photo ". $orig_path ." does not exist!<br />\n");
578 if(!is_readable($orig_path)) {
579 $this->_error("Photo ". $orig_path ." is not readable for user ". $this->getuid() ."<br />\n");
583 /* If the thumbnail doesn't exist yet, try to create it */
584 if(!file_exists($thumb_path)) {
585 $this->gen_thumb($photo, true);
586 $thumb_path = $this->get_thumb_path($this->cfg->photo_width, $photo);
589 /* get mime-type, height and width from the original photo */
590 $info = getimagesize($orig_path);
592 /* get EXIF information if JPEG */
593 if($info['mime'] == "image/jpeg") {
594 $meta = $this->get_meta_informations($orig_path);
597 /* If EXIF data are available, use them */
598 if(isset($meta['ExifImageWidth'])) {
599 $meta_res = $meta['ExifImageWidth'] ."x". $meta['ExifImageLength'];
601 $meta_res = $info[0] ."x". $info[1];
604 $meta_date = isset($meta['FileDateTime']) ? strftime("%a %x %X", $meta['FileDateTime']) : "n/a";
605 $meta_make = isset($meta['Make']) ? $meta['Make'] ." / ". $meta['Model'] : "n/a";
606 $meta_size = isset($meta['FileSize']) ? round($meta['FileSize']/1024, 1) ."kbyte" : "n/a";
608 $extern_link = "index.php?mode=showp&id=". $photo;
609 $current_tags = $this->getCurrentTags();
610 if($current_tags != "") {
611 $extern_link.= "&tags=". $current_tags;
613 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
614 $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
617 $this->tmpl->assign('extern_link', $extern_link);
619 if(!file_exists($thumb_path)) {
620 $this->_error("Can't open file ". $thumb_path ."\n");
624 $info_thumb = getimagesize($thumb_path);
626 $this->tmpl->assign('description', $details['description']);
627 $this->tmpl->assign('image_name', $this->parse_uri($details['uri'], 'filename'));
629 $this->tmpl->assign('width', $info_thumb[0]);
630 $this->tmpl->assign('height', $info_thumb[1]);
631 $this->tmpl->assign('ExifMadeOn', $meta_date);
632 $this->tmpl->assign('ExifMadeWith', $meta_make);
633 $this->tmpl->assign('ExifOrigResolution', $meta_res);
634 $this->tmpl->assign('ExifFileSize', $meta_size);
636 if($this->is_user_friendly_url()) {
637 $this->tmpl->assign('image_url', '/photo/'. $photo ."/". $this->cfg->photo_width);
638 $this->tmpl->assign('image_url_full', '/photo/'. $photo);
641 $this->tmpl->assign('image_url', 'phpfspot_img.php?idx='. $photo ."&width=". $this->cfg->photo_width);
642 $this->tmpl->assign('image_url_full', 'phpfspot_img.php?idx='. $photo);
645 $this->tmpl->assign('image_filename', $this->parse_uri($details['uri'], 'filename'));
647 $this->tmpl->assign('tags', $this->get_photo_tags($photo));
648 $this->tmpl->assign('current_page', $this->getCurrentPage($current, $count));
649 $this->tmpl->assign('current_img', $photo);
652 $this->tmpl->assign('previous_url', "javascript:showPhoto(". $previous_img .");");
653 $this->tmpl->assign('prev_img', $previous_img);
657 $this->tmpl->assign('next_url', "javascript:showPhoto(". $next_img .");");
658 $this->tmpl->assign('next_img', $next_img);
660 $this->tmpl->assign('mini_width', $this->cfg->mini_width);
661 $this->tmpl->assign('photo_width', $this->cfg->photo_width);
662 $this->tmpl->assign('photo_number', $i);
663 $this->tmpl->assign('photo_count', count($all_photos));
665 return $this->tmpl->fetch("single_photo.tpl");
670 * all available tags and tag cloud
672 * this function outputs all available tags (time ordered)
673 * and in addition output them as tag cloud (tags which have
674 * many photos will appears more then others)
676 public function getAvailableTags()
678 /* retrive tags from database */
683 $result = $this->db->db_query("
684 SELECT tag_id as id, count(tag_id) as quantity
694 while($row = $this->db->db_fetch_object($result)) {
695 $tags[$row['id']] = $row['quantity'];
698 // change these font sizes if you will
699 $max_size = 125; // max font size in %
700 $min_size = 75; // min font size in %
703 $max_sat = hexdec('cc');
704 $min_sat = hexdec('44');
706 // get the largest and smallest array values
707 $max_qty = max(array_values($tags));
708 $min_qty = min(array_values($tags));
710 // find the range of values
711 $spread = $max_qty - $min_qty;
712 if (0 == $spread) { // we don't want to divide by zero
716 // determine the font-size increment
717 // this is the increase per tag quantity (times used)
718 $step = ($max_size - $min_size)/($spread);
719 $step_sat = ($max_sat - $min_sat)/($spread);
721 // loop through our tag array
722 foreach ($tags as $key => $value) {
724 if(isset($_SESSION['selected_tags']) && in_array($key, $_SESSION['selected_tags']))
727 // calculate CSS font-size
728 // find the $value in excess of $min_qty
729 // multiply by the font-size increment ($size)
730 // and add the $min_size set above
731 $size = $min_size + (($value - $min_qty) * $step);
732 // uncomment if you want sizes in whole %:
735 $color = $min_sat + ($value - $min_qty) * $step_sat;
741 if(isset($this->tags[$key])) {
742 if($this->is_user_friendly_url())
743 $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>, ";
745 $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>, ";
749 $output = substr($output, 0, strlen($output)-2);
752 } // getAvailableTags()
755 * output all selected tags
757 * this function output all tags which have been selected
758 * by the user. the selected tags are stored in the
759 * session-variable $_SESSION['selected_tags']
762 public function getSelectedTags($type = 'link')
764 /* retrive tags from database */
769 foreach($this->avail_tags as $tag)
771 // return all selected tags
772 if(isset($_SESSION['selected_tags']) && in_array($tag, $_SESSION['selected_tags'])) {
777 $output.= "<a href=\"javascript:Tags('del', ". $tag .");\" class=\"tag\">". $this->tags[$tag] ."</a>, ";
781 <div class=\"tagresulttag\">
782 <a href=\"javascript:Tags('del', ". $tag .");\" title=\"". $this->tags[$tag] ."\">
783 <img src=\"". $this->cfg->web_path ."/phpfspot_img.php?tagidx=". $tag ."\" />
793 $output = substr($output, 0, strlen($output)-2);
797 return "no tags selected";
800 } // getSelectedTags()
803 * add tag to users session variable
805 * this function will add the specified to users current
806 * tag selection. if a date search has been made before
807 * it will be now cleared
810 public function addTag($tag)
812 if(!isset($_SESSION['selected_tags']))
813 $_SESSION['selected_tags'] = Array();
815 if(isset($_SESSION['searchfor_tag']))
816 unset($_SESSION['searchfor_tag']);
818 // has the user requested to hide this tag, and still someone,
819 // somehow tries to add it, don't allow this.
820 if(!isset($this->cfg->hide_tags) &&
821 in_array($this->get_tag_name($tag), $this->cfg->hide_tags))
824 if(!in_array($tag, $_SESSION['selected_tags']))
825 array_push($_SESSION['selected_tags'], $tag);
832 * remove tag to users session variable
834 * this function removes the specified tag from
835 * users current tag selection
839 public function delTag($tag)
841 if(isset($_SESSION['searchfor_tag']))
842 unset($_SESSION['searchfor_tag']);
844 if(isset($_SESSION['selected_tags'])) {
845 $key = array_search($tag, $_SESSION['selected_tags']);
846 unset($_SESSION['selected_tags'][$key]);
847 sort($_SESSION['selected_tags']);
855 * reset tag selection
857 * if there is any tag selection, it will be
860 public function resetTags()
862 if(isset($_SESSION['selected_tags']))
863 unset($_SESSION['selected_tags']);
868 * returns the value for the autocomplete tag-search
871 public function get_xml_tag_list()
873 if(!isset($_GET['search']) || !is_string($_GET['search']))
874 $_GET['search'] = '';
879 /* retrive tags from database */
882 $matched_tags = Array();
884 header("Content-Type: text/xml");
886 $string = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n";
887 $string.= "<results>\n";
889 foreach($this->avail_tags as $tag)
891 if(!empty($_GET['search']) &&
892 preg_match("/". $_GET['search'] ."/i", $this->tags[$tag]) &&
893 count($matched_tags) < $length) {
895 $count = $this->get_num_photos($tag);
898 $string.= " <rs id=\"". $i ."\" info=\"". $count ." photo\">". $this->tags[$tag] ."</rs>\n";
901 $string.= " <rs id=\"". $i ."\" info=\"". $count ." photos\">". $this->tags[$tag] ."</rs>\n";
907 /* if we have collected enough items, break out */
908 if(count($matched_tags) >= $length)
912 $string.= "</results>\n";
916 } // get_xml_tag_list()
922 * if a specific photo was requested (external link)
923 * unset the session variable now
925 public function resetPhotoView()
927 if(isset($_SESSION['current_photo']))
928 unset($_SESSION['current_photo']);
930 } // resetPhotoView();
935 * if any tag search has taken place, reset it now
937 public function resetTagSearch()
939 if(isset($_SESSION['searchfor_tag']))
940 unset($_SESSION['searchfor_tag']);
942 } // resetTagSearch()
947 * if any name search has taken place, reset it now
949 public function resetNameSearch()
951 if(isset($_SESSION['searchfor_name']))
952 unset($_SESSION['searchfor_name']);
954 } // resetNameSearch()
959 * if any date search has taken place, reset
962 public function resetDateSearch()
964 if(isset($_SESSION['from_date']))
965 unset($_SESSION['from_date']);
966 if(isset($_SESSION['to_date']))
967 unset($_SESSION['to_date']);
969 } // resetDateSearch();
972 * return all photo according selection
974 * this function returns all photos based on
975 * the tag-selection, tag- or date-search.
976 * the tag-search also has to take care of AND
977 * and OR conjunctions
980 public function getPhotoSelection()
982 $matched_photos = Array();
983 $additional_where_cond = "";
985 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
986 $from_date = $_SESSION['from_date'];
987 $to_date = $_SESSION['to_date'];
988 $additional_where_cond.= "
989 p.time>='". $from_date ."'
991 p.time<='". $to_date ."'
995 if(isset($_SESSION['searchfor_name'])) {
996 if($this->dbver < 9) {
997 $additional_where_cond.= "
999 p.name LIKE '%". $_SESSION['searchfor_name'] ."%'
1001 p.description LIKE '%". $_SESSION['searchfor_name'] ."%'
1006 $additional_where_cond.= "
1008 basename(p.uri) LIKE '%". $_SESSION['searchfor_name'] ."%'
1010 p.description LIKE '%". $_SESSION['searchfor_name'] ."%'
1016 if(isset($_SESSION['sort_order'])) {
1017 $order_str = $this->get_sort_order();
1020 /* return a search result */
1021 if(isset($_SESSION['searchfor_tag']) && $_SESSION['searchfor_tag'] != '') {
1023 SELECT DISTINCT pt1.photo_id
1025 INNER JOIN photo_tags pt2
1026 ON pt1.photo_id=pt2.photo_id
1030 ON pt1.photo_id=p.id
1033 WHERE t.name LIKE '%". $_SESSION['searchfor_tag'] ."%' ";
1035 if(isset($additional_where_cond) && !empty($additional_where_cond))
1036 $query_str.= "AND ". $additional_where_cond ." ";
1038 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1039 $query_str.= "AND t2.name IN ('".implode("','",$this->cfg->show_tags)."')";
1042 if(isset($order_str))
1043 $query_str.= $order_str;
1045 $result = $this->db->db_query($query_str);
1046 while($row = $this->db->db_fetch_object($result)) {
1047 array_push($matched_photos, $row['photo_id']);
1049 return $matched_photos;
1052 /* return according the selected tags */
1053 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
1055 foreach($_SESSION['selected_tags'] as $tag)
1056 $selected.= $tag .",";
1057 $selected = substr($selected, 0, strlen($selected)-1);
1059 /* photo has to match at least on of the selected tags */
1060 if($_SESSION['tag_condition'] == 'or') {
1062 SELECT DISTINCT pt1.photo_id
1064 INNER JOIN photo_tags pt2
1065 ON pt1.photo_id=pt2.photo_id
1069 ON pt1.photo_id=p.id
1070 WHERE pt1.tag_id IN (". $selected .")
1072 if(isset($additional_where_cond) && !empty($additional_where_cond))
1073 $query_str.= "AND ". $additional_where_cond ." ";
1075 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1076 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags)."')";
1079 if(isset($order_str))
1080 $query_str.= $order_str;
1082 /* photo has to match all selected tags */
1083 elseif($_SESSION['tag_condition'] == 'and') {
1085 if(count($_SESSION['selected_tags']) >= 32) {
1086 print "A SQLite limit of 32 tables within a JOIN SELECT avoids to<br />\n";
1087 print "evaluate your tag selection. Please remove some tags from your selection.\n";
1091 /* Join together a table looking like
1093 pt1.photo_id pt1.tag_id pt2.photo_id pt2.tag_id ...
1095 so the query can quickly return all images matching the
1096 selected tags in an AND condition
1101 SELECT DISTINCT pt1.photo_id
1105 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1112 for($i = 0; $i < count($_SESSION['selected_tags']); $i++) {
1114 INNER JOIN photo_tags pt". ($i+2) ."
1115 ON pt1.photo_id=pt". ($i+2) .".photo_id
1120 ON pt1.photo_id=p.id
1122 $query_str.= "WHERE pt2.tag_id=". $_SESSION['selected_tags'][0]." ";
1123 for($i = 1; $i < count($_SESSION['selected_tags']); $i++) {
1125 AND pt". ($i+2) .".tag_id=". $_SESSION['selected_tags'][$i] ."
1128 if(isset($additional_where_cond) && !empty($additional_where_cond))
1129 $query_str.= "AND ". $additional_where_cond;
1131 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1132 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags). "')";
1135 if(isset($order_str))
1136 $query_str.= $order_str;
1140 $result = $this->db->db_query($query_str);
1141 while($row = $this->db->db_fetch_object($result)) {
1142 array_push($matched_photos, $row['photo_id']);
1144 return $matched_photos;
1147 /* return all available photos */
1149 SELECT DISTINCT p.id
1151 LEFT JOIN photo_tags pt
1157 if(isset($additional_where_cond) && !empty($additional_where_cond))
1158 $query_str.= "WHERE ". $additional_where_cond ." ";
1160 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1161 if(isset($additional_where_cond) && !empty($additional_where_cond))
1162 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags). "')";
1164 $query_str.= "WHERE t.name IN ('".implode("','",$this->cfg->show_tags). "')";
1167 if(isset($order_str))
1168 $query_str.= $order_str;
1170 $result = $this->db->db_query($query_str);
1171 while($row = $this->db->db_fetch_object($result)) {
1172 array_push($matched_photos, $row['id']);
1174 return $matched_photos;
1176 } // getPhotoSelection()
1179 * control HTML ouput for photo index
1181 * this function provides all the necessary information
1182 * for the photo index template.
1185 public function showPhotoIndex()
1187 $photos = $this->getPhotoSelection();
1189 $count = count($photos);
1191 /* if all thumbnails should be shown on one page */
1192 if(!isset($this->cfg->thumbs_per_page) || $this->cfg->thumbs_per_page == 0) {
1196 /* thumbnails should be splitted up in several pages */
1197 elseif($this->cfg->thumbs_per_page > 0) {
1199 if(!isset($_SESSION['begin_with']) || $_SESSION['begin_with'] == 0) {
1203 $begin_with = $_SESSION['begin_with'];
1206 $end_with = $begin_with + $this->cfg->thumbs_per_page;
1210 $images[$thumbs] = Array();
1211 $img_height[$thumbs] = Array();
1212 $img_width[$thumbs] = Array();
1213 $img_id[$thumbs] = Array();
1214 $img_name[$thumbs] = Array();
1215 $img_fullname[$thumbs] = Array();
1216 $img_title = Array();
1218 for($i = $begin_with; $i < $end_with; $i++) {
1220 if(isset($photos[$i])) {
1222 $images[$thumbs] = $photos[$i];
1223 $img_id[$thumbs] = $i;
1224 $img_name[$thumbs] = htmlspecialchars($this->getPhotoName($photos[$i], 15));
1225 $img_fullname[$thumbs] = htmlspecialchars($this->getPhotoName($photos[$i], 0));
1226 $img_title[$thumbs] = "Click to view photo ". htmlspecialchars($this->getPhotoName($photos[$i], 0));
1228 $thumb_path = $this->get_thumb_path($this->cfg->thumb_width, $photos[$i]);
1230 if(file_exists($thumb_path)) {
1231 $info = getimagesize($thumb_path);
1232 $img_width[$thumbs] = $info[0];
1233 $img_height[$thumbs] = $info[1];
1239 // +1 for for smarty's selection iteration
1242 if(isset($_SESSION['searchfor_tag']) && $_SESSION['searchfor_tag'] != '')
1243 $this->tmpl->assign('searchfor_tag', $_SESSION['searchfor_tag']);
1245 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1246 $this->tmpl->assign('from_date', $this->ts2str($_SESSION['from_date']));
1247 $this->tmpl->assign('to_date', $this->ts2str($_SESSION['to_date']));
1250 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
1251 $this->tmpl->assign('tag_result', 1);
1254 /* do we have to display the page selector ? */
1255 if($this->cfg->thumbs_per_page != 0) {
1259 /* calculate the page switchers */
1260 $previous_start = $begin_with - $this->cfg->thumbs_per_page;
1261 $next_start = $begin_with + $this->cfg->thumbs_per_page;
1263 if($begin_with != 0)
1264 $this->tmpl->assign("previous_url", "javascript:showPhotoIndex(". $previous_start .");");
1265 if($end_with < $count)
1266 $this->tmpl->assign("next_url", "javascript:showPhotoIndex(". $next_start .");");
1268 $photo_per_page = $this->cfg->thumbs_per_page;
1269 $last_page = ceil($count / $photo_per_page);
1271 /* get the current selected page */
1272 if($begin_with == 0) {
1276 for($i = $begin_with; $i >= 0; $i-=$photo_per_page) {
1283 for($i = 1; $i <= $last_page; $i++) {
1285 if($current_page == $i)
1286 $style = "style=\"font-size: 125%; text-decoration: underline;\"";
1287 elseif($current_page-1 == $i || $current_page+1 == $i)
1288 $style = "style=\"font-size: 105%;\"";
1289 elseif(($current_page-5 >= $i) && ($i != 1) ||
1290 ($current_page+5 <= $i) && ($i != $last_page))
1291 $style = "style=\"font-size: 75%;\"";
1295 $start_with = ($i*$photo_per_page)-$photo_per_page;
1297 if($this->is_user_friendly_url()) {
1298 $select = "<a href=\"". $this->cfg->web_path ."/tag/205/". $start_with ."\"";
1301 $select = "<a href=\"". $this->cfg->web_path ."/index.php?mode=showpi tags=". $current_tags ." begin_with=". $begin_with ."\"";
1303 $select.= " onclick=\"showPhotoIndex(". $start_with ."); return false;\"";
1307 $select.= ">". $i ."</a> ";
1309 // until 9 pages we show the selector from 1-9
1310 if($last_page <= 9) {
1311 $page_select.= $select;
1314 if($i == 1 /* first page */ ||
1315 $i == $last_page /* last page */ ||
1316 $i == $current_page /* current page */ ||
1317 $i == ceil($last_page * 0.25) /* first quater */ ||
1318 $i == ceil($last_page * 0.5) /* half */ ||
1319 $i == ceil($last_page * 0.75) /* third quater */ ||
1320 (in_array($i, array(1,2,3,4,5,6)) && $current_page <= 4) /* the first 6 */ ||
1321 (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 */ ||
1322 $i == $current_page-3 || $i == $current_page-2 || $i == $current_page-1 /* three before */ ||
1323 $i == $current_page+3 || $i == $current_page+2 || $i == $current_page+1 /* three after */) {
1325 $page_select.= $select;
1333 $page_select.= "......... ";
1338 /* only show the page selector if we have more then one page */
1340 $this->tmpl->assign('page_selector', $page_select);
1343 $current_tags = $this->getCurrentTags();
1344 $extern_link = "index.php?mode=showpi";
1345 $rss_link = "index.php?mode=rss";
1346 if($current_tags != "") {
1347 $extern_link.= "&tags=". $current_tags;
1348 $rss_link.= "&tags=". $current_tags;
1350 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1351 $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
1352 $rss_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
1355 $export_link = "index.php?mode=export";
1356 $slideshow_link = "index.php?mode=slideshow";
1358 $this->tmpl->assign('extern_link', $extern_link);
1359 $this->tmpl->assign('slideshow_link', $slideshow_link);
1360 $this->tmpl->assign('export_link', $export_link);
1361 $this->tmpl->assign('rss_link', $rss_link);
1362 $this->tmpl->assign('count', $count);
1363 $this->tmpl->assign('width', $this->cfg->thumb_width);
1364 $this->tmpl->assign('preview_width', $this->cfg->photo_width);
1365 $this->tmpl->assign('thumb_container_width', $this->cfg->thumb_width);
1366 $this->tmpl->assign('thumb_container_height', $this->cfg->thumb_height+20);
1367 $this->tmpl->assign('images', $images);
1368 $this->tmpl->assign('img_width', $img_width);
1369 $this->tmpl->assign('img_height', $img_height);
1370 $this->tmpl->assign('img_id', $img_id);
1371 $this->tmpl->assign('img_name', $img_name);
1372 $this->tmpl->assign('img_fullname', $img_fullname);
1373 $this->tmpl->assign('img_title', $img_title);
1374 $this->tmpl->assign('thumbs', $thumbs);
1375 $this->tmpl->assign('selected_tags', $this->getSelectedTags('img'));
1377 $result = $this->tmpl->fetch("photo_index.tpl");
1379 /* if we are returning to photo index from an photo-view,
1380 scroll the window to the last shown photo-thumbnail.
1381 after this, unset the last_photo session variable.
1383 if(isset($_SESSION['last_photo'])) {
1384 $result.= "<script language=\"JavaScript\">moveToThumb(". $_SESSION['last_photo'] .");</script>\n";
1385 unset($_SESSION['last_photo']);
1390 } // showPhotoIndex()
1393 * show credit template
1395 public function showCredits()
1397 $this->tmpl->assign('version', $this->cfg->version);
1398 $this->tmpl->assign('product', $this->cfg->product);
1399 $this->tmpl->assign('db_version', $this->dbver);
1400 $this->tmpl->show("credits.tpl");
1405 * create thumbnails for the requested width
1407 * this function creates image thumbnails of $orig_image
1408 * stored as $thumb_image. It will check if the image is
1409 * in a supported format, if necessary rotate the image
1410 * (based on EXIF orientation meta headers) and re-sizing.
1411 * @param string $orig_image
1412 * @param string $thumb_image
1413 * @param integer $width
1416 public function create_thumbnail($orig_image, $thumb_image, $width)
1418 if(!file_exists($orig_image)) {
1422 $mime = $this->get_mime_info($orig_image);
1424 /* check if original photo is a support image type */
1425 if(!$this->checkifImageSupported($mime))
1432 $meta = $this->get_meta_informations($orig_image);
1438 switch($meta['Orientation']) {
1439 case 1: /* top, left */
1440 /* nothing to do */ break;
1441 case 2: /* top, right */
1442 $rotate = 0; $flip_hori = true; break;
1443 case 3: /* bottom, left */
1444 $rotate = 180; break;
1445 case 4: /* bottom, right */
1446 $flip_vert = true; break;
1447 case 5: /* left side, top */
1448 $rotate = 90; $flip_vert = true; break;
1449 case 6: /* right side, top */
1450 $rotate = 90; break;
1451 case 7: /* left side, bottom */
1452 $rotate = 270; $flip_vert = true; break;
1453 case 8: /* right side, bottom */
1454 $rotate = 270; break;
1457 $src_img = @imagecreatefromjpeg($orig_image);
1463 $src_img = @imagecreatefrompng($orig_image);
1467 case 'image/x-portable-pixmap':
1469 $src_img = new Imagick($orig_image);
1470 $handler = "imagick";
1475 if(!isset($src_img) || empty($src_img)) {
1476 print "Can't load image from ". $orig_image ."\n";
1484 /* grabs the height and width */
1485 $cur_width = imagesx($src_img);
1486 $cur_height = imagesy($src_img);
1488 // If requested width is more then the actual image width,
1489 // do not generate a thumbnail, instead safe the original
1490 // as thumbnail but with lower quality. But if the image
1491 // is to heigh too, then we still have to resize it.
1492 if($width >= $cur_width && $cur_height < $this->cfg->thumb_height) {
1493 $result = imagejpeg($src_img, $thumb_image, 75);
1494 imagedestroy($src_img);
1501 $cur_width = $src_img->getImageWidth();
1502 $cur_height = $src_img->getImageHeight();
1504 // If requested width is more then the actual image width,
1505 // do not generate a thumbnail, instead safe the original
1506 // as thumbnail but with lower quality. But if the image
1507 // is to heigh too, then we still have to resize it.
1508 if($width >= $cur_width && $cur_height < $this->cfg->thumb_height) {
1509 $src_img->setCompressionQuality(75);
1510 $src_img->setImageFormat('jpeg');
1511 $src_img->writeImage($thumb_image);
1513 $src_img->destroy();
1520 // If the image will be rotate because EXIF orientation said so
1521 // 'virtually rotate' the image for further calculations
1522 if($rotate == 90 || $rotate == 270) {
1524 $cur_width = $cur_height;
1528 /* calculates aspect ratio */
1529 $aspect_ratio = $cur_height / $cur_width;
1532 if($aspect_ratio < 1) {
1534 $new_h = abs($new_w * $aspect_ratio);
1536 /* 'virtually' rotate the image and calculate it's ratio */
1537 $tmp_w = $cur_height;
1538 $tmp_h = $cur_width;
1539 /* now get the ratio from the 'rotated' image */
1540 $tmp_ratio = $tmp_h/$tmp_w;
1541 /* now calculate the new dimensions */
1543 $tmp_h = abs($tmp_w * $tmp_ratio);
1545 // now that we know, how high they photo should be, if it
1546 // gets rotated, use this high to scale the image
1548 $new_w = abs($new_h / $aspect_ratio);
1550 // If the image will be rotate because EXIF orientation said so
1551 // now 'virtually rotate' back the image for the image manipulation
1552 if($rotate == 90 || $rotate == 270) {
1563 /* creates new image of that size */
1564 $dst_img = imagecreatetruecolor($new_w, $new_h);
1566 imagefill($dst_img, 0, 0, ImageColorAllocate($dst_img, 255, 255, 255));
1568 /* copies resized portion of original image into new image */
1569 imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $new_w, $new_h, imagesx($src_img), imagesy($src_img));
1571 /* needs the image to be flipped horizontal? */
1573 $this->_debug("(FLIP)");
1574 $dst_img = $this->flipImage($dst_img, 'hori');
1576 /* needs the image to be flipped vertical? */
1578 $this->_debug("(FLIP)");
1579 $dst_img = $this->flipImage($dst_img, 'vert');
1583 $this->_debug("(ROTATE)");
1584 $dst_img = $this->rotateImage($dst_img, $rotate);
1587 /* write down new generated file */
1588 $result = imagejpeg($dst_img, $thumb_image, 75);
1590 /* free your mind */
1591 imagedestroy($dst_img);
1592 imagedestroy($src_img);
1594 if($result === false) {
1595 print "Can't write thumbnail ". $thumb_image ."\n";
1605 $src_img->resizeImage($new_w, $new_h, Imagick::FILTER_LANCZOS, 1);
1607 /* needs the image to be flipped horizontal? */
1609 $this->_debug("(FLIP)");
1610 $src_img->rotateImage(new ImagickPixel(), 90);
1611 $src_img->flipImage();
1612 $src_img->rotateImage(new ImagickPixel(), -90);
1614 /* needs the image to be flipped vertical? */
1616 $this->_debug("(FLIP)");
1617 $src_img->flipImage();
1621 $this->_debug("(ROTATE)");
1622 $src_img->rotateImage(new ImagickPixel(), $rotate);
1625 $src_img->setCompressionQuality(75);
1626 $src_img->setImageFormat('jpeg');
1628 if(!$src_img->writeImage($thumb_image)) {
1629 print "Can't write thumbnail ". $thumb_image ."\n";
1634 $src_img->destroy();
1641 } // create_thumbnail()
1644 * return all exif meta data from the file
1645 * @param string $file
1648 public function get_meta_informations($file)
1650 return exif_read_data($file);
1652 } // get_meta_informations()
1655 * create phpfspot own sqlite database
1657 * this function creates phpfspots own sqlite database
1658 * if it does not exist yet. this own is used to store
1659 * some necessary informations (md5 sum's, ...).
1661 public function check_config_table()
1663 // if the config table doesn't exist yet, create it
1664 if(!$this->cfg_db->db_check_table_exists("images")) {
1665 $this->cfg_db->db_exec("
1666 CREATE TABLE images (
1667 img_idx int primary key,
1673 } // check_config_table
1676 * Generates a thumbnail from photo idx
1678 * This function will generate JPEG thumbnails from provided F-Spot photo
1681 * 1. Check if all thumbnail generations (width) are already in place and
1683 * 2. Check if the md5sum of the original file has changed
1684 * 3. Generate the thumbnails if needed
1685 * @param integer $idx
1686 * @param integer $force
1687 * @param boolean $overwrite
1689 public function gen_thumb($idx = 0, $force = 0, $overwrite = false)
1693 $resolutions = Array(
1694 $this->cfg->thumb_width,
1695 $this->cfg->photo_width,
1696 $this->cfg->mini_width,
1700 /* get details from F-Spot's database */
1701 $details = $this->get_photo_details($idx);
1703 /* calculate file MD5 sum */
1704 $full_path = $this->translate_path($this->parse_uri($details['uri'], 'fullpath'));
1706 if(!file_exists($full_path)) {
1707 $this->_error("File ". $full_path ." does not exist\n");
1711 if(!is_readable($full_path)) {
1712 $this->_error("File ". $full_path ." is not readable for ". $this->getuid() ."\n");
1716 $this->_debug("Image [". $idx ."] ". $this->shrink_text($this->parse_uri($details['uri'], 'filename'), 20) ." Thumbnails:");
1718 /* If Nikon NEF format, we need to treat it another way */
1719 if(isset($this->cfg->dcraw_bin) &&
1720 file_exists($this->cfg->dcraw_bin) &&
1721 is_executable($this->cfg->dcraw_bin) &&
1722 preg_match('/\.nef$/i', $details['uri'])) {
1724 $ppm_path = preg_replace('/\.nef$/i', '.ppm', $full_path);
1726 /* if PPM file does not exist, let dcraw convert it from NEF */
1727 if(!file_exists($ppm_path)) {
1728 system($this->cfg->dcraw_bin ." -a ". $full_path);
1731 /* for now we handle the PPM instead of the NEF */
1732 $full_path = $ppm_path;
1736 $file_md5 = md5_file($full_path);
1739 foreach($resolutions as $resolution) {
1741 $generate_it = false;
1743 $thumb_sub_path = substr($file_md5, 0, 2);
1744 $thumb_path = $this->cfg->thumb_path ."/". $thumb_sub_path ."/". $resolution ."_". $file_md5;
1746 /* if thumbnail-subdirectory does not exist yet, create it */
1747 if(!file_exists(dirname($thumb_path))) {
1748 mkdir(dirname($thumb_path), 0755);
1751 /* if the thumbnail file doesn't exist, create it */
1752 if(!file_exists($thumb_path)) {
1753 $generate_it = true;
1755 /* if the file hasn't changed there is no need to regen the thumb */
1756 elseif($file_md5 != $this->getMD5($idx) || $force) {
1757 $generate_it = true;
1760 if($generate_it || $overwrite) {
1762 $this->_debug(" ". $resolution ."px");
1763 if(!$this->create_thumbnail($full_path, $thumb_path, $resolution))
1771 $this->_debug(" already exist");
1774 /* set the new/changed MD5 sum for the current photo */
1776 $this->setMD5($idx, $file_md5);
1779 $this->_debug("\n");
1784 * returns stored md5 sum for a specific photo
1786 * this function queries the phpfspot database for a
1787 * stored MD5 checksum of the specified photo
1788 * @param integer $idx
1789 * @return string|null
1791 public function getMD5($idx)
1793 $result = $this->cfg_db->db_query("
1796 WHERE img_idx='". $idx ."'
1802 $img = $this->cfg_db->db_fetch_object($result);
1803 return $img['img_md5'];
1808 * set MD5 sum for the specific photo
1809 * @param integer $idx
1810 * @param string $md5
1812 private function setMD5($idx, $md5)
1814 $result = $this->cfg_db->db_exec("
1815 REPLACE INTO images (img_idx, img_md5)
1816 VALUES ('". $idx ."', '". $md5 ."')
1822 * store current tag condition
1824 * this function stores the current tag condition
1825 * (AND or OR) in the users session variables
1826 * @param string $mode
1829 public function setTagCondition($mode)
1831 $_SESSION['tag_condition'] = $mode;
1835 } // setTagCondition()
1838 * invoke tag & date search
1840 * this function will return all matching tags and store
1841 * them in the session variable selected_tags. furthermore
1842 * it also handles the date search.
1843 * getPhotoSelection() will then only return the matching
1847 public function startSearch()
1849 if(isset($_POST['from']) && $this->isValidDate($_POST['from'])) {
1850 $from = $_POST['from'];
1852 if(isset($_POST['to']) && $this->isValidDate($_POST['to'])) {
1856 if(isset($_POST['for_tag']) && is_string($_POST['for_tag'])) {
1857 $searchfor_tag = $_POST['for_tag'];
1858 $_SESSION['searchfor_tag'] = $_POST['for_tag'];
1861 if(isset($_POST['for_name']) && is_string($_POST['for_name'])) {
1862 $searchfor_name = $_POST['for_name'];
1863 $_SESSION['searchfor_name'] = $_POST['for_name'];
1868 if(isset($from) && !empty($from))
1869 $_SESSION['from_date'] = strtotime($from ." 00:00:00");
1871 unset($_SESSION['from_date']);
1873 if(isset($to) && !empty($to))
1874 $_SESSION['to_date'] = strtotime($to ." 23:59:59");
1876 unset($_SESSION['to_date']);
1878 if(isset($searchfor_tag) && !empty($searchfor_tag)) {
1879 /* new search, reset the current selected tags */
1880 $_SESSION['selected_tags'] = Array();
1881 foreach($this->avail_tags as $tag) {
1882 if(preg_match('/'. $searchfor_tag .'/i', $this->tags[$tag]))
1883 array_push($_SESSION['selected_tags'], $tag);
1892 * updates sort order in session variable
1894 * this function is invoked by RPC and will sort the requested
1895 * sort order in the session variable.
1896 * @param string $sort_order
1899 public function updateSortOrder($order)
1901 if(isset($this->sort_orders[$order])) {
1902 $_SESSION['sort_order'] = $order;
1906 return "unkown error";
1908 } // updateSortOrder()
1913 * this function rotates the image according the
1915 * @param string $img
1916 * @param integer $degress
1919 private function rotateImage($img, $degrees)
1921 if(function_exists("imagerotate")) {
1922 $img = imagerotate($img, $degrees, 0);
1924 function imagerotate($src_img, $angle)
1926 $src_x = imagesx($src_img);
1927 $src_y = imagesy($src_img);
1928 if ($angle == 180) {
1932 elseif ($src_x <= $src_y) {
1936 elseif ($src_x >= $src_y) {
1941 $rotate=imagecreatetruecolor($dest_x,$dest_y);
1942 imagealphablending($rotate, false);
1947 for ($y = 0; $y < ($src_y); $y++) {
1948 for ($x = 0; $x < ($src_x); $x++) {
1949 $color = imagecolorat($src_img, $x, $y);
1950 imagesetpixel($rotate, $dest_x - $y - 1, $x, $color);
1956 for ($y = 0; $y < ($src_y); $y++) {
1957 for ($x = 0; $x < ($src_x); $x++) {
1958 $color = imagecolorat($src_img, $x, $y);
1959 imagesetpixel($rotate, $y, $dest_y - $x - 1, $color);
1965 for ($y = 0; $y < ($src_y); $y++) {
1966 for ($x = 0; $x < ($src_x); $x++) {
1967 $color = imagecolorat($src_img, $x, $y);
1968 imagesetpixel($rotate, $dest_x - $x - 1, $dest_y - $y - 1, $color);
1982 $img = imagerotate($img, $degrees);
1991 * returns flipped image
1993 * this function will return an either horizontal or
1994 * vertical flipped truecolor image.
1995 * @param string $image
1996 * @param string $mode
1999 private function flipImage($image, $mode)
2001 $w = imagesx($image);
2002 $h = imagesy($image);
2003 $flipped = imagecreatetruecolor($w, $h);
2007 for ($y = 0; $y < $h; $y++) {
2008 imagecopy($flipped, $image, 0, $y, 0, $h - $y - 1, $w, 1);
2012 for ($x = 0; $x < $w; $x++) {
2013 imagecopy($flipped, $image, $x, 0, $w - $x - 1, 0, 1, $h);
2023 * return all assigned tags for the specified photo
2024 * @param integer $idx
2027 private function get_photo_tags($idx)
2029 $result = $this->db->db_query("
2032 INNER JOIN photo_tags pt
2034 WHERE pt.photo_id='". $idx ."'
2039 while($row = $this->db->db_fetch_object($result)) {
2040 if(isset($this->cfg->hide_tags) && in_array($row['name'], $this->cfg->hide_tags))
2042 $tags[$row['id']] = $row['name'];
2047 } // get_photo_tags()
2050 * create on-the-fly images with text within
2051 * @param string $txt
2052 * @param string $color
2053 * @param integer $space
2054 * @param integer $font
2057 public function showTextImage($txt, $color=000000, $space=4, $font=4, $w=300)
2059 if (strlen($color) != 6)
2062 $int = hexdec($color);
2063 $h = imagefontheight($font);
2064 $fw = imagefontwidth($font);
2065 $txt = explode("\n", wordwrap($txt, ($w / $fw), "\n"));
2066 $lines = count($txt);
2067 $im = imagecreate($w, (($h * $lines) + ($lines * $space)));
2068 $bg = imagecolorallocate($im, 255, 255, 255);
2069 $color = imagecolorallocate($im, 0xFF & ($int >> 0x10), 0xFF & ($int >> 0x8), 0xFF & $int);
2072 foreach ($txt as $text) {
2073 $x = (($w - ($fw * strlen($text))) / 2);
2074 imagestring($im, $font, $x, $y, $text, $color);
2075 $y += ($h + $space);
2078 Header("Content-type: image/png");
2081 } // showTextImage()
2084 * check if all requirements are met
2087 private function check_requirements()
2089 if(!function_exists("imagecreatefromjpeg")) {
2090 print "PHP GD library extension is missing<br />\n";
2094 if($this->cfg->db_access == "native" && !function_exists("sqlite3_open")) {
2095 print "PHP SQLite3 library extension is missing<br />\n";
2099 /* Check for HTML_AJAX PEAR package, lent from Horde project */
2100 ini_set('track_errors', 1);
2101 @include_once 'HTML/AJAX/Server.php';
2102 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
2103 print "PEAR HTML_AJAX package is missing<br />\n";
2106 @include_once 'Calendar/Calendar.php';
2107 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
2108 print "PEAR Calendar package is missing<br />\n";
2111 @include_once 'Console/Getopt.php';
2112 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
2113 print "PEAR Console_Getopt package is missing<br />\n";
2116 @include_once $this->cfg->smarty_path .'/libs/Smarty.class.php';
2117 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
2118 print "Smarty template engine can not be found in ". $this->cfg->smarty_path ."/libs/Smarty.class.php<br />\n";
2121 ini_restore('track_errors');
2128 } // check_requirements()
2130 private function _debug($text)
2132 if($this->fromcmd) {
2139 * check if specified MIME type is supported
2140 * @param string $mime
2143 public function checkifImageSupported($mime)
2145 $supported_types = Array(
2148 "image/x-portable-pixmap",
2152 if(in_array($mime, $supported_types))
2157 } // checkifImageSupported()
2161 * @param string $text
2163 public function _error($text)
2165 switch($this->cfg->logging) {
2168 print "<img src=\"resources/green_info.png\" alt=\"warning\" />\n";
2169 print $text ."<br />\n";
2175 error_log($text, 3, $his->cfg->log_file);
2179 $this->runtime_error = true;
2184 * output calendard input fields
2185 * @param string $mode
2188 private function get_calendar($mode)
2190 $year = isset($_SESSION[$mode .'_date']) ? date("Y", $_SESSION[$mode .'_date']) : date("Y");
2191 $month = isset($_SESSION[$mode .'_date']) ? date("m", $_SESSION[$mode .'_date']) : date("m");
2192 $day = isset($_SESSION[$mode .'_date']) ? date("d", $_SESSION[$mode .'_date']) : date("d");
2194 $output = "<input type=\"text\" size=\"3\" id=\"". $mode ."year\" value=\"". $year ."\"";
2195 if(!isset($_SESSION[$mode .'_date']))
2196 $output.= " disabled=\"disabled\"";
2198 $output.= "<input type=\"text\" size=\"1\" id=\"". $mode ."month\" value=\"". $month ."\"";
2199 if(!isset($_SESSION[$mode .'_date']))
2200 $output.= " disabled=\"disabled\"";
2202 $output.= "<input type=\"text\" size=\"1\" id=\"". $mode ."day\" value=\"". $day ."\"";
2203 if(!isset($_SESSION[$mode .'_date']))
2204 $output.= " disabled=\"disabled\"";
2212 * output calendar matrix
2213 * @param integer $year
2214 * @param integer $month
2215 * @param integer $day
2217 public function get_calendar_matrix($year = 0, $month = 0, $day = 0)
2219 if (!isset($year)) $year = date('Y');
2220 if (!isset($month)) $month = date('m');
2221 if (!isset($day)) $day = date('d');
2226 require_once CALENDAR_ROOT.'Month/Weekdays.php';
2227 require_once CALENDAR_ROOT.'Day.php';
2230 $month = new Calendar_Month_Weekdays($year,$month);
2233 $prevStamp = $month->prevMonth(true);
2234 $prev = "javascript:setMonth(". date('Y',$prevStamp) .", ". date('n',$prevStamp) .", ". date('j',$prevStamp) .");";
2235 $nextStamp = $month->nextMonth(true);
2236 $next = "javascript:setMonth(". date('Y',$nextStamp) .", ". date('n',$nextStamp) .", ". date('j',$nextStamp) .");";
2238 $selectedDays = array (
2239 new Calendar_Day($year,$month,$day),
2240 new Calendar_Day($year,12,25),
2243 // Build the days in the month
2244 $month->build($selectedDays);
2246 $this->tmpl->assign('current_month', date('F Y',$month->getTimeStamp()));
2247 $this->tmpl->assign('prev_month', $prev);
2248 $this->tmpl->assign('next_month', $next);
2250 while ( $day = $month->fetch() ) {
2252 if(!isset($matrix[$rows]))
2253 $matrix[$rows] = Array();
2257 $dayStamp = $day->thisDay(true);
2258 $link = "javascript:setCalendarDate(". date('Y',$dayStamp) .", ". date('n',$dayStamp).", ". date('j',$dayStamp) .");";
2260 // isFirst() to find start of week
2261 if ( $day->isFirst() )
2264 if ( $day->isSelected() ) {
2265 $string.= "<td class=\"selected\">".$day->thisDay()."</td>\n";
2266 } else if ( $day->isEmpty() ) {
2267 $string.= "<td> </td>\n";
2269 $string.= "<td><a class=\"calendar\" href=\"".$link."\">".$day->thisDay()."</a></td>\n";
2272 // isLast() to find end of week
2273 if ( $day->isLast() )
2274 $string.= "</tr>\n";
2276 $matrix[$rows][$cols] = $string;
2286 $this->tmpl->assign('matrix', $matrix);
2287 $this->tmpl->assign('rows', $rows);
2288 $this->tmpl->show("calendar.tpl");
2290 } // get_calendar_matrix()
2293 * output export page
2294 * @param string $mode
2296 public function getExport($mode)
2298 $pictures = $this->getPhotoSelection();
2299 $current_tags = $this->getCurrentTags();
2301 foreach($pictures as $picture) {
2303 $orig_url = $this->get_phpfspot_url() ."/index.php?mode=showp&id=". $picture;
2304 if($current_tags != "") {
2305 $orig_url.= "&tags=". $current_tags;
2307 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
2308 $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
2311 if($this->is_user_friendly_url()) {
2312 $thumb_url = $this->get_phpfspot_url() ."/photo/". $picture ."/". $this->cfg->thumb_width;
2315 $thumb_url = $this->get_phpfspot_url() ."/phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
2321 // <a href="%pictureurl%"><img src="%thumbnailurl%" ></a>
2322 print htmlspecialchars("<a href=\"". $orig_url ."\"><img src=\"". $thumb_url ."\" /></a>") ."<br />\n";
2326 // "[%pictureurl% %thumbnailurl%]"
2327 print htmlspecialchars("[".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
2330 case 'MoinMoinList':
2331 // " * [%pictureurl% %thumbnailurl%]"
2332 print " " . htmlspecialchars("* [".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
2343 public function getRSSFeed()
2345 Header("Content-type: text/xml; charset=utf-8");
2346 print "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
2349 xmlns:media="http://search.yahoo.com/mrss/"
2350 xmlns:dc="http://purl.org/dc/elements/1.1/"
2353 <title>phpfspot</title>
2354 <description>phpfspot RSS feed</description>
2355 <link><?php print htmlspecialchars($this->get_phpfspot_url()); ?></link>
2356 <pubDate><?php print strftime("%a, %d %b %Y %T %z"); ?></pubDate>
2357 <generator>phpfspot</generator>
2360 $pictures = $this->getPhotoSelection();
2361 $current_tags = $this->getCurrentTags();
2363 foreach($pictures as $picture) {
2365 $orig_url = $this->get_phpfspot_url() ."/index.php?mode=showp&id=". $picture;
2366 if($current_tags != "") {
2367 $orig_url.= "&tags=". $current_tags;
2369 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
2370 $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
2373 $details = $this->get_photo_details($picture);
2375 if($this->is_user_friendly_url()) {
2376 $thumb_url = $this->get_phpfspot_url() ."/photo/". $picture ."/". $this->cfg->thumb_width;
2379 $thumb_url = $this->get_phpfspot_url() ."/phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
2382 $thumb_html = htmlspecialchars("
2383 <a href=\"". $orig_url ."\"><img src=\"". $thumb_url ."\" /></a>
2385 ". $details['description']);
2387 $orig_path = $this->translate_path($this->parse_uri($details['uri'], 'fullpath'));
2389 /* get EXIF information if JPEG */
2390 if($details['mime'] == "image/jpeg") {
2391 $meta = $this->get_meta_informations($orig_path);
2394 $meta_date = isset($meta['FileDateTime']) ? $meta['FileDateTime'] : filemtime($orig_path);
2398 <title><?php print htmlspecialchars($this->parse_uri($details['uri'], 'filename')); ?></title>
2399 <link><?php print htmlspecialchars($orig_url); ?></link>
2400 <guid><?php print htmlspecialchars($orig_url); ?></guid>
2401 <dc:date.Taken><?php print strftime("%Y-%m-%dT%H:%M:%S+00:00", $meta_date); ?></dc:date.Taken>
2403 <?php print $thumb_html; ?>
2405 <pubDate><?php print strftime("%a, %d %b %Y %T %z", $meta_date); ?></pubDate>
2420 * return all selected tags as one string
2423 private function getCurrentTags()
2426 if(isset($_SESSION['selected_tags']) && $_SESSION['selected_tags'] != "") {
2427 foreach($_SESSION['selected_tags'] as $tag)
2428 $current_tags.= $tag .",";
2429 $current_tags = substr($current_tags, 0, strlen($current_tags)-1);
2431 return $current_tags;
2433 } // getCurrentTags()
2436 * return the current photo
2438 public function getCurrentPhoto()
2440 if(isset($_SESSION['current_photo'])) {
2441 print $_SESSION['current_photo'];
2443 } // getCurrentPhoto()
2446 * tells the client browser what to do
2448 * this function is getting called via AJAX by the
2449 * client browsers. it will tell them what they have
2450 * to do next. This is necessary for directly jumping
2451 * into photo index or single photo view when the are
2452 * requested with specific URLs
2455 public function whatToDo()
2457 if(isset($_SESSION['current_photo']) && $_SESSION['start_action'] == 'showp') {
2459 elseif(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
2460 return "showpi_tags";
2462 elseif(isset($_SESSION['start_action']) && $_SESSION['start_action'] == 'showpi') {
2469 * return the current process-user
2472 private function getuid()
2474 if($uid = posix_getuid()) {
2475 if($user = posix_getpwuid($uid)) {
2476 return $user['name'];
2485 * returns a select-dropdown box to select photo index sort parameters
2486 * @param array $params
2487 * @param smarty $smarty
2490 public function smarty_sort_select_list($params, &$smarty)
2494 foreach($this->sort_orders as $key => $value) {
2495 $output.= "<option value=\"". $key ."\"";
2496 if($key == $_SESSION['sort_order']) {
2497 $output.= " selected=\"selected\"";
2499 $output.= ">". $value ."</option>";
2504 } // smarty_sort_select_list()
2507 * returns the currently selected sort order
2510 private function get_sort_order()
2512 switch($_SESSION['sort_order']) {
2514 return " ORDER BY p.time ASC";
2517 return " ORDER BY p.time DESC";
2520 if($this->dbver < 9) {
2521 return " ORDER BY p.name ASC";
2524 return " ORDER BY basename(p.uri) ASC";
2528 if($this->dbver < 9) {
2529 return " ORDER BY p.name DESC";
2532 return " ORDER BY basename(p.uri) DESC";
2536 return " ORDER BY t.name ASC ,p.time ASC";
2539 return " ORDER BY t.name DESC ,p.time ASC";
2543 } // get_sort_order()
2546 * return the next to be shown slide show image
2548 * this function returns the URL of the next image
2549 * in the slideshow sequence.
2552 public function getNextSlideShowImage()
2554 $all_photos = $this->getPhotoSelection();
2556 if(!isset($_SESSION['slideshow_img']) || $_SESSION['slideshow_img'] == count($all_photos)-1)
2557 $_SESSION['slideshow_img'] = 0;
2559 $_SESSION['slideshow_img']++;
2561 if($this->is_user_friendly_url()) {
2562 return $this->get_phpfspot_url() ."/photo/". $all_photos[$_SESSION['slideshow_img']] ."/". $this->cfg->photo_width;
2565 return $this->get_phpfspot_url() ."/phpfspot_img.php?idx=". $all_photos[$_SESSION['slideshow_img']] ."&width=". $this->cfg->photo_width;
2567 } // getNextSlideShowImage()
2570 * return the previous to be shown slide show image
2572 * this function returns the URL of the previous image
2573 * in the slideshow sequence.
2576 public function getPrevSlideShowImage()
2578 $all_photos = $this->getPhotoSelection();
2580 if(!isset($_SESSION['slideshow_img']) || $_SESSION['slideshow_img'] == 0)
2581 $_SESSION['slideshow_img'] = 0;
2583 $_SESSION['slideshow_img']--;
2585 if($this->is_user_friendly_url()) {
2586 return $this->get_phpfspot_url() ."/photo/". $all_photos[$_SESSION['slideshow_img']] ."/". $this->cfg->photo_width;
2589 return $this->get_phpfspot_url() ."/phpfspot_img.php?idx=". $all_photos[$_SESSION['slideshow_img']] ."&width=". $this->cfg->photo_width;
2591 } // getPrevSlideShowImage()
2593 public function resetSlideShow()
2595 if(isset($_SESSION['slideshow_img']))
2596 unset($_SESSION['slideshow_img']);
2598 } // resetSlideShow()
2603 * this function will get all photos from the fspot
2604 * database and randomly return ONE entry
2606 * saddly there is yet no sqlite3 function which returns
2607 * the bulk result in array, so we have to fill up our
2611 public function get_random_photo()
2620 /* if show_tags is set, only return details for photos which
2621 are specified to be shown
2623 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
2625 INNER JOIN photo_tags pt
2630 t.name IN ('".implode("','",$this->cfg->show_tags)."')";
2633 $result = $this->db->db_query($query_str);
2635 while($row = $this->db->db_fetch_object($result)) {
2636 array_push($all, $row['id']);
2639 return $all[array_rand($all)];
2641 } // get_random_photo()
2644 * get random photo tag photo
2646 * this function will get all photos tagged with the requested
2647 * tag from the fspot database and randomly return ONE entry
2649 * saddly there is yet no sqlite3 function which returns
2650 * the bulk result in array, so we have to fill up our
2654 public function get_random_tag_photo($tagidx)
2661 INNER JOIN photo_tags pt
2665 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
2673 pt.tag_id LIKE '". $tagidx ."'
2676 /*if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
2679 t.name IN ('".implode("','",$this->cfg->show_tags)."')
2683 $result = $this->db->db_query($query_str);
2685 while($row = $this->db->db_fetch_object($result)) {
2686 array_push($all, $row['id']);
2689 return $all[array_rand($all)];
2691 } // get_random_tag_photo()
2694 * validates provided date
2696 * this function validates if the provided date
2697 * contains a valid date and will return true
2699 * @param string $date_str
2702 public function isValidDate($date_str)
2704 $timestamp = strtotime($date_str);
2706 if(is_numeric($timestamp))
2714 * timestamp to string conversion
2715 * @param integer $timestamp
2718 private function ts2str($timestamp)
2720 if(!empty($timestamp) && is_numeric($timestamp))
2721 return strftime("%Y-%m-%d", $timestamp);
2726 * extract tag-names from $_GET['tags']
2727 * @param string $tags_str
2730 private function extractTags($tags_str)
2732 $not_validated = split(',', $tags_str);
2733 $validated = array();
2735 foreach($not_validated as $tag) {
2736 if(is_numeric($tag))
2737 array_push($validated, $tag);
2745 * returns the full path to a thumbnail
2746 * @param integer $width
2747 * @param integer $photo
2750 public function get_thumb_path($width, $photo)
2752 $md5 = $this->getMD5($photo);
2753 $sub_path = substr($md5, 0, 2);
2754 return $this->cfg->thumb_path
2762 } // get_thumb_path()
2765 * returns server's virtual host name
2768 private function get_server_name()
2770 return $_SERVER['SERVER_NAME'];
2771 } // get_server_name()
2774 * returns type of webprotocol which is currently used
2777 private function get_web_protocol()
2779 if(!isset($_SERVER['HTTPS']))
2783 } // get_web_protocol()
2786 * return url to this phpfspot installation
2789 private function get_phpfspot_url()
2791 return $this->get_web_protocol() ."://". $this->get_server_name() . $this->cfg->web_path;
2793 } // get_phpfspot_url()
2796 * returns the number of photos which are tagged with $tag_id
2797 * @param integer $tag_id
2800 public function get_num_photos($tag_id)
2802 if($result = $this->db->db_fetchSingleRow("
2803 SELECT count(*) as number
2806 tag_id LIKE '". $tag_id ."'")) {
2808 return $result['number'];
2814 } // get_num_photos()
2817 * check file exists and is readable
2819 * returns true, if everything is ok, otherwise false
2820 * if $silent is not set, this function will output and
2822 * @param string $file
2823 * @param boolean $silent
2826 private function check_readable($file, $silent = null)
2828 if(!file_exists($file)) {
2830 print "File \"". $file ."\" does not exist.\n";
2834 if(!is_readable($file)) {
2836 print "File \"". $file ."\" is not reachable for user ". $this->getuid() ."\n";
2842 } // check_readable()
2845 * check if all needed indices are present
2847 * this function checks, if some needed indices are already
2848 * present, or if not, create them on the fly. they are
2849 * necessary to speed up some queries like that one look for
2850 * all tags, when show_tags is specified in the configuration.
2852 private function checkDbIndices()
2854 $result = $this->db->db_exec("
2855 CREATE INDEX IF NOT EXISTS
2862 } // checkDbIndices()
2865 * retrive F-Spot database version
2867 * this function will return the F-Spot database version number
2868 * It is stored within the sqlite3 database in the table meta
2869 * @return string|null
2871 public function getFspotDBVersion()
2873 if($result = $this->db->db_fetchSingleRow("
2874 SELECT data as version
2877 name LIKE 'F-Spot Database Version'
2879 return $result['version'];
2883 } // getFspotDBVersion()
2886 * parse the provided URI and will returned the requested chunk
2887 * @param string $uri
2888 * @param string $mode
2891 public function parse_uri($uri, $mode)
2893 if(($components = parse_url($uri)) !== false) {
2897 return basename($components['path']);
2900 return dirname($components['path']);
2903 return $components['path'];
2913 * validate config options
2915 * this function checks if all necessary configuration options are
2916 * specified and set.
2919 private function check_config_options()
2921 if(!isset($this->cfg->page_title) || $this->cfg->page_title == "")
2922 $this->_error("Please set \$page_title in phpfspot_cfg");
2924 if(!isset($this->cfg->base_path) || $this->cfg->base_path == "")
2925 $this->_error("Please set \$base_path in phpfspot_cfg");
2927 if(!isset($this->cfg->web_path) || $this->cfg->web_path == "")
2928 $this->_error("Please set \$web_path in phpfspot_cfg");
2930 if(!isset($this->cfg->thumb_path) || $this->cfg->thumb_path == "")
2931 $this->_error("Please set \$thumb_path in phpfspot_cfg");
2933 if(!isset($this->cfg->smarty_path) || $this->cfg->smarty_path == "")
2934 $this->_error("Please set \$smarty_path in phpfspot_cfg");
2936 if(!isset($this->cfg->fspot_db) || $this->cfg->fspot_db == "")
2937 $this->_error("Please set \$fspot_db in phpfspot_cfg");
2939 if(!isset($this->cfg->db_access) || $this->cfg->db_access == "")
2940 $this->_error("Please set \$db_access in phpfspot_cfg");
2942 if(!isset($this->cfg->phpfspot_db) || $this->cfg->phpfspot_db == "")
2943 $this->_error("Please set \$phpfspot_db in phpfspot_cfg");
2945 if(!isset($this->cfg->thumb_width) || $this->cfg->thumb_width == "")
2946 $this->_error("Please set \$thumb_width in phpfspot_cfg");
2948 if(!isset($this->cfg->thumb_height) || $this->cfg->thumb_height == "")
2949 $this->_error("Please set \$thumb_height in phpfspot_cfg");
2951 if(!isset($this->cfg->photo_width) || $this->cfg->photo_width == "")
2952 $this->_error("Please set \$photo_width in phpfspot_cfg");
2954 if(!isset($this->cfg->mini_width) || $this->cfg->mini_width == "")
2955 $this->_error("Please set \$mini_width in phpfspot_cfg");
2957 if(!isset($this->cfg->thumbs_per_page))
2958 $this->_error("Please set \$thumbs_per_page in phpfspot_cfg");
2960 if(!isset($this->cfg->path_replace_from) || $this->cfg->path_replace_from == "")
2961 $this->_error("Please set \$path_replace_from in phpfspot_cfg");
2963 if(!isset($this->cfg->path_replace_to) || $this->cfg->path_replace_to == "")
2964 $this->_error("Please set \$path_replace_to in phpfspot_cfg");
2966 if(!isset($this->cfg->hide_tags))
2967 $this->_error("Please set \$hide_tags in phpfspot_cfg");
2969 if(!isset($this->cfg->theme_name))
2970 $this->_error("Please set \$theme_name in phpfspot_cfg");
2972 if(!isset($this->cfg->logging))
2973 $this->_error("Please set \$logging in phpfspot_cfg");
2975 if(isset($this->cfg->logging) && $this->cfg->logging == 'logfile') {
2977 if(!isset($this->cfg->log_file))
2978 $this->_error("Please set \$log_file because you set logging = log_file in phpfspot_cfg");
2980 if(!is_writeable($this->cfg->log_file))
2981 $this->_error("The specified \$log_file ". $log_file ." is not writeable!");
2985 /* remove trailing slash, if set */
2986 if($this->cfg->web_path == "/")
2987 $this->cfg->web_path = "";
2988 elseif(preg_match('/\/$/', $this->cfg->web_path))
2989 $this->cfg->web_path = preg_replace('/\/$/', '', $this->cfg->web_path);
2991 return $this->runtime_error;
2993 } // check_config_options()
2996 * cleanup phpfspot own database
2998 * When photos are getting delete from F-Spot, there will remain
2999 * remain some residues in phpfspot own database. This function
3000 * will try to wipe them out.
3002 public function cleanup_phpfspot_db()
3004 $to_delete = Array();
3006 $result = $this->cfg_db->db_query("
3009 ORDER BY img_idx ASC
3012 while($row = $this->cfg_db->db_fetch_object($result)) {
3013 if(!$this->db->db_fetchSingleRow("
3016 WHERE id='". $row['img_idx'] ."'")) {
3018 array_push($to_delete, $row['img_idx'], ',');
3022 print count($to_delete) ." unnecessary objects will be removed from phpfspot's database.\n";
3024 $this->cfg_db->db_exec("
3026 WHERE img_idx IN (". implode($to_delete) .")
3029 } // cleanup_phpfspot_db()
3032 * return first image of the page, the $current photo
3035 * this function is used to find out the first photo of the
3036 * current page, in which the $current photo lies. this is
3037 * used to display the correct photo, when calling showPhotoIndex()
3039 * @param integer $current
3040 * @param integer $max
3043 private function getCurrentPage($current, $max)
3045 if(isset($this->cfg->thumbs_per_page) && !empty($this->cfg->thumbs_per_page)) {
3046 for($page_start = 0; $page_start <= $max; $page_start+=$this->cfg->thumbs_per_page) {
3047 if($current >= $page_start && $current < ($page_start+$this->cfg->thumbs_per_page))
3053 } // getCurrentPage()
3058 * this function tries to find out the correct mime-type
3059 * for the provided file.
3060 * @param string $file
3063 public function get_mime_info($file)
3065 $details = getimagesize($file);
3067 /* if getimagesize() returns empty, try at least to find out the
3070 if(empty($details) && function_exists('mime_content_type')) {
3072 // mime_content_type is marked as deprecated in the documentation,
3073 // but is it really necessary to force users to install a PECL
3075 $details['mime'] = mime_content_type($file);
3078 return $details['mime'];
3080 } // get_mime_info()
3083 * return tag-name by tag-idx
3085 * this function returns the tag-name for the requested
3086 * tag specified by tag-idx.
3087 * @param integer $idx
3090 public function get_tag_name($idx)
3092 if($result = $this->db->db_fetchSingleRow("
3096 id LIKE '". $idx ."'")) {
3098 return $result['name'];
3107 * parse user friendly url which got rewritten by the websever
3108 * @param string $request_uri
3111 private function parse_user_friendly_url($request_uri)
3113 if(preg_match('/\/photoview\/|\/photo\/|\/tag\//', $request_uri)) {
3115 $options = explode('/', $request_uri);
3117 switch($options[1]) {
3119 if(is_numeric($options[2])) {
3120 $this->session_cleanup();
3121 //unset($_SESSION['start_action']);
3122 //unset($_SESSION['selected_tags']);
3123 $_GET['mode'] = 'showp';
3124 return $this->showPhoto($options[2]);
3128 if(is_numeric($options[2])) {
3129 require_once "phpfspot_img.php";
3130 $img = new PHPFSPOT_IMG;
3131 if(isset($options[3]) && is_numeric($options[3]))
3132 $img->showImg($options[2], $options[3]);
3134 $img->showImg($options[2]);
3139 if(is_numeric($options[2])) {
3140 $this->session_cleanup();
3141 $_GET['tags'] = $options[2];
3142 $_SESSION['selected_tags'] = Array($options[2]);
3143 if(isset($options[3]) && is_numeric($options[3]))
3144 $_SESSION['begin_with'] = $options[3];
3145 return $this->showPhotoIndex();
3151 } // parse_user_friendly_url()
3154 * check if user-friendly-urls are enabled
3156 * this function will return true, if the config option
3157 * $user_friendly_url has been set. Otherwise false.
3160 private function is_user_friendly_url()
3162 if(isset($this->cfg->user_friendly_url) && $this->cfg->user_friendly_url)
3167 } // is_user_friendly_url()
3172 * this function will cleanup user's session information
3174 private function session_cleanup()
3176 unset($_SESSION['begin_with']);
3177 $this->resetDateSearch();
3178 $this->resetPhotoView();
3179 $this->resetTagSearch();
3180 $this->resetNameSearch();
3181 $this->resetDateSearch();
3184 } // session_cleanup()