cfg = new PHPFSPOT_CFG; /* verify config settings */ if($this->check_config_options()) { exit(1); } /* set application name and version information */ $this->cfg->product = "phpfspot"; $this->cfg->version = "1.5"; $this->sort_orders= array( 'date_asc' => 'Date ↑', 'date_desc' => 'Date ↓', 'name_asc' => 'Name ↑', 'name_desc' => 'Name ↓', 'tags_asc' => 'Tags ↑', 'tags_desc' => 'Tags ↓', ); /* Check necessary requirements */ if(!$this->check_requirements()) { exit(1); } /******* Opening F-Spot's sqlite database *********/ /* Check if database file is writeable */ if(!is_writeable($this->cfg->fspot_db)) { print $this->cfg->fspot_db ." is not writeable for user ". $this->getuid() ."\n"; exit(1); } /* open the database */ $this->db = new PHPFSPOT_DB($this, $this->cfg->fspot_db); /* change sqlite temp directory, if requested */ if(isset($this->cfg->sqlite_temp_dir)) { $this->db->db_exec(" PRAGMA temp_store_directory = '". $this->cfg->sqlite_temp_dir ."' "); } $this->dbver = $this->getFspotDBVersion(); if(!is_writeable($this->cfg->base_path ."/templates_c")) { print $this->cfg->base_path ."/templates_c: directory is not writeable for user ". $this->getuid() ."\n"; exit(1); } if(!is_writeable($this->cfg->thumb_path)) { print $this->cfg->thumb_path .": directory is not writeable for user ". $this->getuid() ."\n"; exit(1); } /******* Opening phpfspot's sqlite database *********/ /* Check if directory where the database file is stored is writeable */ if(!is_writeable(dirname($this->cfg->phpfspot_db))) { print dirname($this->cfg->phpfspot_db) .": directory is not writeable for user ". $this->getuid() ."\n"; exit(1); } /* Check if database file is writeable */ if(!is_writeable($this->cfg->phpfspot_db)) { print $this->cfg->phpfspot_db ." is not writeable for user ". $this->getuid() ."\n"; exit(1); } /* open the database */ $this->cfg_db = new PHPFSPOT_DB($this, $this->cfg->phpfspot_db); /* change sqlite temp directory, if requested */ if(isset($this->cfg->sqlite_temp_dir)) { $this->cfg_db->db_exec(" PRAGMA temp_store_directory = '". $this->cfg->sqlite_temp_dir ."' "); } /* Check if some tables need to be created */ $this->check_config_table(); /* overload Smarty class with our own template handler */ require_once "phpfspot_tmpl.php"; $this->tmpl = new PHPFSPOT_TMPL(); $this->tmpl->assign('web_path', $this->cfg->web_path); /* check if all necessary indices exist */ $this->checkDbIndices(); /* if session is not yet started, do it now */ if(session_id() == "") session_start(); if(!isset($_SESSION['tag_condition'])) $_SESSION['tag_condition'] = 'or'; if(!isset($_SESSION['sort_order'])) $_SESSION['sort_order'] = 'date_desc'; if(!isset($_SESSION['searchfor_tag'])) $_SESSION['searchfor_tag'] = ''; // if begin_with is still set but thumbs_per_page is now 0, unset it if(isset($_SESSION['begin_with']) && $this->cfg->thumbs_per_page == 0) unset($_SESSION['begin_with']); // if user-friendly-url's are enabled, set also a flag for the template handler if($this->is_user_friendly_url()) { $this->tmpl->assign('user_friendly_url', 'true'); } } // __construct() public function __destruct() { } // __destruct() /** * show - generate html output * * this function can be called after the constructor has * prepared everyhing. it will load the index.tpl smarty * template. if necessary it will registere pre-selects * (photo index, photo, tag search, date search) into * users session. */ public function show() { $this->tmpl->assign('searchfor_tag', $_SESSION['searchfor_tag']); $this->tmpl->assign('page_title', $this->cfg->page_title); $this->tmpl->assign('current_condition', $_SESSION['tag_condition']); $this->tmpl->assign('template_path', 'themes/'. $this->cfg->theme_name); /* parse URL */ if($this->is_user_friendly_url()) { $content = $this->parse_user_friendly_url($_SERVER['REQUEST_URI']); } if(isset($_GET['mode'])) { $_SESSION['start_action'] = $_GET['mode']; switch($_GET['mode']) { case 'showpi': if(isset($_GET['tags'])) { $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']); } if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) { $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00"); } if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) { $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59"); } break; case 'showp': if(isset($_GET['tags'])) { $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']); $_SESSION['start_action'] = 'showp'; } if(isset($_GET['id']) && is_numeric($_GET['id'])) { $_SESSION['current_photo'] = $_GET['id']; $_SESSION['start_action'] = 'showp'; } if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) { $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00"); } if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) { $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59"); } break; case 'export': $this->tmpl->show("export.tpl"); return; break; case 'slideshow': $this->tmpl->show("slideshow.tpl"); return; break; case 'rss': if(isset($_GET['tags'])) { $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']); } if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) { $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00"); } if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) { $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59"); } $this->getRSSFeed(); return; break; } } if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) $this->tmpl->assign('date_search_enabled', true); $this->tmpl->register_function("sort_select_list", array(&$this, "smarty_sort_select_list"), false); $this->tmpl->assign('search_from_date', $this->get_calendar('from')); $this->tmpl->assign('search_to_date', $this->get_calendar('to')); $this->tmpl->assign('preset_selected_tags', $this->getSelectedTags()); $this->tmpl->assign('preset_available_tags', $this->getAvailableTags()); if(!isset($content)) { if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) $this->tmpl->assign('initial_content', $this->showPhotoIndex()); else $this->tmpl->assign('initial_content', $this->tmpl->fetch('welcome.tpl')); } else $this->tmpl->assign('initial_content', $content); $this->tmpl->show("index.tpl"); } // show() /** * get_tags - grab all tags of f-spot's database * * this function will get all available tags from * the f-spot database and store them within two * arrays within this class for later usage. in * fact, if the user requests (hide_tags) it will * opt-out some of them. * * this function is getting called once by show() */ private function get_tags() { $this->avail_tags = Array(); $count = 0; if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) { $query_str=" SELECT DISTINCT t1.id as id, t1.name as name FROM photo_tags pt1 INNER JOIN photo_tags pt2 ON pt1.photo_id=pt2.photo_id INNER JOIN tags t1 ON t1.id=pt1.tag_id INNER JOIN tags t2 ON t2.id=pt2.tag_id WHERE t2.name IN ('".implode("','",$this->cfg->show_tags)."') ORDER BY t1.sort_priority ASC"; $result = $this->db->db_query($query_str); } else { $result = $this->db->db_query(" SELECT id,name FROM tags ORDER BY sort_priority ASC "); } while($row = $this->db->db_fetch_object($result)) { $tag_id = $row['id']; $tag_name = $row['name']; /* if the user has specified to ignore this tag in phpfspot's configuration, ignore it here so it does not get added to the tag list. */ if(in_array($row['name'], $this->cfg->hide_tags)) continue; /* if you include the following if-clause and the user has specified to only show certain tags which are specified in phpfspot's configuration, ignore all others so they will not be added to the tag list. if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags) && !in_array($row['name'], $this->cfg->show_tags)) continue; */ $this->tags[$tag_id] = $tag_name; $this->avail_tags[$count] = $tag_id; $count++; } } // get_tags() /** * extract all photo details * * retrieve all available details from f-spot's * database and return them as object * @param integer $idx * @return object|null */ public function get_photo_details($idx) { if($this->dbver < 9) { $query_str = " SELECT p.id, p.name, p.time, p.directory_path, p.description FROM photos p "; } else { $query_str = " SELECT p.id, p.uri, p.time, p.description FROM photos p "; } /* if show_tags is set, only return details for photos which are specified to be shown */ if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) { $query_str.= " INNER JOIN photo_tags pt ON p.id=pt.photo_id INNER JOIN tags t ON pt.tag_id=t.id WHERE p.id='". $idx ."' AND t.name IN ('".implode("','",$this->cfg->show_tags)."')"; } else { $query_str.= " WHERE p.id='". $idx ."' "; } if($result = $this->db->db_query($query_str)) { $row = $this->db->db_fetch_object($result); if($this->dbver < 9) { $row['uri'] = "file://". $row['directory_path'] ."/". $row['name']; } return $row; } return null; } // get_photo_details /** * returns aligned photo names * * this function returns aligned (length) names for * an specific photo. If the length of the name exceeds * $limit the name will be shrinked (...) * @param integer $idx * @param integer $limit * @return string|null */ public function getPhotoName($idx, $limit = 0) { if($details = $this->get_photo_details($idx)) { if($long_name = $this->parse_uri($details['uri'], 'filename')) { $name = $this->shrink_text($long_name, $limit); return $name; } } return null; } // getPhotoName() /** * shrink text according provided limit * * If the length of the name exceeds $limit the * text will be shortend and some content in between * will be replaced with "..." * @param string $ext * @param integer $limit * @return string */ private function shrink_text($text, $limit) { if($limit != 0 && strlen($text) > $limit) { $text = substr($text, 0, $limit-5) ."...". substr($text, -($limit-5)); } return $text; } // shrink_text(); /** * translate f-spoth photo path * * as the full-qualified path recorded in the f-spot database * is usally not the same as on the webserver, this function * will replace the path with that one specified in the cfg * @param string $path * @return string */ public function translate_path($path) { return str_replace($this->cfg->path_replace_from, $this->cfg->path_replace_to, $path); } // translate_path /** * control HTML ouput for a single photo * * this function provides all the necessary information * for the single photo template. * @param integer photo */ public function showPhoto($photo) { /* get all photos from the current photo selection */ $all_photos = $this->getPhotoSelection(); $count = count($all_photos); for($i = 0; $i < $count; $i++) { // $get_next will be set, when the photo which has to // be displayed has been found - this means that the // next available is in fact the NEXT image (for the // navigation icons) if(isset($get_next)) { $next_img = $all_photos[$i]; break; } /* the next photo is our NEXT photo */ if($all_photos[$i] == $photo) { $get_next = 1; } else { $previous_img = $all_photos[$i]; } if($photo == $all_photos[$i]) { $current = $i; } } $details = $this->get_photo_details($photo); if(!$details) { print "error"; return; } $orig_path = $this->translate_path($this->parse_uri($details['uri'], 'fullpath')); $thumb_path = $this->get_thumb_path($this->cfg->photo_width, $photo); if(!file_exists($orig_path)) { $this->_error("Photo ". $orig_path ." does not exist!
\n"); return; } if(!is_readable($orig_path)) { $this->_error("Photo ". $orig_path ." is not readable for user ". $this->getuid() ."
\n"); return; } /* If the thumbnail doesn't exist yet, try to create it */ if(!file_exists($thumb_path)) { $this->gen_thumb($photo, true); $thumb_path = $this->get_thumb_path($this->cfg->photo_width, $photo); } /* get mime-type, height and width from the original photo */ $info = getimagesize($orig_path); /* get EXIF information if JPEG */ if($info['mime'] == "image/jpeg") { $meta = $this->get_meta_informations($orig_path); } /* If EXIF data are available, use them */ if(isset($meta['ExifImageWidth'])) { $meta_res = $meta['ExifImageWidth'] ."x". $meta['ExifImageLength']; } else { $meta_res = $info[0] ."x". $info[1]; } $meta_date = isset($meta['FileDateTime']) ? strftime("%a %x %X", $meta['FileDateTime']) : "n/a"; $meta_make = isset($meta['Make']) ? $meta['Make'] ." / ". $meta['Model'] : "n/a"; $meta_size = isset($meta['FileSize']) ? round($meta['FileSize']/1024, 1) ."kbyte" : "n/a"; $extern_link = "index.php?mode=showp&id=". $photo; $current_tags = $this->getCurrentTags(); if($current_tags != "") { $extern_link.= "&tags=". $current_tags; } if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) { $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']); } $this->tmpl->assign('extern_link', $extern_link); if(!file_exists($thumb_path)) { $this->_error("Can't open file ". $thumb_path ."\n"); return; } $info_thumb = getimagesize($thumb_path); $this->tmpl->assign('description', $details['description']); $this->tmpl->assign('image_name', $this->parse_uri($details['uri'], 'filename')); $this->tmpl->assign('width', $info_thumb[0]); $this->tmpl->assign('height', $info_thumb[1]); $this->tmpl->assign('ExifMadeOn', $meta_date); $this->tmpl->assign('ExifMadeWith', $meta_make); $this->tmpl->assign('ExifOrigResolution', $meta_res); $this->tmpl->assign('ExifFileSize', $meta_size); if($this->is_user_friendly_url()) { $this->tmpl->assign('image_url', '/photo/'. $photo ."/". $this->cfg->photo_width); $this->tmpl->assign('image_url_full', '/photo/'. $photo); } else { $this->tmpl->assign('image_url', 'phpfspot_img.php?idx='. $photo ."&width=". $this->cfg->photo_width); $this->tmpl->assign('image_url_full', 'phpfspot_img.php?idx='. $photo); } $this->tmpl->assign('image_filename', $this->parse_uri($details['uri'], 'filename')); $this->tmpl->assign('tags', $this->get_photo_tags($photo)); $this->tmpl->assign('current_page', $this->getCurrentPage($current, $count)); $this->tmpl->assign('current_img', $photo); if($previous_img) { $this->tmpl->assign('previous_url', "javascript:showImage(". $previous_img .");"); $this->tmpl->assign('prev_img', $previous_img); } if($next_img) { $this->tmpl->assign('next_url', "javascript:showImage(". $next_img .");"); $this->tmpl->assign('next_img', $next_img); } $this->tmpl->assign('mini_width', $this->cfg->mini_width); $this->tmpl->assign('photo_width', $this->cfg->photo_width); $this->tmpl->assign('photo_number', $i); $this->tmpl->assign('photo_count', count($all_photos)); return $this->tmpl->fetch("single_photo.tpl"); } // showPhoto() /** * all available tags and tag cloud * * this function outputs all available tags (time ordered) * and in addition output them as tag cloud (tags which have * many photos will appears more then others) */ public function getAvailableTags() { /* retrive tags from database */ $this->get_tags(); $output = ""; $result = $this->db->db_query(" SELECT tag_id as id, count(tag_id) as quantity FROM photo_tags INNER JOIN tags t ON t.id = tag_id GROUP BY tag_id ORDER BY t.name ASC "); $tags = Array(); while($row = $this->db->db_fetch_object($result)) { $tags[$row['id']] = $row['quantity']; } // change these font sizes if you will $max_size = 125; // max font size in % $min_size = 75; // min font size in % // color $max_sat = hexdec('cc'); $min_sat = hexdec('44'); // get the largest and smallest array values $max_qty = max(array_values($tags)); $min_qty = min(array_values($tags)); // find the range of values $spread = $max_qty - $min_qty; if (0 == $spread) { // we don't want to divide by zero $spread = 1; } // determine the font-size increment // this is the increase per tag quantity (times used) $step = ($max_size - $min_size)/($spread); $step_sat = ($max_sat - $min_sat)/($spread); // loop through our tag array foreach ($tags as $key => $value) { if(isset($_SESSION['selected_tags']) && in_array($key, $_SESSION['selected_tags'])) continue; // calculate CSS font-size // find the $value in excess of $min_qty // multiply by the font-size increment ($size) // and add the $min_size set above $size = $min_size + (($value - $min_qty) * $step); // uncomment if you want sizes in whole %: $size = ceil($size); $color = $min_sat + ($value - $min_qty) * $step_sat; $r = '44'; $g = dechex($color); $b = '88'; if(isset($this->tags[$key])) { if($this->is_user_friendly_url()) $output.= "cfg->web_path ."/tag/". $key ."\" onclick=\"Tags('add', ". $key ."); return false;\" class=\"tag\" style=\"font-size: ". $size ."%; color: #". $r.$g.$b .";\">". $this->tags[$key] .", "; else $output.= "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] .", "; } } $output = substr($output, 0, strlen($output)-2); return $output; } // getAvailableTags() /** * output all selected tags * * this function output all tags which have been selected * by the user. the selected tags are stored in the * session-variable $_SESSION['selected_tags'] * @return string */ public function getSelectedTags($type = 'link') { /* retrive tags from database */ $this->get_tags(); $output = ""; foreach($this->avail_tags as $tag) { // return all selected tags if(isset($_SESSION['selected_tags']) && in_array($tag, $_SESSION['selected_tags'])) { switch($type) { default: case 'link': $output.= "". $this->tags[$tag] .", "; break; case 'img': $output.= "
tags[$tag] ."\"> cfg->web_path ."/phpfspot_img.php?tagidx=". $tag ."\" />
"; break; } } } if($output != "") { $output = substr($output, 0, strlen($output)-2); return $output; } else { return "no tags selected"; } } // getSelectedTags() /** * add tag to users session variable * * this function will add the specified to users current * tag selection. if a date search has been made before * it will be now cleared * @return string */ public function addTag($tag) { if(!isset($_SESSION['selected_tags'])) $_SESSION['selected_tags'] = Array(); if(isset($_SESSION['searchfor_tag'])) unset($_SESSION['searchfor_tag']); // has the user requested to hide this tag, and still someone, // somehow tries to add it, don't allow this. if(!isset($this->cfg->hide_tags) && in_array($this->get_tag_name($tag), $this->cfg->hide_tags)) return "ok"; if(!in_array($tag, $_SESSION['selected_tags'])) array_push($_SESSION['selected_tags'], $tag); return "ok"; } // addTag() /** * remove tag to users session variable * * this function removes the specified tag from * users current tag selection * @param string $tag * @return string */ public function delTag($tag) { if(isset($_SESSION['searchfor_tag'])) unset($_SESSION['searchfor_tag']); if(isset($_SESSION['selected_tags'])) { $key = array_search($tag, $_SESSION['selected_tags']); unset($_SESSION['selected_tags'][$key]); sort($_SESSION['selected_tags']); } return "ok"; } // delTag() /** * reset tag selection * * if there is any tag selection, it will be * deleted now */ public function resetTags() { if(isset($_SESSION['selected_tags'])) unset($_SESSION['selected_tags']); } // resetTags() /** * returns the value for the autocomplete tag-search * @return string */ public function get_xml_tag_list() { if(!isset($_GET['search']) || !is_string($_GET['search'])) $_GET['search'] = ''; $length = 15; $i = 1; /* retrive tags from database */ $this->get_tags(); $matched_tags = Array(); header("Content-Type: text/xml"); $string = "\n"; $string.= "\n"; foreach($this->avail_tags as $tag) { if(!empty($_GET['search']) && preg_match("/". $_GET['search'] ."/i", $this->tags[$tag]) && count($matched_tags) < $length) { $count = $this->get_num_photos($tag); if($count == 1) { $string.= " ". $this->tags[$tag] ."\n"; } else { $string.= " ". $this->tags[$tag] ."\n"; } $i++; } /* if we have collected enough items, break out */ if(count($matched_tags) >= $length) break; } $string.= "\n"; return $string; } // get_xml_tag_list() /** * reset single photo * * if a specific photo was requested (external link) * unset the session variable now */ public function resetPhotoView() { if(isset($_SESSION['current_photo'])) unset($_SESSION['current_photo']); } // resetPhotoView(); /** * reset tag search * * if any tag search has taken place, reset it now */ public function resetTagSearch() { if(isset($_SESSION['searchfor_tag'])) unset($_SESSION['searchfor_tag']); } // resetTagSearch() /** * reset name search * * if any name search has taken place, reset it now */ public function resetNameSearch() { if(isset($_SESSION['searchfor_name'])) unset($_SESSION['searchfor_name']); } // resetNameSearch() /** * reset date search * * if any date search has taken place, reset * it now */ public function resetDateSearch() { if(isset($_SESSION['from_date'])) unset($_SESSION['from_date']); if(isset($_SESSION['to_date'])) unset($_SESSION['to_date']); } // resetDateSearch(); /** * return all photo according selection * * this function returns all photos based on * the tag-selection, tag- or date-search. * the tag-search also has to take care of AND * and OR conjunctions * @return array */ public function getPhotoSelection() { $matched_photos = Array(); $additional_where_cond = ""; if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) { $from_date = $_SESSION['from_date']; $to_date = $_SESSION['to_date']; $additional_where_cond.= " p.time>='". $from_date ."' AND p.time<='". $to_date ."' "; } if(isset($_SESSION['searchfor_name'])) { if($this->dbver < 9) { $additional_where_cond.= " ( p.name LIKE '%". $_SESSION['searchfor_name'] ."%' OR p.description LIKE '%". $_SESSION['searchfor_name'] ."%' ) "; } else { $additional_where_cond.= " ( basename(p.uri) LIKE '%". $_SESSION['searchfor_name'] ."%' OR p.description LIKE '%". $_SESSION['searchfor_name'] ."%' ) "; } } if(isset($_SESSION['sort_order'])) { $order_str = $this->get_sort_order(); } /* return a search result */ if(isset($_SESSION['searchfor_tag']) && $_SESSION['searchfor_tag'] != '') { $query_str = " SELECT DISTINCT pt1.photo_id FROM photo_tags pt1 INNER JOIN photo_tags pt2 ON pt1.photo_id=pt2.photo_id INNER JOIN tags t ON pt1.tag_id=t.id INNER JOIN photos p ON pt1.photo_id=p.id INNER JOIN tags t2 ON pt2.tag_id=t2.id WHERE t.name LIKE '%". $_SESSION['searchfor_tag'] ."%' "; if(isset($additional_where_cond) && !empty($additional_where_cond)) $query_str.= "AND ". $additional_where_cond ." "; if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) { $query_str.= "AND t2.name IN ('".implode("','",$this->cfg->show_tags)."')"; } if(isset($order_str)) $query_str.= $order_str; $result = $this->db->db_query($query_str); while($row = $this->db->db_fetch_object($result)) { array_push($matched_photos, $row['photo_id']); } return $matched_photos; } /* return according the selected tags */ if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) { $selected = ""; foreach($_SESSION['selected_tags'] as $tag) $selected.= $tag .","; $selected = substr($selected, 0, strlen($selected)-1); /* photo has to match at least on of the selected tags */ if($_SESSION['tag_condition'] == 'or') { $query_str = " SELECT DISTINCT pt1.photo_id FROM photo_tags pt1 INNER JOIN photo_tags pt2 ON pt1.photo_id=pt2.photo_id INNER JOIN tags t ON pt2.tag_id=t.id INNER JOIN photos p ON pt1.photo_id=p.id WHERE pt1.tag_id IN (". $selected .") "; if(isset($additional_where_cond) && !empty($additional_where_cond)) $query_str.= "AND ". $additional_where_cond ." "; if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) { $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags)."')"; } if(isset($order_str)) $query_str.= $order_str; } /* photo has to match all selected tags */ elseif($_SESSION['tag_condition'] == 'and') { if(count($_SESSION['selected_tags']) >= 32) { print "A SQLite limit of 32 tables within a JOIN SELECT avoids to
\n"; print "evaluate your tag selection. Please remove some tags from your selection.\n"; return Array(); } /* Join together a table looking like pt1.photo_id pt1.tag_id pt2.photo_id pt2.tag_id ... so the query can quickly return all images matching the selected tags in an AND condition */ $query_str = " SELECT DISTINCT pt1.photo_id FROM photo_tags pt1 "; if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) { $query_str.= " INNER JOIN tags t ON pt1.tag_id=t.id "; } for($i = 0; $i < count($_SESSION['selected_tags']); $i++) { $query_str.= " INNER JOIN photo_tags pt". ($i+2) ." ON pt1.photo_id=pt". ($i+2) .".photo_id "; } $query_str.= " INNER JOIN photos p ON pt1.photo_id=p.id "; $query_str.= "WHERE pt2.tag_id=". $_SESSION['selected_tags'][0]." "; for($i = 1; $i < count($_SESSION['selected_tags']); $i++) { $query_str.= " AND pt". ($i+2) .".tag_id=". $_SESSION['selected_tags'][$i] ." "; } if(isset($additional_where_cond) && !empty($additional_where_cond)) $query_str.= "AND ". $additional_where_cond; if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) { $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags). "')"; } if(isset($order_str)) $query_str.= $order_str; } $result = $this->db->db_query($query_str); while($row = $this->db->db_fetch_object($result)) { array_push($matched_photos, $row['photo_id']); } return $matched_photos; } /* return all available photos */ $query_str = " SELECT DISTINCT p.id FROM photos p LEFT JOIN photo_tags pt ON p.id=pt.photo_id LEFT JOIN tags t ON pt.tag_id=t.id "; if(isset($additional_where_cond) && !empty($additional_where_cond)) $query_str.= "WHERE ". $additional_where_cond ." "; if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) { if(isset($additional_where_cond) && !empty($additional_where_cond)) $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags). "')"; else $query_str.= "WHERE t.name IN ('".implode("','",$this->cfg->show_tags). "')"; } if(isset($order_str)) $query_str.= $order_str; $result = $this->db->db_query($query_str); while($row = $this->db->db_fetch_object($result)) { array_push($matched_photos, $row['id']); } return $matched_photos; } // getPhotoSelection() /** * control HTML ouput for photo index * * this function provides all the necessary information * for the photo index template. * @return string */ public function showPhotoIndex() { $photos = $this->getPhotoSelection(); $count = count($photos); /* if all thumbnails should be shown on one page */ if(!isset($this->cfg->thumbs_per_page) || $this->cfg->thumbs_per_page == 0) { $begin_with = 0; $end_with = $count; } /* thumbnails should be splitted up in several pages */ elseif($this->cfg->thumbs_per_page > 0) { if(!isset($_SESSION['begin_with']) || $_SESSION['begin_with'] == 0) { $begin_with = 0; } else { $begin_with = $_SESSION['begin_with']; } $end_with = $begin_with + $this->cfg->thumbs_per_page; } $thumbs = 0; $images[$thumbs] = Array(); $img_height[$thumbs] = Array(); $img_width[$thumbs] = Array(); $img_id[$thumbs] = Array(); $img_name[$thumbs] = Array(); $img_fullname[$thumbs] = Array(); $img_title = Array(); for($i = $begin_with; $i < $end_with; $i++) { if(isset($photos[$i])) { $images[$thumbs] = $photos[$i]; $img_id[$thumbs] = $i; $img_name[$thumbs] = htmlspecialchars($this->getPhotoName($photos[$i], 15)); $img_fullname[$thumbs] = htmlspecialchars($this->getPhotoName($photos[$i], 0)); $img_title[$thumbs] = "Click to view photo ". htmlspecialchars($this->getPhotoName($photos[$i], 0)); $thumb_path = $this->get_thumb_path($this->cfg->thumb_width, $photos[$i]); if(file_exists($thumb_path)) { $info = getimagesize($thumb_path); $img_width[$thumbs] = $info[0]; $img_height[$thumbs] = $info[1]; } $thumbs++; } } // +1 for for smarty's selection iteration $thumbs++; if(isset($_SESSION['searchfor_tag']) && $_SESSION['searchfor_tag'] != '') $this->tmpl->assign('searchfor_tag', $_SESSION['searchfor_tag']); if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) { $this->tmpl->assign('from_date', $this->ts2str($_SESSION['from_date'])); $this->tmpl->assign('to_date', $this->ts2str($_SESSION['to_date'])); } if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) { $this->tmpl->assign('tag_result', 1); } /* do we have to display the page selector ? */ if($this->cfg->thumbs_per_page != 0) { $page_select = ""; /* calculate the page switchers */ $previous_start = $begin_with - $this->cfg->thumbs_per_page; $next_start = $begin_with + $this->cfg->thumbs_per_page; if($begin_with != 0) $this->tmpl->assign("previous_url", "javascript:showPhotoIndex(". $previous_start .");"); if($end_with < $count) $this->tmpl->assign("next_url", "javascript:showPhotoIndex(". $next_start .");"); $photo_per_page = $this->cfg->thumbs_per_page; $last_page = ceil($count / $photo_per_page); /* get the current selected page */ if($begin_with == 0) { $current_page = 1; } else { $current_page = 0; for($i = $begin_with; $i >= 0; $i-=$photo_per_page) { $current_page++; } } $dotdot_made = 0; for($i = 1; $i <= $last_page; $i++) { if($current_page == $i) $style = "style=\"font-size: 125%; text-decoration: underline;\""; elseif($current_page-1 == $i || $current_page+1 == $i) $style = "style=\"font-size: 105%;\""; elseif(($current_page-5 >= $i) && ($i != 1) || ($current_page+5 <= $i) && ($i != $last_page)) $style = "style=\"font-size: 75%;\""; else $style = ""; $start_with = ($i*$photo_per_page)-$photo_per_page; if($this->is_user_friendly_url()) { $select = "cfg->web_path ."/tag/205/". $start_with ."\""; } else { $select = "cfg->web_path ."/index.php?mode=showpi tags=". $current_tags ." begin_with=". $begin_with ."\""; } $select.= " onclick=\"showPhotoIndex(". $start_with ."); return false;\""; if($style != "") $select.= $style; $select.= ">". $i ." "; // until 9 pages we show the selector from 1-9 if($last_page <= 9) { $page_select.= $select; continue; } else { if($i == 1 /* first page */ || $i == $last_page /* last page */ || $i == $current_page /* current page */ || $i == ceil($last_page * 0.25) /* first quater */ || $i == ceil($last_page * 0.5) /* half */ || $i == ceil($last_page * 0.75) /* third quater */ || (in_array($i, array(1,2,3,4,5,6)) && $current_page <= 4) /* the first 6 */ || (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 */ || $i == $current_page-3 || $i == $current_page-2 || $i == $current_page-1 /* three before */ || $i == $current_page+3 || $i == $current_page+2 || $i == $current_page+1 /* three after */) { $page_select.= $select; $dotdot_made = 0; continue; } } if(!$dotdot_made) { $page_select.= "......... "; $dotdot_made = 1; } } /* only show the page selector if we have more then one page */ if($last_page > 1) $this->tmpl->assign('page_selector', $page_select); } $current_tags = $this->getCurrentTags(); $extern_link = "index.php?mode=showpi"; $rss_link = "index.php?mode=rss"; if($current_tags != "") { $extern_link.= "&tags=". $current_tags; $rss_link.= "&tags=". $current_tags; } if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) { $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']); $rss_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']); } $export_link = "index.php?mode=export"; $slideshow_link = "index.php?mode=slideshow"; $this->tmpl->assign('extern_link', $extern_link); $this->tmpl->assign('slideshow_link', $slideshow_link); $this->tmpl->assign('export_link', $export_link); $this->tmpl->assign('rss_link', $rss_link); $this->tmpl->assign('count', $count); $this->tmpl->assign('width', $this->cfg->thumb_width); $this->tmpl->assign('preview_width', $this->cfg->photo_width); $this->tmpl->assign('thumb_container_width', $this->cfg->thumb_width); $this->tmpl->assign('thumb_container_height', $this->cfg->thumb_height+20); $this->tmpl->assign('images', $images); $this->tmpl->assign('img_width', $img_width); $this->tmpl->assign('img_height', $img_height); $this->tmpl->assign('img_id', $img_id); $this->tmpl->assign('img_name', $img_name); $this->tmpl->assign('img_fullname', $img_fullname); $this->tmpl->assign('img_title', $img_title); $this->tmpl->assign('thumbs', $thumbs); $this->tmpl->assign('selected_tags', $this->getSelectedTags('img')); $result = $this->tmpl->fetch("photo_index.tpl"); /* if we are returning to photo index from an photo-view, scroll the window to the last shown photo-thumbnail. after this, unset the last_photo session variable. */ if(isset($_SESSION['last_photo'])) { $result.= "\n"; unset($_SESSION['last_photo']); } return $result; } // showPhotoIndex() /** * show credit template */ public function showCredits() { $this->tmpl->assign('version', $this->cfg->version); $this->tmpl->assign('product', $this->cfg->product); $this->tmpl->assign('db_version', $this->dbver); $this->tmpl->show("credits.tpl"); } // showCredits() /** * create thumbnails for the requested width * * this function creates image thumbnails of $orig_image * stored as $thumb_image. It will check if the image is * in a supported format, if necessary rotate the image * (based on EXIF orientation meta headers) and re-sizing. * @param string $orig_image * @param string $thumb_image * @param integer $width * @return boolean */ public function create_thumbnail($orig_image, $thumb_image, $width) { if(!file_exists($orig_image)) { return false; } $mime = $this->get_mime_info($orig_image); /* check if original photo is a support image type */ if(!$this->checkifImageSupported($mime)) return false; switch($mime) { case 'image/jpeg': $meta = $this->get_meta_informations($orig_image); $rotate = 0; $flip_hori = false; $flip_vert = false; switch($meta['Orientation']) { case 1: /* top, left */ /* nothing to do */ break; case 2: /* top, right */ $rotate = 0; $flip_hori = true; break; case 3: /* bottom, left */ $rotate = 180; break; case 4: /* bottom, right */ $flip_vert = true; break; case 5: /* left side, top */ $rotate = 90; $flip_vert = true; break; case 6: /* right side, top */ $rotate = 90; break; case 7: /* left side, bottom */ $rotate = 270; $flip_vert = true; break; case 8: /* right side, bottom */ $rotate = 270; break; } $src_img = @imagecreatefromjpeg($orig_image); $handler = "gd"; break; case 'image/png': $src_img = @imagecreatefrompng($orig_image); $handler = "gd"; break; case 'image/x-portable-pixmap': $src_img = new Imagick($orig_image); $handler = "imagick"; break; } if(!isset($src_img) || empty($src_img)) { print "Can't load image from ". $orig_image ."\n"; return false; } switch($handler) { case 'gd': /* grabs the height and width */ $cur_width = imagesx($src_img); $cur_height = imagesy($src_img); // If requested width is more then the actual image width, // do not generate a thumbnail, instead safe the original // as thumbnail but with lower quality. But if the image // is to heigh too, then we still have to resize it. if($width >= $cur_width && $cur_height < $this->cfg->thumb_height) { $result = imagejpeg($src_img, $thumb_image, 75); imagedestroy($src_img); return true; } break; case 'imagick': $cur_width = $src_img->getImageWidth(); $cur_height = $src_img->getImageHeight(); // If requested width is more then the actual image width, // do not generate a thumbnail, instead safe the original // as thumbnail but with lower quality. But if the image // is to heigh too, then we still have to resize it. if($width >= $cur_width && $cur_height < $this->cfg->thumb_height) { $src_img->setCompressionQuality(75); $src_img->setImageFormat('jpeg'); $src_img->writeImage($thumb_image); $src_img->clear(); $src_img->destroy(); return true; } break; } // If the image will be rotate because EXIF orientation said so // 'virtually rotate' the image for further calculations if($rotate == 90 || $rotate == 270) { $tmp = $cur_width; $cur_width = $cur_height; $cur_height = $tmp; } /* calculates aspect ratio */ $aspect_ratio = $cur_height / $cur_width; /* sets new size */ if($aspect_ratio < 1) { $new_w = $width; $new_h = abs($new_w * $aspect_ratio); } else { /* 'virtually' rotate the image and calculate it's ratio */ $tmp_w = $cur_height; $tmp_h = $cur_width; /* now get the ratio from the 'rotated' image */ $tmp_ratio = $tmp_h/$tmp_w; /* now calculate the new dimensions */ $tmp_w = $width; $tmp_h = abs($tmp_w * $tmp_ratio); // now that we know, how high they photo should be, if it // gets rotated, use this high to scale the image $new_h = $tmp_h; $new_w = abs($new_h / $aspect_ratio); // If the image will be rotate because EXIF orientation said so // now 'virtually rotate' back the image for the image manipulation if($rotate == 90 || $rotate == 270) { $tmp = $new_w; $new_w = $new_h; $new_h = $tmp; } } switch($handler) { case 'gd': /* creates new image of that size */ $dst_img = imagecreatetruecolor($new_w, $new_h); imagefill($dst_img, 0, 0, ImageColorAllocate($dst_img, 255, 255, 255)); /* copies resized portion of original image into new image */ imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $new_w, $new_h, imagesx($src_img), imagesy($src_img)); /* needs the image to be flipped horizontal? */ if($flip_hori) { $this->_debug("(FLIP)"); $dst_img = $this->flipImage($dst_img, 'hori'); } /* needs the image to be flipped vertical? */ if($flip_vert) { $this->_debug("(FLIP)"); $dst_img = $this->flipImage($dst_img, 'vert'); } if($rotate) { $this->_debug("(ROTATE)"); $dst_img = $this->rotateImage($dst_img, $rotate); } /* write down new generated file */ $result = imagejpeg($dst_img, $thumb_image, 75); /* free your mind */ imagedestroy($dst_img); imagedestroy($src_img); if($result === false) { print "Can't write thumbnail ". $thumb_image ."\n"; return false; } return true; break; case 'imagick': $src_img->resizeImage($new_w, $new_h, Imagick::FILTER_LANCZOS, 1); /* needs the image to be flipped horizontal? */ if($flip_hori) { $this->_debug("(FLIP)"); $src_img->rotateImage(new ImagickPixel(), 90); $src_img->flipImage(); $src_img->rotateImage(new ImagickPixel(), -90); } /* needs the image to be flipped vertical? */ if($flip_vert) { $this->_debug("(FLIP)"); $src_img->flipImage(); } if($rotate) { $this->_debug("(ROTATE)"); $src_img->rotateImage(new ImagickPixel(), $rotate); } $src_img->setCompressionQuality(75); $src_img->setImageFormat('jpeg'); if(!$src_img->writeImage($thumb_image)) { print "Can't write thumbnail ". $thumb_image ."\n"; return false; } $src_img->clear(); $src_img->destroy(); return true; break; } } // create_thumbnail() /** * return all exif meta data from the file * @param string $file * @return array */ public function get_meta_informations($file) { return exif_read_data($file); } // get_meta_informations() /** * create phpfspot own sqlite database * * this function creates phpfspots own sqlite database * if it does not exist yet. this own is used to store * some necessary informations (md5 sum's, ...). */ public function check_config_table() { // if the config table doesn't exist yet, create it if(!$this->cfg_db->db_check_table_exists("images")) { $this->cfg_db->db_exec(" CREATE TABLE images ( img_idx int primary key, img_md5 varchar(32) ) "); } } // check_config_table /** * Generates a thumbnail from photo idx * * This function will generate JPEG thumbnails from provided F-Spot photo * indizes. * * 1. Check if all thumbnail generations (width) are already in place and * readable * 2. Check if the md5sum of the original file has changed * 3. Generate the thumbnails if needed * @param integer $idx * @param integer $force * @param boolean $overwrite */ public function gen_thumb($idx = 0, $force = 0, $overwrite = false) { $error = 0; $resolutions = Array( $this->cfg->thumb_width, $this->cfg->photo_width, $this->cfg->mini_width, 30, ); /* get details from F-Spot's database */ $details = $this->get_photo_details($idx); /* calculate file MD5 sum */ $full_path = $this->translate_path($this->parse_uri($details['uri'], 'fullpath')); if(!file_exists($full_path)) { $this->_error("File ". $full_path ." does not exist\n"); return; } if(!is_readable($full_path)) { $this->_error("File ". $full_path ." is not readable for ". $this->getuid() ."\n"); return; } $this->_debug("Image [". $idx ."] ". $this->shrink_text($this->parse_uri($details['uri'], 'filename'), 20) ." Thumbnails:"); /* If Nikon NEF format, we need to treat it another way */ if(isset($this->cfg->dcraw_bin) && file_exists($this->cfg->dcraw_bin) && is_executable($this->cfg->dcraw_bin) && preg_match('/\.nef$/i', $details['uri'])) { $ppm_path = preg_replace('/\.nef$/i', '.ppm', $full_path); /* if PPM file does not exist, let dcraw convert it from NEF */ if(!file_exists($ppm_path)) { system($this->cfg->dcraw_bin ." -a ". $full_path); } /* for now we handle the PPM instead of the NEF */ $full_path = $ppm_path; } $file_md5 = md5_file($full_path); $changes = false; foreach($resolutions as $resolution) { $generate_it = false; $thumb_sub_path = substr($file_md5, 0, 2); $thumb_path = $this->cfg->thumb_path ."/". $thumb_sub_path ."/". $resolution ."_". $file_md5; /* if thumbnail-subdirectory does not exist yet, create it */ if(!file_exists(dirname($thumb_path))) { mkdir(dirname($thumb_path), 0755); } /* if the thumbnail file doesn't exist, create it */ if(!file_exists($thumb_path)) { $generate_it = true; } /* if the file hasn't changed there is no need to regen the thumb */ elseif($file_md5 != $this->getMD5($idx) || $force) { $generate_it = true; } if($generate_it || $overwrite) { $this->_debug(" ". $resolution ."px"); if(!$this->create_thumbnail($full_path, $thumb_path, $resolution)) $error = 1; $changes = true; } } if(!$changes) { $this->_debug(" already exist"); } /* set the new/changed MD5 sum for the current photo */ if(!$error) { $this->setMD5($idx, $file_md5); } $this->_debug("\n"); } // gen_thumb() /** * returns stored md5 sum for a specific photo * * this function queries the phpfspot database for a * stored MD5 checksum of the specified photo * @param integer $idx * @return string|null */ public function getMD5($idx) { $result = $this->cfg_db->db_query(" SELECT img_md5 FROM images WHERE img_idx='". $idx ."' "); if(!$result) return 0; $img = $this->cfg_db->db_fetch_object($result); return $img['img_md5']; } // getMD5() /** * set MD5 sum for the specific photo * @param integer $idx * @param string $md5 */ private function setMD5($idx, $md5) { $result = $this->cfg_db->db_exec(" REPLACE INTO images (img_idx, img_md5) VALUES ('". $idx ."', '". $md5 ."') "); } // setMD5() /** * store current tag condition * * this function stores the current tag condition * (AND or OR) in the users session variables * @param string $mode * @return string */ public function setTagCondition($mode) { $_SESSION['tag_condition'] = $mode; return "ok"; } // setTagCondition() /** * invoke tag & date search * * this function will return all matching tags and store * them in the session variable selected_tags. furthermore * it also handles the date search. * getPhotoSelection() will then only return the matching * photos. * @return string */ public function startSearch() { if(isset($_POST['from']) && $this->isValidDate($_POST['from'])) { $from = $_POST['from']; } if(isset($_POST['to']) && $this->isValidDate($_POST['to'])) { $to = $_POST['to']; } if(isset($_POST['for_tag']) && is_string($_POST['for_tag'])) { $searchfor_tag = $_POST['for_tag']; $_SESSION['searchfor_tag'] = $_POST['for_tag']; } if(isset($_POST['for_name']) && is_string($_POST['for_name'])) { $searchfor_name = $_POST['for_name']; $_SESSION['searchfor_name'] = $_POST['for_name']; } $this->get_tags(); if(isset($from) && !empty($from)) $_SESSION['from_date'] = strtotime($from ." 00:00:00"); else unset($_SESSION['from_date']); if(isset($to) && !empty($to)) $_SESSION['to_date'] = strtotime($to ." 23:59:59"); else unset($_SESSION['to_date']); if(isset($searchfor_tag) && !empty($searchfor_tag)) { /* new search, reset the current selected tags */ $_SESSION['selected_tags'] = Array(); foreach($this->avail_tags as $tag) { if(preg_match('/'. $searchfor_tag .'/i', $this->tags[$tag])) array_push($_SESSION['selected_tags'], $tag); } } return "ok"; } // startSearch() /** * updates sort order in session variable * * this function is invoked by RPC and will sort the requested * sort order in the session variable. * @param string $sort_order * @return string */ public function updateSortOrder($order) { if(isset($this->sort_orders[$order])) { $_SESSION['sort_order'] = $order; return "ok"; } return "unkown error"; } // updateSortOrder() /** * rotate image * * this function rotates the image according the * specified angel. * @param string $img * @param integer $degress * @return image */ private function rotateImage($img, $degrees) { if(function_exists("imagerotate")) { $img = imagerotate($img, $degrees, 0); } else { function imagerotate($src_img, $angle) { $src_x = imagesx($src_img); $src_y = imagesy($src_img); if ($angle == 180) { $dest_x = $src_x; $dest_y = $src_y; } elseif ($src_x <= $src_y) { $dest_x = $src_y; $dest_y = $src_x; } elseif ($src_x >= $src_y) { $dest_x = $src_y; $dest_y = $src_x; } $rotate=imagecreatetruecolor($dest_x,$dest_y); imagealphablending($rotate, false); switch ($angle) { case 90: for ($y = 0; $y < ($src_y); $y++) { for ($x = 0; $x < ($src_x); $x++) { $color = imagecolorat($src_img, $x, $y); imagesetpixel($rotate, $dest_x - $y - 1, $x, $color); } } break; case 270: for ($y = 0; $y < ($src_y); $y++) { for ($x = 0; $x < ($src_x); $x++) { $color = imagecolorat($src_img, $x, $y); imagesetpixel($rotate, $y, $dest_y - $x - 1, $color); } } break; case 180: for ($y = 0; $y < ($src_y); $y++) { for ($x = 0; $x < ($src_x); $x++) { $color = imagecolorat($src_img, $x, $y); imagesetpixel($rotate, $dest_x - $x - 1, $dest_y - $y - 1, $color); } } break; default: $rotate = $src_img; break; }; return $rotate; } $img = imagerotate($img, $degrees); } return $img; } // rotateImage() /** * returns flipped image * * this function will return an either horizontal or * vertical flipped truecolor image. * @param string $image * @param string $mode * @return image */ private function flipImage($image, $mode) { $w = imagesx($image); $h = imagesy($image); $flipped = imagecreatetruecolor($w, $h); switch($mode) { case 'vert': for ($y = 0; $y < $h; $y++) { imagecopy($flipped, $image, 0, $y, 0, $h - $y - 1, $w, 1); } break; case 'hori': for ($x = 0; $x < $w; $x++) { imagecopy($flipped, $image, $x, 0, $w - $x - 1, 0, 1, $h); } break; } return $flipped; } // flipImage() /** * return all assigned tags for the specified photo * @param integer $idx * @return array */ private function get_photo_tags($idx) { $result = $this->db->db_query(" SELECT t.id, t.name FROM tags t INNER JOIN photo_tags pt ON t.id=pt.tag_id WHERE pt.photo_id='". $idx ."' "); $tags = Array(); while($row = $this->db->db_fetch_object($result)) { if(isset($this->cfg->hide_tags) && in_array($row['name'], $this->cfg->hide_tags)) continue; $tags[$row['id']] = $row['name']; } return $tags; } // get_photo_tags() /** * create on-the-fly images with text within * @param string $txt * @param string $color * @param integer $space * @param integer $font * @param integer $w */ public function showTextImage($txt, $color=000000, $space=4, $font=4, $w=300) { if (strlen($color) != 6) $color = 000000; $int = hexdec($color); $h = imagefontheight($font); $fw = imagefontwidth($font); $txt = explode("\n", wordwrap($txt, ($w / $fw), "\n")); $lines = count($txt); $im = imagecreate($w, (($h * $lines) + ($lines * $space))); $bg = imagecolorallocate($im, 255, 255, 255); $color = imagecolorallocate($im, 0xFF & ($int >> 0x10), 0xFF & ($int >> 0x8), 0xFF & $int); $y = 0; foreach ($txt as $text) { $x = (($w - ($fw * strlen($text))) / 2); imagestring($im, $font, $x, $y, $text, $color); $y += ($h + $space); } Header("Content-type: image/png"); ImagePng($im); } // showTextImage() /** * check if all requirements are met * @return boolean */ private function check_requirements() { if(!function_exists("imagecreatefromjpeg")) { print "PHP GD library extension is missing
\n"; $missing = true; } if($this->cfg->db_access == "native" && !function_exists("sqlite3_open")) { print "PHP SQLite3 library extension is missing
\n"; $missing = true; } /* Check for HTML_AJAX PEAR package, lent from Horde project */ ini_set('track_errors', 1); @include_once 'HTML/AJAX/Server.php'; if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) { print "PEAR HTML_AJAX package is missing
\n"; $missing = true; } @include_once 'Calendar/Calendar.php'; if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) { print "PEAR Calendar package is missing
\n"; $missing = true; } @include_once 'Console/Getopt.php'; if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) { print "PEAR Console_Getopt package is missing
\n"; $missing = true; } @include_once $this->cfg->smarty_path .'/libs/Smarty.class.php'; if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) { print "Smarty template engine can not be found in ". $this->cfg->smarty_path ."/libs/Smarty.class.php
\n"; $missing = true; } ini_restore('track_errors'); if(isset($missing)) return false; return true; } // check_requirements() private function _debug($text) { if($this->fromcmd) { print $text; } } // _debug() /** * check if specified MIME type is supported * @param string $mime * @return boolean */ public function checkifImageSupported($mime) { $supported_types = Array( "image/jpeg", "image/png", "image/x-portable-pixmap", "image/tiff" ); if(in_array($mime, $supported_types)) return true; return false; } // checkifImageSupported() /** * output error text * @param string $text */ public function _error($text) { switch($this->cfg->logging) { default: case 'display': print "\"warning\"\n"; print $text ."
\n"; break; case 'errorlog': error_log($text); break; case 'logfile': error_log($text, 3, $his->cfg->log_file); break; } $this->runtime_error = true; } // _error() /** * output calendard input fields * @param string $mode * @return string */ private function get_calendar($mode) { $year = isset($_SESSION[$mode .'_date']) ? date("Y", $_SESSION[$mode .'_date']) : date("Y"); $month = isset($_SESSION[$mode .'_date']) ? date("m", $_SESSION[$mode .'_date']) : date("m"); $day = isset($_SESSION[$mode .'_date']) ? date("d", $_SESSION[$mode .'_date']) : date("d"); $output = "prevMonth(true); $prev = "javascript:setMonth(". date('Y',$prevStamp) .", ". date('n',$prevStamp) .", ". date('j',$prevStamp) .");"; $nextStamp = $month->nextMonth(true); $next = "javascript:setMonth(". date('Y',$nextStamp) .", ". date('n',$nextStamp) .", ". date('j',$nextStamp) .");"; $selectedDays = array ( new Calendar_Day($year,$month,$day), new Calendar_Day($year,12,25), ); // Build the days in the month $month->build($selectedDays); $this->tmpl->assign('current_month', date('F Y',$month->getTimeStamp())); $this->tmpl->assign('prev_month', $prev); $this->tmpl->assign('next_month', $next); while ( $day = $month->fetch() ) { if(!isset($matrix[$rows])) $matrix[$rows] = Array(); $string = ""; $dayStamp = $day->thisDay(true); $link = "javascript:setCalendarDate(". date('Y',$dayStamp) .", ". date('n',$dayStamp).", ". date('j',$dayStamp) .");"; // isFirst() to find start of week if ( $day->isFirst() ) $string.= "\n"; if ( $day->isSelected() ) { $string.= "".$day->thisDay()."\n"; } else if ( $day->isEmpty() ) { $string.= " \n"; } else { $string.= "".$day->thisDay()."\n"; } // isLast() to find end of week if ( $day->isLast() ) $string.= "\n"; $matrix[$rows][$cols] = $string; $cols++; if($cols > 7) { $cols = 1; $rows++; } } $this->tmpl->assign('matrix', $matrix); $this->tmpl->assign('rows', $rows); $this->tmpl->show("calendar.tpl"); } // get_calendar_matrix() /** * output export page * @param string $mode */ public function getExport($mode) { $pictures = $this->getPhotoSelection(); $current_tags = $this->getCurrentTags(); foreach($pictures as $picture) { $orig_url = $this->get_phpfspot_url() ."/index.php?mode=showp&id=". $picture; if($current_tags != "") { $orig_url.= "&tags=". $current_tags; } if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) { $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date']; } if($this->is_user_friendly_url()) { $thumb_url = $this->get_phpfspot_url() ."/photo/". $picture ."/". $this->cfg->thumb_width; } else { $thumb_url = $this->get_phpfspot_url() ."/phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width; } switch($mode) { case 'HTML': // print htmlspecialchars("") ."
\n"; break; case 'MoinMoin': // "[%pictureurl% %thumbnailurl%]" print htmlspecialchars("[".$orig_url." ".$thumb_url."&fake=1.jpg]") ."
\n"; break; case 'MoinMoinList': // " * [%pictureurl% %thumbnailurl%]" print " " . htmlspecialchars("* [".$orig_url." ".$thumb_url."&fake=1.jpg]") ."
\n"; break; } } } // getExport() /** * output RSS feed */ public function getRSSFeed() { Header("Content-type: text/xml; charset=utf-8"); print "\n"; ?> phpfspot phpfspot RSS feed get_phpfspot_url()); ?> phpfspot getPhotoSelection(); $current_tags = $this->getCurrentTags(); foreach($pictures as $picture) { $orig_url = $this->get_phpfspot_url() ."/index.php?mode=showp&id=". $picture; if($current_tags != "") { $orig_url.= "&tags=". $current_tags; } if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) { $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date']; } $details = $this->get_photo_details($picture); if($this->is_user_friendly_url()) { $thumb_url = $this->get_phpfspot_url() ."/photo/". $picture ."/". $this->cfg->thumb_width; } else { $thumb_url = $this->get_phpfspot_url() ."/phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width; } $thumb_html = htmlspecialchars("
". $details['description']); $orig_path = $this->translate_path($this->parse_uri($details['uri'], 'fullpath')); /* get EXIF information if JPEG */ if($details['mime'] == "image/jpeg") { $meta = $this->get_meta_informations($orig_path); } $meta_date = isset($meta['FileDateTime']) ? $meta['FileDateTime'] : filemtime($orig_path); ?> <?php print htmlspecialchars($this->parse_uri($details['uri'], 'filename')); ?>
sort_orders as $key => $value) { $output.= "