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);
247 if(isset($_GET['mode'])) {
249 $_SESSION['start_action'] = $_GET['mode'];
251 switch($_GET['mode']) {
253 if(isset($_GET['tags'])) {
254 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
256 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
257 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
259 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
260 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
264 if(isset($_GET['tags'])) {
265 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
266 $_SESSION['start_action'] = 'showp';
268 if(isset($_GET['id']) && is_numeric($_GET['id'])) {
269 $_SESSION['current_photo'] = $_GET['id'];
270 $_SESSION['start_action'] = 'showp';
272 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
273 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
275 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
276 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
280 $this->tmpl->show("export.tpl");
284 $this->tmpl->show("slideshow.tpl");
288 if(isset($_GET['tags'])) {
289 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
291 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
292 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
294 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
295 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
303 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date']))
304 $this->tmpl->assign('date_search_enabled', true);
306 $this->tmpl->register_function("sort_select_list", array(&$this, "smarty_sort_select_list"), false);
307 $this->tmpl->assign('from_date', $this->get_calendar('from'));
308 $this->tmpl->assign('to_date', $this->get_calendar('to'));
309 $this->tmpl->assign('content_page', 'welcome.tpl');
310 $this->tmpl->show("index.tpl");
315 * get_tags - grab all tags of f-spot's database
317 * this function will get all available tags from
318 * the f-spot database and store them within two
319 * arrays within this class for later usage. in
320 * fact, if the user requests (hide_tags) it will
321 * opt-out some of them.
323 * this function is getting called once by show()
325 private function get_tags()
327 $this->avail_tags = Array();
330 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
333 DISTINCT t1.id as id, t1.name as name
336 INNER JOIN photo_tags
337 pt2 ON pt1.photo_id=pt2.photo_id
343 t2.name IN ('".implode("','",$this->cfg->show_tags)."')
345 t1.sort_priority ASC";
347 $result = $this->db->db_query($query_str);
351 $result = $this->db->db_query("
354 ORDER BY sort_priority ASC
358 while($row = $this->db->db_fetch_object($result)) {
360 $tag_id = $row['id'];
361 $tag_name = $row['name'];
363 /* if the user has specified to ignore this tag in phpfspot's
364 configuration, ignore it here so it does not get added to
367 if(in_array($row['name'], $this->cfg->hide_tags))
370 /* if you include the following if-clause and the user has specified
371 to only show certain tags which are specified in phpfspot's
372 configuration, ignore all others so they will not be added to the
374 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags) &&
375 !in_array($row['name'], $this->cfg->show_tags))
379 $this->tags[$tag_id] = $tag_name;
380 $this->avail_tags[$count] = $tag_id;
388 * extract all photo details
390 * retrieve all available details from f-spot's
391 * database and return them as object
392 * @param integer $idx
393 * @return object|null
395 public function get_photo_details($idx)
397 if($this->dbver < 9) {
399 SELECT p.id, p.name, p.time, p.directory_path, p.description
405 SELECT p.id, p.uri, p.time, p.description
410 /* if show_tags is set, only return details for photos which
411 are specified to be shown
413 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
415 INNER JOIN photo_tags pt
419 WHERE p.id='". $idx ."'
420 AND t.name IN ('".implode("','",$this->cfg->show_tags)."')";
424 WHERE p.id='". $idx ."'
428 if($result = $this->db->db_query($query_str)) {
430 $row = $this->db->db_fetch_object($result);
432 if($this->dbver < 9) {
433 $row['uri'] = "file://". $row['directory_path'] ."/". $row['name'];
442 } // get_photo_details
445 * returns aligned photo names
447 * this function returns aligned (length) names for
448 * an specific photo. If the length of the name exceeds
449 * $limit the name will be shrinked (...)
450 * @param integer $idx
451 * @param integer $limit
452 * @return string|null
454 public function getPhotoName($idx, $limit = 0)
456 if($details = $this->get_photo_details($idx)) {
457 if($long_name = $this->parse_uri($details['uri'], 'filename')) {
458 $name = $this->shrink_text($long_name, $limit);
468 * shrink text according provided limit
470 * If the length of the name exceeds $limit the
471 * text will be shortend and some content in between
472 * will be replaced with "..."
474 * @param integer $limit
477 private function shrink_text($text, $limit)
479 if($limit != 0 && strlen($text) > $limit) {
480 $text = substr($text, 0, $limit-5) ."...". substr($text, -($limit-5));
488 * translate f-spoth photo path
490 * as the full-qualified path recorded in the f-spot database
491 * is usally not the same as on the webserver, this function
492 * will replace the path with that one specified in the cfg
493 * @param string $path
496 public function translate_path($path)
498 return str_replace($this->cfg->path_replace_from, $this->cfg->path_replace_to, $path);
503 * control HTML ouput for a single photo
505 * this function provides all the necessary information
506 * for the single photo template.
507 * @param integer photo
509 public function showPhoto($photo)
511 /* get all photos from the current photo selection */
512 $all_photos = $this->getPhotoSelection();
513 $count = count($all_photos);
515 for($i = 0; $i < $count; $i++) {
517 // $get_next will be set, when the photo which has to
518 // be displayed has been found - this means that the
519 // next available is in fact the NEXT image (for the
521 if(isset($get_next)) {
522 $next_img = $all_photos[$i];
526 /* the next photo is our NEXT photo */
527 if($all_photos[$i] == $photo) {
531 $previous_img = $all_photos[$i];
534 if($photo == $all_photos[$i]) {
539 $details = $this->get_photo_details($photo);
546 $orig_path = $this->translate_path($this->parse_uri($details['uri'], 'fullpath'));
547 $thumb_path = $this->get_thumb_path($this->cfg->photo_width, $photo);
549 if(!file_exists($orig_path)) {
550 $this->_error("Photo ". $orig_path ." does not exist!<br />\n");
554 if(!is_readable($orig_path)) {
555 $this->_error("Photo ". $orig_path ." is not readable for user ". $this->getuid() ."<br />\n");
559 /* If the thumbnail doesn't exist yet, try to create it */
560 if(!file_exists($thumb_path)) {
561 $this->gen_thumb($photo, true);
562 $thumb_path = $this->get_thumb_path($this->cfg->photo_width, $photo);
565 /* get mime-type, height and width from the original photo */
566 $info = getimagesize($orig_path);
568 /* get EXIF information if JPEG */
569 if($info['mime'] == "image/jpeg") {
570 $meta = $this->get_meta_informations($orig_path);
573 /* If EXIF data are available, use them */
574 if(isset($meta['ExifImageWidth'])) {
575 $meta_res = $meta['ExifImageWidth'] ."x". $meta['ExifImageLength'];
577 $meta_res = $info[0] ."x". $info[1];
580 $meta_date = isset($meta['FileDateTime']) ? strftime("%a %x %X", $meta['FileDateTime']) : "n/a";
581 $meta_make = isset($meta['Make']) ? $meta['Make'] ." / ". $meta['Model'] : "n/a";
582 $meta_size = isset($meta['FileSize']) ? round($meta['FileSize']/1024, 1) ."kbyte" : "n/a";
584 $extern_link = "index.php?mode=showp&id=". $photo;
585 $current_tags = $this->getCurrentTags();
586 if($current_tags != "") {
587 $extern_link.= "&tags=". $current_tags;
589 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
590 $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
593 $this->tmpl->assign('extern_link', $extern_link);
595 if(!file_exists($thumb_path)) {
596 $this->_error("Can't open file ". $thumb_path ."\n");
600 $info_thumb = getimagesize($thumb_path);
602 $this->tmpl->assign('description', $details['description']);
603 $this->tmpl->assign('image_name', $this->parse_uri($details['uri'], 'filename'));
605 $this->tmpl->assign('width', $info_thumb[0]);
606 $this->tmpl->assign('height', $info_thumb[1]);
607 $this->tmpl->assign('ExifMadeOn', $meta_date);
608 $this->tmpl->assign('ExifMadeWith', $meta_make);
609 $this->tmpl->assign('ExifOrigResolution', $meta_res);
610 $this->tmpl->assign('ExifFileSize', $meta_size);
612 $this->tmpl->assign('image_url', 'phpfspot_img.php?idx='. $photo ."&width=". $this->cfg->photo_width);
613 $this->tmpl->assign('image_url_full', 'phpfspot_img.php?idx='. $photo);
614 $this->tmpl->assign('image_filename', $this->parse_uri($details['uri'], 'filename'));
616 $this->tmpl->assign('tags', $this->get_photo_tags($photo));
617 $this->tmpl->assign('current_page', $this->getCurrentPage($current, $count));
618 $this->tmpl->assign('current_img', $photo);
621 $this->tmpl->assign('previous_url', "javascript:showImage(". $previous_img .");");
622 $this->tmpl->assign('prev_img', $previous_img);
626 $this->tmpl->assign('next_url', "javascript:showImage(". $next_img .");");
627 $this->tmpl->assign('next_img', $next_img);
629 $this->tmpl->assign('mini_width', $this->cfg->mini_width);
630 $this->tmpl->assign('photo_width', $this->cfg->photo_width);
631 $this->tmpl->assign('photo_number', $i);
632 $this->tmpl->assign('photo_count', count($all_photos));
634 $this->tmpl->show("single_photo.tpl");
639 * all available tags and tag cloud
641 * this function outputs all available tags (time ordered)
642 * and in addition output them as tag cloud (tags which have
643 * many photos will appears more then others)
645 public function getAvailableTags()
647 /* retrive tags from database */
652 $result = $this->db->db_query("
653 SELECT tag_id as id, count(tag_id) as quantity
663 while($row = $this->db->db_fetch_object($result)) {
664 $tags[$row['id']] = $row['quantity'];
667 // change these font sizes if you will
668 $max_size = 125; // max font size in %
669 $min_size = 75; // min font size in %
672 $max_sat = hexdec('cc');
673 $min_sat = hexdec('44');
675 // get the largest and smallest array values
676 $max_qty = max(array_values($tags));
677 $min_qty = min(array_values($tags));
679 // find the range of values
680 $spread = $max_qty - $min_qty;
681 if (0 == $spread) { // we don't want to divide by zero
685 // determine the font-size increment
686 // this is the increase per tag quantity (times used)
687 $step = ($max_size - $min_size)/($spread);
688 $step_sat = ($max_sat - $min_sat)/($spread);
690 // loop through our tag array
691 foreach ($tags as $key => $value) {
693 if(isset($_SESSION['selected_tags']) && in_array($key, $_SESSION['selected_tags']))
696 // calculate CSS font-size
697 // find the $value in excess of $min_qty
698 // multiply by the font-size increment ($size)
699 // and add the $min_size set above
700 $size = $min_size + (($value - $min_qty) * $step);
701 // uncomment if you want sizes in whole %:
704 $color = $min_sat + ($value - $min_qty) * $step_sat;
710 if(isset($this->tags[$key])) {
711 $output.= "<a href=\"javascript:Tags('add', ". $key .");\" class=\"tag\" style=\"font-size: ". $size ."%; color: #". $r.$g.$b .";\">". $this->tags[$key] ."</a>, ";
716 $output = substr($output, 0, strlen($output)-2);
719 } // getAvailableTags()
722 * output all selected tags
724 * this function output all tags which have been selected
725 * by the user. the selected tags are stored in the
726 * session-variable $_SESSION['selected_tags']
729 public function getSelectedTags($type = 'link')
731 /* retrive tags from database */
736 foreach($this->avail_tags as $tag)
738 // return all selected tags
739 if(isset($_SESSION['selected_tags']) && in_array($tag, $_SESSION['selected_tags'])) {
744 $output.= "<a href=\"javascript:Tags('del', ". $tag .");\" class=\"tag\">". $this->tags[$tag] ."</a>, ";
748 <div style=\"display: table-cell;\">
749 <div style=\"display: table-row; text-align: center;\">
750 <a href=\"javascript:Tags('del', ". $tag .");\" title=\"". $this->tags[$tag] ."\">
751 <img src=\"phpfspot_img.php?tagidx=". $tag ."\" />
754 <div style=\"display: table-row; text-align: center;\">
755 <a href=\"javascript:Tags('del', ". $tag .");\" title=\"". $this->tags[$tag] ."\">
756 <img src=\"resources/underbar.png\" />
767 $output = substr($output, 0, strlen($output)-2);
771 return "no tags selected";
774 } // getSelectedTags()
777 * add tag to users session variable
779 * this function will add the specified to users current
780 * tag selection. if a date search has been made before
781 * it will be now cleared
784 public function addTag($tag)
786 if(!isset($_SESSION['selected_tags']))
787 $_SESSION['selected_tags'] = Array();
789 if(isset($_SESSION['searchfor_tag']))
790 unset($_SESSION['searchfor_tag']);
792 // has the user requested to hide this tag, and still someone,
793 // somehow tries to add it, don't allow this.
794 if(!isset($this->cfg->hide_tags) &&
795 in_array($this->get_tag_name($tag), $this->cfg->hide_tags))
798 if(!in_array($tag, $_SESSION['selected_tags']))
799 array_push($_SESSION['selected_tags'], $tag);
806 * remove tag to users session variable
808 * this function removes the specified tag from
809 * users current tag selection
813 public function delTag($tag)
815 if(isset($_SESSION['searchfor_tag']))
816 unset($_SESSION['searchfor_tag']);
818 if(isset($_SESSION['selected_tags'])) {
819 $key = array_search($tag, $_SESSION['selected_tags']);
820 unset($_SESSION['selected_tags'][$key]);
821 sort($_SESSION['selected_tags']);
829 * reset tag selection
831 * if there is any tag selection, it will be
834 public function resetTags()
836 if(isset($_SESSION['selected_tags']))
837 unset($_SESSION['selected_tags']);
842 * returns the value for the autocomplet tag-search
845 public function get_xml_tag_list()
847 if(!isset($_GET['search']) || !is_string($_GET['search']))
848 $_GET['search'] = '';
853 /* retrive tags from database */
856 $matched_tags = Array();
858 header("Content-Type: text/xml");
860 $string = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n";
861 $string.= "<results>\n";
863 foreach($this->avail_tags as $tag)
865 if(!empty($_GET['search']) &&
866 preg_match("/". $_GET['search'] ."/i", $this->tags[$tag]) &&
867 count($matched_tags) < $length) {
869 $count = $this->get_num_photos($tag);
872 $string.= " <rs id=\"". $i ."\" info=\"". $count ." photo\">". $this->tags[$tag] ."</rs>\n";
875 $string.= " <rs id=\"". $i ."\" info=\"". $count ." photos\">". $this->tags[$tag] ."</rs>\n";
881 /* if we have collected enough items, break out */
882 if(count($matched_tags) >= $length)
886 $string.= "</results>\n";
890 } // get_xml_tag_list()
896 * if a specific photo was requested (external link)
897 * unset the session variable now
899 public function resetPhotoView()
901 if(isset($_SESSION['current_photo']))
902 unset($_SESSION['current_photo']);
904 } // resetPhotoView();
909 * if any tag search has taken place, reset it now
911 public function resetTagSearch()
913 if(isset($_SESSION['searchfor_tag']))
914 unset($_SESSION['searchfor_tag']);
916 } // resetTagSearch()
921 * if any name search has taken place, reset it now
923 public function resetNameSearch()
925 if(isset($_SESSION['searchfor_name']))
926 unset($_SESSION['searchfor_name']);
928 } // resetNameSearch()
933 * if any date search has taken place, reset
936 public function resetDateSearch()
938 if(isset($_SESSION['from_date']))
939 unset($_SESSION['from_date']);
940 if(isset($_SESSION['to_date']))
941 unset($_SESSION['to_date']);
943 } // resetDateSearch();
946 * return all photo according selection
948 * this function returns all photos based on
949 * the tag-selection, tag- or date-search.
950 * the tag-search also has to take care of AND
951 * and OR conjunctions
954 public function getPhotoSelection()
956 $matched_photos = Array();
957 $additional_where_cond = "";
959 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
960 $from_date = $_SESSION['from_date'];
961 $to_date = $_SESSION['to_date'];
962 $additional_where_cond.= "
963 p.time>='". $from_date ."'
965 p.time<='". $to_date ."'
969 if(isset($_SESSION['searchfor_name'])) {
970 if($this->dbver < 9) {
971 $additional_where_cond.= "
973 p.name LIKE '%". $_SESSION['searchfor_name'] ."%'
975 p.description LIKE '%". $_SESSION['searchfor_name'] ."%'
980 $additional_where_cond.= "
982 basename(p.uri) LIKE '%". $_SESSION['searchfor_name'] ."%'
984 p.description LIKE '%". $_SESSION['searchfor_name'] ."%'
990 if(isset($_SESSION['sort_order'])) {
991 $order_str = $this->get_sort_order();
994 /* return a search result */
995 if(isset($_SESSION['searchfor_tag']) && $_SESSION['searchfor_tag'] != '') {
997 SELECT DISTINCT pt1.photo_id
999 INNER JOIN photo_tags pt2
1000 ON pt1.photo_id=pt2.photo_id
1004 ON pt1.photo_id=p.id
1007 WHERE t.name LIKE '%". $_SESSION['searchfor_tag'] ."%' ";
1009 if(isset($additional_where_cond) && !empty($additional_where_cond))
1010 $query_str.= "AND ". $additional_where_cond ." ";
1012 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1013 $query_str.= "AND t2.name IN ('".implode("','",$this->cfg->show_tags)."')";
1016 if(isset($order_str))
1017 $query_str.= $order_str;
1019 $result = $this->db->db_query($query_str);
1020 while($row = $this->db->db_fetch_object($result)) {
1021 array_push($matched_photos, $row['photo_id']);
1023 return $matched_photos;
1026 /* return according the selected tags */
1027 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
1029 foreach($_SESSION['selected_tags'] as $tag)
1030 $selected.= $tag .",";
1031 $selected = substr($selected, 0, strlen($selected)-1);
1033 /* photo has to match at least on of the selected tags */
1034 if($_SESSION['tag_condition'] == 'or') {
1036 SELECT DISTINCT pt1.photo_id
1038 INNER JOIN photo_tags pt2
1039 ON pt1.photo_id=pt2.photo_id
1043 ON pt1.photo_id=p.id
1044 WHERE pt1.tag_id IN (". $selected .")
1046 if(isset($additional_where_cond) && !empty($additional_where_cond))
1047 $query_str.= "AND ". $additional_where_cond ." ";
1049 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1050 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags)."')";
1053 if(isset($order_str))
1054 $query_str.= $order_str;
1056 /* photo has to match all selected tags */
1057 elseif($_SESSION['tag_condition'] == 'and') {
1059 if(count($_SESSION['selected_tags']) >= 32) {
1060 print "A SQLite limit of 32 tables within a JOIN SELECT avoids to<br />\n";
1061 print "evaluate your tag selection. Please remove some tags from your selection.\n";
1065 /* Join together a table looking like
1067 pt1.photo_id pt1.tag_id pt2.photo_id pt2.tag_id ...
1069 so the query can quickly return all images matching the
1070 selected tags in an AND condition
1075 SELECT DISTINCT pt1.photo_id
1079 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1086 for($i = 0; $i < count($_SESSION['selected_tags']); $i++) {
1088 INNER JOIN photo_tags pt". ($i+2) ."
1089 ON pt1.photo_id=pt". ($i+2) .".photo_id
1094 ON pt1.photo_id=p.id
1096 $query_str.= "WHERE pt2.tag_id=". $_SESSION['selected_tags'][0]." ";
1097 for($i = 1; $i < count($_SESSION['selected_tags']); $i++) {
1099 AND pt". ($i+2) .".tag_id=". $_SESSION['selected_tags'][$i] ."
1102 if(isset($additional_where_cond) && !empty($additional_where_cond))
1103 $query_str.= "AND ". $additional_where_cond;
1105 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1106 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags). "')";
1109 if(isset($order_str))
1110 $query_str.= $order_str;
1114 $result = $this->db->db_query($query_str);
1115 while($row = $this->db->db_fetch_object($result)) {
1116 array_push($matched_photos, $row['photo_id']);
1118 return $matched_photos;
1121 /* return all available photos */
1123 SELECT DISTINCT p.id
1125 LEFT JOIN photo_tags pt
1131 if(isset($additional_where_cond) && !empty($additional_where_cond))
1132 $query_str.= "WHERE ". $additional_where_cond ." ";
1134 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1135 if(isset($additional_where_cond) && !empty($additional_where_cond))
1136 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags). "')";
1138 $query_str.= "WHERE t.name IN ('".implode("','",$this->cfg->show_tags). "')";
1141 if(isset($order_str))
1142 $query_str.= $order_str;
1144 $result = $this->db->db_query($query_str);
1145 while($row = $this->db->db_fetch_object($result)) {
1146 array_push($matched_photos, $row['id']);
1148 return $matched_photos;
1150 } // getPhotoSelection()
1153 * control HTML ouput for photo index
1155 * this function provides all the necessary information
1156 * for the photo index template.
1158 public function showPhotoIndex()
1160 $photos = $this->getPhotoSelection();
1162 $count = count($photos);
1164 /* if all thumbnails should be shown on one page */
1165 if(!isset($this->cfg->thumbs_per_page) || $this->cfg->thumbs_per_page == 0) {
1169 /* thumbnails should be splitted up in several pages */
1170 elseif($this->cfg->thumbs_per_page > 0) {
1172 if(!isset($_SESSION['begin_with']) || $_SESSION['begin_with'] == 0) {
1176 $begin_with = $_SESSION['begin_with'];
1179 $end_with = $begin_with + $this->cfg->thumbs_per_page;
1183 $images[$thumbs] = Array();
1184 $img_height[$thumbs] = Array();
1185 $img_width[$thumbs] = Array();
1186 $img_id[$thumbs] = Array();
1187 $img_name[$thumbs] = Array();
1188 $img_fullname[$thumbs] = Array();
1189 $img_title = Array();
1191 for($i = $begin_with; $i < $end_with; $i++) {
1193 if(isset($photos[$i])) {
1195 $images[$thumbs] = $photos[$i];
1196 $img_id[$thumbs] = $i;
1197 $img_name[$thumbs] = htmlspecialchars($this->getPhotoName($photos[$i], 15));
1198 $img_fullname[$thumbs] = htmlspecialchars($this->getPhotoName($photos[$i], 0));
1199 $img_title[$thumbs] = "Click to view photo ". htmlspecialchars($this->getPhotoName($photos[$i], 0));
1201 $thumb_path = $this->get_thumb_path($this->cfg->thumb_width, $photos[$i]);
1203 if(file_exists($thumb_path)) {
1204 $info = getimagesize($thumb_path);
1205 $img_width[$thumbs] = $info[0];
1206 $img_height[$thumbs] = $info[1];
1212 // +1 for for smarty's selection iteration
1215 if(isset($_SESSION['searchfor_tag']) && $_SESSION['searchfor_tag'] != '')
1216 $this->tmpl->assign('searchfor_tag', $_SESSION['searchfor_tag']);
1218 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1219 $this->tmpl->assign('from_date', $this->ts2str($_SESSION['from_date']));
1220 $this->tmpl->assign('to_date', $this->ts2str($_SESSION['to_date']));
1223 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
1224 $this->tmpl->assign('tag_result', 1);
1227 /* do we have to display the page selector ? */
1228 if($this->cfg->thumbs_per_page != 0) {
1232 /* calculate the page switchers */
1233 $previous_start = $begin_with - $this->cfg->thumbs_per_page;
1234 $next_start = $begin_with + $this->cfg->thumbs_per_page;
1236 if($begin_with != 0)
1237 $this->tmpl->assign("previous_url", "javascript:showPhotoIndex(". $previous_start .");");
1238 if($end_with < $count)
1239 $this->tmpl->assign("next_url", "javascript:showPhotoIndex(". $next_start .");");
1241 $photo_per_page = $this->cfg->thumbs_per_page;
1242 $last_page = ceil($count / $photo_per_page);
1244 /* get the current selected page */
1245 if($begin_with == 0) {
1249 for($i = $begin_with; $i >= 0; $i-=$photo_per_page) {
1256 for($i = 1; $i <= $last_page; $i++) {
1258 if($current_page == $i)
1259 $style = "style=\"font-size: 125%; text-decoration: underline;\"";
1260 elseif($current_page-1 == $i || $current_page+1 == $i)
1261 $style = "style=\"font-size: 105%;\"";
1262 elseif(($current_page-5 >= $i) && ($i != 1) ||
1263 ($current_page+5 <= $i) && ($i != $last_page))
1264 $style = "style=\"font-size: 75%;\"";
1268 $select = "<a href=\"javascript:showPhotoIndex(". (($i*$photo_per_page)-$photo_per_page) .");\"";
1271 $select.= ">". $i ."</a> ";
1273 // until 9 pages we show the selector from 1-9
1274 if($last_page <= 9) {
1275 $page_select.= $select;
1278 if($i == 1 /* first page */ ||
1279 $i == $last_page /* last page */ ||
1280 $i == $current_page /* current page */ ||
1281 $i == ceil($last_page * 0.25) /* first quater */ ||
1282 $i == ceil($last_page * 0.5) /* half */ ||
1283 $i == ceil($last_page * 0.75) /* third quater */ ||
1284 (in_array($i, array(1,2,3,4,5,6)) && $current_page <= 4) /* the first 6 */ ||
1285 (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 */ ||
1286 $i == $current_page-3 || $i == $current_page-2 || $i == $current_page-1 /* three before */ ||
1287 $i == $current_page+3 || $i == $current_page+2 || $i == $current_page+1 /* three after */) {
1289 $page_select.= $select;
1297 $page_select.= "......... ";
1302 /* only show the page selector if we have more then one page */
1304 $this->tmpl->assign('page_selector', $page_select);
1308 $current_tags = $this->getCurrentTags();
1309 $extern_link = "index.php?mode=showpi";
1310 $rss_link = "index.php?mode=rss";
1311 if($current_tags != "") {
1312 $extern_link.= "&tags=". $current_tags;
1313 $rss_link.= "&tags=". $current_tags;
1315 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1316 $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
1317 $rss_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
1320 $export_link = "index.php?mode=export";
1321 $slideshow_link = "index.php?mode=slideshow";
1323 $this->tmpl->assign('extern_link', $extern_link);
1324 $this->tmpl->assign('slideshow_link', $slideshow_link);
1325 $this->tmpl->assign('export_link', $export_link);
1326 $this->tmpl->assign('rss_link', $rss_link);
1327 $this->tmpl->assign('count', $count);
1328 $this->tmpl->assign('width', $this->cfg->thumb_width);
1329 $this->tmpl->assign('preview_width', $this->cfg->photo_width);
1330 $this->tmpl->assign('thumb_container_width', $this->cfg->thumb_width);
1331 $this->tmpl->assign('thumb_container_height', $this->cfg->thumb_height+20);
1332 $this->tmpl->assign('images', $images);
1333 $this->tmpl->assign('img_width', $img_width);
1334 $this->tmpl->assign('img_height', $img_height);
1335 $this->tmpl->assign('img_id', $img_id);
1336 $this->tmpl->assign('img_name', $img_name);
1337 $this->tmpl->assign('img_fullname', $img_fullname);
1338 $this->tmpl->assign('img_title', $img_title);
1339 $this->tmpl->assign('thumbs', $thumbs);
1340 $this->tmpl->assign('selected_tags', $this->getSelectedTags('img'));
1342 $this->tmpl->show("photo_index.tpl");
1344 /* if we are returning to photo index from an photo-view,
1345 scroll the window to the last shown photo-thumbnail.
1346 after this, unset the last_photo session variable.
1348 if(isset($_SESSION['last_photo'])) {
1349 print "<script language=\"JavaScript\">moveToThumb(". $_SESSION['last_photo'] .");</script>\n";
1350 unset($_SESSION['last_photo']);
1353 } // showPhotoIndex()
1356 * show credit template
1358 public function showCredits()
1360 $this->tmpl->assign('version', $this->cfg->version);
1361 $this->tmpl->assign('product', $this->cfg->product);
1362 $this->tmpl->assign('db_version', $this->dbver);
1363 $this->tmpl->show("credits.tpl");
1368 * create thumbnails for the requested width
1370 * this function creates image thumbnails of $orig_image
1371 * stored as $thumb_image. It will check if the image is
1372 * in a supported format, if necessary rotate the image
1373 * (based on EXIF orientation meta headers) and re-sizing.
1374 * @param string $orig_image
1375 * @param string $thumb_image
1376 * @param integer $width
1379 public function create_thumbnail($orig_image, $thumb_image, $width)
1381 if(!file_exists($orig_image)) {
1385 $mime = $this->get_mime_info($orig_image);
1387 /* check if original photo is a support image type */
1388 if(!$this->checkifImageSupported($mime))
1395 $meta = $this->get_meta_informations($orig_image);
1401 switch($meta['Orientation']) {
1402 case 1: /* top, left */
1403 /* nothing to do */ break;
1404 case 2: /* top, right */
1405 $rotate = 0; $flip_hori = true; break;
1406 case 3: /* bottom, left */
1407 $rotate = 180; break;
1408 case 4: /* bottom, right */
1409 $flip_vert = true; break;
1410 case 5: /* left side, top */
1411 $rotate = 90; $flip_vert = true; break;
1412 case 6: /* right side, top */
1413 $rotate = 90; break;
1414 case 7: /* left side, bottom */
1415 $rotate = 270; $flip_vert = true; break;
1416 case 8: /* right side, bottom */
1417 $rotate = 270; break;
1420 $src_img = @imagecreatefromjpeg($orig_image);
1426 $src_img = @imagecreatefrompng($orig_image);
1430 case 'image/x-portable-pixmap':
1432 $src_img = new Imagick($orig_image);
1433 $handler = "imagick";
1438 if(!isset($src_img) || empty($src_img)) {
1439 print "Can't load image from ". $orig_image ."\n";
1447 /* grabs the height and width */
1448 $cur_width = imagesx($src_img);
1449 $cur_height = imagesy($src_img);
1451 // If requested width is more then the actual image width,
1452 // do not generate a thumbnail, instead safe the original
1453 // as thumbnail but with lower quality. But if the image
1454 // is to heigh too, then we still have to resize it.
1455 if($width >= $cur_width && $cur_height < $this->cfg->thumb_height) {
1456 $result = imagejpeg($src_img, $thumb_image, 75);
1457 imagedestroy($src_img);
1464 $cur_width = $src_img->getImageWidth();
1465 $cur_height = $src_img->getImageHeight();
1467 // If requested width is more then the actual image width,
1468 // do not generate a thumbnail, instead safe the original
1469 // as thumbnail but with lower quality. But if the image
1470 // is to heigh too, then we still have to resize it.
1471 if($width >= $cur_width && $cur_height < $this->cfg->thumb_height) {
1472 $src_img->setCompressionQuality(75);
1473 $src_img->setImageFormat('jpeg');
1474 $src_img->writeImage($thumb_image);
1476 $src_img->destroy();
1483 // If the image will be rotate because EXIF orientation said so
1484 // 'virtually rotate' the image for further calculations
1485 if($rotate == 90 || $rotate == 270) {
1487 $cur_width = $cur_height;
1491 /* calculates aspect ratio */
1492 $aspect_ratio = $cur_height / $cur_width;
1495 if($aspect_ratio < 1) {
1497 $new_h = abs($new_w * $aspect_ratio);
1499 /* 'virtually' rotate the image and calculate it's ratio */
1500 $tmp_w = $cur_height;
1501 $tmp_h = $cur_width;
1502 /* now get the ratio from the 'rotated' image */
1503 $tmp_ratio = $tmp_h/$tmp_w;
1504 /* now calculate the new dimensions */
1506 $tmp_h = abs($tmp_w * $tmp_ratio);
1508 // now that we know, how high they photo should be, if it
1509 // gets rotated, use this high to scale the image
1511 $new_w = abs($new_h / $aspect_ratio);
1513 // If the image will be rotate because EXIF orientation said so
1514 // now 'virtually rotate' back the image for the image manipulation
1515 if($rotate == 90 || $rotate == 270) {
1526 /* creates new image of that size */
1527 $dst_img = imagecreatetruecolor($new_w, $new_h);
1529 imagefill($dst_img, 0, 0, ImageColorAllocate($dst_img, 255, 255, 255));
1531 /* copies resized portion of original image into new image */
1532 imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $new_w, $new_h, imagesx($src_img), imagesy($src_img));
1534 /* needs the image to be flipped horizontal? */
1536 $this->_debug("(FLIP)");
1537 $dst_img = $this->flipImage($dst_img, 'hori');
1539 /* needs the image to be flipped vertical? */
1541 $this->_debug("(FLIP)");
1542 $dst_img = $this->flipImage($dst_img, 'vert');
1546 $this->_debug("(ROTATE)");
1547 $dst_img = $this->rotateImage($dst_img, $rotate);
1550 /* write down new generated file */
1551 $result = imagejpeg($dst_img, $thumb_image, 75);
1553 /* free your mind */
1554 imagedestroy($dst_img);
1555 imagedestroy($src_img);
1557 if($result === false) {
1558 print "Can't write thumbnail ". $thumb_image ."\n";
1568 $src_img->resizeImage($new_w, $new_h, Imagick::FILTER_LANCZOS, 1);
1570 /* needs the image to be flipped horizontal? */
1572 $this->_debug("(FLIP)");
1573 $src_img->rotateImage(new ImagickPixel(), 90);
1574 $src_img->flipImage();
1575 $src_img->rotateImage(new ImagickPixel(), -90);
1577 /* needs the image to be flipped vertical? */
1579 $this->_debug("(FLIP)");
1580 $src_img->flipImage();
1584 $this->_debug("(ROTATE)");
1585 $src_img->rotateImage(new ImagickPixel(), $rotate);
1588 $src_img->setCompressionQuality(75);
1589 $src_img->setImageFormat('jpeg');
1591 if(!$src_img->writeImage($thumb_image)) {
1592 print "Can't write thumbnail ". $thumb_image ."\n";
1597 $src_img->destroy();
1604 } // create_thumbnail()
1607 * return all exif meta data from the file
1608 * @param string $file
1611 public function get_meta_informations($file)
1613 return exif_read_data($file);
1615 } // get_meta_informations()
1618 * create phpfspot own sqlite database
1620 * this function creates phpfspots own sqlite database
1621 * if it does not exist yet. this own is used to store
1622 * some necessary informations (md5 sum's, ...).
1624 public function check_config_table()
1626 // if the config table doesn't exist yet, create it
1627 if(!$this->cfg_db->db_check_table_exists("images")) {
1628 $this->cfg_db->db_exec("
1629 CREATE TABLE images (
1630 img_idx int primary key,
1636 } // check_config_table
1639 * Generates a thumbnail from photo idx
1641 * This function will generate JPEG thumbnails from provided F-Spot photo
1644 * 1. Check if all thumbnail generations (width) are already in place and
1646 * 2. Check if the md5sum of the original file has changed
1647 * 3. Generate the thumbnails if needed
1648 * @param integer $idx
1649 * @param integer $force
1650 * @param boolean $overwrite
1652 public function gen_thumb($idx = 0, $force = 0, $overwrite = false)
1656 $resolutions = Array(
1657 $this->cfg->thumb_width,
1658 $this->cfg->photo_width,
1659 $this->cfg->mini_width,
1663 /* get details from F-Spot's database */
1664 $details = $this->get_photo_details($idx);
1666 /* calculate file MD5 sum */
1667 $full_path = $this->translate_path($this->parse_uri($details['uri'], 'fullpath'));
1669 if(!file_exists($full_path)) {
1670 $this->_error("File ". $full_path ." does not exist\n");
1674 if(!is_readable($full_path)) {
1675 $this->_error("File ". $full_path ." is not readable for ". $this->getuid() ."\n");
1679 $this->_debug("Image [". $idx ."] ". $this->shrink_text($this->parse_uri($details['uri'], 'filename'), 20) ." Thumbnails:");
1681 /* If Nikon NEF format, we need to treat it another way */
1682 if(isset($this->cfg->dcraw_bin) &&
1683 file_exists($this->cfg->dcraw_bin) &&
1684 is_executable($this->cfg->dcraw_bin) &&
1685 preg_match('/\.nef$/i', $details['uri'])) {
1687 $ppm_path = preg_replace('/\.nef$/i', '.ppm', $full_path);
1689 /* if PPM file does not exist, let dcraw convert it from NEF */
1690 if(!file_exists($ppm_path)) {
1691 system($this->cfg->dcraw_bin ." -a ". $full_path);
1694 /* for now we handle the PPM instead of the NEF */
1695 $full_path = $ppm_path;
1699 $file_md5 = md5_file($full_path);
1702 foreach($resolutions as $resolution) {
1704 $generate_it = false;
1706 $thumb_sub_path = substr($file_md5, 0, 2);
1707 $thumb_path = $this->cfg->thumb_path ."/". $thumb_sub_path ."/". $resolution ."_". $file_md5;
1709 /* if thumbnail-subdirectory does not exist yet, create it */
1710 if(!file_exists(dirname($thumb_path))) {
1711 mkdir(dirname($thumb_path), 0755);
1714 /* if the thumbnail file doesn't exist, create it */
1715 if(!file_exists($thumb_path)) {
1716 $generate_it = true;
1718 /* if the file hasn't changed there is no need to regen the thumb */
1719 elseif($file_md5 != $this->getMD5($idx) || $force) {
1720 $generate_it = true;
1723 if($generate_it || $overwrite) {
1725 $this->_debug(" ". $resolution ."px");
1726 if(!$this->create_thumbnail($full_path, $thumb_path, $resolution))
1734 $this->_debug(" already exist");
1737 /* set the new/changed MD5 sum for the current photo */
1739 $this->setMD5($idx, $file_md5);
1742 $this->_debug("\n");
1747 * returns stored md5 sum for a specific photo
1749 * this function queries the phpfspot database for a
1750 * stored MD5 checksum of the specified photo
1751 * @param integer $idx
1752 * @return string|null
1754 public function getMD5($idx)
1756 $result = $this->cfg_db->db_query("
1759 WHERE img_idx='". $idx ."'
1765 $img = $this->cfg_db->db_fetch_object($result);
1766 return $img['img_md5'];
1771 * set MD5 sum for the specific photo
1772 * @param integer $idx
1773 * @param string $md5
1775 private function setMD5($idx, $md5)
1777 $result = $this->cfg_db->db_exec("
1778 REPLACE INTO images (img_idx, img_md5)
1779 VALUES ('". $idx ."', '". $md5 ."')
1785 * store current tag condition
1787 * this function stores the current tag condition
1788 * (AND or OR) in the users session variables
1789 * @param string $mode
1792 public function setTagCondition($mode)
1794 $_SESSION['tag_condition'] = $mode;
1798 } // setTagCondition()
1801 * invoke tag & date search
1803 * this function will return all matching tags and store
1804 * them in the session variable selected_tags. furthermore
1805 * it also handles the date search.
1806 * getPhotoSelection() will then only return the matching
1810 public function startSearch()
1812 if(isset($_POST['from']) && $this->isValidDate($_POST['from'])) {
1813 $from = $_POST['from'];
1815 if(isset($_POST['to']) && $this->isValidDate($_POST['to'])) {
1819 if(isset($_POST['for_tag']) && is_string($_POST['for_tag'])) {
1820 $searchfor_tag = $_POST['for_tag'];
1821 $_SESSION['searchfor_tag'] = $_POST['for_tag'];
1824 if(isset($_POST['for_name']) && is_string($_POST['for_name'])) {
1825 $searchfor_name = $_POST['for_name'];
1826 $_SESSION['searchfor_name'] = $_POST['for_name'];
1831 if(isset($from) && !empty($from))
1832 $_SESSION['from_date'] = strtotime($from ." 00:00:00");
1834 unset($_SESSION['from_date']);
1836 if(isset($to) && !empty($to))
1837 $_SESSION['to_date'] = strtotime($to ." 23:59:59");
1839 unset($_SESSION['to_date']);
1841 if(isset($searchfor_tag) && !empty($searchfor_tag)) {
1842 /* new search, reset the current selected tags */
1843 $_SESSION['selected_tags'] = Array();
1844 foreach($this->avail_tags as $tag) {
1845 if(preg_match('/'. $searchfor_tag .'/i', $this->tags[$tag]))
1846 array_push($_SESSION['selected_tags'], $tag);
1855 * updates sort order in session variable
1857 * this function is invoked by RPC and will sort the requested
1858 * sort order in the session variable.
1859 * @param string $sort_order
1862 public function updateSortOrder($order)
1864 if(isset($this->sort_orders[$order])) {
1865 $_SESSION['sort_order'] = $order;
1869 return "unkown error";
1871 } // updateSortOrder()
1876 * this function rotates the image according the
1878 * @param string $img
1879 * @param integer $degress
1882 private function rotateImage($img, $degrees)
1884 if(function_exists("imagerotate")) {
1885 $img = imagerotate($img, $degrees, 0);
1887 function imagerotate($src_img, $angle)
1889 $src_x = imagesx($src_img);
1890 $src_y = imagesy($src_img);
1891 if ($angle == 180) {
1895 elseif ($src_x <= $src_y) {
1899 elseif ($src_x >= $src_y) {
1904 $rotate=imagecreatetruecolor($dest_x,$dest_y);
1905 imagealphablending($rotate, false);
1910 for ($y = 0; $y < ($src_y); $y++) {
1911 for ($x = 0; $x < ($src_x); $x++) {
1912 $color = imagecolorat($src_img, $x, $y);
1913 imagesetpixel($rotate, $dest_x - $y - 1, $x, $color);
1919 for ($y = 0; $y < ($src_y); $y++) {
1920 for ($x = 0; $x < ($src_x); $x++) {
1921 $color = imagecolorat($src_img, $x, $y);
1922 imagesetpixel($rotate, $y, $dest_y - $x - 1, $color);
1928 for ($y = 0; $y < ($src_y); $y++) {
1929 for ($x = 0; $x < ($src_x); $x++) {
1930 $color = imagecolorat($src_img, $x, $y);
1931 imagesetpixel($rotate, $dest_x - $x - 1, $dest_y - $y - 1, $color);
1945 $img = imagerotate($img, $degrees);
1954 * returns flipped image
1956 * this function will return an either horizontal or
1957 * vertical flipped truecolor image.
1958 * @param string $image
1959 * @param string $mode
1962 private function flipImage($image, $mode)
1964 $w = imagesx($image);
1965 $h = imagesy($image);
1966 $flipped = imagecreatetruecolor($w, $h);
1970 for ($y = 0; $y < $h; $y++) {
1971 imagecopy($flipped, $image, 0, $y, 0, $h - $y - 1, $w, 1);
1975 for ($x = 0; $x < $w; $x++) {
1976 imagecopy($flipped, $image, $x, 0, $w - $x - 1, 0, 1, $h);
1986 * return all assigned tags for the specified photo
1987 * @param integer $idx
1990 private function get_photo_tags($idx)
1992 $result = $this->db->db_query("
1995 INNER JOIN photo_tags pt
1997 WHERE pt.photo_id='". $idx ."'
2002 while($row = $this->db->db_fetch_object($result)) {
2003 if(isset($this->cfg->hide_tags) && in_array($row['name'], $this->cfg->hide_tags))
2005 $tags[$row['id']] = $row['name'];
2010 } // get_photo_tags()
2013 * create on-the-fly images with text within
2014 * @param string $txt
2015 * @param string $color
2016 * @param integer $space
2017 * @param integer $font
2020 public function showTextImage($txt, $color=000000, $space=4, $font=4, $w=300)
2022 if (strlen($color) != 6)
2025 $int = hexdec($color);
2026 $h = imagefontheight($font);
2027 $fw = imagefontwidth($font);
2028 $txt = explode("\n", wordwrap($txt, ($w / $fw), "\n"));
2029 $lines = count($txt);
2030 $im = imagecreate($w, (($h * $lines) + ($lines * $space)));
2031 $bg = imagecolorallocate($im, 255, 255, 255);
2032 $color = imagecolorallocate($im, 0xFF & ($int >> 0x10), 0xFF & ($int >> 0x8), 0xFF & $int);
2035 foreach ($txt as $text) {
2036 $x = (($w - ($fw * strlen($text))) / 2);
2037 imagestring($im, $font, $x, $y, $text, $color);
2038 $y += ($h + $space);
2041 Header("Content-type: image/png");
2044 } // showTextImage()
2047 * check if all requirements are met
2050 private function check_requirements()
2052 if(!function_exists("imagecreatefromjpeg")) {
2053 print "PHP GD library extension is missing<br />\n";
2057 if($this->cfg->db_access == "native" && !function_exists("sqlite3_open")) {
2058 print "PHP SQLite3 library extension is missing<br />\n";
2062 /* Check for HTML_AJAX PEAR package, lent from Horde project */
2063 ini_set('track_errors', 1);
2064 @include_once 'HTML/AJAX/Server.php';
2065 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
2066 print "PEAR HTML_AJAX package is missing<br />\n";
2069 @include_once 'Calendar/Calendar.php';
2070 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
2071 print "PEAR Calendar package is missing<br />\n";
2074 @include_once 'Console/Getopt.php';
2075 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
2076 print "PEAR Console_Getopt package is missing<br />\n";
2079 @include_once $this->cfg->smarty_path .'/libs/Smarty.class.php';
2080 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
2081 print "Smarty template engine can not be found in ". $this->cfg->smarty_path ."/libs/Smarty.class.php<br />\n";
2084 ini_restore('track_errors');
2091 } // check_requirements()
2093 private function _debug($text)
2095 if($this->fromcmd) {
2102 * check if specified MIME type is supported
2103 * @param string $mime
2106 public function checkifImageSupported($mime)
2108 $supported_types = Array(
2111 "image/x-portable-pixmap",
2115 if(in_array($mime, $supported_types))
2120 } // checkifImageSupported()
2124 * @param string $text
2126 public function _error($text)
2128 switch($this->cfg->logging) {
2131 print "<img src=\"resources/green_info.png\" alt=\"warning\" />\n";
2132 print $text ."<br />\n";
2138 error_log($text, 3, $his->cfg->log_file);
2142 $this->runtime_error = true;
2147 * output calendard input fields
2148 * @param string $mode
2151 private function get_calendar($mode)
2153 $year = isset($_SESSION[$mode .'_date']) ? date("Y", $_SESSION[$mode .'_date']) : date("Y");
2154 $month = isset($_SESSION[$mode .'_date']) ? date("m", $_SESSION[$mode .'_date']) : date("m");
2155 $day = isset($_SESSION[$mode .'_date']) ? date("d", $_SESSION[$mode .'_date']) : date("d");
2157 $output = "<input type=\"text\" size=\"3\" id=\"". $mode ."year\" value=\"". $year ."\"";
2158 if(!isset($_SESSION[$mode .'_date']))
2159 $output.= " disabled=\"disabled\"";
2161 $output.= "<input type=\"text\" size=\"1\" id=\"". $mode ."month\" value=\"". $month ."\"";
2162 if(!isset($_SESSION[$mode .'_date']))
2163 $output.= " disabled=\"disabled\"";
2165 $output.= "<input type=\"text\" size=\"1\" id=\"". $mode ."day\" value=\"". $day ."\"";
2166 if(!isset($_SESSION[$mode .'_date']))
2167 $output.= " disabled=\"disabled\"";
2175 * output calendar matrix
2176 * @param integer $year
2177 * @param integer $month
2178 * @param integer $day
2180 public function get_calendar_matrix($year = 0, $month = 0, $day = 0)
2182 if (!isset($year)) $year = date('Y');
2183 if (!isset($month)) $month = date('m');
2184 if (!isset($day)) $day = date('d');
2189 require_once CALENDAR_ROOT.'Month/Weekdays.php';
2190 require_once CALENDAR_ROOT.'Day.php';
2193 $month = new Calendar_Month_Weekdays($year,$month);
2196 $prevStamp = $month->prevMonth(true);
2197 $prev = "javascript:setMonth(". date('Y',$prevStamp) .", ". date('n',$prevStamp) .", ". date('j',$prevStamp) .");";
2198 $nextStamp = $month->nextMonth(true);
2199 $next = "javascript:setMonth(". date('Y',$nextStamp) .", ". date('n',$nextStamp) .", ". date('j',$nextStamp) .");";
2201 $selectedDays = array (
2202 new Calendar_Day($year,$month,$day),
2203 new Calendar_Day($year,12,25),
2206 // Build the days in the month
2207 $month->build($selectedDays);
2209 $this->tmpl->assign('current_month', date('F Y',$month->getTimeStamp()));
2210 $this->tmpl->assign('prev_month', $prev);
2211 $this->tmpl->assign('next_month', $next);
2213 while ( $day = $month->fetch() ) {
2215 if(!isset($matrix[$rows]))
2216 $matrix[$rows] = Array();
2220 $dayStamp = $day->thisDay(true);
2221 $link = "javascript:setCalendarDate(". date('Y',$dayStamp) .", ". date('n',$dayStamp).", ". date('j',$dayStamp) .");";
2223 // isFirst() to find start of week
2224 if ( $day->isFirst() )
2227 if ( $day->isSelected() ) {
2228 $string.= "<td class=\"selected\">".$day->thisDay()."</td>\n";
2229 } else if ( $day->isEmpty() ) {
2230 $string.= "<td> </td>\n";
2232 $string.= "<td><a class=\"calendar\" href=\"".$link."\">".$day->thisDay()."</a></td>\n";
2235 // isLast() to find end of week
2236 if ( $day->isLast() )
2237 $string.= "</tr>\n";
2239 $matrix[$rows][$cols] = $string;
2249 $this->tmpl->assign('matrix', $matrix);
2250 $this->tmpl->assign('rows', $rows);
2251 $this->tmpl->show("calendar.tpl");
2253 } // get_calendar_matrix()
2256 * output export page
2257 * @param string $mode
2259 public function getExport($mode)
2261 $pictures = $this->getPhotoSelection();
2262 $current_tags = $this->getCurrentTags();
2264 foreach($pictures as $picture) {
2266 $orig_url = $this->get_phpfspot_url() ."index.php?mode=showp&id=". $picture;
2267 if($current_tags != "") {
2268 $orig_url.= "&tags=". $current_tags;
2270 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
2271 $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
2274 $thumb_url = $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
2279 // <a href="%pictureurl%"><img src="%thumbnailurl%" ></a>
2280 print htmlspecialchars("<a href=\"". $orig_url ."\"><img src=\"". $thumb_url ."\" /></a>") ."<br />\n";
2284 // "[%pictureurl% %thumbnailurl%]"
2285 print htmlspecialchars("[".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
2288 case 'MoinMoinList':
2289 // " * [%pictureurl% %thumbnailurl%]"
2290 print " " . htmlspecialchars("* [".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
2301 public function getRSSFeed()
2303 Header("Content-type: text/xml; charset=utf-8");
2304 print "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
2307 xmlns:media="http://search.yahoo.com/mrss/"
2308 xmlns:dc="http://purl.org/dc/elements/1.1/"
2311 <title>phpfspot</title>
2312 <description>phpfspot RSS feed</description>
2313 <link><?php print htmlspecialchars($this->get_phpfspot_url()); ?></link>
2314 <pubDate><?php print strftime("%a, %d %b %Y %T %z"); ?></pubDate>
2315 <generator>phpfspot</generator>
2318 $pictures = $this->getPhotoSelection();
2319 $current_tags = $this->getCurrentTags();
2321 foreach($pictures as $picture) {
2323 $orig_url = $this->get_phpfspot_url() ."index.php?mode=showp&id=". $picture;
2324 if($current_tags != "") {
2325 $orig_url.= "&tags=". $current_tags;
2327 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
2328 $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
2331 $details = $this->get_photo_details($picture);
2333 $thumb_url = $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
2334 $thumb_html = htmlspecialchars("
2335 <a href=\"". $orig_url ."\"><img src=\"". $thumb_url ."\" /></a>
2337 ". $details['description']);
2339 $orig_path = $this->translate_path($this->parse_uri($details['uri'], 'fullpath'));
2341 /* get EXIF information if JPEG */
2342 if($details['mime'] == "image/jpeg") {
2343 $meta = $this->get_meta_informations($orig_path);
2346 $meta_date = isset($meta['FileDateTime']) ? $meta['FileDateTime'] : filemtime($orig_path);
2350 <title><?php print htmlspecialchars($this->parse_uri($details['uri'], 'filename')); ?></title>
2351 <link><?php print htmlspecialchars($orig_url); ?></link>
2352 <guid><?php print htmlspecialchars($orig_url); ?></guid>
2353 <dc:date.Taken><?php print strftime("%Y-%m-%dT%H:%M:%S+00:00", $meta_date); ?></dc:date.Taken>
2355 <?php print $thumb_html; ?>
2357 <pubDate><?php print strftime("%a, %d %b %Y %T %z", $meta_date); ?></pubDate>
2372 * return all selected tags as one string
2375 private function getCurrentTags()
2378 if(isset($_SESSION['selected_tags']) && $_SESSION['selected_tags'] != "") {
2379 foreach($_SESSION['selected_tags'] as $tag)
2380 $current_tags.= $tag .",";
2381 $current_tags = substr($current_tags, 0, strlen($current_tags)-1);
2383 return $current_tags;
2385 } // getCurrentTags()
2388 * return the current photo
2390 public function getCurrentPhoto()
2392 if(isset($_SESSION['current_photo'])) {
2393 print $_SESSION['current_photo'];
2395 } // getCurrentPhoto()
2398 * tells the client browser what to do
2400 * this function is getting called via AJAX by the
2401 * client browsers. it will tell them what they have
2402 * to do next. This is necessary for directly jumping
2403 * into photo index or single photo view when the are
2404 * requested with specific URLs
2407 public function whatToDo()
2409 if(isset($_SESSION['current_photo']) && $_SESSION['start_action'] == 'showp') {
2410 return "show_photo";
2412 elseif(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
2413 return "showpi_tags";
2415 elseif(isset($_SESSION['start_action']) && $_SESSION['start_action'] == 'showpi') {
2419 return "nothing special";
2424 * return the current process-user
2427 private function getuid()
2429 if($uid = posix_getuid()) {
2430 if($user = posix_getpwuid($uid)) {
2431 return $user['name'];
2440 * returns a select-dropdown box to select photo index sort parameters
2441 * @param array $params
2442 * @param smarty $smarty
2445 public function smarty_sort_select_list($params, &$smarty)
2449 foreach($this->sort_orders as $key => $value) {
2450 $output.= "<option value=\"". $key ."\"";
2451 if($key == $_SESSION['sort_order']) {
2452 $output.= " selected=\"selected\"";
2454 $output.= ">". $value ."</option>";
2459 } // smarty_sort_select_list()
2462 * returns the currently selected sort order
2465 private function get_sort_order()
2467 switch($_SESSION['sort_order']) {
2469 return " ORDER BY p.time ASC";
2472 return " ORDER BY p.time DESC";
2475 if($this->dbver < 9) {
2476 return " ORDER BY p.name ASC";
2479 return " ORDER BY basename(p.uri) ASC";
2483 if($this->dbver < 9) {
2484 return " ORDER BY p.name DESC";
2487 return " ORDER BY basename(p.uri) DESC";
2491 return " ORDER BY t.name ASC ,p.time ASC";
2494 return " ORDER BY t.name DESC ,p.time ASC";
2498 } // get_sort_order()
2501 * return the next to be shown slide show image
2503 * this function returns the URL of the next image
2504 * in the slideshow sequence.
2507 public function getNextSlideShowImage()
2509 $all_photos = $this->getPhotoSelection();
2511 if(!isset($_SESSION['slideshow_img']) || $_SESSION['slideshow_img'] == count($all_photos)-1)
2512 $_SESSION['slideshow_img'] = 0;
2514 $_SESSION['slideshow_img']++;
2516 return $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $all_photos[$_SESSION['slideshow_img']] ."&width=". $this->cfg->photo_width;
2518 } // getNextSlideShowImage()
2521 * return the previous to be shown slide show image
2523 * this function returns the URL of the previous image
2524 * in the slideshow sequence.
2527 public function getPrevSlideShowImage()
2529 $all_photos = $this->getPhotoSelection();
2531 if(!isset($_SESSION['slideshow_img']) || $_SESSION['slideshow_img'] == 0)
2532 $_SESSION['slideshow_img'] = 0;
2534 $_SESSION['slideshow_img']--;
2536 return $this->get_phpfspot_url() ."phpfspot_img.php?idx=". $all_photos[$_SESSION['slideshow_img']] ."&width=". $this->cfg->photo_width;
2538 } // getPrevSlideShowImage()
2540 public function resetSlideShow()
2542 if(isset($_SESSION['slideshow_img']))
2543 unset($_SESSION['slideshow_img']);
2545 } // resetSlideShow()
2550 * this function will get all photos from the fspot
2551 * database and randomly return ONE entry
2553 * saddly there is yet no sqlite3 function which returns
2554 * the bulk result in array, so we have to fill up our
2558 public function get_random_photo()
2567 /* if show_tags is set, only return details for photos which
2568 are specified to be shown
2570 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
2572 INNER JOIN photo_tags pt
2577 t.name IN ('".implode("','",$this->cfg->show_tags)."')";
2580 $result = $this->db->db_query($query_str);
2582 while($row = $this->db->db_fetch_object($result)) {
2583 array_push($all, $row['id']);
2586 return $all[array_rand($all)];
2588 } // get_random_photo()
2591 * get random photo tag photo
2593 * this function will get all photos tagged with the requested
2594 * tag from the fspot database and randomly return ONE entry
2596 * saddly there is yet no sqlite3 function which returns
2597 * the bulk result in array, so we have to fill up our
2601 public function get_random_tag_photo($tagidx)
2608 INNER JOIN photo_tags pt
2612 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
2620 pt.tag_id LIKE '". $tagidx ."'
2623 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
2626 t.name IN ('".implode("','",$this->cfg->show_tags)."')
2630 $result = $this->db->db_query($query_str);
2632 while($row = $this->db->db_fetch_object($result)) {
2633 array_push($all, $row['id']);
2636 return $all[array_rand($all)];
2638 } // get_random_tag_photo()
2641 * validates provided date
2643 * this function validates if the provided date
2644 * contains a valid date and will return true
2646 * @param string $date_str
2649 public function isValidDate($date_str)
2651 $timestamp = strtotime($date_str);
2653 if(is_numeric($timestamp))
2661 * timestamp to string conversion
2662 * @param integer $timestamp
2665 private function ts2str($timestamp)
2667 return strftime("%Y-%m-%d", $timestamp);
2671 * extract tag-names from $_GET['tags']
2672 * @param string $tags_str
2675 private function extractTags($tags_str)
2677 $not_validated = split(',', $tags_str);
2678 $validated = array();
2680 foreach($not_validated as $tag) {
2681 if(is_numeric($tag))
2682 array_push($validated, $tag);
2690 * returns the full path to a thumbnail
2691 * @param integer $width
2692 * @param integer $photo
2695 public function get_thumb_path($width, $photo)
2697 $md5 = $this->getMD5($photo);
2698 $sub_path = substr($md5, 0, 2);
2699 return $this->cfg->thumb_path
2707 } // get_thumb_path()
2710 * returns server's virtual host name
2713 private function get_server_name()
2715 return $_SERVER['SERVER_NAME'];
2716 } // get_server_name()
2719 * returns type of webprotocol which is currently used
2722 private function get_web_protocol()
2724 if(!isset($_SERVER['HTTPS']))
2728 } // get_web_protocol()
2731 * return url to this phpfspot installation
2734 private function get_phpfspot_url()
2736 return $this->get_web_protocol() ."://". $this->get_server_name() . $this->cfg->web_path;
2737 } // get_phpfspot_url()
2740 * returns the number of photos which are tagged with $tag_id
2741 * @param integer $tag_id
2744 public function get_num_photos($tag_id)
2746 if($result = $this->db->db_fetchSingleRow("
2747 SELECT count(*) as number
2750 tag_id LIKE '". $tag_id ."'")) {
2752 return $result['number'];
2758 } // get_num_photos()
2761 * check file exists and is readable
2763 * returns true, if everything is ok, otherwise false
2764 * if $silent is not set, this function will output and
2766 * @param string $file
2767 * @param boolean $silent
2770 private function check_readable($file, $silent = null)
2772 if(!file_exists($file)) {
2774 print "File \"". $file ."\" does not exist.\n";
2778 if(!is_readable($file)) {
2780 print "File \"". $file ."\" is not reachable for user ". $this->getuid() ."\n";
2786 } // check_readable()
2789 * check if all needed indices are present
2791 * this function checks, if some needed indices are already
2792 * present, or if not, create them on the fly. they are
2793 * necessary to speed up some queries like that one look for
2794 * all tags, when show_tags is specified in the configuration.
2796 private function checkDbIndices()
2798 $result = $this->db->db_exec("
2799 CREATE INDEX IF NOT EXISTS
2806 } // checkDbIndices()
2809 * retrive F-Spot database version
2811 * this function will return the F-Spot database version number
2812 * It is stored within the sqlite3 database in the table meta
2813 * @return string|null
2815 public function getFspotDBVersion()
2817 if($result = $this->db->db_fetchSingleRow("
2818 SELECT data as version
2821 name LIKE 'F-Spot Database Version'
2823 return $result['version'];
2827 } // getFspotDBVersion()
2830 * parse the provided URI and will returned the requested chunk
2831 * @param string $uri
2832 * @param string $mode
2835 public function parse_uri($uri, $mode)
2837 if(($components = parse_url($uri)) !== false) {
2841 return basename($components['path']);
2844 return dirname($components['path']);
2847 return $components['path'];
2857 * validate config options
2859 * this function checks if all necessary configuration options are
2860 * specified and set.
2863 private function check_config_options()
2865 if(!isset($this->cfg->page_title) || $this->cfg->page_title == "")
2866 $this->_error("Please set \$page_title in phpfspot_cfg");
2868 if(!isset($this->cfg->base_path) || $this->cfg->base_path == "")
2869 $this->_error("Please set \$base_path in phpfspot_cfg");
2871 if(!isset($this->cfg->web_path) || $this->cfg->web_path == "")
2872 $this->_error("Please set \$web_path in phpfspot_cfg");
2874 if(!isset($this->cfg->thumb_path) || $this->cfg->thumb_path == "")
2875 $this->_error("Please set \$thumb_path in phpfspot_cfg");
2877 if(!isset($this->cfg->smarty_path) || $this->cfg->smarty_path == "")
2878 $this->_error("Please set \$smarty_path in phpfspot_cfg");
2880 if(!isset($this->cfg->fspot_db) || $this->cfg->fspot_db == "")
2881 $this->_error("Please set \$fspot_db in phpfspot_cfg");
2883 if(!isset($this->cfg->db_access) || $this->cfg->db_access == "")
2884 $this->_error("Please set \$db_access in phpfspot_cfg");
2886 if(!isset($this->cfg->phpfspot_db) || $this->cfg->phpfspot_db == "")
2887 $this->_error("Please set \$phpfspot_db in phpfspot_cfg");
2889 if(!isset($this->cfg->thumb_width) || $this->cfg->thumb_width == "")
2890 $this->_error("Please set \$thumb_width in phpfspot_cfg");
2892 if(!isset($this->cfg->thumb_height) || $this->cfg->thumb_height == "")
2893 $this->_error("Please set \$thumb_height in phpfspot_cfg");
2895 if(!isset($this->cfg->photo_width) || $this->cfg->photo_width == "")
2896 $this->_error("Please set \$photo_width in phpfspot_cfg");
2898 if(!isset($this->cfg->mini_width) || $this->cfg->mini_width == "")
2899 $this->_error("Please set \$mini_width in phpfspot_cfg");
2901 if(!isset($this->cfg->thumbs_per_page))
2902 $this->_error("Please set \$thumbs_per_page in phpfspot_cfg");
2904 if(!isset($this->cfg->path_replace_from) || $this->cfg->path_replace_from == "")
2905 $this->_error("Please set \$path_replace_from in phpfspot_cfg");
2907 if(!isset($this->cfg->path_replace_to) || $this->cfg->path_replace_to == "")
2908 $this->_error("Please set \$path_replace_to in phpfspot_cfg");
2910 if(!isset($this->cfg->hide_tags))
2911 $this->_error("Please set \$hide_tags in phpfspot_cfg");
2913 if(!isset($this->cfg->theme_name))
2914 $this->_error("Please set \$theme_name in phpfspot_cfg");
2916 if(!isset($this->cfg->logging))
2917 $this->_error("Please set \$logging in phpfspot_cfg");
2919 if(isset($this->cfg->logging) && $this->cfg->logging == 'logfile') {
2921 if(!isset($this->cfg->log_file))
2922 $this->_error("Please set \$log_file because you set logging = log_file in phpfspot_cfg");
2924 if(!is_writeable($this->cfg->log_file))
2925 $this->_error("The specified \$log_file ". $log_file ." is not writeable!");
2929 /* check for pending slash on web_path */
2930 if(!preg_match("/\/$/", $this->cfg->web_path))
2931 $this->cfg->web_path.= "/";
2933 return $this->runtime_error;
2935 } // check_config_options()
2938 * cleanup phpfspot own database
2940 * When photos are getting delete from F-Spot, there will remain
2941 * remain some residues in phpfspot own database. This function
2942 * will try to wipe them out.
2944 public function cleanup_phpfspot_db()
2946 $to_delete = Array();
2948 $result = $this->cfg_db->db_query("
2951 ORDER BY img_idx ASC
2954 while($row = $this->cfg_db->db_fetch_object($result)) {
2955 if(!$this->db->db_fetchSingleRow("
2958 WHERE id='". $row['img_idx'] ."'")) {
2960 array_push($to_delete, $row['img_idx'], ',');
2964 print count($to_delete) ." unnecessary objects will be removed from phpfspot's database.\n";
2966 $this->cfg_db->db_exec("
2968 WHERE img_idx IN (". implode($to_delete) .")
2971 } // cleanup_phpfspot_db()
2974 * return first image of the page, the $current photo
2977 * this function is used to find out the first photo of the
2978 * current page, in which the $current photo lies. this is
2979 * used to display the correct photo, when calling showPhotoIndex()
2981 * @param integer $current
2982 * @param integer $max
2985 private function getCurrentPage($current, $max)
2987 if(isset($this->cfg->thumbs_per_page) && !empty($this->cfg->thumbs_per_page)) {
2988 for($page_start = 0; $page_start <= $max; $page_start+=$this->cfg->thumbs_per_page) {
2989 if($current >= $page_start && $current < ($page_start+$this->cfg->thumbs_per_page))
2995 } // getCurrentPage()
3000 * this function tries to find out the correct mime-type
3001 * for the provided file.
3002 * @param string $file
3005 public function get_mime_info($file)
3007 $details = getimagesize($orig_image);
3009 /* if getimagesize() returns empty, try at least to find out the
3012 if(empty($details) && function_exists('mime_content_type')) {
3014 // mime_content_type is marked as deprecated in the documentation,
3015 // but is it really necessary to force users to install a PECL
3017 $details['mime'] = mime_content_type($file);
3020 return $details['mime'];
3022 } // get_mime_info()
3025 * return tag-name by tag-idx
3027 * this function returns the tag-name for the requested
3028 * tag specified by tag-idx.
3029 * @param integer $idx
3032 public function get_tag_name($idx)
3034 if($result = $this->db->db_fetchSingleRow("
3038 id LIKE '". $idx ."'")) {
3040 return $result['name'];