3 /***************************************************************************
5 * phpfspot, presents your F-Spot photo collection in Web browsers.
7 * Copyright (c) by Andreas Unterkircher
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 ***************************************************************************/
25 require_once "phpfspot_cfg.php";
26 require_once "phpfspot_db.php";
31 * this class contains the most functions which will to the major
39 * phpfspot configuration
47 * SQLite database handle to f-spot database
55 * SQLite database handle to phpfspot database
63 * Smarty template engine
64 * @link http://smarty.php.net smarty.php.net
65 * @see PHPFSPOT_TMPL()
79 * list of available, not-selected, tags
86 * true if runtime error occued
90 private $runtime_error = false;
93 * F-Spot database version
100 * class constructor ($cfg, $db, $cfg_db, $tmpl, $db_ver)
102 * this function will be called on class construct
103 * and will check requirements, loads configuration,
104 * open databases and start the user session
106 public function __construct()
109 * register PHPFSPOT class global
111 * @global PHPFSPOT $GLOBALS['phpfspot']
114 $GLOBALS['phpfspot'] =& $this;
116 $this->cfg = new PHPFSPOT_CFG;
118 /* verify config settings */
119 if($this->check_config_options()) {
123 /* set application name and version information */
124 $this->cfg->product = "phpfspot";
125 $this->cfg->version = "1.5";
127 $this->sort_orders= array(
128 'date_asc' => 'Date ↑',
129 'date_desc' => 'Date ↓',
130 'name_asc' => 'Name ↑',
131 'name_desc' => 'Name ↓',
132 'tags_asc' => 'Tags ↑',
133 'tags_desc' => 'Tags ↓',
136 /* Check necessary requirements */
137 if(!$this->check_requirements()) {
141 /******* Opening F-Spot's sqlite database *********/
143 /* Check if database file is writeable */
144 if(!is_writeable($this->cfg->fspot_db)) {
145 print $this->cfg->fspot_db ." is not writeable for user ". $this->getuid() ."\n";
149 /* open the database */
150 $this->db = new PHPFSPOT_DB($this, $this->cfg->fspot_db);
152 /* change sqlite temp directory, if requested */
153 if(isset($this->cfg->sqlite_temp_dir)) {
156 temp_store_directory = '". $this->cfg->sqlite_temp_dir ."'
160 $this->dbver = $this->getFspotDBVersion();
162 if(!is_writeable($this->cfg->base_path ."/templates_c")) {
163 print $this->cfg->base_path ."/templates_c: directory is not writeable for user ". $this->getuid() ."\n";
167 if(!is_writeable($this->cfg->thumb_path)) {
168 print $this->cfg->thumb_path .": directory is not writeable for user ". $this->getuid() ."\n";
172 /******* Opening phpfspot's sqlite database *********/
174 /* Check if directory where the database file is stored is writeable */
175 if(!is_writeable(dirname($this->cfg->phpfspot_db))) {
176 print dirname($this->cfg->phpfspot_db) .": directory is not writeable for user ". $this->getuid() ."\n";
180 /* Check if database file is writeable */
181 if(!is_writeable($this->cfg->phpfspot_db)) {
182 print $this->cfg->phpfspot_db ." is not writeable for user ". $this->getuid() ."\n";
186 /* open the database */
187 $this->cfg_db = new PHPFSPOT_DB($this, $this->cfg->phpfspot_db);
189 /* change sqlite temp directory, if requested */
190 if(isset($this->cfg->sqlite_temp_dir)) {
191 $this->cfg_db->db_exec("
193 temp_store_directory = '". $this->cfg->sqlite_temp_dir ."'
197 /* Check if some tables need to be created */
198 $this->check_config_table();
200 /* overload Smarty class with our own template handler */
201 require_once "phpfspot_tmpl.php";
202 $this->tmpl = new PHPFSPOT_TMPL();
204 $this->tmpl->assign('web_path', $this->cfg->web_path);
206 /* check if all necessary indices exist */
207 $this->checkDbIndices();
209 /* if session is not yet started, do it now */
210 if(session_id() == "")
213 if(!isset($_SESSION['tag_condition']))
214 $_SESSION['tag_condition'] = 'or';
216 if(!isset($_SESSION['sort_order']))
217 $_SESSION['sort_order'] = 'date_desc';
219 if(!isset($_SESSION['searchfor_tag']))
220 $_SESSION['searchfor_tag'] = '';
222 // if begin_with is still set but thumbs_per_page is now 0, unset it
223 if(isset($_SESSION['begin_with']) && $this->cfg->thumbs_per_page == 0)
224 unset($_SESSION['begin_with']);
226 // if user-friendly-url's are enabled, set also a flag for the template handler
227 if($this->is_user_friendly_url()) {
228 $this->tmpl->assign('user_friendly_url', 'true');
233 public function __destruct()
239 * show - generate html output
241 * this function can be called after the constructor has
242 * prepared everyhing. it will load the index.tpl smarty
243 * template. if necessary it will registere pre-selects
244 * (photo index, photo, tag search, date search) into
247 public function show()
249 $this->tmpl->assign('searchfor_tag', $_SESSION['searchfor_tag']);
250 $this->tmpl->assign('page_title', $this->cfg->page_title);
251 $this->tmpl->assign('current_condition', $_SESSION['tag_condition']);
252 $this->tmpl->assign('template_path', 'themes/'. $this->cfg->theme_name);
255 if($this->is_user_friendly_url()) {
256 $content = $this->parse_user_friendly_url($_SERVER['REQUEST_URI']);
259 if(isset($_GET['mode'])) {
261 $_SESSION['start_action'] = $_GET['mode'];
263 switch($_GET['mode']) {
265 if(isset($_GET['tags'])) {
266 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
268 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
269 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
271 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
272 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
276 if(isset($_GET['tags'])) {
277 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
278 $_SESSION['start_action'] = 'showp';
280 if(isset($_GET['id']) && is_numeric($_GET['id'])) {
281 $_SESSION['current_photo'] = $_GET['id'];
282 $_SESSION['start_action'] = 'showp';
284 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
285 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
287 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
288 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
292 $this->tmpl->show("export.tpl");
296 $this->tmpl->show("slideshow.tpl");
300 if(isset($_GET['tags'])) {
301 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
303 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
304 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
306 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
307 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
315 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date']))
316 $this->tmpl->assign('date_search_enabled', true);
318 $this->tmpl->register_function("sort_select_list", array(&$this, "smarty_sort_select_list"), false);
319 $this->tmpl->assign('search_from_date', $this->get_calendar('from'));
320 $this->tmpl->assign('search_to_date', $this->get_calendar('to'));
322 $this->tmpl->assign('preset_selected_tags', $this->getSelectedTags());
323 $this->tmpl->assign('preset_available_tags', $this->getAvailableTags());
325 if(!isset($content)) {
326 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags']))
327 $this->tmpl->assign('initial_content', $this->showPhotoIndex());
329 $this->tmpl->assign('initial_content', $this->tmpl->fetch('welcome.tpl'));
332 $this->tmpl->assign('initial_content', $content);
334 $this->tmpl->show("index.tpl");
339 * get_tags - grab all tags of f-spot's database
341 * this function will get all available tags from
342 * the f-spot database and store them within two
343 * arrays within this class for later usage. in
344 * fact, if the user requests (hide_tags) it will
345 * opt-out some of them.
347 * this function is getting called once by show()
349 private function get_tags()
351 $this->avail_tags = Array();
354 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
357 DISTINCT t1.id as id, t1.name as name
360 INNER JOIN photo_tags
361 pt2 ON pt1.photo_id=pt2.photo_id
367 t2.name IN ('".implode("','",$this->cfg->show_tags)."')
369 t1.sort_priority ASC";
371 $result = $this->db->db_query($query_str);
375 $result = $this->db->db_query("
378 ORDER BY sort_priority ASC
382 while($row = $this->db->db_fetch_object($result)) {
384 $tag_id = $row['id'];
385 $tag_name = $row['name'];
387 /* if the user has specified to ignore this tag in phpfspot's
388 configuration, ignore it here so it does not get added to
391 if(in_array($row['name'], $this->cfg->hide_tags))
394 /* if you include the following if-clause and the user has specified
395 to only show certain tags which are specified in phpfspot's
396 configuration, ignore all others so they will not be added to the
398 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags) &&
399 !in_array($row['name'], $this->cfg->show_tags))
403 $this->tags[$tag_id] = $tag_name;
404 $this->avail_tags[$count] = $tag_id;
412 * extract all photo details
414 * retrieve all available details from f-spot's
415 * database and return them as object
416 * @param integer $idx
417 * @return object|null
419 public function get_photo_details($idx)
421 if($this->dbver < 9) {
423 SELECT p.id, p.name, p.time, p.directory_path, p.description
429 SELECT p.id, p.uri, p.time, p.description
434 /* if show_tags is set, only return details for photos which
435 are specified to be shown
437 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
439 INNER JOIN photo_tags pt
443 WHERE p.id='". $idx ."'
444 AND t.name IN ('".implode("','",$this->cfg->show_tags)."')";
448 WHERE p.id='". $idx ."'
452 if($result = $this->db->db_query($query_str)) {
454 $row = $this->db->db_fetch_object($result);
456 if($this->dbver < 9) {
457 $row['uri'] = "file://". $row['directory_path'] ."/". $row['name'];
466 } // get_photo_details
469 * returns aligned photo names
471 * this function returns aligned (length) names for
472 * an specific photo. If the length of the name exceeds
473 * $limit the name will be shrinked (...)
474 * @param integer $idx
475 * @param integer $limit
476 * @return string|null
478 public function getPhotoName($idx, $limit = 0)
480 if($details = $this->get_photo_details($idx)) {
481 if($long_name = $this->parse_uri($details['uri'], 'filename')) {
482 $name = $this->shrink_text($long_name, $limit);
492 * shrink text according provided limit
494 * If the length of the name exceeds $limit the
495 * text will be shortend and some content in between
496 * will be replaced with "..."
498 * @param integer $limit
501 private function shrink_text($text, $limit)
503 if($limit != 0 && strlen($text) > $limit) {
504 $text = substr($text, 0, $limit-5) ."...". substr($text, -($limit-5));
512 * translate f-spoth photo path
514 * as the full-qualified path recorded in the f-spot database
515 * is usally not the same as on the webserver, this function
516 * will replace the path with that one specified in the cfg
517 * @param string $path
520 public function translate_path($path)
522 return str_replace($this->cfg->path_replace_from, $this->cfg->path_replace_to, $path);
527 * control HTML ouput for a single photo
529 * this function provides all the necessary information
530 * for the single photo template.
531 * @param integer photo
533 public function showPhoto($photo)
535 /* get all photos from the current photo selection */
536 $all_photos = $this->getPhotoSelection();
537 $count = count($all_photos);
539 for($i = 0; $i < $count; $i++) {
541 // $get_next will be set, when the photo which has to
542 // be displayed has been found - this means that the
543 // next available is in fact the NEXT image (for the
545 if(isset($get_next)) {
546 $next_img = $all_photos[$i];
550 /* the next photo is our NEXT photo */
551 if($all_photos[$i] == $photo) {
555 $previous_img = $all_photos[$i];
558 if($photo == $all_photos[$i]) {
563 $details = $this->get_photo_details($photo);
570 $orig_path = $this->translate_path($this->parse_uri($details['uri'], 'fullpath'));
571 $thumb_path = $this->get_thumb_path($this->cfg->photo_width, $photo);
573 if(!file_exists($orig_path)) {
574 $this->_error("Photo ". $orig_path ." does not exist!<br />\n");
578 if(!is_readable($orig_path)) {
579 $this->_error("Photo ". $orig_path ." is not readable for user ". $this->getuid() ."<br />\n");
583 /* If the thumbnail doesn't exist yet, try to create it */
584 if(!file_exists($thumb_path)) {
585 $this->gen_thumb($photo, true);
586 $thumb_path = $this->get_thumb_path($this->cfg->photo_width, $photo);
589 /* get mime-type, height and width from the original photo */
590 $info = getimagesize($orig_path);
592 /* get EXIF information if JPEG */
593 if($info['mime'] == "image/jpeg") {
594 $meta = $this->get_meta_informations($orig_path);
597 /* If EXIF data are available, use them */
598 if(isset($meta['ExifImageWidth'])) {
599 $meta_res = $meta['ExifImageWidth'] ."x". $meta['ExifImageLength'];
601 $meta_res = $info[0] ."x". $info[1];
604 $meta_date = isset($meta['FileDateTime']) ? strftime("%a %x %X", $meta['FileDateTime']) : "n/a";
605 $meta_make = isset($meta['Make']) ? $meta['Make'] ." / ". $meta['Model'] : "n/a";
606 $meta_size = isset($meta['FileSize']) ? round($meta['FileSize']/1024, 1) ."kbyte" : "n/a";
608 $extern_link = "index.php?mode=showp&id=". $photo;
609 $current_tags = $this->getCurrentTags();
610 if($current_tags != "") {
611 $extern_link.= "&tags=". $current_tags;
613 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
614 $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
617 $this->tmpl->assign('extern_link', $extern_link);
619 if(!file_exists($thumb_path)) {
620 $this->_error("Can't open file ". $thumb_path ."\n");
624 $info_thumb = getimagesize($thumb_path);
626 $this->tmpl->assign('description', $details['description']);
627 $this->tmpl->assign('image_name', $this->parse_uri($details['uri'], 'filename'));
629 $this->tmpl->assign('width', $info_thumb[0]);
630 $this->tmpl->assign('height', $info_thumb[1]);
631 $this->tmpl->assign('ExifMadeOn', $meta_date);
632 $this->tmpl->assign('ExifMadeWith', $meta_make);
633 $this->tmpl->assign('ExifOrigResolution', $meta_res);
634 $this->tmpl->assign('ExifFileSize', $meta_size);
636 if($this->is_user_friendly_url()) {
637 $this->tmpl->assign('image_url', '/photo/'. $photo ."/". $this->cfg->photo_width);
638 $this->tmpl->assign('image_url_full', '/photo/'. $photo);
641 $this->tmpl->assign('image_url', 'phpfspot_img.php?idx='. $photo ."&width=". $this->cfg->photo_width);
642 $this->tmpl->assign('image_url_full', 'phpfspot_img.php?idx='. $photo);
645 $this->tmpl->assign('image_filename', $this->parse_uri($details['uri'], 'filename'));
647 $this->tmpl->assign('tags', $this->get_photo_tags($photo));
648 $this->tmpl->assign('current_page', $this->getCurrentPage($current, $count));
649 $this->tmpl->assign('current_img', $photo);
652 $this->tmpl->assign('previous_url', "javascript:showImage(". $previous_img .");");
653 $this->tmpl->assign('prev_img', $previous_img);
657 $this->tmpl->assign('next_url', "javascript:showImage(". $next_img .");");
658 $this->tmpl->assign('next_img', $next_img);
660 $this->tmpl->assign('mini_width', $this->cfg->mini_width);
661 $this->tmpl->assign('photo_width', $this->cfg->photo_width);
662 $this->tmpl->assign('photo_number', $i);
663 $this->tmpl->assign('photo_count', count($all_photos));
665 return $this->tmpl->fetch("single_photo.tpl");
670 * all available tags and tag cloud
672 * this function outputs all available tags (time ordered)
673 * and in addition output them as tag cloud (tags which have
674 * many photos will appears more then others)
676 public function getAvailableTags()
678 /* retrive tags from database */
683 $result = $this->db->db_query("
684 SELECT tag_id as id, count(tag_id) as quantity
694 while($row = $this->db->db_fetch_object($result)) {
695 $tags[$row['id']] = $row['quantity'];
698 // change these font sizes if you will
699 $max_size = 125; // max font size in %
700 $min_size = 75; // min font size in %
703 $max_sat = hexdec('cc');
704 $min_sat = hexdec('44');
706 // get the largest and smallest array values
707 $max_qty = max(array_values($tags));
708 $min_qty = min(array_values($tags));
710 // find the range of values
711 $spread = $max_qty - $min_qty;
712 if (0 == $spread) { // we don't want to divide by zero
716 // determine the font-size increment
717 // this is the increase per tag quantity (times used)
718 $step = ($max_size - $min_size)/($spread);
719 $step_sat = ($max_sat - $min_sat)/($spread);
721 // loop through our tag array
722 foreach ($tags as $key => $value) {
724 if(isset($_SESSION['selected_tags']) && in_array($key, $_SESSION['selected_tags']))
727 // calculate CSS font-size
728 // find the $value in excess of $min_qty
729 // multiply by the font-size increment ($size)
730 // and add the $min_size set above
731 $size = $min_size + (($value - $min_qty) * $step);
732 // uncomment if you want sizes in whole %:
735 $color = $min_sat + ($value - $min_qty) * $step_sat;
741 if(isset($this->tags[$key])) {
742 if($this->is_user_friendly_url())
743 $output.= "<a href=\"". $this->cfg->web_path ."/tag/". $key ."\" onclick=\"Tags('add', ". $key ."); return false;\" class=\"tag\" style=\"font-size: ". $size ."%; color: #". $r.$g.$b .";\">". $this->tags[$key] ."</a>, ";
745 $output.= "<a href=\"". $this->cfg->web_path ."/index.php?mode=showpi\" onclick=\"Tags('add', ". $key ."); return false;\" class=\"tag\" style=\"font-size: ". $size ."%; color: #". $r.$g.$b .";\">". $this->tags[$key] ."</a>, ";
749 $output = substr($output, 0, strlen($output)-2);
752 } // getAvailableTags()
755 * output all selected tags
757 * this function output all tags which have been selected
758 * by the user. the selected tags are stored in the
759 * session-variable $_SESSION['selected_tags']
762 public function getSelectedTags($type = 'link')
764 /* retrive tags from database */
769 foreach($this->avail_tags as $tag)
771 // return all selected tags
772 if(isset($_SESSION['selected_tags']) && in_array($tag, $_SESSION['selected_tags'])) {
777 $output.= "<a href=\"javascript:Tags('del', ". $tag .");\" class=\"tag\">". $this->tags[$tag] ."</a>, ";
781 <div style=\"display: table-cell;\">
782 <div style=\"display: table-row; text-align: center;\">
783 <a href=\"javascript:Tags('del', ". $tag .");\" title=\"". $this->tags[$tag] ."\">
784 <img src=\"". $this->cfg->web_path ."/phpfspot_img.php?tagidx=". $tag ."\" />
787 <div style=\"display: table-row; text-align: center;\">
788 <a href=\"javascript:Tags('del', ". $tag .");\" title=\"". $this->tags[$tag] ."\">
789 <img src=\"". $this->cfg->web_path ."/resources/underbar.png\" />
800 $output = substr($output, 0, strlen($output)-2);
804 return "no tags selected";
807 } // getSelectedTags()
810 * add tag to users session variable
812 * this function will add the specified to users current
813 * tag selection. if a date search has been made before
814 * it will be now cleared
817 public function addTag($tag)
819 if(!isset($_SESSION['selected_tags']))
820 $_SESSION['selected_tags'] = Array();
822 if(isset($_SESSION['searchfor_tag']))
823 unset($_SESSION['searchfor_tag']);
825 // has the user requested to hide this tag, and still someone,
826 // somehow tries to add it, don't allow this.
827 if(!isset($this->cfg->hide_tags) &&
828 in_array($this->get_tag_name($tag), $this->cfg->hide_tags))
831 if(!in_array($tag, $_SESSION['selected_tags']))
832 array_push($_SESSION['selected_tags'], $tag);
839 * remove tag to users session variable
841 * this function removes the specified tag from
842 * users current tag selection
846 public function delTag($tag)
848 if(isset($_SESSION['searchfor_tag']))
849 unset($_SESSION['searchfor_tag']);
851 if(isset($_SESSION['selected_tags'])) {
852 $key = array_search($tag, $_SESSION['selected_tags']);
853 unset($_SESSION['selected_tags'][$key]);
854 sort($_SESSION['selected_tags']);
862 * reset tag selection
864 * if there is any tag selection, it will be
867 public function resetTags()
869 if(isset($_SESSION['selected_tags']))
870 unset($_SESSION['selected_tags']);
875 * returns the value for the autocomplete tag-search
878 public function get_xml_tag_list()
880 if(!isset($_GET['search']) || !is_string($_GET['search']))
881 $_GET['search'] = '';
886 /* retrive tags from database */
889 $matched_tags = Array();
891 header("Content-Type: text/xml");
893 $string = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n";
894 $string.= "<results>\n";
896 foreach($this->avail_tags as $tag)
898 if(!empty($_GET['search']) &&
899 preg_match("/". $_GET['search'] ."/i", $this->tags[$tag]) &&
900 count($matched_tags) < $length) {
902 $count = $this->get_num_photos($tag);
905 $string.= " <rs id=\"". $i ."\" info=\"". $count ." photo\">". $this->tags[$tag] ."</rs>\n";
908 $string.= " <rs id=\"". $i ."\" info=\"". $count ." photos\">". $this->tags[$tag] ."</rs>\n";
914 /* if we have collected enough items, break out */
915 if(count($matched_tags) >= $length)
919 $string.= "</results>\n";
923 } // get_xml_tag_list()
929 * if a specific photo was requested (external link)
930 * unset the session variable now
932 public function resetPhotoView()
934 if(isset($_SESSION['current_photo']))
935 unset($_SESSION['current_photo']);
937 } // resetPhotoView();
942 * if any tag search has taken place, reset it now
944 public function resetTagSearch()
946 if(isset($_SESSION['searchfor_tag']))
947 unset($_SESSION['searchfor_tag']);
949 } // resetTagSearch()
954 * if any name search has taken place, reset it now
956 public function resetNameSearch()
958 if(isset($_SESSION['searchfor_name']))
959 unset($_SESSION['searchfor_name']);
961 } // resetNameSearch()
966 * if any date search has taken place, reset
969 public function resetDateSearch()
971 if(isset($_SESSION['from_date']))
972 unset($_SESSION['from_date']);
973 if(isset($_SESSION['to_date']))
974 unset($_SESSION['to_date']);
976 } // resetDateSearch();
979 * return all photo according selection
981 * this function returns all photos based on
982 * the tag-selection, tag- or date-search.
983 * the tag-search also has to take care of AND
984 * and OR conjunctions
987 public function getPhotoSelection()
989 $matched_photos = Array();
990 $additional_where_cond = "";
992 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
993 $from_date = $_SESSION['from_date'];
994 $to_date = $_SESSION['to_date'];
995 $additional_where_cond.= "
996 p.time>='". $from_date ."'
998 p.time<='". $to_date ."'
1002 if(isset($_SESSION['searchfor_name'])) {
1003 if($this->dbver < 9) {
1004 $additional_where_cond.= "
1006 p.name LIKE '%". $_SESSION['searchfor_name'] ."%'
1008 p.description LIKE '%". $_SESSION['searchfor_name'] ."%'
1013 $additional_where_cond.= "
1015 basename(p.uri) LIKE '%". $_SESSION['searchfor_name'] ."%'
1017 p.description LIKE '%". $_SESSION['searchfor_name'] ."%'
1023 if(isset($_SESSION['sort_order'])) {
1024 $order_str = $this->get_sort_order();
1027 /* return a search result */
1028 if(isset($_SESSION['searchfor_tag']) && $_SESSION['searchfor_tag'] != '') {
1030 SELECT DISTINCT pt1.photo_id
1032 INNER JOIN photo_tags pt2
1033 ON pt1.photo_id=pt2.photo_id
1037 ON pt1.photo_id=p.id
1040 WHERE t.name LIKE '%". $_SESSION['searchfor_tag'] ."%' ";
1042 if(isset($additional_where_cond) && !empty($additional_where_cond))
1043 $query_str.= "AND ". $additional_where_cond ." ";
1045 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1046 $query_str.= "AND t2.name IN ('".implode("','",$this->cfg->show_tags)."')";
1049 if(isset($order_str))
1050 $query_str.= $order_str;
1052 $result = $this->db->db_query($query_str);
1053 while($row = $this->db->db_fetch_object($result)) {
1054 array_push($matched_photos, $row['photo_id']);
1056 return $matched_photos;
1059 /* return according the selected tags */
1060 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
1062 foreach($_SESSION['selected_tags'] as $tag)
1063 $selected.= $tag .",";
1064 $selected = substr($selected, 0, strlen($selected)-1);
1066 /* photo has to match at least on of the selected tags */
1067 if($_SESSION['tag_condition'] == 'or') {
1069 SELECT DISTINCT pt1.photo_id
1071 INNER JOIN photo_tags pt2
1072 ON pt1.photo_id=pt2.photo_id
1076 ON pt1.photo_id=p.id
1077 WHERE pt1.tag_id IN (". $selected .")
1079 if(isset($additional_where_cond) && !empty($additional_where_cond))
1080 $query_str.= "AND ". $additional_where_cond ." ";
1082 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1083 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags)."')";
1086 if(isset($order_str))
1087 $query_str.= $order_str;
1089 /* photo has to match all selected tags */
1090 elseif($_SESSION['tag_condition'] == 'and') {
1092 if(count($_SESSION['selected_tags']) >= 32) {
1093 print "A SQLite limit of 32 tables within a JOIN SELECT avoids to<br />\n";
1094 print "evaluate your tag selection. Please remove some tags from your selection.\n";
1098 /* Join together a table looking like
1100 pt1.photo_id pt1.tag_id pt2.photo_id pt2.tag_id ...
1102 so the query can quickly return all images matching the
1103 selected tags in an AND condition
1108 SELECT DISTINCT pt1.photo_id
1112 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1119 for($i = 0; $i < count($_SESSION['selected_tags']); $i++) {
1121 INNER JOIN photo_tags pt". ($i+2) ."
1122 ON pt1.photo_id=pt". ($i+2) .".photo_id
1127 ON pt1.photo_id=p.id
1129 $query_str.= "WHERE pt2.tag_id=". $_SESSION['selected_tags'][0]." ";
1130 for($i = 1; $i < count($_SESSION['selected_tags']); $i++) {
1132 AND pt". ($i+2) .".tag_id=". $_SESSION['selected_tags'][$i] ."
1135 if(isset($additional_where_cond) && !empty($additional_where_cond))
1136 $query_str.= "AND ". $additional_where_cond;
1138 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1139 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags). "')";
1142 if(isset($order_str))
1143 $query_str.= $order_str;
1147 $result = $this->db->db_query($query_str);
1148 while($row = $this->db->db_fetch_object($result)) {
1149 array_push($matched_photos, $row['photo_id']);
1151 return $matched_photos;
1154 /* return all available photos */
1156 SELECT DISTINCT p.id
1158 LEFT JOIN photo_tags pt
1164 if(isset($additional_where_cond) && !empty($additional_where_cond))
1165 $query_str.= "WHERE ". $additional_where_cond ." ";
1167 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1168 if(isset($additional_where_cond) && !empty($additional_where_cond))
1169 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags). "')";
1171 $query_str.= "WHERE t.name IN ('".implode("','",$this->cfg->show_tags). "')";
1174 if(isset($order_str))
1175 $query_str.= $order_str;
1177 $result = $this->db->db_query($query_str);
1178 while($row = $this->db->db_fetch_object($result)) {
1179 array_push($matched_photos, $row['id']);
1181 return $matched_photos;
1183 } // getPhotoSelection()
1186 * control HTML ouput for photo index
1188 * this function provides all the necessary information
1189 * for the photo index template.
1192 public function showPhotoIndex()
1194 $photos = $this->getPhotoSelection();
1196 $count = count($photos);
1198 /* if all thumbnails should be shown on one page */
1199 if(!isset($this->cfg->thumbs_per_page) || $this->cfg->thumbs_per_page == 0) {
1203 /* thumbnails should be splitted up in several pages */
1204 elseif($this->cfg->thumbs_per_page > 0) {
1206 if(!isset($_SESSION['begin_with']) || $_SESSION['begin_with'] == 0) {
1210 $begin_with = $_SESSION['begin_with'];
1213 $end_with = $begin_with + $this->cfg->thumbs_per_page;
1217 $images[$thumbs] = Array();
1218 $img_height[$thumbs] = Array();
1219 $img_width[$thumbs] = Array();
1220 $img_id[$thumbs] = Array();
1221 $img_name[$thumbs] = Array();
1222 $img_fullname[$thumbs] = Array();
1223 $img_title = Array();
1225 for($i = $begin_with; $i < $end_with; $i++) {
1227 if(isset($photos[$i])) {
1229 $images[$thumbs] = $photos[$i];
1230 $img_id[$thumbs] = $i;
1231 $img_name[$thumbs] = htmlspecialchars($this->getPhotoName($photos[$i], 15));
1232 $img_fullname[$thumbs] = htmlspecialchars($this->getPhotoName($photos[$i], 0));
1233 $img_title[$thumbs] = "Click to view photo ". htmlspecialchars($this->getPhotoName($photos[$i], 0));
1235 $thumb_path = $this->get_thumb_path($this->cfg->thumb_width, $photos[$i]);
1237 if(file_exists($thumb_path)) {
1238 $info = getimagesize($thumb_path);
1239 $img_width[$thumbs] = $info[0];
1240 $img_height[$thumbs] = $info[1];
1246 // +1 for for smarty's selection iteration
1249 if(isset($_SESSION['searchfor_tag']) && $_SESSION['searchfor_tag'] != '')
1250 $this->tmpl->assign('searchfor_tag', $_SESSION['searchfor_tag']);
1252 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1253 $this->tmpl->assign('from_date', $this->ts2str($_SESSION['from_date']));
1254 $this->tmpl->assign('to_date', $this->ts2str($_SESSION['to_date']));
1257 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
1258 $this->tmpl->assign('tag_result', 1);
1261 /* do we have to display the page selector ? */
1262 if($this->cfg->thumbs_per_page != 0) {
1266 /* calculate the page switchers */
1267 $previous_start = $begin_with - $this->cfg->thumbs_per_page;
1268 $next_start = $begin_with + $this->cfg->thumbs_per_page;
1270 if($begin_with != 0)
1271 $this->tmpl->assign("previous_url", "javascript:showPhotoIndex(". $previous_start .");");
1272 if($end_with < $count)
1273 $this->tmpl->assign("next_url", "javascript:showPhotoIndex(". $next_start .");");
1275 $photo_per_page = $this->cfg->thumbs_per_page;
1276 $last_page = ceil($count / $photo_per_page);
1278 /* get the current selected page */
1279 if($begin_with == 0) {
1283 for($i = $begin_with; $i >= 0; $i-=$photo_per_page) {
1290 for($i = 1; $i <= $last_page; $i++) {
1292 if($current_page == $i)
1293 $style = "style=\"font-size: 125%; text-decoration: underline;\"";
1294 elseif($current_page-1 == $i || $current_page+1 == $i)
1295 $style = "style=\"font-size: 105%;\"";
1296 elseif(($current_page-5 >= $i) && ($i != 1) ||
1297 ($current_page+5 <= $i) && ($i != $last_page))
1298 $style = "style=\"font-size: 75%;\"";
1302 $start_with = ($i*$photo_per_page)-$photo_per_page;
1304 if($this->is_user_friendly_url()) {
1305 $select = "<a href=\"". $this->cfg->web_path ."/tag/205/". $start_with ."\"";
1308 $select = "<a href=\"". $this->cfg->web_path ."/index.php?mode=showpi tags=". $current_tags ." begin_with=". $begin_with ."\"";
1310 $select.= " onclick=\"showPhotoIndex(". $start_with ."); return false;\"";
1314 $select.= ">". $i ."</a> ";
1316 // until 9 pages we show the selector from 1-9
1317 if($last_page <= 9) {
1318 $page_select.= $select;
1321 if($i == 1 /* first page */ ||
1322 $i == $last_page /* last page */ ||
1323 $i == $current_page /* current page */ ||
1324 $i == ceil($last_page * 0.25) /* first quater */ ||
1325 $i == ceil($last_page * 0.5) /* half */ ||
1326 $i == ceil($last_page * 0.75) /* third quater */ ||
1327 (in_array($i, array(1,2,3,4,5,6)) && $current_page <= 4) /* the first 6 */ ||
1328 (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 */ ||
1329 $i == $current_page-3 || $i == $current_page-2 || $i == $current_page-1 /* three before */ ||
1330 $i == $current_page+3 || $i == $current_page+2 || $i == $current_page+1 /* three after */) {
1332 $page_select.= $select;
1340 $page_select.= "......... ";
1345 /* only show the page selector if we have more then one page */
1347 $this->tmpl->assign('page_selector', $page_select);
1350 $current_tags = $this->getCurrentTags();
1351 $extern_link = "index.php?mode=showpi";
1352 $rss_link = "index.php?mode=rss";
1353 if($current_tags != "") {
1354 $extern_link.= "&tags=". $current_tags;
1355 $rss_link.= "&tags=". $current_tags;
1357 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1358 $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
1359 $rss_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
1362 $export_link = "index.php?mode=export";
1363 $slideshow_link = "index.php?mode=slideshow";
1365 $this->tmpl->assign('extern_link', $extern_link);
1366 $this->tmpl->assign('slideshow_link', $slideshow_link);
1367 $this->tmpl->assign('export_link', $export_link);
1368 $this->tmpl->assign('rss_link', $rss_link);
1369 $this->tmpl->assign('count', $count);
1370 $this->tmpl->assign('width', $this->cfg->thumb_width);
1371 $this->tmpl->assign('preview_width', $this->cfg->photo_width);
1372 $this->tmpl->assign('thumb_container_width', $this->cfg->thumb_width);
1373 $this->tmpl->assign('thumb_container_height', $this->cfg->thumb_height+20);
1374 $this->tmpl->assign('images', $images);
1375 $this->tmpl->assign('img_width', $img_width);
1376 $this->tmpl->assign('img_height', $img_height);
1377 $this->tmpl->assign('img_id', $img_id);
1378 $this->tmpl->assign('img_name', $img_name);
1379 $this->tmpl->assign('img_fullname', $img_fullname);
1380 $this->tmpl->assign('img_title', $img_title);
1381 $this->tmpl->assign('thumbs', $thumbs);
1382 $this->tmpl->assign('selected_tags', $this->getSelectedTags('img'));
1384 $result = $this->tmpl->fetch("photo_index.tpl");
1386 /* if we are returning to photo index from an photo-view,
1387 scroll the window to the last shown photo-thumbnail.
1388 after this, unset the last_photo session variable.
1390 if(isset($_SESSION['last_photo'])) {
1391 $result.= "<script language=\"JavaScript\">moveToThumb(". $_SESSION['last_photo'] .");</script>\n";
1392 unset($_SESSION['last_photo']);
1397 } // showPhotoIndex()
1400 * show credit template
1402 public function showCredits()
1404 $this->tmpl->assign('version', $this->cfg->version);
1405 $this->tmpl->assign('product', $this->cfg->product);
1406 $this->tmpl->assign('db_version', $this->dbver);
1407 $this->tmpl->show("credits.tpl");
1412 * create thumbnails for the requested width
1414 * this function creates image thumbnails of $orig_image
1415 * stored as $thumb_image. It will check if the image is
1416 * in a supported format, if necessary rotate the image
1417 * (based on EXIF orientation meta headers) and re-sizing.
1418 * @param string $orig_image
1419 * @param string $thumb_image
1420 * @param integer $width
1423 public function create_thumbnail($orig_image, $thumb_image, $width)
1425 if(!file_exists($orig_image)) {
1429 $mime = $this->get_mime_info($orig_image);
1431 /* check if original photo is a support image type */
1432 if(!$this->checkifImageSupported($mime))
1439 $meta = $this->get_meta_informations($orig_image);
1445 switch($meta['Orientation']) {
1446 case 1: /* top, left */
1447 /* nothing to do */ break;
1448 case 2: /* top, right */
1449 $rotate = 0; $flip_hori = true; break;
1450 case 3: /* bottom, left */
1451 $rotate = 180; break;
1452 case 4: /* bottom, right */
1453 $flip_vert = true; break;
1454 case 5: /* left side, top */
1455 $rotate = 90; $flip_vert = true; break;
1456 case 6: /* right side, top */
1457 $rotate = 90; break;
1458 case 7: /* left side, bottom */
1459 $rotate = 270; $flip_vert = true; break;
1460 case 8: /* right side, bottom */
1461 $rotate = 270; break;
1464 $src_img = @imagecreatefromjpeg($orig_image);
1470 $src_img = @imagecreatefrompng($orig_image);
1474 case 'image/x-portable-pixmap':
1476 $src_img = new Imagick($orig_image);
1477 $handler = "imagick";
1482 if(!isset($src_img) || empty($src_img)) {
1483 print "Can't load image from ". $orig_image ."\n";
1491 /* grabs the height and width */
1492 $cur_width = imagesx($src_img);
1493 $cur_height = imagesy($src_img);
1495 // If requested width is more then the actual image width,
1496 // do not generate a thumbnail, instead safe the original
1497 // as thumbnail but with lower quality. But if the image
1498 // is to heigh too, then we still have to resize it.
1499 if($width >= $cur_width && $cur_height < $this->cfg->thumb_height) {
1500 $result = imagejpeg($src_img, $thumb_image, 75);
1501 imagedestroy($src_img);
1508 $cur_width = $src_img->getImageWidth();
1509 $cur_height = $src_img->getImageHeight();
1511 // If requested width is more then the actual image width,
1512 // do not generate a thumbnail, instead safe the original
1513 // as thumbnail but with lower quality. But if the image
1514 // is to heigh too, then we still have to resize it.
1515 if($width >= $cur_width && $cur_height < $this->cfg->thumb_height) {
1516 $src_img->setCompressionQuality(75);
1517 $src_img->setImageFormat('jpeg');
1518 $src_img->writeImage($thumb_image);
1520 $src_img->destroy();
1527 // If the image will be rotate because EXIF orientation said so
1528 // 'virtually rotate' the image for further calculations
1529 if($rotate == 90 || $rotate == 270) {
1531 $cur_width = $cur_height;
1535 /* calculates aspect ratio */
1536 $aspect_ratio = $cur_height / $cur_width;
1539 if($aspect_ratio < 1) {
1541 $new_h = abs($new_w * $aspect_ratio);
1543 /* 'virtually' rotate the image and calculate it's ratio */
1544 $tmp_w = $cur_height;
1545 $tmp_h = $cur_width;
1546 /* now get the ratio from the 'rotated' image */
1547 $tmp_ratio = $tmp_h/$tmp_w;
1548 /* now calculate the new dimensions */
1550 $tmp_h = abs($tmp_w * $tmp_ratio);
1552 // now that we know, how high they photo should be, if it
1553 // gets rotated, use this high to scale the image
1555 $new_w = abs($new_h / $aspect_ratio);
1557 // If the image will be rotate because EXIF orientation said so
1558 // now 'virtually rotate' back the image for the image manipulation
1559 if($rotate == 90 || $rotate == 270) {
1570 /* creates new image of that size */
1571 $dst_img = imagecreatetruecolor($new_w, $new_h);
1573 imagefill($dst_img, 0, 0, ImageColorAllocate($dst_img, 255, 255, 255));
1575 /* copies resized portion of original image into new image */
1576 imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $new_w, $new_h, imagesx($src_img), imagesy($src_img));
1578 /* needs the image to be flipped horizontal? */
1580 $this->_debug("(FLIP)");
1581 $dst_img = $this->flipImage($dst_img, 'hori');
1583 /* needs the image to be flipped vertical? */
1585 $this->_debug("(FLIP)");
1586 $dst_img = $this->flipImage($dst_img, 'vert');
1590 $this->_debug("(ROTATE)");
1591 $dst_img = $this->rotateImage($dst_img, $rotate);
1594 /* write down new generated file */
1595 $result = imagejpeg($dst_img, $thumb_image, 75);
1597 /* free your mind */
1598 imagedestroy($dst_img);
1599 imagedestroy($src_img);
1601 if($result === false) {
1602 print "Can't write thumbnail ". $thumb_image ."\n";
1612 $src_img->resizeImage($new_w, $new_h, Imagick::FILTER_LANCZOS, 1);
1614 /* needs the image to be flipped horizontal? */
1616 $this->_debug("(FLIP)");
1617 $src_img->rotateImage(new ImagickPixel(), 90);
1618 $src_img->flipImage();
1619 $src_img->rotateImage(new ImagickPixel(), -90);
1621 /* needs the image to be flipped vertical? */
1623 $this->_debug("(FLIP)");
1624 $src_img->flipImage();
1628 $this->_debug("(ROTATE)");
1629 $src_img->rotateImage(new ImagickPixel(), $rotate);
1632 $src_img->setCompressionQuality(75);
1633 $src_img->setImageFormat('jpeg');
1635 if(!$src_img->writeImage($thumb_image)) {
1636 print "Can't write thumbnail ". $thumb_image ."\n";
1641 $src_img->destroy();
1648 } // create_thumbnail()
1651 * return all exif meta data from the file
1652 * @param string $file
1655 public function get_meta_informations($file)
1657 return exif_read_data($file);
1659 } // get_meta_informations()
1662 * create phpfspot own sqlite database
1664 * this function creates phpfspots own sqlite database
1665 * if it does not exist yet. this own is used to store
1666 * some necessary informations (md5 sum's, ...).
1668 public function check_config_table()
1670 // if the config table doesn't exist yet, create it
1671 if(!$this->cfg_db->db_check_table_exists("images")) {
1672 $this->cfg_db->db_exec("
1673 CREATE TABLE images (
1674 img_idx int primary key,
1680 } // check_config_table
1683 * Generates a thumbnail from photo idx
1685 * This function will generate JPEG thumbnails from provided F-Spot photo
1688 * 1. Check if all thumbnail generations (width) are already in place and
1690 * 2. Check if the md5sum of the original file has changed
1691 * 3. Generate the thumbnails if needed
1692 * @param integer $idx
1693 * @param integer $force
1694 * @param boolean $overwrite
1696 public function gen_thumb($idx = 0, $force = 0, $overwrite = false)
1700 $resolutions = Array(
1701 $this->cfg->thumb_width,
1702 $this->cfg->photo_width,
1703 $this->cfg->mini_width,
1707 /* get details from F-Spot's database */
1708 $details = $this->get_photo_details($idx);
1710 /* calculate file MD5 sum */
1711 $full_path = $this->translate_path($this->parse_uri($details['uri'], 'fullpath'));
1713 if(!file_exists($full_path)) {
1714 $this->_error("File ". $full_path ." does not exist\n");
1718 if(!is_readable($full_path)) {
1719 $this->_error("File ". $full_path ." is not readable for ". $this->getuid() ."\n");
1723 $this->_debug("Image [". $idx ."] ". $this->shrink_text($this->parse_uri($details['uri'], 'filename'), 20) ." Thumbnails:");
1725 /* If Nikon NEF format, we need to treat it another way */
1726 if(isset($this->cfg->dcraw_bin) &&
1727 file_exists($this->cfg->dcraw_bin) &&
1728 is_executable($this->cfg->dcraw_bin) &&
1729 preg_match('/\.nef$/i', $details['uri'])) {
1731 $ppm_path = preg_replace('/\.nef$/i', '.ppm', $full_path);
1733 /* if PPM file does not exist, let dcraw convert it from NEF */
1734 if(!file_exists($ppm_path)) {
1735 system($this->cfg->dcraw_bin ." -a ". $full_path);
1738 /* for now we handle the PPM instead of the NEF */
1739 $full_path = $ppm_path;
1743 $file_md5 = md5_file($full_path);
1746 foreach($resolutions as $resolution) {
1748 $generate_it = false;
1750 $thumb_sub_path = substr($file_md5, 0, 2);
1751 $thumb_path = $this->cfg->thumb_path ."/". $thumb_sub_path ."/". $resolution ."_". $file_md5;
1753 /* if thumbnail-subdirectory does not exist yet, create it */
1754 if(!file_exists(dirname($thumb_path))) {
1755 mkdir(dirname($thumb_path), 0755);
1758 /* if the thumbnail file doesn't exist, create it */
1759 if(!file_exists($thumb_path)) {
1760 $generate_it = true;
1762 /* if the file hasn't changed there is no need to regen the thumb */
1763 elseif($file_md5 != $this->getMD5($idx) || $force) {
1764 $generate_it = true;
1767 if($generate_it || $overwrite) {
1769 $this->_debug(" ". $resolution ."px");
1770 if(!$this->create_thumbnail($full_path, $thumb_path, $resolution))
1778 $this->_debug(" already exist");
1781 /* set the new/changed MD5 sum for the current photo */
1783 $this->setMD5($idx, $file_md5);
1786 $this->_debug("\n");
1791 * returns stored md5 sum for a specific photo
1793 * this function queries the phpfspot database for a
1794 * stored MD5 checksum of the specified photo
1795 * @param integer $idx
1796 * @return string|null
1798 public function getMD5($idx)
1800 $result = $this->cfg_db->db_query("
1803 WHERE img_idx='". $idx ."'
1809 $img = $this->cfg_db->db_fetch_object($result);
1810 return $img['img_md5'];
1815 * set MD5 sum for the specific photo
1816 * @param integer $idx
1817 * @param string $md5
1819 private function setMD5($idx, $md5)
1821 $result = $this->cfg_db->db_exec("
1822 REPLACE INTO images (img_idx, img_md5)
1823 VALUES ('". $idx ."', '". $md5 ."')
1829 * store current tag condition
1831 * this function stores the current tag condition
1832 * (AND or OR) in the users session variables
1833 * @param string $mode
1836 public function setTagCondition($mode)
1838 $_SESSION['tag_condition'] = $mode;
1842 } // setTagCondition()
1845 * invoke tag & date search
1847 * this function will return all matching tags and store
1848 * them in the session variable selected_tags. furthermore
1849 * it also handles the date search.
1850 * getPhotoSelection() will then only return the matching
1854 public function startSearch()
1856 if(isset($_POST['from']) && $this->isValidDate($_POST['from'])) {
1857 $from = $_POST['from'];
1859 if(isset($_POST['to']) && $this->isValidDate($_POST['to'])) {
1863 if(isset($_POST['for_tag']) && is_string($_POST['for_tag'])) {
1864 $searchfor_tag = $_POST['for_tag'];
1865 $_SESSION['searchfor_tag'] = $_POST['for_tag'];
1868 if(isset($_POST['for_name']) && is_string($_POST['for_name'])) {
1869 $searchfor_name = $_POST['for_name'];
1870 $_SESSION['searchfor_name'] = $_POST['for_name'];
1875 if(isset($from) && !empty($from))
1876 $_SESSION['from_date'] = strtotime($from ." 00:00:00");
1878 unset($_SESSION['from_date']);
1880 if(isset($to) && !empty($to))
1881 $_SESSION['to_date'] = strtotime($to ." 23:59:59");
1883 unset($_SESSION['to_date']);
1885 if(isset($searchfor_tag) && !empty($searchfor_tag)) {
1886 /* new search, reset the current selected tags */
1887 $_SESSION['selected_tags'] = Array();
1888 foreach($this->avail_tags as $tag) {
1889 if(preg_match('/'. $searchfor_tag .'/i', $this->tags[$tag]))
1890 array_push($_SESSION['selected_tags'], $tag);
1899 * updates sort order in session variable
1901 * this function is invoked by RPC and will sort the requested
1902 * sort order in the session variable.
1903 * @param string $sort_order
1906 public function updateSortOrder($order)
1908 if(isset($this->sort_orders[$order])) {
1909 $_SESSION['sort_order'] = $order;
1913 return "unkown error";
1915 } // updateSortOrder()
1920 * this function rotates the image according the
1922 * @param string $img
1923 * @param integer $degress
1926 private function rotateImage($img, $degrees)
1928 if(function_exists("imagerotate")) {
1929 $img = imagerotate($img, $degrees, 0);
1931 function imagerotate($src_img, $angle)
1933 $src_x = imagesx($src_img);
1934 $src_y = imagesy($src_img);
1935 if ($angle == 180) {
1939 elseif ($src_x <= $src_y) {
1943 elseif ($src_x >= $src_y) {
1948 $rotate=imagecreatetruecolor($dest_x,$dest_y);
1949 imagealphablending($rotate, false);
1954 for ($y = 0; $y < ($src_y); $y++) {
1955 for ($x = 0; $x < ($src_x); $x++) {
1956 $color = imagecolorat($src_img, $x, $y);
1957 imagesetpixel($rotate, $dest_x - $y - 1, $x, $color);
1963 for ($y = 0; $y < ($src_y); $y++) {
1964 for ($x = 0; $x < ($src_x); $x++) {
1965 $color = imagecolorat($src_img, $x, $y);
1966 imagesetpixel($rotate, $y, $dest_y - $x - 1, $color);
1972 for ($y = 0; $y < ($src_y); $y++) {
1973 for ($x = 0; $x < ($src_x); $x++) {
1974 $color = imagecolorat($src_img, $x, $y);
1975 imagesetpixel($rotate, $dest_x - $x - 1, $dest_y - $y - 1, $color);
1989 $img = imagerotate($img, $degrees);
1998 * returns flipped image
2000 * this function will return an either horizontal or
2001 * vertical flipped truecolor image.
2002 * @param string $image
2003 * @param string $mode
2006 private function flipImage($image, $mode)
2008 $w = imagesx($image);
2009 $h = imagesy($image);
2010 $flipped = imagecreatetruecolor($w, $h);
2014 for ($y = 0; $y < $h; $y++) {
2015 imagecopy($flipped, $image, 0, $y, 0, $h - $y - 1, $w, 1);
2019 for ($x = 0; $x < $w; $x++) {
2020 imagecopy($flipped, $image, $x, 0, $w - $x - 1, 0, 1, $h);
2030 * return all assigned tags for the specified photo
2031 * @param integer $idx
2034 private function get_photo_tags($idx)
2036 $result = $this->db->db_query("
2039 INNER JOIN photo_tags pt
2041 WHERE pt.photo_id='". $idx ."'
2046 while($row = $this->db->db_fetch_object($result)) {
2047 if(isset($this->cfg->hide_tags) && in_array($row['name'], $this->cfg->hide_tags))
2049 $tags[$row['id']] = $row['name'];
2054 } // get_photo_tags()
2057 * create on-the-fly images with text within
2058 * @param string $txt
2059 * @param string $color
2060 * @param integer $space
2061 * @param integer $font
2064 public function showTextImage($txt, $color=000000, $space=4, $font=4, $w=300)
2066 if (strlen($color) != 6)
2069 $int = hexdec($color);
2070 $h = imagefontheight($font);
2071 $fw = imagefontwidth($font);
2072 $txt = explode("\n", wordwrap($txt, ($w / $fw), "\n"));
2073 $lines = count($txt);
2074 $im = imagecreate($w, (($h * $lines) + ($lines * $space)));
2075 $bg = imagecolorallocate($im, 255, 255, 255);
2076 $color = imagecolorallocate($im, 0xFF & ($int >> 0x10), 0xFF & ($int >> 0x8), 0xFF & $int);
2079 foreach ($txt as $text) {
2080 $x = (($w - ($fw * strlen($text))) / 2);
2081 imagestring($im, $font, $x, $y, $text, $color);
2082 $y += ($h + $space);
2085 Header("Content-type: image/png");
2088 } // showTextImage()
2091 * check if all requirements are met
2094 private function check_requirements()
2096 if(!function_exists("imagecreatefromjpeg")) {
2097 print "PHP GD library extension is missing<br />\n";
2101 if($this->cfg->db_access == "native" && !function_exists("sqlite3_open")) {
2102 print "PHP SQLite3 library extension is missing<br />\n";
2106 /* Check for HTML_AJAX PEAR package, lent from Horde project */
2107 ini_set('track_errors', 1);
2108 @include_once 'HTML/AJAX/Server.php';
2109 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
2110 print "PEAR HTML_AJAX package is missing<br />\n";
2113 @include_once 'Calendar/Calendar.php';
2114 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
2115 print "PEAR Calendar package is missing<br />\n";
2118 @include_once 'Console/Getopt.php';
2119 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
2120 print "PEAR Console_Getopt package is missing<br />\n";
2123 @include_once $this->cfg->smarty_path .'/libs/Smarty.class.php';
2124 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
2125 print "Smarty template engine can not be found in ". $this->cfg->smarty_path ."/libs/Smarty.class.php<br />\n";
2128 ini_restore('track_errors');
2135 } // check_requirements()
2137 private function _debug($text)
2139 if($this->fromcmd) {
2146 * check if specified MIME type is supported
2147 * @param string $mime
2150 public function checkifImageSupported($mime)
2152 $supported_types = Array(
2155 "image/x-portable-pixmap",
2159 if(in_array($mime, $supported_types))
2164 } // checkifImageSupported()
2168 * @param string $text
2170 public function _error($text)
2172 switch($this->cfg->logging) {
2175 print "<img src=\"resources/green_info.png\" alt=\"warning\" />\n";
2176 print $text ."<br />\n";
2182 error_log($text, 3, $his->cfg->log_file);
2186 $this->runtime_error = true;
2191 * output calendard input fields
2192 * @param string $mode
2195 private function get_calendar($mode)
2197 $year = isset($_SESSION[$mode .'_date']) ? date("Y", $_SESSION[$mode .'_date']) : date("Y");
2198 $month = isset($_SESSION[$mode .'_date']) ? date("m", $_SESSION[$mode .'_date']) : date("m");
2199 $day = isset($_SESSION[$mode .'_date']) ? date("d", $_SESSION[$mode .'_date']) : date("d");
2201 $output = "<input type=\"text\" size=\"3\" id=\"". $mode ."year\" value=\"". $year ."\"";
2202 if(!isset($_SESSION[$mode .'_date']))
2203 $output.= " disabled=\"disabled\"";
2205 $output.= "<input type=\"text\" size=\"1\" id=\"". $mode ."month\" value=\"". $month ."\"";
2206 if(!isset($_SESSION[$mode .'_date']))
2207 $output.= " disabled=\"disabled\"";
2209 $output.= "<input type=\"text\" size=\"1\" id=\"". $mode ."day\" value=\"". $day ."\"";
2210 if(!isset($_SESSION[$mode .'_date']))
2211 $output.= " disabled=\"disabled\"";
2219 * output calendar matrix
2220 * @param integer $year
2221 * @param integer $month
2222 * @param integer $day
2224 public function get_calendar_matrix($year = 0, $month = 0, $day = 0)
2226 if (!isset($year)) $year = date('Y');
2227 if (!isset($month)) $month = date('m');
2228 if (!isset($day)) $day = date('d');
2233 require_once CALENDAR_ROOT.'Month/Weekdays.php';
2234 require_once CALENDAR_ROOT.'Day.php';
2237 $month = new Calendar_Month_Weekdays($year,$month);
2240 $prevStamp = $month->prevMonth(true);
2241 $prev = "javascript:setMonth(". date('Y',$prevStamp) .", ". date('n',$prevStamp) .", ". date('j',$prevStamp) .");";
2242 $nextStamp = $month->nextMonth(true);
2243 $next = "javascript:setMonth(". date('Y',$nextStamp) .", ". date('n',$nextStamp) .", ". date('j',$nextStamp) .");";
2245 $selectedDays = array (
2246 new Calendar_Day($year,$month,$day),
2247 new Calendar_Day($year,12,25),
2250 // Build the days in the month
2251 $month->build($selectedDays);
2253 $this->tmpl->assign('current_month', date('F Y',$month->getTimeStamp()));
2254 $this->tmpl->assign('prev_month', $prev);
2255 $this->tmpl->assign('next_month', $next);
2257 while ( $day = $month->fetch() ) {
2259 if(!isset($matrix[$rows]))
2260 $matrix[$rows] = Array();
2264 $dayStamp = $day->thisDay(true);
2265 $link = "javascript:setCalendarDate(". date('Y',$dayStamp) .", ". date('n',$dayStamp).", ". date('j',$dayStamp) .");";
2267 // isFirst() to find start of week
2268 if ( $day->isFirst() )
2271 if ( $day->isSelected() ) {
2272 $string.= "<td class=\"selected\">".$day->thisDay()."</td>\n";
2273 } else if ( $day->isEmpty() ) {
2274 $string.= "<td> </td>\n";
2276 $string.= "<td><a class=\"calendar\" href=\"".$link."\">".$day->thisDay()."</a></td>\n";
2279 // isLast() to find end of week
2280 if ( $day->isLast() )
2281 $string.= "</tr>\n";
2283 $matrix[$rows][$cols] = $string;
2293 $this->tmpl->assign('matrix', $matrix);
2294 $this->tmpl->assign('rows', $rows);
2295 $this->tmpl->show("calendar.tpl");
2297 } // get_calendar_matrix()
2300 * output export page
2301 * @param string $mode
2303 public function getExport($mode)
2305 $pictures = $this->getPhotoSelection();
2306 $current_tags = $this->getCurrentTags();
2308 foreach($pictures as $picture) {
2310 $orig_url = $this->get_phpfspot_url() ."/index.php?mode=showp&id=". $picture;
2311 if($current_tags != "") {
2312 $orig_url.= "&tags=". $current_tags;
2314 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
2315 $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
2318 if($this->is_user_friendly_url()) {
2319 $thumb_url = $this->get_phpfspot_url() ."/photo/". $picture ."/". $this->cfg->thumb_width;
2322 $thumb_url = $this->get_phpfspot_url() ."/phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
2328 // <a href="%pictureurl%"><img src="%thumbnailurl%" ></a>
2329 print htmlspecialchars("<a href=\"". $orig_url ."\"><img src=\"". $thumb_url ."\" /></a>") ."<br />\n";
2333 // "[%pictureurl% %thumbnailurl%]"
2334 print htmlspecialchars("[".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
2337 case 'MoinMoinList':
2338 // " * [%pictureurl% %thumbnailurl%]"
2339 print " " . htmlspecialchars("* [".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
2350 public function getRSSFeed()
2352 Header("Content-type: text/xml; charset=utf-8");
2353 print "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
2356 xmlns:media="http://search.yahoo.com/mrss/"
2357 xmlns:dc="http://purl.org/dc/elements/1.1/"
2360 <title>phpfspot</title>
2361 <description>phpfspot RSS feed</description>
2362 <link><?php print htmlspecialchars($this->get_phpfspot_url()); ?></link>
2363 <pubDate><?php print strftime("%a, %d %b %Y %T %z"); ?></pubDate>
2364 <generator>phpfspot</generator>
2367 $pictures = $this->getPhotoSelection();
2368 $current_tags = $this->getCurrentTags();
2370 foreach($pictures as $picture) {
2372 $orig_url = $this->get_phpfspot_url() ."/index.php?mode=showp&id=". $picture;
2373 if($current_tags != "") {
2374 $orig_url.= "&tags=". $current_tags;
2376 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
2377 $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
2380 $details = $this->get_photo_details($picture);
2382 if($this->is_user_friendly_url()) {
2383 $thumb_url = $this->get_phpfspot_url() ."/photo/". $picture ."/". $this->cfg->thumb_width;
2386 $thumb_url = $this->get_phpfspot_url() ."/phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
2389 $thumb_html = htmlspecialchars("
2390 <a href=\"". $orig_url ."\"><img src=\"". $thumb_url ."\" /></a>
2392 ". $details['description']);
2394 $orig_path = $this->translate_path($this->parse_uri($details['uri'], 'fullpath'));
2396 /* get EXIF information if JPEG */
2397 if($details['mime'] == "image/jpeg") {
2398 $meta = $this->get_meta_informations($orig_path);
2401 $meta_date = isset($meta['FileDateTime']) ? $meta['FileDateTime'] : filemtime($orig_path);
2405 <title><?php print htmlspecialchars($this->parse_uri($details['uri'], 'filename')); ?></title>
2406 <link><?php print htmlspecialchars($orig_url); ?></link>
2407 <guid><?php print htmlspecialchars($orig_url); ?></guid>
2408 <dc:date.Taken><?php print strftime("%Y-%m-%dT%H:%M:%S+00:00", $meta_date); ?></dc:date.Taken>
2410 <?php print $thumb_html; ?>
2412 <pubDate><?php print strftime("%a, %d %b %Y %T %z", $meta_date); ?></pubDate>
2427 * return all selected tags as one string
2430 private function getCurrentTags()
2433 if(isset($_SESSION['selected_tags']) && $_SESSION['selected_tags'] != "") {
2434 foreach($_SESSION['selected_tags'] as $tag)
2435 $current_tags.= $tag .",";
2436 $current_tags = substr($current_tags, 0, strlen($current_tags)-1);
2438 return $current_tags;
2440 } // getCurrentTags()
2443 * return the current photo
2445 public function getCurrentPhoto()
2447 if(isset($_SESSION['current_photo'])) {
2448 print $_SESSION['current_photo'];
2450 } // getCurrentPhoto()
2453 * tells the client browser what to do
2455 * this function is getting called via AJAX by the
2456 * client browsers. it will tell them what they have
2457 * to do next. This is necessary for directly jumping
2458 * into photo index or single photo view when the are
2459 * requested with specific URLs
2462 public function whatToDo()
2464 if(isset($_SESSION['current_photo']) && $_SESSION['start_action'] == 'showp') {
2466 elseif(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
2467 return "showpi_tags";
2469 elseif(isset($_SESSION['start_action']) && $_SESSION['start_action'] == 'showpi') {
2476 * return the current process-user
2479 private function getuid()
2481 if($uid = posix_getuid()) {
2482 if($user = posix_getpwuid($uid)) {
2483 return $user['name'];
2492 * returns a select-dropdown box to select photo index sort parameters
2493 * @param array $params
2494 * @param smarty $smarty
2497 public function smarty_sort_select_list($params, &$smarty)
2501 foreach($this->sort_orders as $key => $value) {
2502 $output.= "<option value=\"". $key ."\"";
2503 if($key == $_SESSION['sort_order']) {
2504 $output.= " selected=\"selected\"";
2506 $output.= ">". $value ."</option>";
2511 } // smarty_sort_select_list()
2514 * returns the currently selected sort order
2517 private function get_sort_order()
2519 switch($_SESSION['sort_order']) {
2521 return " ORDER BY p.time ASC";
2524 return " ORDER BY p.time DESC";
2527 if($this->dbver < 9) {
2528 return " ORDER BY p.name ASC";
2531 return " ORDER BY basename(p.uri) ASC";
2535 if($this->dbver < 9) {
2536 return " ORDER BY p.name DESC";
2539 return " ORDER BY basename(p.uri) DESC";
2543 return " ORDER BY t.name ASC ,p.time ASC";
2546 return " ORDER BY t.name DESC ,p.time ASC";
2550 } // get_sort_order()
2553 * return the next to be shown slide show image
2555 * this function returns the URL of the next image
2556 * in the slideshow sequence.
2559 public function getNextSlideShowImage()
2561 $all_photos = $this->getPhotoSelection();
2563 if(!isset($_SESSION['slideshow_img']) || $_SESSION['slideshow_img'] == count($all_photos)-1)
2564 $_SESSION['slideshow_img'] = 0;
2566 $_SESSION['slideshow_img']++;
2568 if($this->is_user_friendly_url()) {
2569 return $this->get_phpfspot_url() ."/photo/". $all_photos[$_SESSION['slideshow_img']] ."/". $this->cfg->photo_width;
2572 return $this->get_phpfspot_url() ."/phpfspot_img.php?idx=". $all_photos[$_SESSION['slideshow_img']] ."&width=". $this->cfg->photo_width;
2574 } // getNextSlideShowImage()
2577 * return the previous to be shown slide show image
2579 * this function returns the URL of the previous image
2580 * in the slideshow sequence.
2583 public function getPrevSlideShowImage()
2585 $all_photos = $this->getPhotoSelection();
2587 if(!isset($_SESSION['slideshow_img']) || $_SESSION['slideshow_img'] == 0)
2588 $_SESSION['slideshow_img'] = 0;
2590 $_SESSION['slideshow_img']--;
2592 if($this->is_user_friendly_url()) {
2593 return $this->get_phpfspot_url() ."/photo/". $all_photos[$_SESSION['slideshow_img']] ."/". $this->cfg->photo_width;
2596 return $this->get_phpfspot_url() ."/phpfspot_img.php?idx=". $all_photos[$_SESSION['slideshow_img']] ."&width=". $this->cfg->photo_width;
2598 } // getPrevSlideShowImage()
2600 public function resetSlideShow()
2602 if(isset($_SESSION['slideshow_img']))
2603 unset($_SESSION['slideshow_img']);
2605 } // resetSlideShow()
2610 * this function will get all photos from the fspot
2611 * database and randomly return ONE entry
2613 * saddly there is yet no sqlite3 function which returns
2614 * the bulk result in array, so we have to fill up our
2618 public function get_random_photo()
2627 /* if show_tags is set, only return details for photos which
2628 are specified to be shown
2630 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
2632 INNER JOIN photo_tags pt
2637 t.name IN ('".implode("','",$this->cfg->show_tags)."')";
2640 $result = $this->db->db_query($query_str);
2642 while($row = $this->db->db_fetch_object($result)) {
2643 array_push($all, $row['id']);
2646 return $all[array_rand($all)];
2648 } // get_random_photo()
2651 * get random photo tag photo
2653 * this function will get all photos tagged with the requested
2654 * tag from the fspot database and randomly return ONE entry
2656 * saddly there is yet no sqlite3 function which returns
2657 * the bulk result in array, so we have to fill up our
2661 public function get_random_tag_photo($tagidx)
2668 INNER JOIN photo_tags pt
2672 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
2680 pt.tag_id LIKE '". $tagidx ."'
2683 /*if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
2686 t.name IN ('".implode("','",$this->cfg->show_tags)."')
2690 $result = $this->db->db_query($query_str);
2692 while($row = $this->db->db_fetch_object($result)) {
2693 array_push($all, $row['id']);
2696 return $all[array_rand($all)];
2698 } // get_random_tag_photo()
2701 * validates provided date
2703 * this function validates if the provided date
2704 * contains a valid date and will return true
2706 * @param string $date_str
2709 public function isValidDate($date_str)
2711 $timestamp = strtotime($date_str);
2713 if(is_numeric($timestamp))
2721 * timestamp to string conversion
2722 * @param integer $timestamp
2725 private function ts2str($timestamp)
2727 if(!empty($timestamp) && is_numeric($timestamp))
2728 return strftime("%Y-%m-%d", $timestamp);
2733 * extract tag-names from $_GET['tags']
2734 * @param string $tags_str
2737 private function extractTags($tags_str)
2739 $not_validated = split(',', $tags_str);
2740 $validated = array();
2742 foreach($not_validated as $tag) {
2743 if(is_numeric($tag))
2744 array_push($validated, $tag);
2752 * returns the full path to a thumbnail
2753 * @param integer $width
2754 * @param integer $photo
2757 public function get_thumb_path($width, $photo)
2759 $md5 = $this->getMD5($photo);
2760 $sub_path = substr($md5, 0, 2);
2761 return $this->cfg->thumb_path
2769 } // get_thumb_path()
2772 * returns server's virtual host name
2775 private function get_server_name()
2777 return $_SERVER['SERVER_NAME'];
2778 } // get_server_name()
2781 * returns type of webprotocol which is currently used
2784 private function get_web_protocol()
2786 if(!isset($_SERVER['HTTPS']))
2790 } // get_web_protocol()
2793 * return url to this phpfspot installation
2796 private function get_phpfspot_url()
2798 return $this->get_web_protocol() ."://". $this->get_server_name() . $this->cfg->web_path;
2800 } // get_phpfspot_url()
2803 * returns the number of photos which are tagged with $tag_id
2804 * @param integer $tag_id
2807 public function get_num_photos($tag_id)
2809 if($result = $this->db->db_fetchSingleRow("
2810 SELECT count(*) as number
2813 tag_id LIKE '". $tag_id ."'")) {
2815 return $result['number'];
2821 } // get_num_photos()
2824 * check file exists and is readable
2826 * returns true, if everything is ok, otherwise false
2827 * if $silent is not set, this function will output and
2829 * @param string $file
2830 * @param boolean $silent
2833 private function check_readable($file, $silent = null)
2835 if(!file_exists($file)) {
2837 print "File \"". $file ."\" does not exist.\n";
2841 if(!is_readable($file)) {
2843 print "File \"". $file ."\" is not reachable for user ". $this->getuid() ."\n";
2849 } // check_readable()
2852 * check if all needed indices are present
2854 * this function checks, if some needed indices are already
2855 * present, or if not, create them on the fly. they are
2856 * necessary to speed up some queries like that one look for
2857 * all tags, when show_tags is specified in the configuration.
2859 private function checkDbIndices()
2861 $result = $this->db->db_exec("
2862 CREATE INDEX IF NOT EXISTS
2869 } // checkDbIndices()
2872 * retrive F-Spot database version
2874 * this function will return the F-Spot database version number
2875 * It is stored within the sqlite3 database in the table meta
2876 * @return string|null
2878 public function getFspotDBVersion()
2880 if($result = $this->db->db_fetchSingleRow("
2881 SELECT data as version
2884 name LIKE 'F-Spot Database Version'
2886 return $result['version'];
2890 } // getFspotDBVersion()
2893 * parse the provided URI and will returned the requested chunk
2894 * @param string $uri
2895 * @param string $mode
2898 public function parse_uri($uri, $mode)
2900 if(($components = parse_url($uri)) !== false) {
2904 return basename($components['path']);
2907 return dirname($components['path']);
2910 return $components['path'];
2920 * validate config options
2922 * this function checks if all necessary configuration options are
2923 * specified and set.
2926 private function check_config_options()
2928 if(!isset($this->cfg->page_title) || $this->cfg->page_title == "")
2929 $this->_error("Please set \$page_title in phpfspot_cfg");
2931 if(!isset($this->cfg->base_path) || $this->cfg->base_path == "")
2932 $this->_error("Please set \$base_path in phpfspot_cfg");
2934 if(!isset($this->cfg->web_path) || $this->cfg->web_path == "")
2935 $this->_error("Please set \$web_path in phpfspot_cfg");
2937 if(!isset($this->cfg->thumb_path) || $this->cfg->thumb_path == "")
2938 $this->_error("Please set \$thumb_path in phpfspot_cfg");
2940 if(!isset($this->cfg->smarty_path) || $this->cfg->smarty_path == "")
2941 $this->_error("Please set \$smarty_path in phpfspot_cfg");
2943 if(!isset($this->cfg->fspot_db) || $this->cfg->fspot_db == "")
2944 $this->_error("Please set \$fspot_db in phpfspot_cfg");
2946 if(!isset($this->cfg->db_access) || $this->cfg->db_access == "")
2947 $this->_error("Please set \$db_access in phpfspot_cfg");
2949 if(!isset($this->cfg->phpfspot_db) || $this->cfg->phpfspot_db == "")
2950 $this->_error("Please set \$phpfspot_db in phpfspot_cfg");
2952 if(!isset($this->cfg->thumb_width) || $this->cfg->thumb_width == "")
2953 $this->_error("Please set \$thumb_width in phpfspot_cfg");
2955 if(!isset($this->cfg->thumb_height) || $this->cfg->thumb_height == "")
2956 $this->_error("Please set \$thumb_height in phpfspot_cfg");
2958 if(!isset($this->cfg->photo_width) || $this->cfg->photo_width == "")
2959 $this->_error("Please set \$photo_width in phpfspot_cfg");
2961 if(!isset($this->cfg->mini_width) || $this->cfg->mini_width == "")
2962 $this->_error("Please set \$mini_width in phpfspot_cfg");
2964 if(!isset($this->cfg->thumbs_per_page))
2965 $this->_error("Please set \$thumbs_per_page in phpfspot_cfg");
2967 if(!isset($this->cfg->path_replace_from) || $this->cfg->path_replace_from == "")
2968 $this->_error("Please set \$path_replace_from in phpfspot_cfg");
2970 if(!isset($this->cfg->path_replace_to) || $this->cfg->path_replace_to == "")
2971 $this->_error("Please set \$path_replace_to in phpfspot_cfg");
2973 if(!isset($this->cfg->hide_tags))
2974 $this->_error("Please set \$hide_tags in phpfspot_cfg");
2976 if(!isset($this->cfg->theme_name))
2977 $this->_error("Please set \$theme_name in phpfspot_cfg");
2979 if(!isset($this->cfg->logging))
2980 $this->_error("Please set \$logging in phpfspot_cfg");
2982 if(isset($this->cfg->logging) && $this->cfg->logging == 'logfile') {
2984 if(!isset($this->cfg->log_file))
2985 $this->_error("Please set \$log_file because you set logging = log_file in phpfspot_cfg");
2987 if(!is_writeable($this->cfg->log_file))
2988 $this->_error("The specified \$log_file ". $log_file ." is not writeable!");
2992 /* remove trailing slash, if set */
2993 if($this->cfg->web_path == "/")
2994 $this->cfg->web_path = "";
2995 elseif(preg_match('/\/$/', $this->cfg->web_path))
2996 $this->cfg->web_path = preg_replace('/\/$/', '', $this->cfg->web_path);
2998 return $this->runtime_error;
3000 } // check_config_options()
3003 * cleanup phpfspot own database
3005 * When photos are getting delete from F-Spot, there will remain
3006 * remain some residues in phpfspot own database. This function
3007 * will try to wipe them out.
3009 public function cleanup_phpfspot_db()
3011 $to_delete = Array();
3013 $result = $this->cfg_db->db_query("
3016 ORDER BY img_idx ASC
3019 while($row = $this->cfg_db->db_fetch_object($result)) {
3020 if(!$this->db->db_fetchSingleRow("
3023 WHERE id='". $row['img_idx'] ."'")) {
3025 array_push($to_delete, $row['img_idx'], ',');
3029 print count($to_delete) ." unnecessary objects will be removed from phpfspot's database.\n";
3031 $this->cfg_db->db_exec("
3033 WHERE img_idx IN (". implode($to_delete) .")
3036 } // cleanup_phpfspot_db()
3039 * return first image of the page, the $current photo
3042 * this function is used to find out the first photo of the
3043 * current page, in which the $current photo lies. this is
3044 * used to display the correct photo, when calling showPhotoIndex()
3046 * @param integer $current
3047 * @param integer $max
3050 private function getCurrentPage($current, $max)
3052 if(isset($this->cfg->thumbs_per_page) && !empty($this->cfg->thumbs_per_page)) {
3053 for($page_start = 0; $page_start <= $max; $page_start+=$this->cfg->thumbs_per_page) {
3054 if($current >= $page_start && $current < ($page_start+$this->cfg->thumbs_per_page))
3060 } // getCurrentPage()
3065 * this function tries to find out the correct mime-type
3066 * for the provided file.
3067 * @param string $file
3070 public function get_mime_info($file)
3072 $details = getimagesize($file);
3074 /* if getimagesize() returns empty, try at least to find out the
3077 if(empty($details) && function_exists('mime_content_type')) {
3079 // mime_content_type is marked as deprecated in the documentation,
3080 // but is it really necessary to force users to install a PECL
3082 $details['mime'] = mime_content_type($file);
3085 return $details['mime'];
3087 } // get_mime_info()
3090 * return tag-name by tag-idx
3092 * this function returns the tag-name for the requested
3093 * tag specified by tag-idx.
3094 * @param integer $idx
3097 public function get_tag_name($idx)
3099 if($result = $this->db->db_fetchSingleRow("
3103 id LIKE '". $idx ."'")) {
3105 return $result['name'];
3114 * parse user friendly url which got rewritten by the websever
3115 * @param string $request_uri
3118 private function parse_user_friendly_url($request_uri)
3120 if(preg_match('/\/photoview\/|\/photo\/|\/tag\//', $request_uri)) {
3122 unset($_SESSION['start_action']);
3123 unset($_SESSION['selected_tags']);
3125 $options = explode('/', $request_uri);
3127 switch($options[1]) {
3129 if(is_numeric($options[2])) {
3130 $_GET['mode'] = 'showp';
3131 return $this->showPhoto($options[2]);
3135 if(is_numeric($options[2])) {
3136 require_once "phpfspot_img.php";
3137 $img = new PHPFSPOT_IMG;
3138 if(isset($options[3]) && is_numeric($options[3]))
3139 $img->showImg($options[2], $options[3]);
3141 $img->showImg($options[2]);
3146 if(is_numeric($options[2])) {
3147 $this->session_cleanup();
3148 $_GET['tags'] = $options[2];
3149 $_SESSION['selected_tags'] = Array($options[2]);
3150 if(isset($options[3]) && is_numeric($options[3]))
3151 $_SESSION['begin_with'] = $options[3];
3152 return $this->showPhotoIndex();
3158 } // parse_user_friendly_url()
3161 * check if user-friendly-urls are enabled
3163 * this function will return true, if the config option
3164 * $user_friendly_url has been set. Otherwise false.
3167 private function is_user_friendly_url()
3169 if(isset($this->cfg->user_friendly_url) && $this->cfg->user_friendly_url)
3174 } // is_user_friendly_url()
3179 * this function will cleanup user's session information
3181 private function session_cleanup()
3183 unset($_SESSION['begin_with']);
3184 $this->resetDateSearch();
3185 $this->resetPhotoView();
3186 $this->resetTagSearch();
3187 $this->resetNameSearch();
3188 $this->resetDateSearch();
3190 } // session_cleanup()