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 /* get F-Spot database version */
161 $this->dbver = $this->getFspotDBVersion();
163 if(!is_writeable($this->cfg->base_path ."/templates_c")) {
164 print $this->cfg->base_path ."/templates_c: directory is not writeable for user ". $this->getuid() ."\n";
168 if(!is_writeable($this->cfg->thumb_path)) {
169 print $this->cfg->thumb_path .": directory is not writeable for user ". $this->getuid() ."\n";
173 /******* Opening phpfspot's sqlite database *********/
175 /* Check if directory where the database file is stored is writeable */
176 if(!is_writeable(dirname($this->cfg->phpfspot_db))) {
177 print dirname($this->cfg->phpfspot_db) .": directory is not writeable for user ". $this->getuid() ."\n";
181 /* Check if database file is writeable */
182 if(!is_writeable($this->cfg->phpfspot_db)) {
183 print $this->cfg->phpfspot_db ." is not writeable for user ". $this->getuid() ."\n";
187 /* open the database */
188 $this->cfg_db = new PHPFSPOT_DB($this, $this->cfg->phpfspot_db);
190 /* change sqlite temp directory, if requested */
191 if(isset($this->cfg->sqlite_temp_dir)) {
192 $this->cfg_db->db_exec("
194 temp_store_directory = '". $this->cfg->sqlite_temp_dir ."'
198 /* Check if some tables need to be created */
199 $this->check_config_table();
201 /* overload Smarty class with our own template handler */
202 require_once "phpfspot_tmpl.php";
203 $this->tmpl = new PHPFSPOT_TMPL();
205 $this->tmpl->assign('web_path', $this->cfg->web_path);
207 /* Starting with F-Spot 0.4.2, the rating-feature was available */
208 if($this->dbver > 10) {
209 $this->sort_orders = array_merge($this->sort_orders, array(
210 'rate_asc' => 'Rate ↑',
211 'rate_desc' => 'Rate ↓',
215 /* check if all necessary indices exist */
216 $this->checkDbIndices();
218 /* if session is not yet started, do it now */
219 if(session_id() == "")
222 if(!isset($_SESSION['tag_condition']))
223 $_SESSION['tag_condition'] = 'or';
225 if(!isset($_SESSION['sort_order']))
226 $_SESSION['sort_order'] = 'date_desc';
228 if(!isset($_SESSION['searchfor_tag']))
229 $_SESSION['searchfor_tag'] = '';
231 // if begin_with is still set but thumbs_per_page is now 0, unset it
232 if(isset($_SESSION['begin_with']) && $this->cfg->thumbs_per_page == 0)
233 unset($_SESSION['begin_with']);
235 // if user-friendly-url's are enabled, set also a flag for the template handler
236 if($this->is_user_friendly_url()) {
237 $this->tmpl->assign('user_friendly_url', 'true');
242 public function __destruct()
248 * show - generate html output
250 * this function can be called after the constructor has
251 * prepared everyhing. it will load the index.tpl smarty
252 * template. if necessary it will registere pre-selects
253 * (photo index, photo, tag search, date search) into
256 public function show()
258 $this->tmpl->assign('searchfor_tag', $_SESSION['searchfor_tag']);
259 $this->tmpl->assign('page_title', $this->cfg->page_title);
260 $this->tmpl->assign('current_condition', $_SESSION['tag_condition']);
261 $this->tmpl->assign('template_path', 'themes/'. $this->cfg->theme_name);
264 if($this->is_user_friendly_url()) {
265 $content = $this->parse_user_friendly_url($_SERVER['REQUEST_URI']);
268 if(isset($_GET['mode'])) {
270 $_SESSION['start_action'] = $_GET['mode'];
272 switch($_GET['mode']) {
274 if(isset($_GET['tags'])) {
275 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
277 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
278 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
280 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
281 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
285 if(isset($_GET['tags'])) {
286 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
287 $_SESSION['start_action'] = 'showp';
289 if(isset($_GET['id']) && is_numeric($_GET['id'])) {
290 $_SESSION['current_photo'] = $_GET['id'];
291 $_SESSION['start_action'] = 'showp';
293 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
294 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
296 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
297 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
301 $this->tmpl->show("export.tpl");
305 $this->tmpl->show("slideshow.tpl");
309 if(isset($_GET['tags'])) {
310 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
312 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
313 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
315 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
316 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
324 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date']))
325 $this->tmpl->assign('date_search_enabled', true);
327 $this->tmpl->register_function("sort_select_list", array(&$this, "smarty_sort_select_list"), false);
328 $this->tmpl->assign('search_from_date', $this->get_calendar('from'));
329 $this->tmpl->assign('search_to_date', $this->get_calendar('to'));
331 $this->tmpl->assign('preset_selected_tags', $this->getSelectedTags());
332 $this->tmpl->assign('preset_available_tags', $this->getAvailableTags());
334 if(!isset($content)) {
335 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags']))
336 $this->tmpl->assign('initial_content', $this->showPhotoIndex());
338 $this->tmpl->assign('initial_content', $this->tmpl->fetch('welcome.tpl'));
341 $this->tmpl->assign('initial_content', $content);
343 $this->tmpl->show("index.tpl");
348 * get_tags - grab all tags of f-spot's database
350 * this function will get all available tags from
351 * the f-spot database and store them within two
352 * arrays within this class for later usage. in
353 * fact, if the user requests (hide_tags) it will
354 * opt-out some of them.
356 * this function is getting called once by show()
358 private function get_tags()
360 $this->avail_tags = Array();
363 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
366 DISTINCT t1.id as id, t1.name as name
369 INNER JOIN photo_tags
370 pt2 ON pt1.photo_id=pt2.photo_id
376 t2.name IN ('".implode("','",$this->cfg->show_tags)."')
378 t1.sort_priority ASC";
380 $result = $this->db->db_query($query_str);
384 $result = $this->db->db_query("
387 ORDER BY sort_priority ASC
391 while($row = $this->db->db_fetch_object($result)) {
393 $tag_id = $row['id'];
394 $tag_name = $row['name'];
396 /* if the user has specified to ignore this tag in phpfspot's
397 configuration, ignore it here so it does not get added to
400 if(in_array($row['name'], $this->cfg->hide_tags))
403 /* if you include the following if-clause and the user has specified
404 to only show certain tags which are specified in phpfspot's
405 configuration, ignore all others so they will not be added to the
407 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags) &&
408 !in_array($row['name'], $this->cfg->show_tags))
412 $this->tags[$tag_id] = $tag_name;
413 $this->avail_tags[$count] = $tag_id;
421 * extract all photo details
423 * retrieve all available details from f-spot's
424 * database and return them as object
425 * @param integer $idx
426 * @return object|null
428 public function get_photo_details($idx)
430 if($this->dbver < 9) {
432 SELECT p.id, p.name, p.time, p.directory_path, p.description
437 /* till F-Spot version 0.4.1 */
438 if($this->dbver < 11) {
440 SELECT p.id, p.uri, p.time, p.description
446 SELECT p.id, p.uri, p.time, p.description, p.rating
452 /* if show_tags is set, only return details for photos which
453 are specified to be shown
455 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
457 INNER JOIN photo_tags pt
461 WHERE p.id='". $idx ."'
462 AND t.name IN ('".implode("','",$this->cfg->show_tags)."')";
466 WHERE p.id='". $idx ."'
470 if($result = $this->db->db_query($query_str)) {
472 $row = $this->db->db_fetch_object($result);
474 if($this->dbver < 9) {
475 $row['uri'] = "file://". $row['directory_path'] ."/". $row['name'];
484 } // get_photo_details
487 * returns aligned photo names
489 * this function returns aligned (length) names for
490 * an specific photo. If the length of the name exceeds
491 * $limit the name will be shrinked (...)
492 * @param integer $idx
493 * @param integer $limit
494 * @return string|null
496 public function getPhotoName($idx, $limit = 0)
498 if($details = $this->get_photo_details($idx)) {
499 if($long_name = $this->parse_uri($details['uri'], 'filename')) {
500 $name = $this->shrink_text($long_name, $limit);
510 * shrink text according provided limit
512 * If the length of the name exceeds $limit the
513 * text will be shortend and some content in between
514 * will be replaced with "..."
516 * @param integer $limit
519 private function shrink_text($text, $limit)
521 if($limit != 0 && strlen($text) > $limit) {
522 $text = substr($text, 0, $limit-5) ."...". substr($text, -($limit-5));
530 * translate f-spoth photo path
532 * as the full-qualified path recorded in the f-spot database
533 * is usally not the same as on the webserver, this function
534 * will replace the path with that one specified in the cfg
535 * @param string $path
538 public function translate_path($path)
540 return str_replace($this->cfg->path_replace_from, $this->cfg->path_replace_to, $path);
545 * control HTML ouput for a single photo
547 * this function provides all the necessary information
548 * for the single photo template.
549 * @param integer photo
551 public function showPhoto($photo)
553 /* get all photos from the current photo selection */
554 $all_photos = $this->getPhotoSelection();
555 $count = count($all_photos);
557 for($i = 0; $i < $count; $i++) {
559 // $get_next will be set, when the photo which has to
560 // be displayed has been found - this means that the
561 // next available is in fact the NEXT image (for the
563 if(isset($get_next)) {
564 $next_img = $all_photos[$i];
568 /* the next photo is our NEXT photo */
569 if($all_photos[$i] == $photo) {
573 $previous_img = $all_photos[$i];
576 if($photo == $all_photos[$i]) {
581 $details = $this->get_photo_details($photo);
588 $orig_path = $this->translate_path($this->parse_uri($details['uri'], 'fullpath'));
589 $thumb_path = $this->get_thumb_path($this->cfg->photo_width, $photo);
591 if(!file_exists($orig_path)) {
592 $this->_error("Photo ". $orig_path ." does not exist!<br />\n");
596 if(!is_readable($orig_path)) {
597 $this->_error("Photo ". $orig_path ." is not readable for user ". $this->getuid() ."<br />\n");
601 /* If the thumbnail doesn't exist yet, try to create it */
602 if(!file_exists($thumb_path)) {
603 $this->gen_thumb($photo, true);
604 $thumb_path = $this->get_thumb_path($this->cfg->photo_width, $photo);
607 /* get mime-type, height and width from the original photo */
608 $info = getimagesize($orig_path);
610 /* get EXIF information if JPEG */
611 if($info['mime'] == "image/jpeg") {
612 $meta = $this->get_meta_informations($orig_path);
615 /* If EXIF data are available, use them */
616 if(isset($meta['ExifImageWidth'])) {
617 $meta_res = $meta['ExifImageWidth'] ."x". $meta['ExifImageLength'];
619 $meta_res = $info[0] ."x". $info[1];
622 $meta_date = isset($meta['FileDateTime']) ? strftime("%a %x %X", $meta['FileDateTime']) : "n/a";
623 $meta_make = isset($meta['Make']) ? $meta['Make'] ." / ". $meta['Model'] : "n/a";
624 $meta_size = isset($meta['FileSize']) ? round($meta['FileSize']/1024, 1) ."kbyte" : "n/a";
626 $extern_link = "index.php?mode=showp&id=". $photo;
627 $current_tags = $this->getCurrentTags();
628 if($current_tags != "") {
629 $extern_link.= "&tags=". $current_tags;
631 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
632 $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
635 $this->tmpl->assign('extern_link', $extern_link);
637 if(!file_exists($thumb_path)) {
638 $this->_error("Can't open file ". $thumb_path ."\n");
642 $info_thumb = getimagesize($thumb_path);
644 $this->tmpl->assign('description', $details['description']);
645 $this->tmpl->assign('image_name', $this->parse_uri($details['uri'], 'filename'));
647 $this->tmpl->assign('width', $info_thumb[0]);
648 $this->tmpl->assign('height', $info_thumb[1]);
649 $this->tmpl->assign('ExifMadeOn', $meta_date);
650 $this->tmpl->assign('ExifMadeWith', $meta_make);
651 $this->tmpl->assign('ExifOrigResolution', $meta_res);
652 $this->tmpl->assign('ExifFileSize', $meta_size);
654 if($this->is_user_friendly_url()) {
655 $this->tmpl->assign('image_url', '/photo/'. $photo ."/". $this->cfg->photo_width);
656 $this->tmpl->assign('image_url_full', '/photo/'. $photo);
659 $this->tmpl->assign('image_url', 'phpfspot_img.php?idx='. $photo ."&width=". $this->cfg->photo_width);
660 $this->tmpl->assign('image_url_full', 'phpfspot_img.php?idx='. $photo);
663 $this->tmpl->assign('image_filename', $this->parse_uri($details['uri'], 'filename'));
665 $this->tmpl->assign('tags', $this->get_photo_tags($photo));
666 $this->tmpl->assign('current_page', $this->getCurrentPage($current, $count));
667 $this->tmpl->assign('current_img', $photo);
670 $this->tmpl->assign('previous_url', "javascript:showPhoto(". $previous_img .");");
671 $this->tmpl->assign('prev_img', $previous_img);
675 $this->tmpl->assign('next_url', "javascript:showPhoto(". $next_img .");");
676 $this->tmpl->assign('next_img', $next_img);
678 $this->tmpl->assign('mini_width', $this->cfg->mini_width);
679 $this->tmpl->assign('photo_width', $this->cfg->photo_width);
680 $this->tmpl->assign('photo_number', $i);
681 $this->tmpl->assign('photo_count', count($all_photos));
683 return $this->tmpl->fetch("single_photo.tpl");
688 * all available tags and tag cloud
690 * this function outputs all available tags (time ordered)
691 * and in addition output them as tag cloud (tags which have
692 * many photos will appears more then others)
694 public function getAvailableTags()
696 /* retrive tags from database */
701 $result = $this->db->db_query("
702 SELECT tag_id as id, count(tag_id) as quantity
712 while($row = $this->db->db_fetch_object($result)) {
713 $tags[$row['id']] = $row['quantity'];
716 // change these font sizes if you will
717 $max_size = 125; // max font size in %
718 $min_size = 75; // min font size in %
721 $max_sat = hexdec('cc');
722 $min_sat = hexdec('44');
724 // get the largest and smallest array values
725 $max_qty = max(array_values($tags));
726 $min_qty = min(array_values($tags));
728 // find the range of values
729 $spread = $max_qty - $min_qty;
730 if (0 == $spread) { // we don't want to divide by zero
734 // determine the font-size increment
735 // this is the increase per tag quantity (times used)
736 $step = ($max_size - $min_size)/($spread);
737 $step_sat = ($max_sat - $min_sat)/($spread);
739 // loop through our tag array
740 foreach ($tags as $key => $value) {
742 if(isset($_SESSION['selected_tags']) && in_array($key, $_SESSION['selected_tags']))
745 // calculate CSS font-size
746 // find the $value in excess of $min_qty
747 // multiply by the font-size increment ($size)
748 // and add the $min_size set above
749 $size = $min_size + (($value - $min_qty) * $step);
750 // uncomment if you want sizes in whole %:
753 $color = $min_sat + ($value - $min_qty) * $step_sat;
759 if(isset($this->tags[$key])) {
760 if($this->is_user_friendly_url())
761 $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>, ";
763 $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>, ";
767 $output = substr($output, 0, strlen($output)-2);
770 } // getAvailableTags()
773 * output all selected tags
775 * this function output all tags which have been selected
776 * by the user. the selected tags are stored in the
777 * session-variable $_SESSION['selected_tags']
780 public function getSelectedTags($type = 'link')
782 /* retrive tags from database */
787 foreach($this->avail_tags as $tag)
789 // return all selected tags
790 if(isset($_SESSION['selected_tags']) && in_array($tag, $_SESSION['selected_tags'])) {
795 $output.= "<a href=\"javascript:Tags('del', ". $tag .");\" class=\"tag\">". $this->tags[$tag] ."</a>, ";
799 <div class=\"tagresulttag\">
800 <a href=\"javascript:Tags('del', ". $tag .");\" title=\"". $this->tags[$tag] ."\">
801 <img src=\"". $this->cfg->web_path ."/phpfspot_img.php?tagidx=". $tag ."\" />
811 $output = substr($output, 0, strlen($output)-2);
815 return "no tags selected";
818 } // getSelectedTags()
821 * add tag to users session variable
823 * this function will add the specified to users current
824 * tag selection. if a date search has been made before
825 * it will be now cleared
828 public function addTag($tag)
830 if(!isset($_SESSION['selected_tags']))
831 $_SESSION['selected_tags'] = Array();
833 if(isset($_SESSION['searchfor_tag']))
834 unset($_SESSION['searchfor_tag']);
836 // has the user requested to hide this tag, and still someone,
837 // somehow tries to add it, don't allow this.
838 if(!isset($this->cfg->hide_tags) &&
839 in_array($this->get_tag_name($tag), $this->cfg->hide_tags))
842 if(!in_array($tag, $_SESSION['selected_tags']))
843 array_push($_SESSION['selected_tags'], $tag);
850 * remove tag to users session variable
852 * this function removes the specified tag from
853 * users current tag selection
857 public function delTag($tag)
859 if(isset($_SESSION['searchfor_tag']))
860 unset($_SESSION['searchfor_tag']);
862 if(isset($_SESSION['selected_tags'])) {
863 $key = array_search($tag, $_SESSION['selected_tags']);
864 unset($_SESSION['selected_tags'][$key]);
865 sort($_SESSION['selected_tags']);
873 * reset tag selection
875 * if there is any tag selection, it will be
878 public function resetTags()
880 if(isset($_SESSION['selected_tags']))
881 unset($_SESSION['selected_tags']);
886 * returns the value for the autocomplete tag-search
889 public function get_xml_tag_list()
891 if(!isset($_GET['search']) || !is_string($_GET['search']))
892 $_GET['search'] = '';
897 /* retrive tags from database */
900 $matched_tags = Array();
902 header("Content-Type: text/xml");
904 $string = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n";
905 $string.= "<results>\n";
907 foreach($this->avail_tags as $tag)
909 if(!empty($_GET['search']) &&
910 preg_match("/". $_GET['search'] ."/i", $this->tags[$tag]) &&
911 count($matched_tags) < $length) {
913 $count = $this->get_num_photos($tag);
916 $string.= " <rs id=\"". $i ."\" info=\"". $count ." photo\">". $this->tags[$tag] ."</rs>\n";
919 $string.= " <rs id=\"". $i ."\" info=\"". $count ." photos\">". $this->tags[$tag] ."</rs>\n";
925 /* if we have collected enough items, break out */
926 if(count($matched_tags) >= $length)
930 $string.= "</results>\n";
934 } // get_xml_tag_list()
940 * if a specific photo was requested (external link)
941 * unset the session variable now
943 public function resetPhotoView()
945 if(isset($_SESSION['current_photo']))
946 unset($_SESSION['current_photo']);
948 } // resetPhotoView();
953 * if any tag search has taken place, reset it now
955 public function resetTagSearch()
957 if(isset($_SESSION['searchfor_tag']))
958 unset($_SESSION['searchfor_tag']);
960 } // resetTagSearch()
965 * if any name search has taken place, reset it now
967 public function resetNameSearch()
969 if(isset($_SESSION['searchfor_name']))
970 unset($_SESSION['searchfor_name']);
972 } // resetNameSearch()
977 * if any date search has taken place, reset
980 public function resetDateSearch()
982 if(isset($_SESSION['from_date']))
983 unset($_SESSION['from_date']);
984 if(isset($_SESSION['to_date']))
985 unset($_SESSION['to_date']);
987 } // resetDateSearch();
990 * return all photo according selection
992 * this function returns all photos based on
993 * the tag-selection, tag- or date-search.
994 * the tag-search also has to take care of AND
995 * and OR conjunctions
998 public function getPhotoSelection()
1000 $matched_photos = Array();
1001 $additional_where_cond = "";
1003 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1004 $from_date = $_SESSION['from_date'];
1005 $to_date = $_SESSION['to_date'];
1006 $additional_where_cond.= "
1007 p.time>='". $from_date ."'
1009 p.time<='". $to_date ."'
1013 if(isset($_SESSION['searchfor_name'])) {
1014 if($this->dbver < 9) {
1015 $additional_where_cond.= "
1017 p.name LIKE '%". $_SESSION['searchfor_name'] ."%'
1019 p.description LIKE '%". $_SESSION['searchfor_name'] ."%'
1024 $additional_where_cond.= "
1026 basename(p.uri) LIKE '%". $_SESSION['searchfor_name'] ."%'
1028 p.description LIKE '%". $_SESSION['searchfor_name'] ."%'
1034 if(isset($_SESSION['sort_order'])) {
1035 $order_str = $this->get_sort_order();
1038 /* return a search result */
1039 if(isset($_SESSION['searchfor_tag']) && $_SESSION['searchfor_tag'] != '') {
1041 SELECT DISTINCT pt1.photo_id
1043 INNER JOIN photo_tags pt2
1044 ON pt1.photo_id=pt2.photo_id
1048 ON pt1.photo_id=p.id
1051 WHERE t.name LIKE '%". $_SESSION['searchfor_tag'] ."%' ";
1053 if(isset($additional_where_cond) && !empty($additional_where_cond))
1054 $query_str.= "AND ". $additional_where_cond ." ";
1056 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1057 $query_str.= "AND t2.name IN ('".implode("','",$this->cfg->show_tags)."')";
1060 if(isset($order_str))
1061 $query_str.= $order_str;
1063 $result = $this->db->db_query($query_str);
1064 while($row = $this->db->db_fetch_object($result)) {
1065 array_push($matched_photos, $row['photo_id']);
1067 return $matched_photos;
1070 /* return according the selected tags */
1071 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
1073 foreach($_SESSION['selected_tags'] as $tag)
1074 $selected.= $tag .",";
1075 $selected = substr($selected, 0, strlen($selected)-1);
1077 /* photo has to match at least on of the selected tags */
1078 if($_SESSION['tag_condition'] == 'or') {
1080 SELECT DISTINCT pt1.photo_id
1082 INNER JOIN photo_tags pt2
1083 ON pt1.photo_id=pt2.photo_id
1087 ON pt1.photo_id=p.id
1088 WHERE pt1.tag_id IN (". $selected .")
1090 if(isset($additional_where_cond) && !empty($additional_where_cond))
1091 $query_str.= "AND ". $additional_where_cond ." ";
1093 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1094 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags)."')";
1097 if(isset($order_str))
1098 $query_str.= $order_str;
1100 /* photo has to match all selected tags */
1101 elseif($_SESSION['tag_condition'] == 'and') {
1103 if(count($_SESSION['selected_tags']) >= 32) {
1104 print "A SQLite limit of 32 tables within a JOIN SELECT avoids to<br />\n";
1105 print "evaluate your tag selection. Please remove some tags from your selection.\n";
1109 /* Join together a table looking like
1111 pt1.photo_id pt1.tag_id pt2.photo_id pt2.tag_id ...
1113 so the query can quickly return all images matching the
1114 selected tags in an AND condition
1119 SELECT DISTINCT pt1.photo_id
1123 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1130 for($i = 0; $i < count($_SESSION['selected_tags']); $i++) {
1132 INNER JOIN photo_tags pt". ($i+2) ."
1133 ON pt1.photo_id=pt". ($i+2) .".photo_id
1138 ON pt1.photo_id=p.id
1140 $query_str.= "WHERE pt2.tag_id=". $_SESSION['selected_tags'][0]." ";
1141 for($i = 1; $i < count($_SESSION['selected_tags']); $i++) {
1143 AND pt". ($i+2) .".tag_id=". $_SESSION['selected_tags'][$i] ."
1146 if(isset($additional_where_cond) && !empty($additional_where_cond))
1147 $query_str.= "AND ". $additional_where_cond;
1149 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1150 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags). "')";
1153 if(isset($order_str))
1154 $query_str.= $order_str;
1158 $result = $this->db->db_query($query_str);
1159 while($row = $this->db->db_fetch_object($result)) {
1160 array_push($matched_photos, $row['photo_id']);
1162 return $matched_photos;
1165 /* return all available photos */
1167 SELECT DISTINCT p.id
1169 LEFT JOIN photo_tags pt
1175 if(isset($additional_where_cond) && !empty($additional_where_cond))
1176 $query_str.= "WHERE ". $additional_where_cond ." ";
1178 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1179 if(isset($additional_where_cond) && !empty($additional_where_cond))
1180 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags). "')";
1182 $query_str.= "WHERE t.name IN ('".implode("','",$this->cfg->show_tags). "')";
1185 if(isset($order_str))
1186 $query_str.= $order_str;
1188 $result = $this->db->db_query($query_str);
1189 while($row = $this->db->db_fetch_object($result)) {
1190 array_push($matched_photos, $row['id']);
1192 return $matched_photos;
1194 } // getPhotoSelection()
1197 * control HTML ouput for photo index
1199 * this function provides all the necessary information
1200 * for the photo index template.
1203 public function showPhotoIndex()
1205 $photos = $this->getPhotoSelection();
1207 $count = count($photos);
1209 /* if all thumbnails should be shown on one page */
1210 if(!isset($this->cfg->thumbs_per_page) || $this->cfg->thumbs_per_page == 0) {
1214 /* thumbnails should be splitted up in several pages */
1215 elseif($this->cfg->thumbs_per_page > 0) {
1217 if(!isset($_SESSION['begin_with']) || $_SESSION['begin_with'] == 0) {
1221 $begin_with = $_SESSION['begin_with'];
1224 $end_with = $begin_with + $this->cfg->thumbs_per_page;
1228 $images[$thumbs] = Array();
1229 $img_height[$thumbs] = Array();
1230 $img_width[$thumbs] = Array();
1231 $img_id[$thumbs] = Array();
1232 $img_name[$thumbs] = Array();
1233 $img_fullname[$thumbs] = Array();
1234 $img_title = Array();
1236 for($i = $begin_with; $i < $end_with; $i++) {
1238 if(isset($photos[$i])) {
1240 $images[$thumbs] = $photos[$i];
1241 $img_id[$thumbs] = $i;
1242 $img_name[$thumbs] = htmlspecialchars($this->getPhotoName($photos[$i], 15));
1243 $img_fullname[$thumbs] = htmlspecialchars($this->getPhotoName($photos[$i], 0));
1244 $img_title[$thumbs] = "Click to view photo ". htmlspecialchars($this->getPhotoName($photos[$i], 0));
1246 $thumb_path = $this->get_thumb_path($this->cfg->thumb_width, $photos[$i]);
1248 if(file_exists($thumb_path)) {
1249 $info = getimagesize($thumb_path);
1250 $img_width[$thumbs] = $info[0];
1251 $img_height[$thumbs] = $info[1];
1257 // +1 for for smarty's selection iteration
1260 if(isset($_SESSION['searchfor_tag']) && $_SESSION['searchfor_tag'] != '')
1261 $this->tmpl->assign('searchfor_tag', $_SESSION['searchfor_tag']);
1263 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1264 $this->tmpl->assign('from_date', $this->ts2str($_SESSION['from_date']));
1265 $this->tmpl->assign('to_date', $this->ts2str($_SESSION['to_date']));
1268 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
1269 $this->tmpl->assign('tag_result', 1);
1272 /* do we have to display the page selector ? */
1273 if($this->cfg->thumbs_per_page != 0) {
1277 /* calculate the page switchers */
1278 $previous_start = $begin_with - $this->cfg->thumbs_per_page;
1279 $next_start = $begin_with + $this->cfg->thumbs_per_page;
1281 if($begin_with != 0)
1282 $this->tmpl->assign("previous_url", "javascript:showPhotoIndex(". $previous_start .");");
1283 if($end_with < $count)
1284 $this->tmpl->assign("next_url", "javascript:showPhotoIndex(". $next_start .");");
1286 $photo_per_page = $this->cfg->thumbs_per_page;
1287 $last_page = ceil($count / $photo_per_page);
1289 /* get the current selected page */
1290 if($begin_with == 0) {
1294 for($i = $begin_with; $i >= 0; $i-=$photo_per_page) {
1301 for($i = 1; $i <= $last_page; $i++) {
1303 if($current_page == $i)
1304 $style = "style=\"font-size: 125%; text-decoration: underline;\"";
1305 elseif($current_page-1 == $i || $current_page+1 == $i)
1306 $style = "style=\"font-size: 105%;\"";
1307 elseif(($current_page-5 >= $i) && ($i != 1) ||
1308 ($current_page+5 <= $i) && ($i != $last_page))
1309 $style = "style=\"font-size: 75%;\"";
1313 $start_with = ($i*$photo_per_page)-$photo_per_page;
1315 if($this->is_user_friendly_url()) {
1316 $select = "<a href=\"". $this->cfg->web_path ."/tag/205/". $start_with ."\"";
1319 $select = "<a href=\"". $this->cfg->web_path ."/index.php?mode=showpi tags=". $current_tags ." begin_with=". $begin_with ."\"";
1321 $select.= " onclick=\"showPhotoIndex(". $start_with ."); return false;\"";
1325 $select.= ">". $i ."</a> ";
1327 // until 9 pages we show the selector from 1-9
1328 if($last_page <= 9) {
1329 $page_select.= $select;
1332 if($i == 1 /* first page */ ||
1333 $i == $last_page /* last page */ ||
1334 $i == $current_page /* current page */ ||
1335 $i == ceil($last_page * 0.25) /* first quater */ ||
1336 $i == ceil($last_page * 0.5) /* half */ ||
1337 $i == ceil($last_page * 0.75) /* third quater */ ||
1338 (in_array($i, array(1,2,3,4,5,6)) && $current_page <= 4) /* the first 6 */ ||
1339 (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 */ ||
1340 $i == $current_page-3 || $i == $current_page-2 || $i == $current_page-1 /* three before */ ||
1341 $i == $current_page+3 || $i == $current_page+2 || $i == $current_page+1 /* three after */) {
1343 $page_select.= $select;
1351 $page_select.= "......... ";
1356 /* only show the page selector if we have more then one page */
1358 $this->tmpl->assign('page_selector', $page_select);
1361 $current_tags = $this->getCurrentTags();
1362 $extern_link = "index.php?mode=showpi";
1363 $rss_link = "index.php?mode=rss";
1364 if($current_tags != "") {
1365 $extern_link.= "&tags=". $current_tags;
1366 $rss_link.= "&tags=". $current_tags;
1368 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1369 $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
1370 $rss_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
1373 $export_link = "index.php?mode=export";
1374 $slideshow_link = "index.php?mode=slideshow";
1376 $this->tmpl->assign('extern_link', $extern_link);
1377 $this->tmpl->assign('slideshow_link', $slideshow_link);
1378 $this->tmpl->assign('export_link', $export_link);
1379 $this->tmpl->assign('rss_link', $rss_link);
1380 $this->tmpl->assign('count', $count);
1381 $this->tmpl->assign('width', $this->cfg->thumb_width);
1382 $this->tmpl->assign('preview_width', $this->cfg->photo_width);
1383 $this->tmpl->assign('thumb_container_width', $this->cfg->thumb_width);
1384 $this->tmpl->assign('thumb_container_height', $this->cfg->thumb_height+20);
1385 $this->tmpl->assign('images', $images);
1386 $this->tmpl->assign('img_width', $img_width);
1387 $this->tmpl->assign('img_height', $img_height);
1388 $this->tmpl->assign('img_id', $img_id);
1389 $this->tmpl->assign('img_name', $img_name);
1390 $this->tmpl->assign('img_fullname', $img_fullname);
1391 $this->tmpl->assign('img_title', $img_title);
1392 $this->tmpl->assign('thumbs', $thumbs);
1393 $this->tmpl->assign('selected_tags', $this->getSelectedTags('img'));
1395 $result = $this->tmpl->fetch("photo_index.tpl");
1397 /* if we are returning to photo index from an photo-view,
1398 scroll the window to the last shown photo-thumbnail.
1399 after this, unset the last_photo session variable.
1401 if(isset($_SESSION['last_photo'])) {
1402 $result.= "<script language=\"JavaScript\">moveToThumb(". $_SESSION['last_photo'] .");</script>\n";
1403 unset($_SESSION['last_photo']);
1408 } // showPhotoIndex()
1411 * show credit template
1413 public function showCredits()
1415 $this->tmpl->assign('version', $this->cfg->version);
1416 $this->tmpl->assign('product', $this->cfg->product);
1417 $this->tmpl->assign('db_version', $this->dbver);
1418 $this->tmpl->show("credits.tpl");
1423 * create thumbnails for the requested width
1425 * this function creates image thumbnails of $orig_image
1426 * stored as $thumb_image. It will check if the image is
1427 * in a supported format, if necessary rotate the image
1428 * (based on EXIF orientation meta headers) and re-sizing.
1429 * @param string $orig_image
1430 * @param string $thumb_image
1431 * @param integer $width
1434 public function create_thumbnail($orig_image, $thumb_image, $width)
1436 if(!file_exists($orig_image)) {
1440 $mime = $this->get_mime_info($orig_image);
1442 /* check if original photo is a support image type */
1443 if(!$this->checkifImageSupported($mime))
1450 $meta = $this->get_meta_informations($orig_image);
1456 switch($meta['Orientation']) {
1457 case 1: /* top, left */
1458 /* nothing to do */ break;
1459 case 2: /* top, right */
1460 $rotate = 0; $flip_hori = true; break;
1461 case 3: /* bottom, left */
1462 $rotate = 180; break;
1463 case 4: /* bottom, right */
1464 $flip_vert = true; break;
1465 case 5: /* left side, top */
1466 $rotate = 90; $flip_vert = true; break;
1467 case 6: /* right side, top */
1468 $rotate = 90; break;
1469 case 7: /* left side, bottom */
1470 $rotate = 270; $flip_vert = true; break;
1471 case 8: /* right side, bottom */
1472 $rotate = 270; break;
1475 $src_img = @imagecreatefromjpeg($orig_image);
1481 $src_img = @imagecreatefrompng($orig_image);
1485 case 'image/x-portable-pixmap':
1487 $src_img = new Imagick($orig_image);
1488 $handler = "imagick";
1493 if(!isset($src_img) || empty($src_img)) {
1494 print "Can't load image from ". $orig_image ."\n";
1502 /* grabs the height and width */
1503 $cur_width = imagesx($src_img);
1504 $cur_height = imagesy($src_img);
1506 // If requested width is more then the actual image width,
1507 // do not generate a thumbnail, instead safe the original
1508 // as thumbnail but with lower quality. But if the image
1509 // is to heigh too, then we still have to resize it.
1510 if($width >= $cur_width && $cur_height < $this->cfg->thumb_height) {
1511 $result = imagejpeg($src_img, $thumb_image, 75);
1512 imagedestroy($src_img);
1519 $cur_width = $src_img->getImageWidth();
1520 $cur_height = $src_img->getImageHeight();
1522 // If requested width is more then the actual image width,
1523 // do not generate a thumbnail, instead safe the original
1524 // as thumbnail but with lower quality. But if the image
1525 // is to heigh too, then we still have to resize it.
1526 if($width >= $cur_width && $cur_height < $this->cfg->thumb_height) {
1527 $src_img->setCompressionQuality(75);
1528 $src_img->setImageFormat('jpeg');
1529 $src_img->writeImage($thumb_image);
1531 $src_img->destroy();
1538 // If the image will be rotate because EXIF orientation said so
1539 // 'virtually rotate' the image for further calculations
1540 if($rotate == 90 || $rotate == 270) {
1542 $cur_width = $cur_height;
1546 /* calculates aspect ratio */
1547 $aspect_ratio = $cur_height / $cur_width;
1550 if($aspect_ratio < 1) {
1552 $new_h = abs($new_w * $aspect_ratio);
1554 /* 'virtually' rotate the image and calculate it's ratio */
1555 $tmp_w = $cur_height;
1556 $tmp_h = $cur_width;
1557 /* now get the ratio from the 'rotated' image */
1558 $tmp_ratio = $tmp_h/$tmp_w;
1559 /* now calculate the new dimensions */
1561 $tmp_h = abs($tmp_w * $tmp_ratio);
1563 // now that we know, how high they photo should be, if it
1564 // gets rotated, use this high to scale the image
1566 $new_w = abs($new_h / $aspect_ratio);
1568 // If the image will be rotate because EXIF orientation said so
1569 // now 'virtually rotate' back the image for the image manipulation
1570 if($rotate == 90 || $rotate == 270) {
1581 /* creates new image of that size */
1582 $dst_img = imagecreatetruecolor($new_w, $new_h);
1584 imagefill($dst_img, 0, 0, ImageColorAllocate($dst_img, 255, 255, 255));
1586 /* copies resized portion of original image into new image */
1587 imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $new_w, $new_h, imagesx($src_img), imagesy($src_img));
1589 /* needs the image to be flipped horizontal? */
1591 $this->_debug("(FLIP)");
1592 $dst_img = $this->flipImage($dst_img, 'hori');
1594 /* needs the image to be flipped vertical? */
1596 $this->_debug("(FLIP)");
1597 $dst_img = $this->flipImage($dst_img, 'vert');
1601 $this->_debug("(ROTATE)");
1602 $dst_img = $this->rotateImage($dst_img, $rotate);
1605 /* write down new generated file */
1606 $result = imagejpeg($dst_img, $thumb_image, 75);
1608 /* free your mind */
1609 imagedestroy($dst_img);
1610 imagedestroy($src_img);
1612 if($result === false) {
1613 print "Can't write thumbnail ". $thumb_image ."\n";
1623 $src_img->resizeImage($new_w, $new_h, Imagick::FILTER_LANCZOS, 1);
1625 /* needs the image to be flipped horizontal? */
1627 $this->_debug("(FLIP)");
1628 $src_img->rotateImage(new ImagickPixel(), 90);
1629 $src_img->flipImage();
1630 $src_img->rotateImage(new ImagickPixel(), -90);
1632 /* needs the image to be flipped vertical? */
1634 $this->_debug("(FLIP)");
1635 $src_img->flipImage();
1639 $this->_debug("(ROTATE)");
1640 $src_img->rotateImage(new ImagickPixel(), $rotate);
1643 $src_img->setCompressionQuality(75);
1644 $src_img->setImageFormat('jpeg');
1646 if(!$src_img->writeImage($thumb_image)) {
1647 print "Can't write thumbnail ". $thumb_image ."\n";
1652 $src_img->destroy();
1659 } // create_thumbnail()
1662 * return all exif meta data from the file
1663 * @param string $file
1666 public function get_meta_informations($file)
1668 return exif_read_data($file);
1670 } // get_meta_informations()
1673 * create phpfspot own sqlite database
1675 * this function creates phpfspots own sqlite database
1676 * if it does not exist yet. this own is used to store
1677 * some necessary informations (md5 sum's, ...).
1679 public function check_config_table()
1681 // if the config table doesn't exist yet, create it
1682 if(!$this->cfg_db->db_check_table_exists("images")) {
1683 $this->cfg_db->db_exec("
1684 CREATE TABLE images (
1685 img_idx int primary key,
1691 } // check_config_table
1694 * Generates a thumbnail from photo idx
1696 * This function will generate JPEG thumbnails from provided F-Spot photo
1699 * 1. Check if all thumbnail generations (width) are already in place and
1701 * 2. Check if the md5sum of the original file has changed
1702 * 3. Generate the thumbnails if needed
1703 * @param integer $idx
1704 * @param integer $force
1705 * @param boolean $overwrite
1707 public function gen_thumb($idx = 0, $force = 0, $overwrite = false)
1711 $resolutions = Array(
1712 $this->cfg->thumb_width,
1713 $this->cfg->photo_width,
1714 $this->cfg->mini_width,
1718 /* get details from F-Spot's database */
1719 $details = $this->get_photo_details($idx);
1721 /* calculate file MD5 sum */
1722 $full_path = $this->translate_path($this->parse_uri($details['uri'], 'fullpath'));
1724 if(!file_exists($full_path)) {
1725 $this->_error("File ". $full_path ." does not exist\n");
1729 if(!is_readable($full_path)) {
1730 $this->_error("File ". $full_path ." is not readable for ". $this->getuid() ."\n");
1734 $this->_debug("Image [". $idx ."] ". $this->shrink_text($this->parse_uri($details['uri'], 'filename'), 20) ." Thumbnails:");
1736 /* If Nikon NEF format, we need to treat it another way */
1737 if(isset($this->cfg->dcraw_bin) &&
1738 file_exists($this->cfg->dcraw_bin) &&
1739 is_executable($this->cfg->dcraw_bin) &&
1740 preg_match('/\.nef$/i', $details['uri'])) {
1742 $ppm_path = preg_replace('/\.nef$/i', '.ppm', $full_path);
1744 /* if PPM file does not exist, let dcraw convert it from NEF */
1745 if(!file_exists($ppm_path)) {
1746 system($this->cfg->dcraw_bin ." -a ". $full_path);
1749 /* for now we handle the PPM instead of the NEF */
1750 $full_path = $ppm_path;
1754 $file_md5 = md5_file($full_path);
1757 foreach($resolutions as $resolution) {
1759 $generate_it = false;
1761 $thumb_sub_path = substr($file_md5, 0, 2);
1762 $thumb_path = $this->cfg->thumb_path ."/". $thumb_sub_path ."/". $resolution ."_". $file_md5;
1764 /* if thumbnail-subdirectory does not exist yet, create it */
1765 if(!file_exists(dirname($thumb_path))) {
1766 mkdir(dirname($thumb_path), 0755);
1769 /* if the thumbnail file doesn't exist, create it */
1770 if(!file_exists($thumb_path)) {
1771 $generate_it = true;
1773 /* if the file hasn't changed there is no need to regen the thumb */
1774 elseif($file_md5 != $this->getMD5($idx) || $force) {
1775 $generate_it = true;
1778 if($generate_it || $overwrite) {
1780 $this->_debug(" ". $resolution ."px");
1781 if(!$this->create_thumbnail($full_path, $thumb_path, $resolution))
1789 $this->_debug(" already exist");
1792 /* set the new/changed MD5 sum for the current photo */
1794 $this->setMD5($idx, $file_md5);
1797 $this->_debug("\n");
1802 * returns stored md5 sum for a specific photo
1804 * this function queries the phpfspot database for a
1805 * stored MD5 checksum of the specified photo
1806 * @param integer $idx
1807 * @return string|null
1809 public function getMD5($idx)
1811 $result = $this->cfg_db->db_query("
1814 WHERE img_idx='". $idx ."'
1820 $img = $this->cfg_db->db_fetch_object($result);
1821 return $img['img_md5'];
1826 * set MD5 sum for the specific photo
1827 * @param integer $idx
1828 * @param string $md5
1830 private function setMD5($idx, $md5)
1832 $result = $this->cfg_db->db_exec("
1833 REPLACE INTO images (img_idx, img_md5)
1834 VALUES ('". $idx ."', '". $md5 ."')
1840 * store current tag condition
1842 * this function stores the current tag condition
1843 * (AND or OR) in the users session variables
1844 * @param string $mode
1847 public function setTagCondition($mode)
1849 $_SESSION['tag_condition'] = $mode;
1853 } // setTagCondition()
1856 * invoke tag & date search
1858 * this function will return all matching tags and store
1859 * them in the session variable selected_tags. furthermore
1860 * it also handles the date search.
1861 * getPhotoSelection() will then only return the matching
1865 public function startSearch()
1867 if(isset($_POST['from']) && $this->isValidDate($_POST['from'])) {
1868 $from = $_POST['from'];
1870 if(isset($_POST['to']) && $this->isValidDate($_POST['to'])) {
1874 if(isset($_POST['for_tag']) && is_string($_POST['for_tag'])) {
1875 $searchfor_tag = $_POST['for_tag'];
1876 $_SESSION['searchfor_tag'] = $_POST['for_tag'];
1879 if(isset($_POST['for_name']) && is_string($_POST['for_name'])) {
1880 $searchfor_name = $_POST['for_name'];
1881 $_SESSION['searchfor_name'] = $_POST['for_name'];
1886 if(isset($from) && !empty($from))
1887 $_SESSION['from_date'] = strtotime($from ." 00:00:00");
1889 unset($_SESSION['from_date']);
1891 if(isset($to) && !empty($to))
1892 $_SESSION['to_date'] = strtotime($to ." 23:59:59");
1894 unset($_SESSION['to_date']);
1896 if(isset($searchfor_tag) && !empty($searchfor_tag)) {
1897 /* new search, reset the current selected tags */
1898 $_SESSION['selected_tags'] = Array();
1899 foreach($this->avail_tags as $tag) {
1900 if(preg_match('/'. $searchfor_tag .'/i', $this->tags[$tag]))
1901 array_push($_SESSION['selected_tags'], $tag);
1910 * updates sort order in session variable
1912 * this function is invoked by RPC and will sort the requested
1913 * sort order in the session variable.
1914 * @param string $sort_order
1917 public function updateSortOrder($order)
1919 if(isset($this->sort_orders[$order])) {
1920 $_SESSION['sort_order'] = $order;
1924 return "unkown error";
1926 } // updateSortOrder()
1931 * this function rotates the image according the
1933 * @param string $img
1934 * @param integer $degress
1937 private function rotateImage($img, $degrees)
1939 if(function_exists("imagerotate")) {
1940 $img = imagerotate($img, $degrees, 0);
1942 function imagerotate($src_img, $angle)
1944 $src_x = imagesx($src_img);
1945 $src_y = imagesy($src_img);
1946 if ($angle == 180) {
1950 elseif ($src_x <= $src_y) {
1954 elseif ($src_x >= $src_y) {
1959 $rotate=imagecreatetruecolor($dest_x,$dest_y);
1960 imagealphablending($rotate, false);
1965 for ($y = 0; $y < ($src_y); $y++) {
1966 for ($x = 0; $x < ($src_x); $x++) {
1967 $color = imagecolorat($src_img, $x, $y);
1968 imagesetpixel($rotate, $dest_x - $y - 1, $x, $color);
1974 for ($y = 0; $y < ($src_y); $y++) {
1975 for ($x = 0; $x < ($src_x); $x++) {
1976 $color = imagecolorat($src_img, $x, $y);
1977 imagesetpixel($rotate, $y, $dest_y - $x - 1, $color);
1983 for ($y = 0; $y < ($src_y); $y++) {
1984 for ($x = 0; $x < ($src_x); $x++) {
1985 $color = imagecolorat($src_img, $x, $y);
1986 imagesetpixel($rotate, $dest_x - $x - 1, $dest_y - $y - 1, $color);
2000 $img = imagerotate($img, $degrees);
2009 * returns flipped image
2011 * this function will return an either horizontal or
2012 * vertical flipped truecolor image.
2013 * @param string $image
2014 * @param string $mode
2017 private function flipImage($image, $mode)
2019 $w = imagesx($image);
2020 $h = imagesy($image);
2021 $flipped = imagecreatetruecolor($w, $h);
2025 for ($y = 0; $y < $h; $y++) {
2026 imagecopy($flipped, $image, 0, $y, 0, $h - $y - 1, $w, 1);
2030 for ($x = 0; $x < $w; $x++) {
2031 imagecopy($flipped, $image, $x, 0, $w - $x - 1, 0, 1, $h);
2041 * return all assigned tags for the specified photo
2042 * @param integer $idx
2045 private function get_photo_tags($idx)
2047 $result = $this->db->db_query("
2050 INNER JOIN photo_tags pt
2052 WHERE pt.photo_id='". $idx ."'
2057 while($row = $this->db->db_fetch_object($result)) {
2058 if(isset($this->cfg->hide_tags) && in_array($row['name'], $this->cfg->hide_tags))
2060 $tags[$row['id']] = $row['name'];
2065 } // get_photo_tags()
2068 * create on-the-fly images with text within
2069 * @param string $txt
2070 * @param string $color
2071 * @param integer $space
2072 * @param integer $font
2075 public function showTextImage($txt, $color=000000, $space=4, $font=4, $w=300)
2077 if (strlen($color) != 6)
2080 $int = hexdec($color);
2081 $h = imagefontheight($font);
2082 $fw = imagefontwidth($font);
2083 $txt = explode("\n", wordwrap($txt, ($w / $fw), "\n"));
2084 $lines = count($txt);
2085 $im = imagecreate($w, (($h * $lines) + ($lines * $space)));
2086 $bg = imagecolorallocate($im, 255, 255, 255);
2087 $color = imagecolorallocate($im, 0xFF & ($int >> 0x10), 0xFF & ($int >> 0x8), 0xFF & $int);
2090 foreach ($txt as $text) {
2091 $x = (($w - ($fw * strlen($text))) / 2);
2092 imagestring($im, $font, $x, $y, $text, $color);
2093 $y += ($h + $space);
2096 Header("Content-type: image/png");
2099 } // showTextImage()
2102 * check if all requirements are met
2105 private function check_requirements()
2107 if(!function_exists("imagecreatefromjpeg")) {
2108 print "PHP GD library extension is missing<br />\n";
2112 if($this->cfg->db_access == "native" && !function_exists("sqlite3_open")) {
2113 print "PHP SQLite3 library extension is missing<br />\n";
2117 /* Check for HTML_AJAX PEAR package, lent from Horde project */
2118 ini_set('track_errors', 1);
2119 @include_once 'HTML/AJAX/Server.php';
2120 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
2121 print "PEAR HTML_AJAX package is missing<br />\n";
2124 @include_once 'Calendar/Calendar.php';
2125 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
2126 print "PEAR Calendar package is missing<br />\n";
2129 @include_once 'Console/Getopt.php';
2130 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
2131 print "PEAR Console_Getopt package is missing<br />\n";
2134 @include_once $this->cfg->smarty_path .'/libs/Smarty.class.php';
2135 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
2136 print "Smarty template engine can not be found in ". $this->cfg->smarty_path ."/libs/Smarty.class.php<br />\n";
2139 ini_restore('track_errors');
2146 } // check_requirements()
2148 private function _debug($text)
2150 if($this->fromcmd) {
2157 * check if specified MIME type is supported
2158 * @param string $mime
2161 public function checkifImageSupported($mime)
2163 $supported_types = Array(
2166 "image/x-portable-pixmap",
2170 if(in_array($mime, $supported_types))
2175 } // checkifImageSupported()
2179 * @param string $text
2181 public function _error($text)
2183 switch($this->cfg->logging) {
2186 print "<img src=\"resources/green_info.png\" alt=\"warning\" />\n";
2187 print $text ."<br />\n";
2193 error_log($text, 3, $his->cfg->log_file);
2197 $this->runtime_error = true;
2202 * output calendard input fields
2203 * @param string $mode
2206 private function get_calendar($mode)
2208 $year = isset($_SESSION[$mode .'_date']) ? date("Y", $_SESSION[$mode .'_date']) : date("Y");
2209 $month = isset($_SESSION[$mode .'_date']) ? date("m", $_SESSION[$mode .'_date']) : date("m");
2210 $day = isset($_SESSION[$mode .'_date']) ? date("d", $_SESSION[$mode .'_date']) : date("d");
2212 $output = "<input type=\"text\" size=\"3\" id=\"". $mode ."year\" value=\"". $year ."\"";
2213 if(!isset($_SESSION[$mode .'_date']))
2214 $output.= " disabled=\"disabled\"";
2216 $output.= "<input type=\"text\" size=\"1\" id=\"". $mode ."month\" value=\"". $month ."\"";
2217 if(!isset($_SESSION[$mode .'_date']))
2218 $output.= " disabled=\"disabled\"";
2220 $output.= "<input type=\"text\" size=\"1\" id=\"". $mode ."day\" value=\"". $day ."\"";
2221 if(!isset($_SESSION[$mode .'_date']))
2222 $output.= " disabled=\"disabled\"";
2230 * output calendar matrix
2231 * @param integer $year
2232 * @param integer $month
2233 * @param integer $day
2235 public function get_calendar_matrix($year = 0, $month = 0, $day = 0)
2237 if (!isset($year)) $year = date('Y');
2238 if (!isset($month)) $month = date('m');
2239 if (!isset($day)) $day = date('d');
2244 require_once CALENDAR_ROOT.'Month/Weekdays.php';
2245 require_once CALENDAR_ROOT.'Day.php';
2248 $month = new Calendar_Month_Weekdays($year,$month);
2251 $prevStamp = $month->prevMonth(true);
2252 $prev = "javascript:setMonth(". date('Y',$prevStamp) .", ". date('n',$prevStamp) .", ". date('j',$prevStamp) .");";
2253 $nextStamp = $month->nextMonth(true);
2254 $next = "javascript:setMonth(". date('Y',$nextStamp) .", ". date('n',$nextStamp) .", ". date('j',$nextStamp) .");";
2256 $selectedDays = array (
2257 new Calendar_Day($year,$month,$day),
2258 new Calendar_Day($year,12,25),
2261 // Build the days in the month
2262 $month->build($selectedDays);
2264 $this->tmpl->assign('current_month', date('F Y',$month->getTimeStamp()));
2265 $this->tmpl->assign('prev_month', $prev);
2266 $this->tmpl->assign('next_month', $next);
2268 while ( $day = $month->fetch() ) {
2270 if(!isset($matrix[$rows]))
2271 $matrix[$rows] = Array();
2275 $dayStamp = $day->thisDay(true);
2276 $link = "javascript:setCalendarDate(". date('Y',$dayStamp) .", ". date('n',$dayStamp).", ". date('j',$dayStamp) .");";
2278 // isFirst() to find start of week
2279 if ( $day->isFirst() )
2282 if ( $day->isSelected() ) {
2283 $string.= "<td class=\"selected\">".$day->thisDay()."</td>\n";
2284 } else if ( $day->isEmpty() ) {
2285 $string.= "<td> </td>\n";
2287 $string.= "<td><a class=\"calendar\" href=\"".$link."\">".$day->thisDay()."</a></td>\n";
2290 // isLast() to find end of week
2291 if ( $day->isLast() )
2292 $string.= "</tr>\n";
2294 $matrix[$rows][$cols] = $string;
2304 $this->tmpl->assign('matrix', $matrix);
2305 $this->tmpl->assign('rows', $rows);
2306 $this->tmpl->show("calendar.tpl");
2308 } // get_calendar_matrix()
2311 * output export page
2312 * @param string $mode
2314 public function getExport($mode)
2316 $pictures = $this->getPhotoSelection();
2317 $current_tags = $this->getCurrentTags();
2319 foreach($pictures as $picture) {
2321 $orig_url = $this->get_phpfspot_url() ."/index.php?mode=showp&id=". $picture;
2322 if($current_tags != "") {
2323 $orig_url.= "&tags=". $current_tags;
2325 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
2326 $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
2329 if($this->is_user_friendly_url()) {
2330 $thumb_url = $this->get_phpfspot_url() ."/photo/". $picture ."/". $this->cfg->thumb_width;
2333 $thumb_url = $this->get_phpfspot_url() ."/phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
2339 // <a href="%pictureurl%"><img src="%thumbnailurl%" ></a>
2340 print htmlspecialchars("<a href=\"". $orig_url ."\"><img src=\"". $thumb_url ."\" /></a>") ."<br />\n";
2344 // "[%pictureurl% %thumbnailurl%]"
2345 print htmlspecialchars("[".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
2348 case 'MoinMoinList':
2349 // " * [%pictureurl% %thumbnailurl%]"
2350 print " " . htmlspecialchars("* [".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
2361 public function getRSSFeed()
2363 Header("Content-type: text/xml; charset=utf-8");
2364 print "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
2367 xmlns:media="http://search.yahoo.com/mrss/"
2368 xmlns:dc="http://purl.org/dc/elements/1.1/"
2371 <title>phpfspot</title>
2372 <description>phpfspot RSS feed</description>
2373 <link><?php print htmlspecialchars($this->get_phpfspot_url()); ?></link>
2374 <pubDate><?php print strftime("%a, %d %b %Y %T %z"); ?></pubDate>
2375 <generator>phpfspot</generator>
2378 $pictures = $this->getPhotoSelection();
2379 $current_tags = $this->getCurrentTags();
2381 foreach($pictures as $picture) {
2383 $orig_url = $this->get_phpfspot_url() ."/index.php?mode=showp&id=". $picture;
2384 if($current_tags != "") {
2385 $orig_url.= "&tags=". $current_tags;
2387 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
2388 $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
2391 $details = $this->get_photo_details($picture);
2393 if($this->is_user_friendly_url()) {
2394 $thumb_url = $this->get_phpfspot_url() ."/photo/". $picture ."/". $this->cfg->thumb_width;
2397 $thumb_url = $this->get_phpfspot_url() ."/phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
2400 $thumb_html = htmlspecialchars("
2401 <a href=\"". $orig_url ."\"><img src=\"". $thumb_url ."\" /></a>
2403 ". $details['description']);
2405 $orig_path = $this->translate_path($this->parse_uri($details['uri'], 'fullpath'));
2407 /* get EXIF information if JPEG */
2408 if($details['mime'] == "image/jpeg") {
2409 $meta = $this->get_meta_informations($orig_path);
2412 $meta_date = isset($meta['FileDateTime']) ? $meta['FileDateTime'] : filemtime($orig_path);
2416 <title><?php print htmlspecialchars($this->parse_uri($details['uri'], 'filename')); ?></title>
2417 <link><?php print htmlspecialchars($orig_url); ?></link>
2418 <guid><?php print htmlspecialchars($orig_url); ?></guid>
2419 <dc:date.Taken><?php print strftime("%Y-%m-%dT%H:%M:%S+00:00", $meta_date); ?></dc:date.Taken>
2421 <?php print $thumb_html; ?>
2423 <pubDate><?php print strftime("%a, %d %b %Y %T %z", $meta_date); ?></pubDate>
2438 * return all selected tags as one string
2441 private function getCurrentTags()
2444 if(isset($_SESSION['selected_tags']) && $_SESSION['selected_tags'] != "") {
2445 foreach($_SESSION['selected_tags'] as $tag)
2446 $current_tags.= $tag .",";
2447 $current_tags = substr($current_tags, 0, strlen($current_tags)-1);
2449 return $current_tags;
2451 } // getCurrentTags()
2454 * return the current photo
2456 public function getCurrentPhoto()
2458 if(isset($_SESSION['current_photo'])) {
2459 print $_SESSION['current_photo'];
2461 } // getCurrentPhoto()
2464 * tells the client browser what to do
2466 * this function is getting called via AJAX by the
2467 * client browsers. it will tell them what they have
2468 * to do next. This is necessary for directly jumping
2469 * into photo index or single photo view when the are
2470 * requested with specific URLs
2473 public function whatToDo()
2475 if(isset($_SESSION['current_photo']) && $_SESSION['start_action'] == 'showp') {
2477 elseif(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
2478 return "showpi_tags";
2480 elseif(isset($_SESSION['start_action']) && $_SESSION['start_action'] == 'showpi') {
2487 * return the current process-user
2490 private function getuid()
2492 if($uid = posix_getuid()) {
2493 if($user = posix_getpwuid($uid)) {
2494 return $user['name'];
2503 * returns a select-dropdown box to select photo index sort parameters
2504 * @param array $params
2505 * @param smarty $smarty
2508 public function smarty_sort_select_list($params, &$smarty)
2512 foreach($this->sort_orders as $key => $value) {
2513 $output.= "<option value=\"". $key ."\"";
2514 if($key == $_SESSION['sort_order']) {
2515 $output.= " selected=\"selected\"";
2517 $output.= ">". $value ."</option>";
2522 } // smarty_sort_select_list()
2525 * returns the currently selected sort order
2528 private function get_sort_order()
2530 switch($_SESSION['sort_order']) {
2532 return " ORDER BY p.time ASC";
2535 return " ORDER BY p.time DESC";
2538 if($this->dbver < 9) {
2539 return " ORDER BY p.name ASC";
2542 return " ORDER BY basename(p.uri) ASC";
2546 if($this->dbver < 9) {
2547 return " ORDER BY p.name DESC";
2550 return " ORDER BY basename(p.uri) DESC";
2554 return " ORDER BY t.name ASC ,p.time ASC";
2557 return " ORDER BY t.name DESC ,p.time ASC";
2560 return " ORDER BY t.name ASC, p.rating ASC";
2563 return " ORDER BY t.name DESC, p.rating DESC";
2567 } // get_sort_order()
2570 * return the next to be shown slide show image
2572 * this function returns the URL of the next image
2573 * in the slideshow sequence.
2576 public function getNextSlideShowImage()
2578 $all_photos = $this->getPhotoSelection();
2580 if(!isset($_SESSION['slideshow_img']) || $_SESSION['slideshow_img'] == count($all_photos)-1)
2581 $_SESSION['slideshow_img'] = 0;
2583 $_SESSION['slideshow_img']++;
2585 if($this->is_user_friendly_url()) {
2586 return $this->get_phpfspot_url() ."/photo/". $all_photos[$_SESSION['slideshow_img']] ."/". $this->cfg->photo_width;
2589 return $this->get_phpfspot_url() ."/phpfspot_img.php?idx=". $all_photos[$_SESSION['slideshow_img']] ."&width=". $this->cfg->photo_width;
2591 } // getNextSlideShowImage()
2594 * return the previous to be shown slide show image
2596 * this function returns the URL of the previous image
2597 * in the slideshow sequence.
2600 public function getPrevSlideShowImage()
2602 $all_photos = $this->getPhotoSelection();
2604 if(!isset($_SESSION['slideshow_img']) || $_SESSION['slideshow_img'] == 0)
2605 $_SESSION['slideshow_img'] = 0;
2607 $_SESSION['slideshow_img']--;
2609 if($this->is_user_friendly_url()) {
2610 return $this->get_phpfspot_url() ."/photo/". $all_photos[$_SESSION['slideshow_img']] ."/". $this->cfg->photo_width;
2613 return $this->get_phpfspot_url() ."/phpfspot_img.php?idx=". $all_photos[$_SESSION['slideshow_img']] ."&width=". $this->cfg->photo_width;
2615 } // getPrevSlideShowImage()
2617 public function resetSlideShow()
2619 if(isset($_SESSION['slideshow_img']))
2620 unset($_SESSION['slideshow_img']);
2622 } // resetSlideShow()
2627 * this function will get all photos from the fspot
2628 * database and randomly return ONE entry
2630 * saddly there is yet no sqlite3 function which returns
2631 * the bulk result in array, so we have to fill up our
2635 public function get_random_photo()
2644 /* if show_tags is set, only return details for photos which
2645 are specified to be shown
2647 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
2649 INNER JOIN photo_tags pt
2654 t.name IN ('".implode("','",$this->cfg->show_tags)."')";
2657 $result = $this->db->db_query($query_str);
2659 while($row = $this->db->db_fetch_object($result)) {
2660 array_push($all, $row['id']);
2663 return $all[array_rand($all)];
2665 } // get_random_photo()
2668 * get random photo tag photo
2670 * this function will get all photos tagged with the requested
2671 * tag from the fspot database and randomly return ONE entry
2673 * saddly there is yet no sqlite3 function which returns
2674 * the bulk result in array, so we have to fill up our
2678 public function get_random_tag_photo($tagidx)
2685 INNER JOIN photo_tags pt
2689 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
2697 pt.tag_id LIKE '". $tagidx ."'
2700 /*if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
2703 t.name IN ('".implode("','",$this->cfg->show_tags)."')
2707 $result = $this->db->db_query($query_str);
2709 while($row = $this->db->db_fetch_object($result)) {
2710 array_push($all, $row['id']);
2713 return $all[array_rand($all)];
2715 } // get_random_tag_photo()
2718 * validates provided date
2720 * this function validates if the provided date
2721 * contains a valid date and will return true
2723 * @param string $date_str
2726 public function isValidDate($date_str)
2728 $timestamp = strtotime($date_str);
2730 if(is_numeric($timestamp))
2738 * timestamp to string conversion
2739 * @param integer $timestamp
2742 private function ts2str($timestamp)
2744 if(!empty($timestamp) && is_numeric($timestamp))
2745 return strftime("%Y-%m-%d", $timestamp);
2750 * extract tag-names from $_GET['tags']
2751 * @param string $tags_str
2754 private function extractTags($tags_str)
2756 $not_validated = split(',', $tags_str);
2757 $validated = array();
2759 foreach($not_validated as $tag) {
2760 if(is_numeric($tag))
2761 array_push($validated, $tag);
2769 * returns the full path to a thumbnail
2770 * @param integer $width
2771 * @param integer $photo
2774 public function get_thumb_path($width, $photo)
2776 $md5 = $this->getMD5($photo);
2777 $sub_path = substr($md5, 0, 2);
2778 return $this->cfg->thumb_path
2786 } // get_thumb_path()
2789 * returns server's virtual host name
2792 private function get_server_name()
2794 return $_SERVER['SERVER_NAME'];
2795 } // get_server_name()
2798 * returns type of webprotocol which is currently used
2801 private function get_web_protocol()
2803 if(!isset($_SERVER['HTTPS']))
2807 } // get_web_protocol()
2810 * return url to this phpfspot installation
2813 private function get_phpfspot_url()
2815 return $this->get_web_protocol() ."://". $this->get_server_name() . $this->cfg->web_path;
2817 } // get_phpfspot_url()
2820 * returns the number of photos which are tagged with $tag_id
2821 * @param integer $tag_id
2824 public function get_num_photos($tag_id)
2826 if($result = $this->db->db_fetchSingleRow("
2827 SELECT count(*) as number
2830 tag_id LIKE '". $tag_id ."'")) {
2832 return $result['number'];
2838 } // get_num_photos()
2841 * check file exists and is readable
2843 * returns true, if everything is ok, otherwise false
2844 * if $silent is not set, this function will output and
2846 * @param string $file
2847 * @param boolean $silent
2850 private function check_readable($file, $silent = null)
2852 if(!file_exists($file)) {
2854 print "File \"". $file ."\" does not exist.\n";
2858 if(!is_readable($file)) {
2860 print "File \"". $file ."\" is not reachable for user ". $this->getuid() ."\n";
2866 } // check_readable()
2869 * check if all needed indices are present
2871 * this function checks, if some needed indices are already
2872 * present, or if not, create them on the fly. they are
2873 * necessary to speed up some queries like that one look for
2874 * all tags, when show_tags is specified in the configuration.
2876 private function checkDbIndices()
2878 $result = $this->db->db_exec("
2879 CREATE INDEX IF NOT EXISTS
2886 } // checkDbIndices()
2889 * retrive F-Spot database version
2891 * this function will return the F-Spot database version number
2892 * It is stored within the sqlite3 database in the table meta
2893 * @return string|null
2895 public function getFspotDBVersion()
2897 if($result = $this->db->db_fetchSingleRow("
2898 SELECT data as version
2901 name LIKE 'F-Spot Database Version'
2903 return $result['version'];
2907 } // getFspotDBVersion()
2910 * parse the provided URI and will returned the requested chunk
2911 * @param string $uri
2912 * @param string $mode
2915 public function parse_uri($uri, $mode)
2917 if(($components = parse_url($uri)) !== false) {
2921 return basename($components['path']);
2924 return dirname($components['path']);
2927 return $components['path'];
2937 * validate config options
2939 * this function checks if all necessary configuration options are
2940 * specified and set.
2943 private function check_config_options()
2945 if(!isset($this->cfg->page_title) || $this->cfg->page_title == "")
2946 $this->_error("Please set \$page_title in phpfspot_cfg");
2948 if(!isset($this->cfg->base_path) || $this->cfg->base_path == "")
2949 $this->_error("Please set \$base_path in phpfspot_cfg");
2951 if(!isset($this->cfg->web_path) || $this->cfg->web_path == "")
2952 $this->_error("Please set \$web_path in phpfspot_cfg");
2954 if(!isset($this->cfg->thumb_path) || $this->cfg->thumb_path == "")
2955 $this->_error("Please set \$thumb_path in phpfspot_cfg");
2957 if(!isset($this->cfg->smarty_path) || $this->cfg->smarty_path == "")
2958 $this->_error("Please set \$smarty_path in phpfspot_cfg");
2960 if(!isset($this->cfg->fspot_db) || $this->cfg->fspot_db == "")
2961 $this->_error("Please set \$fspot_db in phpfspot_cfg");
2963 if(!isset($this->cfg->db_access) || $this->cfg->db_access == "")
2964 $this->_error("Please set \$db_access in phpfspot_cfg");
2966 if(!isset($this->cfg->phpfspot_db) || $this->cfg->phpfspot_db == "")
2967 $this->_error("Please set \$phpfspot_db in phpfspot_cfg");
2969 if(!isset($this->cfg->thumb_width) || $this->cfg->thumb_width == "")
2970 $this->_error("Please set \$thumb_width in phpfspot_cfg");
2972 if(!isset($this->cfg->thumb_height) || $this->cfg->thumb_height == "")
2973 $this->_error("Please set \$thumb_height in phpfspot_cfg");
2975 if(!isset($this->cfg->photo_width) || $this->cfg->photo_width == "")
2976 $this->_error("Please set \$photo_width in phpfspot_cfg");
2978 if(!isset($this->cfg->mini_width) || $this->cfg->mini_width == "")
2979 $this->_error("Please set \$mini_width in phpfspot_cfg");
2981 if(!isset($this->cfg->thumbs_per_page))
2982 $this->_error("Please set \$thumbs_per_page in phpfspot_cfg");
2984 if(!isset($this->cfg->path_replace_from) || $this->cfg->path_replace_from == "")
2985 $this->_error("Please set \$path_replace_from in phpfspot_cfg");
2987 if(!isset($this->cfg->path_replace_to) || $this->cfg->path_replace_to == "")
2988 $this->_error("Please set \$path_replace_to in phpfspot_cfg");
2990 if(!isset($this->cfg->hide_tags))
2991 $this->_error("Please set \$hide_tags in phpfspot_cfg");
2993 if(!isset($this->cfg->theme_name))
2994 $this->_error("Please set \$theme_name in phpfspot_cfg");
2996 if(!isset($this->cfg->logging))
2997 $this->_error("Please set \$logging in phpfspot_cfg");
2999 if(isset($this->cfg->logging) && $this->cfg->logging == 'logfile') {
3001 if(!isset($this->cfg->log_file))
3002 $this->_error("Please set \$log_file because you set logging = log_file in phpfspot_cfg");
3004 if(!is_writeable($this->cfg->log_file))
3005 $this->_error("The specified \$log_file ". $log_file ." is not writeable!");
3009 /* remove trailing slash, if set */
3010 if($this->cfg->web_path == "/")
3011 $this->cfg->web_path = "";
3012 elseif(preg_match('/\/$/', $this->cfg->web_path))
3013 $this->cfg->web_path = preg_replace('/\/$/', '', $this->cfg->web_path);
3015 return $this->runtime_error;
3017 } // check_config_options()
3020 * cleanup phpfspot own database
3022 * When photos are getting delete from F-Spot, there will remain
3023 * remain some residues in phpfspot own database. This function
3024 * will try to wipe them out.
3026 public function cleanup_phpfspot_db()
3028 $to_delete = Array();
3030 $result = $this->cfg_db->db_query("
3033 ORDER BY img_idx ASC
3036 while($row = $this->cfg_db->db_fetch_object($result)) {
3037 if(!$this->db->db_fetchSingleRow("
3040 WHERE id='". $row['img_idx'] ."'")) {
3042 array_push($to_delete, $row['img_idx'], ',');
3046 print count($to_delete) ." unnecessary objects will be removed from phpfspot's database.\n";
3048 $this->cfg_db->db_exec("
3050 WHERE img_idx IN (". implode($to_delete) .")
3053 } // cleanup_phpfspot_db()
3056 * return first image of the page, the $current photo
3059 * this function is used to find out the first photo of the
3060 * current page, in which the $current photo lies. this is
3061 * used to display the correct photo, when calling showPhotoIndex()
3063 * @param integer $current
3064 * @param integer $max
3067 private function getCurrentPage($current, $max)
3069 if(isset($this->cfg->thumbs_per_page) && !empty($this->cfg->thumbs_per_page)) {
3070 for($page_start = 0; $page_start <= $max; $page_start+=$this->cfg->thumbs_per_page) {
3071 if($current >= $page_start && $current < ($page_start+$this->cfg->thumbs_per_page))
3077 } // getCurrentPage()
3082 * this function tries to find out the correct mime-type
3083 * for the provided file.
3084 * @param string $file
3087 public function get_mime_info($file)
3089 $details = getimagesize($file);
3091 /* if getimagesize() returns empty, try at least to find out the
3094 if(empty($details) && function_exists('mime_content_type')) {
3096 // mime_content_type is marked as deprecated in the documentation,
3097 // but is it really necessary to force users to install a PECL
3099 $details['mime'] = mime_content_type($file);
3102 return $details['mime'];
3104 } // get_mime_info()
3107 * return tag-name by tag-idx
3109 * this function returns the tag-name for the requested
3110 * tag specified by tag-idx.
3111 * @param integer $idx
3114 public function get_tag_name($idx)
3116 if($result = $this->db->db_fetchSingleRow("
3120 id LIKE '". $idx ."'")) {
3122 return $result['name'];
3131 * parse user friendly url which got rewritten by the websever
3132 * @param string $request_uri
3135 private function parse_user_friendly_url($request_uri)
3137 if(preg_match('/\/photoview\/|\/photo\/|\/tag\//', $request_uri)) {
3139 $options = explode('/', $request_uri);
3141 switch($options[1]) {
3143 if(is_numeric($options[2])) {
3144 $this->session_cleanup();
3145 //unset($_SESSION['start_action']);
3146 //unset($_SESSION['selected_tags']);
3147 $_GET['mode'] = 'showp';
3148 return $this->showPhoto($options[2]);
3152 if(is_numeric($options[2])) {
3153 require_once "phpfspot_img.php";
3154 $img = new PHPFSPOT_IMG;
3155 if(isset($options[3]) && is_numeric($options[3]))
3156 $img->showImg($options[2], $options[3]);
3158 $img->showImg($options[2]);
3163 if(is_numeric($options[2])) {
3164 $this->session_cleanup();
3165 $_GET['tags'] = $options[2];
3166 $_SESSION['selected_tags'] = Array($options[2]);
3167 if(isset($options[3]) && is_numeric($options[3]))
3168 $_SESSION['begin_with'] = $options[3];
3169 return $this->showPhotoIndex();
3175 } // parse_user_friendly_url()
3178 * check if user-friendly-urls are enabled
3180 * this function will return true, if the config option
3181 * $user_friendly_url has been set. Otherwise false.
3184 private function is_user_friendly_url()
3186 if(isset($this->cfg->user_friendly_url) && $this->cfg->user_friendly_url)
3191 } // is_user_friendly_url()
3196 * this function will cleanup user's session information
3198 private function session_cleanup()
3200 unset($_SESSION['begin_with']);
3201 $this->resetDateSearch();
3202 $this->resetPhotoView();
3203 $this->resetTagSearch();
3204 $this->resetNameSearch();
3205 $this->resetDateSearch();
3208 } // session_cleanup()