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 /* check if all necessary indices exist */
205 $this->checkDbIndices();
207 /* if session is not yet started, do it now */
208 if(session_id() == "")
211 if(!isset($_SESSION['tag_condition']))
212 $_SESSION['tag_condition'] = 'or';
214 if(!isset($_SESSION['sort_order']))
215 $_SESSION['sort_order'] = 'date_desc';
217 if(!isset($_SESSION['searchfor_tag']))
218 $_SESSION['searchfor_tag'] = '';
220 // if begin_with is still set but thumbs_per_page is now 0, unset it
221 if(isset($_SESSION['begin_with']) && $this->cfg->thumbs_per_page == 0)
222 unset($_SESSION['begin_with']);
226 public function __destruct()
232 * show - generate html output
234 * this function can be called after the constructor has
235 * prepared everyhing. it will load the index.tpl smarty
236 * template. if necessary it will registere pre-selects
237 * (photo index, photo, tag search, date search) into
240 public function show()
242 $this->tmpl->assign('searchfor_tag', $_SESSION['searchfor_tag']);
243 $this->tmpl->assign('page_title', $this->cfg->page_title);
244 $this->tmpl->assign('current_condition', $_SESSION['tag_condition']);
245 $this->tmpl->assign('template_path', 'themes/'. $this->cfg->theme_name);
248 if($this->is_user_friendly_url()) {
249 $content = $this->parse_user_friendly_url($_SERVER['REQUEST_URI']);
252 if(isset($_GET['mode'])) {
254 $_SESSION['start_action'] = $_GET['mode'];
256 switch($_GET['mode']) {
258 if(isset($_GET['tags'])) {
259 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
261 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
262 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
264 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
265 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
269 if(isset($_GET['tags'])) {
270 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
271 $_SESSION['start_action'] = 'showp';
273 if(isset($_GET['id']) && is_numeric($_GET['id'])) {
274 $_SESSION['current_photo'] = $_GET['id'];
275 $_SESSION['start_action'] = 'showp';
277 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
278 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
280 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
281 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
285 $this->tmpl->show("export.tpl");
289 $this->tmpl->show("slideshow.tpl");
293 if(isset($_GET['tags'])) {
294 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
296 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
297 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
299 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
300 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
308 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date']))
309 $this->tmpl->assign('date_search_enabled', true);
311 $this->tmpl->register_function("sort_select_list", array(&$this, "smarty_sort_select_list"), false);
312 $this->tmpl->assign('from_date', $this->get_calendar('from'));
313 $this->tmpl->assign('to_date', $this->get_calendar('to'));
316 $this->tmpl->assign('content_page', $this->tmpl->fetch('welcome.tpl'));
318 $this->tmpl->assign('content_page', $content);
320 $this->tmpl->show("index.tpl");
325 * get_tags - grab all tags of f-spot's database
327 * this function will get all available tags from
328 * the f-spot database and store them within two
329 * arrays within this class for later usage. in
330 * fact, if the user requests (hide_tags) it will
331 * opt-out some of them.
333 * this function is getting called once by show()
335 private function get_tags()
337 $this->avail_tags = Array();
340 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
343 DISTINCT t1.id as id, t1.name as name
346 INNER JOIN photo_tags
347 pt2 ON pt1.photo_id=pt2.photo_id
353 t2.name IN ('".implode("','",$this->cfg->show_tags)."')
355 t1.sort_priority ASC";
357 $result = $this->db->db_query($query_str);
361 $result = $this->db->db_query("
364 ORDER BY sort_priority ASC
368 while($row = $this->db->db_fetch_object($result)) {
370 $tag_id = $row['id'];
371 $tag_name = $row['name'];
373 /* if the user has specified to ignore this tag in phpfspot's
374 configuration, ignore it here so it does not get added to
377 if(in_array($row['name'], $this->cfg->hide_tags))
380 /* if you include the following if-clause and the user has specified
381 to only show certain tags which are specified in phpfspot's
382 configuration, ignore all others so they will not be added to the
384 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags) &&
385 !in_array($row['name'], $this->cfg->show_tags))
389 $this->tags[$tag_id] = $tag_name;
390 $this->avail_tags[$count] = $tag_id;
398 * extract all photo details
400 * retrieve all available details from f-spot's
401 * database and return them as object
402 * @param integer $idx
403 * @return object|null
405 public function get_photo_details($idx)
407 if($this->dbver < 9) {
409 SELECT p.id, p.name, p.time, p.directory_path, p.description
415 SELECT p.id, p.uri, p.time, p.description
420 /* if show_tags is set, only return details for photos which
421 are specified to be shown
423 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
425 INNER JOIN photo_tags pt
429 WHERE p.id='". $idx ."'
430 AND t.name IN ('".implode("','",$this->cfg->show_tags)."')";
434 WHERE p.id='". $idx ."'
438 if($result = $this->db->db_query($query_str)) {
440 $row = $this->db->db_fetch_object($result);
442 if($this->dbver < 9) {
443 $row['uri'] = "file://". $row['directory_path'] ."/". $row['name'];
452 } // get_photo_details
455 * returns aligned photo names
457 * this function returns aligned (length) names for
458 * an specific photo. If the length of the name exceeds
459 * $limit the name will be shrinked (...)
460 * @param integer $idx
461 * @param integer $limit
462 * @return string|null
464 public function getPhotoName($idx, $limit = 0)
466 if($details = $this->get_photo_details($idx)) {
467 if($long_name = $this->parse_uri($details['uri'], 'filename')) {
468 $name = $this->shrink_text($long_name, $limit);
478 * shrink text according provided limit
480 * If the length of the name exceeds $limit the
481 * text will be shortend and some content in between
482 * will be replaced with "..."
484 * @param integer $limit
487 private function shrink_text($text, $limit)
489 if($limit != 0 && strlen($text) > $limit) {
490 $text = substr($text, 0, $limit-5) ."...". substr($text, -($limit-5));
498 * translate f-spoth photo path
500 * as the full-qualified path recorded in the f-spot database
501 * is usally not the same as on the webserver, this function
502 * will replace the path with that one specified in the cfg
503 * @param string $path
506 public function translate_path($path)
508 return str_replace($this->cfg->path_replace_from, $this->cfg->path_replace_to, $path);
513 * control HTML ouput for a single photo
515 * this function provides all the necessary information
516 * for the single photo template.
517 * @param integer photo
519 public function showPhoto($photo)
521 /* get all photos from the current photo selection */
522 $all_photos = $this->getPhotoSelection();
523 $count = count($all_photos);
525 for($i = 0; $i < $count; $i++) {
527 // $get_next will be set, when the photo which has to
528 // be displayed has been found - this means that the
529 // next available is in fact the NEXT image (for the
531 if(isset($get_next)) {
532 $next_img = $all_photos[$i];
536 /* the next photo is our NEXT photo */
537 if($all_photos[$i] == $photo) {
541 $previous_img = $all_photos[$i];
544 if($photo == $all_photos[$i]) {
549 $details = $this->get_photo_details($photo);
556 $orig_path = $this->translate_path($this->parse_uri($details['uri'], 'fullpath'));
557 $thumb_path = $this->get_thumb_path($this->cfg->photo_width, $photo);
559 if(!file_exists($orig_path)) {
560 $this->_error("Photo ". $orig_path ." does not exist!<br />\n");
564 if(!is_readable($orig_path)) {
565 $this->_error("Photo ". $orig_path ." is not readable for user ". $this->getuid() ."<br />\n");
569 /* If the thumbnail doesn't exist yet, try to create it */
570 if(!file_exists($thumb_path)) {
571 $this->gen_thumb($photo, true);
572 $thumb_path = $this->get_thumb_path($this->cfg->photo_width, $photo);
575 /* get mime-type, height and width from the original photo */
576 $info = getimagesize($orig_path);
578 /* get EXIF information if JPEG */
579 if($info['mime'] == "image/jpeg") {
580 $meta = $this->get_meta_informations($orig_path);
583 /* If EXIF data are available, use them */
584 if(isset($meta['ExifImageWidth'])) {
585 $meta_res = $meta['ExifImageWidth'] ."x". $meta['ExifImageLength'];
587 $meta_res = $info[0] ."x". $info[1];
590 $meta_date = isset($meta['FileDateTime']) ? strftime("%a %x %X", $meta['FileDateTime']) : "n/a";
591 $meta_make = isset($meta['Make']) ? $meta['Make'] ." / ". $meta['Model'] : "n/a";
592 $meta_size = isset($meta['FileSize']) ? round($meta['FileSize']/1024, 1) ."kbyte" : "n/a";
594 $extern_link = "index.php?mode=showp&id=". $photo;
595 $current_tags = $this->getCurrentTags();
596 if($current_tags != "") {
597 $extern_link.= "&tags=". $current_tags;
599 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
600 $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
603 $this->tmpl->assign('extern_link', $extern_link);
605 if(!file_exists($thumb_path)) {
606 $this->_error("Can't open file ". $thumb_path ."\n");
610 $info_thumb = getimagesize($thumb_path);
612 $this->tmpl->assign('description', $details['description']);
613 $this->tmpl->assign('image_name', $this->parse_uri($details['uri'], 'filename'));
615 $this->tmpl->assign('width', $info_thumb[0]);
616 $this->tmpl->assign('height', $info_thumb[1]);
617 $this->tmpl->assign('ExifMadeOn', $meta_date);
618 $this->tmpl->assign('ExifMadeWith', $meta_make);
619 $this->tmpl->assign('ExifOrigResolution', $meta_res);
620 $this->tmpl->assign('ExifFileSize', $meta_size);
622 if($this->is_user_friendly_url()) {
623 $this->tmpl->assign('image_url', '/photo/'. $photo ."/". $this->cfg->photo_width);
624 $this->tmpl->assign('image_url_full', '/photo/'. $photo);
627 $this->tmpl->assign('image_url', 'phpfspot_img.php?idx='. $photo ."&width=". $this->cfg->photo_width);
628 $this->tmpl->assign('image_url_full', 'phpfspot_img.php?idx='. $photo);
631 $this->tmpl->assign('image_filename', $this->parse_uri($details['uri'], 'filename'));
633 $this->tmpl->assign('tags', $this->get_photo_tags($photo));
634 $this->tmpl->assign('current_page', $this->getCurrentPage($current, $count));
635 $this->tmpl->assign('current_img', $photo);
638 $this->tmpl->assign('previous_url', "javascript:showImage(". $previous_img .");");
639 $this->tmpl->assign('prev_img', $previous_img);
643 $this->tmpl->assign('next_url', "javascript:showImage(". $next_img .");");
644 $this->tmpl->assign('next_img', $next_img);
646 $this->tmpl->assign('mini_width', $this->cfg->mini_width);
647 $this->tmpl->assign('photo_width', $this->cfg->photo_width);
648 $this->tmpl->assign('photo_number', $i);
649 $this->tmpl->assign('photo_count', count($all_photos));
651 return $this->tmpl->fetch("single_photo.tpl");
656 * all available tags and tag cloud
658 * this function outputs all available tags (time ordered)
659 * and in addition output them as tag cloud (tags which have
660 * many photos will appears more then others)
662 public function getAvailableTags()
664 /* retrive tags from database */
669 $result = $this->db->db_query("
670 SELECT tag_id as id, count(tag_id) as quantity
680 while($row = $this->db->db_fetch_object($result)) {
681 $tags[$row['id']] = $row['quantity'];
684 // change these font sizes if you will
685 $max_size = 125; // max font size in %
686 $min_size = 75; // min font size in %
689 $max_sat = hexdec('cc');
690 $min_sat = hexdec('44');
692 // get the largest and smallest array values
693 $max_qty = max(array_values($tags));
694 $min_qty = min(array_values($tags));
696 // find the range of values
697 $spread = $max_qty - $min_qty;
698 if (0 == $spread) { // we don't want to divide by zero
702 // determine the font-size increment
703 // this is the increase per tag quantity (times used)
704 $step = ($max_size - $min_size)/($spread);
705 $step_sat = ($max_sat - $min_sat)/($spread);
707 // loop through our tag array
708 foreach ($tags as $key => $value) {
710 if(isset($_SESSION['selected_tags']) && in_array($key, $_SESSION['selected_tags']))
713 // calculate CSS font-size
714 // find the $value in excess of $min_qty
715 // multiply by the font-size increment ($size)
716 // and add the $min_size set above
717 $size = $min_size + (($value - $min_qty) * $step);
718 // uncomment if you want sizes in whole %:
721 $color = $min_sat + ($value - $min_qty) * $step_sat;
727 if(isset($this->tags[$key])) {
728 $output.= "<a href=\"javascript:Tags('add', ". $key .");\" class=\"tag\" style=\"font-size: ". $size ."%; color: #". $r.$g.$b .";\">". $this->tags[$key] ."</a>, ";
733 $output = substr($output, 0, strlen($output)-2);
736 } // getAvailableTags()
739 * output all selected tags
741 * this function output all tags which have been selected
742 * by the user. the selected tags are stored in the
743 * session-variable $_SESSION['selected_tags']
746 public function getSelectedTags($type = 'link')
748 /* retrive tags from database */
753 foreach($this->avail_tags as $tag)
755 // return all selected tags
756 if(isset($_SESSION['selected_tags']) && in_array($tag, $_SESSION['selected_tags'])) {
761 $output.= "<a href=\"javascript:Tags('del', ". $tag .");\" class=\"tag\">". $this->tags[$tag] ."</a>, ";
765 <div style=\"display: table-cell;\">
766 <div style=\"display: table-row; text-align: center;\">
767 <a href=\"javascript:Tags('del', ". $tag .");\" title=\"". $this->tags[$tag] ."\">
768 <img src=\"phpfspot_img.php?tagidx=". $tag ."\" />
771 <div style=\"display: table-row; text-align: center;\">
772 <a href=\"javascript:Tags('del', ". $tag .");\" title=\"". $this->tags[$tag] ."\">
773 <img src=\"resources/underbar.png\" />
784 $output = substr($output, 0, strlen($output)-2);
788 return "no tags selected";
791 } // getSelectedTags()
794 * add tag to users session variable
796 * this function will add the specified to users current
797 * tag selection. if a date search has been made before
798 * it will be now cleared
801 public function addTag($tag)
803 if(!isset($_SESSION['selected_tags']))
804 $_SESSION['selected_tags'] = Array();
806 if(isset($_SESSION['searchfor_tag']))
807 unset($_SESSION['searchfor_tag']);
809 // has the user requested to hide this tag, and still someone,
810 // somehow tries to add it, don't allow this.
811 if(!isset($this->cfg->hide_tags) &&
812 in_array($this->get_tag_name($tag), $this->cfg->hide_tags))
815 if(!in_array($tag, $_SESSION['selected_tags']))
816 array_push($_SESSION['selected_tags'], $tag);
823 * remove tag to users session variable
825 * this function removes the specified tag from
826 * users current tag selection
830 public function delTag($tag)
832 if(isset($_SESSION['searchfor_tag']))
833 unset($_SESSION['searchfor_tag']);
835 if(isset($_SESSION['selected_tags'])) {
836 $key = array_search($tag, $_SESSION['selected_tags']);
837 unset($_SESSION['selected_tags'][$key]);
838 sort($_SESSION['selected_tags']);
846 * reset tag selection
848 * if there is any tag selection, it will be
851 public function resetTags()
853 if(isset($_SESSION['selected_tags']))
854 unset($_SESSION['selected_tags']);
859 * returns the value for the autocomplet tag-search
862 public function get_xml_tag_list()
864 if(!isset($_GET['search']) || !is_string($_GET['search']))
865 $_GET['search'] = '';
870 /* retrive tags from database */
873 $matched_tags = Array();
875 header("Content-Type: text/xml");
877 $string = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n";
878 $string.= "<results>\n";
880 foreach($this->avail_tags as $tag)
882 if(!empty($_GET['search']) &&
883 preg_match("/". $_GET['search'] ."/i", $this->tags[$tag]) &&
884 count($matched_tags) < $length) {
886 $count = $this->get_num_photos($tag);
889 $string.= " <rs id=\"". $i ."\" info=\"". $count ." photo\">". $this->tags[$tag] ."</rs>\n";
892 $string.= " <rs id=\"". $i ."\" info=\"". $count ." photos\">". $this->tags[$tag] ."</rs>\n";
898 /* if we have collected enough items, break out */
899 if(count($matched_tags) >= $length)
903 $string.= "</results>\n";
907 } // get_xml_tag_list()
913 * if a specific photo was requested (external link)
914 * unset the session variable now
916 public function resetPhotoView()
918 if(isset($_SESSION['current_photo']))
919 unset($_SESSION['current_photo']);
921 } // resetPhotoView();
926 * if any tag search has taken place, reset it now
928 public function resetTagSearch()
930 if(isset($_SESSION['searchfor_tag']))
931 unset($_SESSION['searchfor_tag']);
933 } // resetTagSearch()
938 * if any name search has taken place, reset it now
940 public function resetNameSearch()
942 if(isset($_SESSION['searchfor_name']))
943 unset($_SESSION['searchfor_name']);
945 } // resetNameSearch()
950 * if any date search has taken place, reset
953 public function resetDateSearch()
955 if(isset($_SESSION['from_date']))
956 unset($_SESSION['from_date']);
957 if(isset($_SESSION['to_date']))
958 unset($_SESSION['to_date']);
960 } // resetDateSearch();
963 * return all photo according selection
965 * this function returns all photos based on
966 * the tag-selection, tag- or date-search.
967 * the tag-search also has to take care of AND
968 * and OR conjunctions
971 public function getPhotoSelection()
973 $matched_photos = Array();
974 $additional_where_cond = "";
976 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
977 $from_date = $_SESSION['from_date'];
978 $to_date = $_SESSION['to_date'];
979 $additional_where_cond.= "
980 p.time>='". $from_date ."'
982 p.time<='". $to_date ."'
986 if(isset($_SESSION['searchfor_name'])) {
987 if($this->dbver < 9) {
988 $additional_where_cond.= "
990 p.name LIKE '%". $_SESSION['searchfor_name'] ."%'
992 p.description LIKE '%". $_SESSION['searchfor_name'] ."%'
997 $additional_where_cond.= "
999 basename(p.uri) LIKE '%". $_SESSION['searchfor_name'] ."%'
1001 p.description LIKE '%". $_SESSION['searchfor_name'] ."%'
1007 if(isset($_SESSION['sort_order'])) {
1008 $order_str = $this->get_sort_order();
1011 /* return a search result */
1012 if(isset($_SESSION['searchfor_tag']) && $_SESSION['searchfor_tag'] != '') {
1014 SELECT DISTINCT pt1.photo_id
1016 INNER JOIN photo_tags pt2
1017 ON pt1.photo_id=pt2.photo_id
1021 ON pt1.photo_id=p.id
1024 WHERE t.name LIKE '%". $_SESSION['searchfor_tag'] ."%' ";
1026 if(isset($additional_where_cond) && !empty($additional_where_cond))
1027 $query_str.= "AND ". $additional_where_cond ." ";
1029 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1030 $query_str.= "AND t2.name IN ('".implode("','",$this->cfg->show_tags)."')";
1033 if(isset($order_str))
1034 $query_str.= $order_str;
1036 $result = $this->db->db_query($query_str);
1037 while($row = $this->db->db_fetch_object($result)) {
1038 array_push($matched_photos, $row['photo_id']);
1040 return $matched_photos;
1043 /* return according the selected tags */
1044 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
1046 foreach($_SESSION['selected_tags'] as $tag)
1047 $selected.= $tag .",";
1048 $selected = substr($selected, 0, strlen($selected)-1);
1050 /* photo has to match at least on of the selected tags */
1051 if($_SESSION['tag_condition'] == 'or') {
1053 SELECT DISTINCT pt1.photo_id
1055 INNER JOIN photo_tags pt2
1056 ON pt1.photo_id=pt2.photo_id
1060 ON pt1.photo_id=p.id
1061 WHERE pt1.tag_id IN (". $selected .")
1063 if(isset($additional_where_cond) && !empty($additional_where_cond))
1064 $query_str.= "AND ". $additional_where_cond ." ";
1066 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1067 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags)."')";
1070 if(isset($order_str))
1071 $query_str.= $order_str;
1073 /* photo has to match all selected tags */
1074 elseif($_SESSION['tag_condition'] == 'and') {
1076 if(count($_SESSION['selected_tags']) >= 32) {
1077 print "A SQLite limit of 32 tables within a JOIN SELECT avoids to<br />\n";
1078 print "evaluate your tag selection. Please remove some tags from your selection.\n";
1082 /* Join together a table looking like
1084 pt1.photo_id pt1.tag_id pt2.photo_id pt2.tag_id ...
1086 so the query can quickly return all images matching the
1087 selected tags in an AND condition
1092 SELECT DISTINCT pt1.photo_id
1096 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1103 for($i = 0; $i < count($_SESSION['selected_tags']); $i++) {
1105 INNER JOIN photo_tags pt". ($i+2) ."
1106 ON pt1.photo_id=pt". ($i+2) .".photo_id
1111 ON pt1.photo_id=p.id
1113 $query_str.= "WHERE pt2.tag_id=". $_SESSION['selected_tags'][0]." ";
1114 for($i = 1; $i < count($_SESSION['selected_tags']); $i++) {
1116 AND pt". ($i+2) .".tag_id=". $_SESSION['selected_tags'][$i] ."
1119 if(isset($additional_where_cond) && !empty($additional_where_cond))
1120 $query_str.= "AND ". $additional_where_cond;
1122 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1123 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags). "')";
1126 if(isset($order_str))
1127 $query_str.= $order_str;
1131 $result = $this->db->db_query($query_str);
1132 while($row = $this->db->db_fetch_object($result)) {
1133 array_push($matched_photos, $row['photo_id']);
1135 return $matched_photos;
1138 /* return all available photos */
1140 SELECT DISTINCT p.id
1142 LEFT JOIN photo_tags pt
1148 if(isset($additional_where_cond) && !empty($additional_where_cond))
1149 $query_str.= "WHERE ". $additional_where_cond ." ";
1151 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1152 if(isset($additional_where_cond) && !empty($additional_where_cond))
1153 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags). "')";
1155 $query_str.= "WHERE t.name IN ('".implode("','",$this->cfg->show_tags). "')";
1158 if(isset($order_str))
1159 $query_str.= $order_str;
1161 $result = $this->db->db_query($query_str);
1162 while($row = $this->db->db_fetch_object($result)) {
1163 array_push($matched_photos, $row['id']);
1165 return $matched_photos;
1167 } // getPhotoSelection()
1170 * control HTML ouput for photo index
1172 * this function provides all the necessary information
1173 * for the photo index template.
1175 public function showPhotoIndex()
1177 $photos = $this->getPhotoSelection();
1179 $count = count($photos);
1181 /* if all thumbnails should be shown on one page */
1182 if(!isset($this->cfg->thumbs_per_page) || $this->cfg->thumbs_per_page == 0) {
1186 /* thumbnails should be splitted up in several pages */
1187 elseif($this->cfg->thumbs_per_page > 0) {
1189 if(!isset($_SESSION['begin_with']) || $_SESSION['begin_with'] == 0) {
1193 $begin_with = $_SESSION['begin_with'];
1196 $end_with = $begin_with + $this->cfg->thumbs_per_page;
1200 $images[$thumbs] = Array();
1201 $img_height[$thumbs] = Array();
1202 $img_width[$thumbs] = Array();
1203 $img_id[$thumbs] = Array();
1204 $img_name[$thumbs] = Array();
1205 $img_fullname[$thumbs] = Array();
1206 $img_title = Array();
1208 for($i = $begin_with; $i < $end_with; $i++) {
1210 if(isset($photos[$i])) {
1212 $images[$thumbs] = $photos[$i];
1213 $img_id[$thumbs] = $i;
1214 $img_name[$thumbs] = htmlspecialchars($this->getPhotoName($photos[$i], 15));
1215 $img_fullname[$thumbs] = htmlspecialchars($this->getPhotoName($photos[$i], 0));
1216 $img_title[$thumbs] = "Click to view photo ". htmlspecialchars($this->getPhotoName($photos[$i], 0));
1218 $thumb_path = $this->get_thumb_path($this->cfg->thumb_width, $photos[$i]);
1220 if(file_exists($thumb_path)) {
1221 $info = getimagesize($thumb_path);
1222 $img_width[$thumbs] = $info[0];
1223 $img_height[$thumbs] = $info[1];
1229 // +1 for for smarty's selection iteration
1232 if(isset($_SESSION['searchfor_tag']) && $_SESSION['searchfor_tag'] != '')
1233 $this->tmpl->assign('searchfor_tag', $_SESSION['searchfor_tag']);
1235 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1236 $this->tmpl->assign('from_date', $this->ts2str($_SESSION['from_date']));
1237 $this->tmpl->assign('to_date', $this->ts2str($_SESSION['to_date']));
1240 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
1241 $this->tmpl->assign('tag_result', 1);
1244 /* do we have to display the page selector ? */
1245 if($this->cfg->thumbs_per_page != 0) {
1249 /* calculate the page switchers */
1250 $previous_start = $begin_with - $this->cfg->thumbs_per_page;
1251 $next_start = $begin_with + $this->cfg->thumbs_per_page;
1253 if($begin_with != 0)
1254 $this->tmpl->assign("previous_url", "javascript:showPhotoIndex(". $previous_start .");");
1255 if($end_with < $count)
1256 $this->tmpl->assign("next_url", "javascript:showPhotoIndex(". $next_start .");");
1258 $photo_per_page = $this->cfg->thumbs_per_page;
1259 $last_page = ceil($count / $photo_per_page);
1261 /* get the current selected page */
1262 if($begin_with == 0) {
1266 for($i = $begin_with; $i >= 0; $i-=$photo_per_page) {
1273 for($i = 1; $i <= $last_page; $i++) {
1275 if($current_page == $i)
1276 $style = "style=\"font-size: 125%; text-decoration: underline;\"";
1277 elseif($current_page-1 == $i || $current_page+1 == $i)
1278 $style = "style=\"font-size: 105%;\"";
1279 elseif(($current_page-5 >= $i) && ($i != 1) ||
1280 ($current_page+5 <= $i) && ($i != $last_page))
1281 $style = "style=\"font-size: 75%;\"";
1285 $select = "<a href=\"javascript:showPhotoIndex(". (($i*$photo_per_page)-$photo_per_page) .");\"";
1288 $select.= ">". $i ."</a> ";
1290 // until 9 pages we show the selector from 1-9
1291 if($last_page <= 9) {
1292 $page_select.= $select;
1295 if($i == 1 /* first page */ ||
1296 $i == $last_page /* last page */ ||
1297 $i == $current_page /* current page */ ||
1298 $i == ceil($last_page * 0.25) /* first quater */ ||
1299 $i == ceil($last_page * 0.5) /* half */ ||
1300 $i == ceil($last_page * 0.75) /* third quater */ ||
1301 (in_array($i, array(1,2,3,4,5,6)) && $current_page <= 4) /* the first 6 */ ||
1302 (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 */ ||
1303 $i == $current_page-3 || $i == $current_page-2 || $i == $current_page-1 /* three before */ ||
1304 $i == $current_page+3 || $i == $current_page+2 || $i == $current_page+1 /* three after */) {
1306 $page_select.= $select;
1314 $page_select.= "......... ";
1319 /* only show the page selector if we have more then one page */
1321 $this->tmpl->assign('page_selector', $page_select);
1325 $current_tags = $this->getCurrentTags();
1326 $extern_link = "index.php?mode=showpi";
1327 $rss_link = "index.php?mode=rss";
1328 if($current_tags != "") {
1329 $extern_link.= "&tags=". $current_tags;
1330 $rss_link.= "&tags=". $current_tags;
1332 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1333 $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
1334 $rss_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
1337 $export_link = "index.php?mode=export";
1338 $slideshow_link = "index.php?mode=slideshow";
1340 $this->tmpl->assign('extern_link', $extern_link);
1341 $this->tmpl->assign('slideshow_link', $slideshow_link);
1342 $this->tmpl->assign('export_link', $export_link);
1343 $this->tmpl->assign('rss_link', $rss_link);
1344 $this->tmpl->assign('count', $count);
1345 $this->tmpl->assign('width', $this->cfg->thumb_width);
1346 $this->tmpl->assign('preview_width', $this->cfg->photo_width);
1347 $this->tmpl->assign('thumb_container_width', $this->cfg->thumb_width);
1348 $this->tmpl->assign('thumb_container_height', $this->cfg->thumb_height+20);
1349 $this->tmpl->assign('images', $images);
1350 $this->tmpl->assign('img_width', $img_width);
1351 $this->tmpl->assign('img_height', $img_height);
1352 $this->tmpl->assign('img_id', $img_id);
1353 $this->tmpl->assign('img_name', $img_name);
1354 $this->tmpl->assign('img_fullname', $img_fullname);
1355 $this->tmpl->assign('img_title', $img_title);
1356 $this->tmpl->assign('thumbs', $thumbs);
1357 $this->tmpl->assign('selected_tags', $this->getSelectedTags('img'));
1359 $result = $this->tmpl->fetch("photo_index.tpl");
1361 /* if we are returning to photo index from an photo-view,
1362 scroll the window to the last shown photo-thumbnail.
1363 after this, unset the last_photo session variable.
1365 if(isset($_SESSION['last_photo'])) {
1366 $result.= "<script language=\"JavaScript\">moveToThumb(". $_SESSION['last_photo'] .");</script>\n";
1367 unset($_SESSION['last_photo']);
1372 } // showPhotoIndex()
1375 * show credit template
1377 public function showCredits()
1379 $this->tmpl->assign('version', $this->cfg->version);
1380 $this->tmpl->assign('product', $this->cfg->product);
1381 $this->tmpl->assign('db_version', $this->dbver);
1382 $this->tmpl->show("credits.tpl");
1387 * create thumbnails for the requested width
1389 * this function creates image thumbnails of $orig_image
1390 * stored as $thumb_image. It will check if the image is
1391 * in a supported format, if necessary rotate the image
1392 * (based on EXIF orientation meta headers) and re-sizing.
1393 * @param string $orig_image
1394 * @param string $thumb_image
1395 * @param integer $width
1398 public function create_thumbnail($orig_image, $thumb_image, $width)
1400 if(!file_exists($orig_image)) {
1404 $mime = $this->get_mime_info($orig_image);
1406 /* check if original photo is a support image type */
1407 if(!$this->checkifImageSupported($mime))
1414 $meta = $this->get_meta_informations($orig_image);
1420 switch($meta['Orientation']) {
1421 case 1: /* top, left */
1422 /* nothing to do */ break;
1423 case 2: /* top, right */
1424 $rotate = 0; $flip_hori = true; break;
1425 case 3: /* bottom, left */
1426 $rotate = 180; break;
1427 case 4: /* bottom, right */
1428 $flip_vert = true; break;
1429 case 5: /* left side, top */
1430 $rotate = 90; $flip_vert = true; break;
1431 case 6: /* right side, top */
1432 $rotate = 90; break;
1433 case 7: /* left side, bottom */
1434 $rotate = 270; $flip_vert = true; break;
1435 case 8: /* right side, bottom */
1436 $rotate = 270; break;
1439 $src_img = @imagecreatefromjpeg($orig_image);
1445 $src_img = @imagecreatefrompng($orig_image);
1449 case 'image/x-portable-pixmap':
1451 $src_img = new Imagick($orig_image);
1452 $handler = "imagick";
1457 if(!isset($src_img) || empty($src_img)) {
1458 print "Can't load image from ". $orig_image ."\n";
1466 /* grabs the height and width */
1467 $cur_width = imagesx($src_img);
1468 $cur_height = imagesy($src_img);
1470 // If requested width is more then the actual image width,
1471 // do not generate a thumbnail, instead safe the original
1472 // as thumbnail but with lower quality. But if the image
1473 // is to heigh too, then we still have to resize it.
1474 if($width >= $cur_width && $cur_height < $this->cfg->thumb_height) {
1475 $result = imagejpeg($src_img, $thumb_image, 75);
1476 imagedestroy($src_img);
1483 $cur_width = $src_img->getImageWidth();
1484 $cur_height = $src_img->getImageHeight();
1486 // If requested width is more then the actual image width,
1487 // do not generate a thumbnail, instead safe the original
1488 // as thumbnail but with lower quality. But if the image
1489 // is to heigh too, then we still have to resize it.
1490 if($width >= $cur_width && $cur_height < $this->cfg->thumb_height) {
1491 $src_img->setCompressionQuality(75);
1492 $src_img->setImageFormat('jpeg');
1493 $src_img->writeImage($thumb_image);
1495 $src_img->destroy();
1502 // If the image will be rotate because EXIF orientation said so
1503 // 'virtually rotate' the image for further calculations
1504 if($rotate == 90 || $rotate == 270) {
1506 $cur_width = $cur_height;
1510 /* calculates aspect ratio */
1511 $aspect_ratio = $cur_height / $cur_width;
1514 if($aspect_ratio < 1) {
1516 $new_h = abs($new_w * $aspect_ratio);
1518 /* 'virtually' rotate the image and calculate it's ratio */
1519 $tmp_w = $cur_height;
1520 $tmp_h = $cur_width;
1521 /* now get the ratio from the 'rotated' image */
1522 $tmp_ratio = $tmp_h/$tmp_w;
1523 /* now calculate the new dimensions */
1525 $tmp_h = abs($tmp_w * $tmp_ratio);
1527 // now that we know, how high they photo should be, if it
1528 // gets rotated, use this high to scale the image
1530 $new_w = abs($new_h / $aspect_ratio);
1532 // If the image will be rotate because EXIF orientation said so
1533 // now 'virtually rotate' back the image for the image manipulation
1534 if($rotate == 90 || $rotate == 270) {
1545 /* creates new image of that size */
1546 $dst_img = imagecreatetruecolor($new_w, $new_h);
1548 imagefill($dst_img, 0, 0, ImageColorAllocate($dst_img, 255, 255, 255));
1550 /* copies resized portion of original image into new image */
1551 imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $new_w, $new_h, imagesx($src_img), imagesy($src_img));
1553 /* needs the image to be flipped horizontal? */
1555 $this->_debug("(FLIP)");
1556 $dst_img = $this->flipImage($dst_img, 'hori');
1558 /* needs the image to be flipped vertical? */
1560 $this->_debug("(FLIP)");
1561 $dst_img = $this->flipImage($dst_img, 'vert');
1565 $this->_debug("(ROTATE)");
1566 $dst_img = $this->rotateImage($dst_img, $rotate);
1569 /* write down new generated file */
1570 $result = imagejpeg($dst_img, $thumb_image, 75);
1572 /* free your mind */
1573 imagedestroy($dst_img);
1574 imagedestroy($src_img);
1576 if($result === false) {
1577 print "Can't write thumbnail ". $thumb_image ."\n";
1587 $src_img->resizeImage($new_w, $new_h, Imagick::FILTER_LANCZOS, 1);
1589 /* needs the image to be flipped horizontal? */
1591 $this->_debug("(FLIP)");
1592 $src_img->rotateImage(new ImagickPixel(), 90);
1593 $src_img->flipImage();
1594 $src_img->rotateImage(new ImagickPixel(), -90);
1596 /* needs the image to be flipped vertical? */
1598 $this->_debug("(FLIP)");
1599 $src_img->flipImage();
1603 $this->_debug("(ROTATE)");
1604 $src_img->rotateImage(new ImagickPixel(), $rotate);
1607 $src_img->setCompressionQuality(75);
1608 $src_img->setImageFormat('jpeg');
1610 if(!$src_img->writeImage($thumb_image)) {
1611 print "Can't write thumbnail ". $thumb_image ."\n";
1616 $src_img->destroy();
1623 } // create_thumbnail()
1626 * return all exif meta data from the file
1627 * @param string $file
1630 public function get_meta_informations($file)
1632 return exif_read_data($file);
1634 } // get_meta_informations()
1637 * create phpfspot own sqlite database
1639 * this function creates phpfspots own sqlite database
1640 * if it does not exist yet. this own is used to store
1641 * some necessary informations (md5 sum's, ...).
1643 public function check_config_table()
1645 // if the config table doesn't exist yet, create it
1646 if(!$this->cfg_db->db_check_table_exists("images")) {
1647 $this->cfg_db->db_exec("
1648 CREATE TABLE images (
1649 img_idx int primary key,
1655 } // check_config_table
1658 * Generates a thumbnail from photo idx
1660 * This function will generate JPEG thumbnails from provided F-Spot photo
1663 * 1. Check if all thumbnail generations (width) are already in place and
1665 * 2. Check if the md5sum of the original file has changed
1666 * 3. Generate the thumbnails if needed
1667 * @param integer $idx
1668 * @param integer $force
1669 * @param boolean $overwrite
1671 public function gen_thumb($idx = 0, $force = 0, $overwrite = false)
1675 $resolutions = Array(
1676 $this->cfg->thumb_width,
1677 $this->cfg->photo_width,
1678 $this->cfg->mini_width,
1682 /* get details from F-Spot's database */
1683 $details = $this->get_photo_details($idx);
1685 /* calculate file MD5 sum */
1686 $full_path = $this->translate_path($this->parse_uri($details['uri'], 'fullpath'));
1688 if(!file_exists($full_path)) {
1689 $this->_error("File ". $full_path ." does not exist\n");
1693 if(!is_readable($full_path)) {
1694 $this->_error("File ". $full_path ." is not readable for ". $this->getuid() ."\n");
1698 $this->_debug("Image [". $idx ."] ". $this->shrink_text($this->parse_uri($details['uri'], 'filename'), 20) ." Thumbnails:");
1700 /* If Nikon NEF format, we need to treat it another way */
1701 if(isset($this->cfg->dcraw_bin) &&
1702 file_exists($this->cfg->dcraw_bin) &&
1703 is_executable($this->cfg->dcraw_bin) &&
1704 preg_match('/\.nef$/i', $details['uri'])) {
1706 $ppm_path = preg_replace('/\.nef$/i', '.ppm', $full_path);
1708 /* if PPM file does not exist, let dcraw convert it from NEF */
1709 if(!file_exists($ppm_path)) {
1710 system($this->cfg->dcraw_bin ." -a ". $full_path);
1713 /* for now we handle the PPM instead of the NEF */
1714 $full_path = $ppm_path;
1718 $file_md5 = md5_file($full_path);
1721 foreach($resolutions as $resolution) {
1723 $generate_it = false;
1725 $thumb_sub_path = substr($file_md5, 0, 2);
1726 $thumb_path = $this->cfg->thumb_path ."/". $thumb_sub_path ."/". $resolution ."_". $file_md5;
1728 /* if thumbnail-subdirectory does not exist yet, create it */
1729 if(!file_exists(dirname($thumb_path))) {
1730 mkdir(dirname($thumb_path), 0755);
1733 /* if the thumbnail file doesn't exist, create it */
1734 if(!file_exists($thumb_path)) {
1735 $generate_it = true;
1737 /* if the file hasn't changed there is no need to regen the thumb */
1738 elseif($file_md5 != $this->getMD5($idx) || $force) {
1739 $generate_it = true;
1742 if($generate_it || $overwrite) {
1744 $this->_debug(" ". $resolution ."px");
1745 if(!$this->create_thumbnail($full_path, $thumb_path, $resolution))
1753 $this->_debug(" already exist");
1756 /* set the new/changed MD5 sum for the current photo */
1758 $this->setMD5($idx, $file_md5);
1761 $this->_debug("\n");
1766 * returns stored md5 sum for a specific photo
1768 * this function queries the phpfspot database for a
1769 * stored MD5 checksum of the specified photo
1770 * @param integer $idx
1771 * @return string|null
1773 public function getMD5($idx)
1775 $result = $this->cfg_db->db_query("
1778 WHERE img_idx='". $idx ."'
1784 $img = $this->cfg_db->db_fetch_object($result);
1785 return $img['img_md5'];
1790 * set MD5 sum for the specific photo
1791 * @param integer $idx
1792 * @param string $md5
1794 private function setMD5($idx, $md5)
1796 $result = $this->cfg_db->db_exec("
1797 REPLACE INTO images (img_idx, img_md5)
1798 VALUES ('". $idx ."', '". $md5 ."')
1804 * store current tag condition
1806 * this function stores the current tag condition
1807 * (AND or OR) in the users session variables
1808 * @param string $mode
1811 public function setTagCondition($mode)
1813 $_SESSION['tag_condition'] = $mode;
1817 } // setTagCondition()
1820 * invoke tag & date search
1822 * this function will return all matching tags and store
1823 * them in the session variable selected_tags. furthermore
1824 * it also handles the date search.
1825 * getPhotoSelection() will then only return the matching
1829 public function startSearch()
1831 if(isset($_POST['from']) && $this->isValidDate($_POST['from'])) {
1832 $from = $_POST['from'];
1834 if(isset($_POST['to']) && $this->isValidDate($_POST['to'])) {
1838 if(isset($_POST['for_tag']) && is_string($_POST['for_tag'])) {
1839 $searchfor_tag = $_POST['for_tag'];
1840 $_SESSION['searchfor_tag'] = $_POST['for_tag'];
1843 if(isset($_POST['for_name']) && is_string($_POST['for_name'])) {
1844 $searchfor_name = $_POST['for_name'];
1845 $_SESSION['searchfor_name'] = $_POST['for_name'];
1850 if(isset($from) && !empty($from))
1851 $_SESSION['from_date'] = strtotime($from ." 00:00:00");
1853 unset($_SESSION['from_date']);
1855 if(isset($to) && !empty($to))
1856 $_SESSION['to_date'] = strtotime($to ." 23:59:59");
1858 unset($_SESSION['to_date']);
1860 if(isset($searchfor_tag) && !empty($searchfor_tag)) {
1861 /* new search, reset the current selected tags */
1862 $_SESSION['selected_tags'] = Array();
1863 foreach($this->avail_tags as $tag) {
1864 if(preg_match('/'. $searchfor_tag .'/i', $this->tags[$tag]))
1865 array_push($_SESSION['selected_tags'], $tag);
1874 * updates sort order in session variable
1876 * this function is invoked by RPC and will sort the requested
1877 * sort order in the session variable.
1878 * @param string $sort_order
1881 public function updateSortOrder($order)
1883 if(isset($this->sort_orders[$order])) {
1884 $_SESSION['sort_order'] = $order;
1888 return "unkown error";
1890 } // updateSortOrder()
1895 * this function rotates the image according the
1897 * @param string $img
1898 * @param integer $degress
1901 private function rotateImage($img, $degrees)
1903 if(function_exists("imagerotate")) {
1904 $img = imagerotate($img, $degrees, 0);
1906 function imagerotate($src_img, $angle)
1908 $src_x = imagesx($src_img);
1909 $src_y = imagesy($src_img);
1910 if ($angle == 180) {
1914 elseif ($src_x <= $src_y) {
1918 elseif ($src_x >= $src_y) {
1923 $rotate=imagecreatetruecolor($dest_x,$dest_y);
1924 imagealphablending($rotate, false);
1929 for ($y = 0; $y < ($src_y); $y++) {
1930 for ($x = 0; $x < ($src_x); $x++) {
1931 $color = imagecolorat($src_img, $x, $y);
1932 imagesetpixel($rotate, $dest_x - $y - 1, $x, $color);
1938 for ($y = 0; $y < ($src_y); $y++) {
1939 for ($x = 0; $x < ($src_x); $x++) {
1940 $color = imagecolorat($src_img, $x, $y);
1941 imagesetpixel($rotate, $y, $dest_y - $x - 1, $color);
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 - $x - 1, $dest_y - $y - 1, $color);
1964 $img = imagerotate($img, $degrees);
1973 * returns flipped image
1975 * this function will return an either horizontal or
1976 * vertical flipped truecolor image.
1977 * @param string $image
1978 * @param string $mode
1981 private function flipImage($image, $mode)
1983 $w = imagesx($image);
1984 $h = imagesy($image);
1985 $flipped = imagecreatetruecolor($w, $h);
1989 for ($y = 0; $y < $h; $y++) {
1990 imagecopy($flipped, $image, 0, $y, 0, $h - $y - 1, $w, 1);
1994 for ($x = 0; $x < $w; $x++) {
1995 imagecopy($flipped, $image, $x, 0, $w - $x - 1, 0, 1, $h);
2005 * return all assigned tags for the specified photo
2006 * @param integer $idx
2009 private function get_photo_tags($idx)
2011 $result = $this->db->db_query("
2014 INNER JOIN photo_tags pt
2016 WHERE pt.photo_id='". $idx ."'
2021 while($row = $this->db->db_fetch_object($result)) {
2022 if(isset($this->cfg->hide_tags) && in_array($row['name'], $this->cfg->hide_tags))
2024 $tags[$row['id']] = $row['name'];
2029 } // get_photo_tags()
2032 * create on-the-fly images with text within
2033 * @param string $txt
2034 * @param string $color
2035 * @param integer $space
2036 * @param integer $font
2039 public function showTextImage($txt, $color=000000, $space=4, $font=4, $w=300)
2041 if (strlen($color) != 6)
2044 $int = hexdec($color);
2045 $h = imagefontheight($font);
2046 $fw = imagefontwidth($font);
2047 $txt = explode("\n", wordwrap($txt, ($w / $fw), "\n"));
2048 $lines = count($txt);
2049 $im = imagecreate($w, (($h * $lines) + ($lines * $space)));
2050 $bg = imagecolorallocate($im, 255, 255, 255);
2051 $color = imagecolorallocate($im, 0xFF & ($int >> 0x10), 0xFF & ($int >> 0x8), 0xFF & $int);
2054 foreach ($txt as $text) {
2055 $x = (($w - ($fw * strlen($text))) / 2);
2056 imagestring($im, $font, $x, $y, $text, $color);
2057 $y += ($h + $space);
2060 Header("Content-type: image/png");
2063 } // showTextImage()
2066 * check if all requirements are met
2069 private function check_requirements()
2071 if(!function_exists("imagecreatefromjpeg")) {
2072 print "PHP GD library extension is missing<br />\n";
2076 if($this->cfg->db_access == "native" && !function_exists("sqlite3_open")) {
2077 print "PHP SQLite3 library extension is missing<br />\n";
2081 /* Check for HTML_AJAX PEAR package, lent from Horde project */
2082 ini_set('track_errors', 1);
2083 @include_once 'HTML/AJAX/Server.php';
2084 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
2085 print "PEAR HTML_AJAX package is missing<br />\n";
2088 @include_once 'Calendar/Calendar.php';
2089 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
2090 print "PEAR Calendar package is missing<br />\n";
2093 @include_once 'Console/Getopt.php';
2094 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
2095 print "PEAR Console_Getopt package is missing<br />\n";
2098 @include_once $this->cfg->smarty_path .'/libs/Smarty.class.php';
2099 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
2100 print "Smarty template engine can not be found in ". $this->cfg->smarty_path ."/libs/Smarty.class.php<br />\n";
2103 ini_restore('track_errors');
2110 } // check_requirements()
2112 private function _debug($text)
2114 if($this->fromcmd) {
2121 * check if specified MIME type is supported
2122 * @param string $mime
2125 public function checkifImageSupported($mime)
2127 $supported_types = Array(
2130 "image/x-portable-pixmap",
2134 if(in_array($mime, $supported_types))
2139 } // checkifImageSupported()
2143 * @param string $text
2145 public function _error($text)
2147 switch($this->cfg->logging) {
2150 print "<img src=\"resources/green_info.png\" alt=\"warning\" />\n";
2151 print $text ."<br />\n";
2157 error_log($text, 3, $his->cfg->log_file);
2161 $this->runtime_error = true;
2166 * output calendard input fields
2167 * @param string $mode
2170 private function get_calendar($mode)
2172 $year = isset($_SESSION[$mode .'_date']) ? date("Y", $_SESSION[$mode .'_date']) : date("Y");
2173 $month = isset($_SESSION[$mode .'_date']) ? date("m", $_SESSION[$mode .'_date']) : date("m");
2174 $day = isset($_SESSION[$mode .'_date']) ? date("d", $_SESSION[$mode .'_date']) : date("d");
2176 $output = "<input type=\"text\" size=\"3\" id=\"". $mode ."year\" value=\"". $year ."\"";
2177 if(!isset($_SESSION[$mode .'_date']))
2178 $output.= " disabled=\"disabled\"";
2180 $output.= "<input type=\"text\" size=\"1\" id=\"". $mode ."month\" value=\"". $month ."\"";
2181 if(!isset($_SESSION[$mode .'_date']))
2182 $output.= " disabled=\"disabled\"";
2184 $output.= "<input type=\"text\" size=\"1\" id=\"". $mode ."day\" value=\"". $day ."\"";
2185 if(!isset($_SESSION[$mode .'_date']))
2186 $output.= " disabled=\"disabled\"";
2194 * output calendar matrix
2195 * @param integer $year
2196 * @param integer $month
2197 * @param integer $day
2199 public function get_calendar_matrix($year = 0, $month = 0, $day = 0)
2201 if (!isset($year)) $year = date('Y');
2202 if (!isset($month)) $month = date('m');
2203 if (!isset($day)) $day = date('d');
2208 require_once CALENDAR_ROOT.'Month/Weekdays.php';
2209 require_once CALENDAR_ROOT.'Day.php';
2212 $month = new Calendar_Month_Weekdays($year,$month);
2215 $prevStamp = $month->prevMonth(true);
2216 $prev = "javascript:setMonth(". date('Y',$prevStamp) .", ". date('n',$prevStamp) .", ". date('j',$prevStamp) .");";
2217 $nextStamp = $month->nextMonth(true);
2218 $next = "javascript:setMonth(". date('Y',$nextStamp) .", ". date('n',$nextStamp) .", ". date('j',$nextStamp) .");";
2220 $selectedDays = array (
2221 new Calendar_Day($year,$month,$day),
2222 new Calendar_Day($year,12,25),
2225 // Build the days in the month
2226 $month->build($selectedDays);
2228 $this->tmpl->assign('current_month', date('F Y',$month->getTimeStamp()));
2229 $this->tmpl->assign('prev_month', $prev);
2230 $this->tmpl->assign('next_month', $next);
2232 while ( $day = $month->fetch() ) {
2234 if(!isset($matrix[$rows]))
2235 $matrix[$rows] = Array();
2239 $dayStamp = $day->thisDay(true);
2240 $link = "javascript:setCalendarDate(". date('Y',$dayStamp) .", ". date('n',$dayStamp).", ". date('j',$dayStamp) .");";
2242 // isFirst() to find start of week
2243 if ( $day->isFirst() )
2246 if ( $day->isSelected() ) {
2247 $string.= "<td class=\"selected\">".$day->thisDay()."</td>\n";
2248 } else if ( $day->isEmpty() ) {
2249 $string.= "<td> </td>\n";
2251 $string.= "<td><a class=\"calendar\" href=\"".$link."\">".$day->thisDay()."</a></td>\n";
2254 // isLast() to find end of week
2255 if ( $day->isLast() )
2256 $string.= "</tr>\n";
2258 $matrix[$rows][$cols] = $string;
2268 $this->tmpl->assign('matrix', $matrix);
2269 $this->tmpl->assign('rows', $rows);
2270 $this->tmpl->show("calendar.tpl");
2272 } // get_calendar_matrix()
2275 * output export page
2276 * @param string $mode
2278 public function getExport($mode)
2280 $pictures = $this->getPhotoSelection();
2281 $current_tags = $this->getCurrentTags();
2283 foreach($pictures as $picture) {
2285 $orig_url = $this->get_phpfspot_url() ."/index.php?mode=showp&id=". $picture;
2286 if($current_tags != "") {
2287 $orig_url.= "&tags=". $current_tags;
2289 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
2290 $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
2293 if($this->is_user_friendly_url()) {
2294 $thumb_url = $this->get_phpfspot_url() ."/photo/". $picture ."/". $this->cfg->thumb_width;
2297 $thumb_url = $this->get_phpfspot_url() ."/phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
2303 // <a href="%pictureurl%"><img src="%thumbnailurl%" ></a>
2304 print htmlspecialchars("<a href=\"". $orig_url ."\"><img src=\"". $thumb_url ."\" /></a>") ."<br />\n";
2308 // "[%pictureurl% %thumbnailurl%]"
2309 print htmlspecialchars("[".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
2312 case 'MoinMoinList':
2313 // " * [%pictureurl% %thumbnailurl%]"
2314 print " " . htmlspecialchars("* [".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
2325 public function getRSSFeed()
2327 Header("Content-type: text/xml; charset=utf-8");
2328 print "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
2331 xmlns:media="http://search.yahoo.com/mrss/"
2332 xmlns:dc="http://purl.org/dc/elements/1.1/"
2335 <title>phpfspot</title>
2336 <description>phpfspot RSS feed</description>
2337 <link><?php print htmlspecialchars($this->get_phpfspot_url()); ?></link>
2338 <pubDate><?php print strftime("%a, %d %b %Y %T %z"); ?></pubDate>
2339 <generator>phpfspot</generator>
2342 $pictures = $this->getPhotoSelection();
2343 $current_tags = $this->getCurrentTags();
2345 foreach($pictures as $picture) {
2347 $orig_url = $this->get_phpfspot_url() ."/index.php?mode=showp&id=". $picture;
2348 if($current_tags != "") {
2349 $orig_url.= "&tags=". $current_tags;
2351 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
2352 $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
2355 $details = $this->get_photo_details($picture);
2357 if($this->is_user_friendly_url()) {
2358 $thumb_url = $this->get_phpfspot_url() ."/photo/". $picture ."/". $this->cfg->thumb_width;
2361 $thumb_url = $this->get_phpfspot_url() ."/phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
2364 $thumb_html = htmlspecialchars("
2365 <a href=\"". $orig_url ."\"><img src=\"". $thumb_url ."\" /></a>
2367 ". $details['description']);
2369 $orig_path = $this->translate_path($this->parse_uri($details['uri'], 'fullpath'));
2371 /* get EXIF information if JPEG */
2372 if($details['mime'] == "image/jpeg") {
2373 $meta = $this->get_meta_informations($orig_path);
2376 $meta_date = isset($meta['FileDateTime']) ? $meta['FileDateTime'] : filemtime($orig_path);
2380 <title><?php print htmlspecialchars($this->parse_uri($details['uri'], 'filename')); ?></title>
2381 <link><?php print htmlspecialchars($orig_url); ?></link>
2382 <guid><?php print htmlspecialchars($orig_url); ?></guid>
2383 <dc:date.Taken><?php print strftime("%Y-%m-%dT%H:%M:%S+00:00", $meta_date); ?></dc:date.Taken>
2385 <?php print $thumb_html; ?>
2387 <pubDate><?php print strftime("%a, %d %b %Y %T %z", $meta_date); ?></pubDate>
2402 * return all selected tags as one string
2405 private function getCurrentTags()
2408 if(isset($_SESSION['selected_tags']) && $_SESSION['selected_tags'] != "") {
2409 foreach($_SESSION['selected_tags'] as $tag)
2410 $current_tags.= $tag .",";
2411 $current_tags = substr($current_tags, 0, strlen($current_tags)-1);
2413 return $current_tags;
2415 } // getCurrentTags()
2418 * return the current photo
2420 public function getCurrentPhoto()
2422 if(isset($_SESSION['current_photo'])) {
2423 print $_SESSION['current_photo'];
2425 } // getCurrentPhoto()
2428 * tells the client browser what to do
2430 * this function is getting called via AJAX by the
2431 * client browsers. it will tell them what they have
2432 * to do next. This is necessary for directly jumping
2433 * into photo index or single photo view when the are
2434 * requested with specific URLs
2437 public function whatToDo()
2439 if(isset($_SESSION['current_photo']) && $_SESSION['start_action'] == 'showp') {
2440 return "show_photo";
2442 elseif(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
2443 return "showpi_tags";
2445 elseif(isset($_SESSION['start_action']) && $_SESSION['start_action'] == 'showpi') {
2449 return "nothing special";
2454 * return the current process-user
2457 private function getuid()
2459 if($uid = posix_getuid()) {
2460 if($user = posix_getpwuid($uid)) {
2461 return $user['name'];
2470 * returns a select-dropdown box to select photo index sort parameters
2471 * @param array $params
2472 * @param smarty $smarty
2475 public function smarty_sort_select_list($params, &$smarty)
2479 foreach($this->sort_orders as $key => $value) {
2480 $output.= "<option value=\"". $key ."\"";
2481 if($key == $_SESSION['sort_order']) {
2482 $output.= " selected=\"selected\"";
2484 $output.= ">". $value ."</option>";
2489 } // smarty_sort_select_list()
2492 * returns the currently selected sort order
2495 private function get_sort_order()
2497 switch($_SESSION['sort_order']) {
2499 return " ORDER BY p.time ASC";
2502 return " ORDER BY p.time DESC";
2505 if($this->dbver < 9) {
2506 return " ORDER BY p.name ASC";
2509 return " ORDER BY basename(p.uri) ASC";
2513 if($this->dbver < 9) {
2514 return " ORDER BY p.name DESC";
2517 return " ORDER BY basename(p.uri) DESC";
2521 return " ORDER BY t.name ASC ,p.time ASC";
2524 return " ORDER BY t.name DESC ,p.time ASC";
2528 } // get_sort_order()
2531 * return the next to be shown slide show image
2533 * this function returns the URL of the next image
2534 * in the slideshow sequence.
2537 public function getNextSlideShowImage()
2539 $all_photos = $this->getPhotoSelection();
2541 if(!isset($_SESSION['slideshow_img']) || $_SESSION['slideshow_img'] == count($all_photos)-1)
2542 $_SESSION['slideshow_img'] = 0;
2544 $_SESSION['slideshow_img']++;
2546 if($this->is_user_friendly_url()) {
2547 return $this->get_phpfspot_url() ."/photo/". $all_photos[$_SESSION['slideshow_img']] ."/". $this->cfg->photo_width;
2550 return $this->get_phpfspot_url() ."/phpfspot_img.php?idx=". $all_photos[$_SESSION['slideshow_img']] ."&width=". $this->cfg->photo_width;
2552 } // getNextSlideShowImage()
2555 * return the previous to be shown slide show image
2557 * this function returns the URL of the previous image
2558 * in the slideshow sequence.
2561 public function getPrevSlideShowImage()
2563 $all_photos = $this->getPhotoSelection();
2565 if(!isset($_SESSION['slideshow_img']) || $_SESSION['slideshow_img'] == 0)
2566 $_SESSION['slideshow_img'] = 0;
2568 $_SESSION['slideshow_img']--;
2570 if($this->is_user_friendly_url()) {
2571 return $this->get_phpfspot_url() ."/photo/". $all_photos[$_SESSION['slideshow_img']] ."/". $this->cfg->photo_width;
2574 return $this->get_phpfspot_url() ."/phpfspot_img.php?idx=". $all_photos[$_SESSION['slideshow_img']] ."&width=". $this->cfg->photo_width;
2576 } // getPrevSlideShowImage()
2578 public function resetSlideShow()
2580 if(isset($_SESSION['slideshow_img']))
2581 unset($_SESSION['slideshow_img']);
2583 } // resetSlideShow()
2588 * this function will get all photos from the fspot
2589 * database and randomly return ONE entry
2591 * saddly there is yet no sqlite3 function which returns
2592 * the bulk result in array, so we have to fill up our
2596 public function get_random_photo()
2605 /* if show_tags is set, only return details for photos which
2606 are specified to be shown
2608 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
2610 INNER JOIN photo_tags pt
2615 t.name IN ('".implode("','",$this->cfg->show_tags)."')";
2618 $result = $this->db->db_query($query_str);
2620 while($row = $this->db->db_fetch_object($result)) {
2621 array_push($all, $row['id']);
2624 return $all[array_rand($all)];
2626 } // get_random_photo()
2629 * get random photo tag photo
2631 * this function will get all photos tagged with the requested
2632 * tag from the fspot database and randomly return ONE entry
2634 * saddly there is yet no sqlite3 function which returns
2635 * the bulk result in array, so we have to fill up our
2639 public function get_random_tag_photo($tagidx)
2646 INNER JOIN photo_tags pt
2650 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
2658 pt.tag_id LIKE '". $tagidx ."'
2661 /*if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
2664 t.name IN ('".implode("','",$this->cfg->show_tags)."')
2668 $result = $this->db->db_query($query_str);
2670 while($row = $this->db->db_fetch_object($result)) {
2671 array_push($all, $row['id']);
2674 return $all[array_rand($all)];
2676 } // get_random_tag_photo()
2679 * validates provided date
2681 * this function validates if the provided date
2682 * contains a valid date and will return true
2684 * @param string $date_str
2687 public function isValidDate($date_str)
2689 $timestamp = strtotime($date_str);
2691 if(is_numeric($timestamp))
2699 * timestamp to string conversion
2700 * @param integer $timestamp
2703 private function ts2str($timestamp)
2705 return strftime("%Y-%m-%d", $timestamp);
2709 * extract tag-names from $_GET['tags']
2710 * @param string $tags_str
2713 private function extractTags($tags_str)
2715 $not_validated = split(',', $tags_str);
2716 $validated = array();
2718 foreach($not_validated as $tag) {
2719 if(is_numeric($tag))
2720 array_push($validated, $tag);
2728 * returns the full path to a thumbnail
2729 * @param integer $width
2730 * @param integer $photo
2733 public function get_thumb_path($width, $photo)
2735 $md5 = $this->getMD5($photo);
2736 $sub_path = substr($md5, 0, 2);
2737 return $this->cfg->thumb_path
2745 } // get_thumb_path()
2748 * returns server's virtual host name
2751 private function get_server_name()
2753 return $_SERVER['SERVER_NAME'];
2754 } // get_server_name()
2757 * returns type of webprotocol which is currently used
2760 private function get_web_protocol()
2762 if(!isset($_SERVER['HTTPS']))
2766 } // get_web_protocol()
2769 * return url to this phpfspot installation
2772 private function get_phpfspot_url()
2774 if($this->cfg->web_path == "/")
2776 /* remove trailing slash */
2777 elseif(preg_match('/\/$/', $this->cfg->web_path))
2778 $web_path = preg_replace('/\/$/', '', $this->cfg->web_path);
2780 $web_path = $this->cfg->web_path;
2782 return $this->get_web_protocol() ."://". $this->get_server_name() . $web_path;
2784 } // get_phpfspot_url()
2787 * returns the number of photos which are tagged with $tag_id
2788 * @param integer $tag_id
2791 public function get_num_photos($tag_id)
2793 if($result = $this->db->db_fetchSingleRow("
2794 SELECT count(*) as number
2797 tag_id LIKE '". $tag_id ."'")) {
2799 return $result['number'];
2805 } // get_num_photos()
2808 * check file exists and is readable
2810 * returns true, if everything is ok, otherwise false
2811 * if $silent is not set, this function will output and
2813 * @param string $file
2814 * @param boolean $silent
2817 private function check_readable($file, $silent = null)
2819 if(!file_exists($file)) {
2821 print "File \"". $file ."\" does not exist.\n";
2825 if(!is_readable($file)) {
2827 print "File \"". $file ."\" is not reachable for user ". $this->getuid() ."\n";
2833 } // check_readable()
2836 * check if all needed indices are present
2838 * this function checks, if some needed indices are already
2839 * present, or if not, create them on the fly. they are
2840 * necessary to speed up some queries like that one look for
2841 * all tags, when show_tags is specified in the configuration.
2843 private function checkDbIndices()
2845 $result = $this->db->db_exec("
2846 CREATE INDEX IF NOT EXISTS
2853 } // checkDbIndices()
2856 * retrive F-Spot database version
2858 * this function will return the F-Spot database version number
2859 * It is stored within the sqlite3 database in the table meta
2860 * @return string|null
2862 public function getFspotDBVersion()
2864 if($result = $this->db->db_fetchSingleRow("
2865 SELECT data as version
2868 name LIKE 'F-Spot Database Version'
2870 return $result['version'];
2874 } // getFspotDBVersion()
2877 * parse the provided URI and will returned the requested chunk
2878 * @param string $uri
2879 * @param string $mode
2882 public function parse_uri($uri, $mode)
2884 if(($components = parse_url($uri)) !== false) {
2888 return basename($components['path']);
2891 return dirname($components['path']);
2894 return $components['path'];
2904 * validate config options
2906 * this function checks if all necessary configuration options are
2907 * specified and set.
2910 private function check_config_options()
2912 if(!isset($this->cfg->page_title) || $this->cfg->page_title == "")
2913 $this->_error("Please set \$page_title in phpfspot_cfg");
2915 if(!isset($this->cfg->base_path) || $this->cfg->base_path == "")
2916 $this->_error("Please set \$base_path in phpfspot_cfg");
2918 if(!isset($this->cfg->web_path) || $this->cfg->web_path == "")
2919 $this->_error("Please set \$web_path in phpfspot_cfg");
2921 if(!isset($this->cfg->thumb_path) || $this->cfg->thumb_path == "")
2922 $this->_error("Please set \$thumb_path in phpfspot_cfg");
2924 if(!isset($this->cfg->smarty_path) || $this->cfg->smarty_path == "")
2925 $this->_error("Please set \$smarty_path in phpfspot_cfg");
2927 if(!isset($this->cfg->fspot_db) || $this->cfg->fspot_db == "")
2928 $this->_error("Please set \$fspot_db in phpfspot_cfg");
2930 if(!isset($this->cfg->db_access) || $this->cfg->db_access == "")
2931 $this->_error("Please set \$db_access in phpfspot_cfg");
2933 if(!isset($this->cfg->phpfspot_db) || $this->cfg->phpfspot_db == "")
2934 $this->_error("Please set \$phpfspot_db in phpfspot_cfg");
2936 if(!isset($this->cfg->thumb_width) || $this->cfg->thumb_width == "")
2937 $this->_error("Please set \$thumb_width in phpfspot_cfg");
2939 if(!isset($this->cfg->thumb_height) || $this->cfg->thumb_height == "")
2940 $this->_error("Please set \$thumb_height in phpfspot_cfg");
2942 if(!isset($this->cfg->photo_width) || $this->cfg->photo_width == "")
2943 $this->_error("Please set \$photo_width in phpfspot_cfg");
2945 if(!isset($this->cfg->mini_width) || $this->cfg->mini_width == "")
2946 $this->_error("Please set \$mini_width in phpfspot_cfg");
2948 if(!isset($this->cfg->thumbs_per_page))
2949 $this->_error("Please set \$thumbs_per_page in phpfspot_cfg");
2951 if(!isset($this->cfg->path_replace_from) || $this->cfg->path_replace_from == "")
2952 $this->_error("Please set \$path_replace_from in phpfspot_cfg");
2954 if(!isset($this->cfg->path_replace_to) || $this->cfg->path_replace_to == "")
2955 $this->_error("Please set \$path_replace_to in phpfspot_cfg");
2957 if(!isset($this->cfg->hide_tags))
2958 $this->_error("Please set \$hide_tags in phpfspot_cfg");
2960 if(!isset($this->cfg->theme_name))
2961 $this->_error("Please set \$theme_name in phpfspot_cfg");
2963 if(!isset($this->cfg->logging))
2964 $this->_error("Please set \$logging in phpfspot_cfg");
2966 if(isset($this->cfg->logging) && $this->cfg->logging == 'logfile') {
2968 if(!isset($this->cfg->log_file))
2969 $this->_error("Please set \$log_file because you set logging = log_file in phpfspot_cfg");
2971 if(!is_writeable($this->cfg->log_file))
2972 $this->_error("The specified \$log_file ". $log_file ." is not writeable!");
2976 /* check for pending slash on web_path */
2977 if(!preg_match("/\/$/", $this->cfg->web_path))
2978 $this->cfg->web_path.= "/";
2980 return $this->runtime_error;
2982 } // check_config_options()
2985 * cleanup phpfspot own database
2987 * When photos are getting delete from F-Spot, there will remain
2988 * remain some residues in phpfspot own database. This function
2989 * will try to wipe them out.
2991 public function cleanup_phpfspot_db()
2993 $to_delete = Array();
2995 $result = $this->cfg_db->db_query("
2998 ORDER BY img_idx ASC
3001 while($row = $this->cfg_db->db_fetch_object($result)) {
3002 if(!$this->db->db_fetchSingleRow("
3005 WHERE id='". $row['img_idx'] ."'")) {
3007 array_push($to_delete, $row['img_idx'], ',');
3011 print count($to_delete) ." unnecessary objects will be removed from phpfspot's database.\n";
3013 $this->cfg_db->db_exec("
3015 WHERE img_idx IN (". implode($to_delete) .")
3018 } // cleanup_phpfspot_db()
3021 * return first image of the page, the $current photo
3024 * this function is used to find out the first photo of the
3025 * current page, in which the $current photo lies. this is
3026 * used to display the correct photo, when calling showPhotoIndex()
3028 * @param integer $current
3029 * @param integer $max
3032 private function getCurrentPage($current, $max)
3034 if(isset($this->cfg->thumbs_per_page) && !empty($this->cfg->thumbs_per_page)) {
3035 for($page_start = 0; $page_start <= $max; $page_start+=$this->cfg->thumbs_per_page) {
3036 if($current >= $page_start && $current < ($page_start+$this->cfg->thumbs_per_page))
3042 } // getCurrentPage()
3047 * this function tries to find out the correct mime-type
3048 * for the provided file.
3049 * @param string $file
3052 public function get_mime_info($file)
3054 $details = getimagesize($file);
3056 /* if getimagesize() returns empty, try at least to find out the
3059 if(empty($details) && function_exists('mime_content_type')) {
3061 // mime_content_type is marked as deprecated in the documentation,
3062 // but is it really necessary to force users to install a PECL
3064 $details['mime'] = mime_content_type($file);
3067 return $details['mime'];
3069 } // get_mime_info()
3072 * return tag-name by tag-idx
3074 * this function returns the tag-name for the requested
3075 * tag specified by tag-idx.
3076 * @param integer $idx
3079 public function get_tag_name($idx)
3081 if($result = $this->db->db_fetchSingleRow("
3085 id LIKE '". $idx ."'")) {
3087 return $result['name'];
3096 private function parse_user_friendly_url($request_uri)
3098 if(preg_match('/\/photoview\/|\/photo\/|\/tag\//', $request_uri)) {
3100 unset($_SESSION['start_action']);
3101 unset($_SESSION['selected_tags']);
3103 $options = explode('/', $request_uri);
3105 switch($options[1]) {
3107 if(is_numeric($options[2])) {
3108 return $this->showPhoto($options[2]);
3112 if(is_numeric($options[2])) {
3113 require_once "phpfspot_img.php";
3114 $img = new PHPFSPOT_IMG;
3115 if(isset($options[3]) && is_numeric($options[3]))
3116 $img->showImg($options[2], $options[3]);
3118 $img->showImg($options[2]);
3123 if(is_numeric($options[2])) {
3124 $_GET['mode'] = 'showpi';
3125 $_SESSION['selected_tags'] = Array($options[2]);
3126 $this->tmpl->assign('preset_selected_tags', $this->getSelectedTags());
3127 $_GET['tags'] = $options[2];
3128 return $this->showPhotoIndex();
3134 } // parse_user_friendly_url()
3137 * check if user-friendly-urls are enabled
3139 * this function will return true, if the config option
3140 * $user_friendly_url has been set. Otherwise false.
3143 private function is_user_friendly_url()
3145 if(isset($this->cfg->user_friendly_url) && $this->cfg->user_friendly_url)
3150 } // is_user_friendly_url()