3 /***************************************************************************
5 * phpfspot, presents your F-Spot photo collection in Web browsers.
7 * Copyright (c) by Andreas Unterkircher
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 ***************************************************************************/
25 require_once "phpfspot_cfg.php";
26 require_once "phpfspot_db.php";
31 * this class contains the most functions which will to the major
39 * phpfspot configuration
47 * SQLite database handle to f-spot database
55 * SQLite database handle to phpfspot database
63 * Smarty template engine
64 * @link http://smarty.php.net smarty.php.net
65 * @see PHPFSPOT_TMPL()
79 * list of available, not-selected, tags
86 * true if runtime error occued
90 private $runtime_error = false;
93 * F-Spot database version
100 * class constructor ($cfg, $db, $cfg_db, $tmpl, $db_ver)
102 * this function will be called on class construct
103 * and will check requirements, loads configuration,
104 * open databases and start the user session
106 public function __construct()
109 * register PHPFSPOT class global
111 * @global PHPFSPOT $GLOBALS['phpfspot']
114 $GLOBALS['phpfspot'] =& $this;
116 $this->cfg = new PHPFSPOT_CFG;
118 /* verify config settings */
119 if($this->check_config_options()) {
123 /* set application name and version information */
124 $this->cfg->product = "phpfspot";
125 $this->cfg->version = "1.5";
127 $this->sort_orders= array(
128 'date_asc' => 'Date ↑',
129 'date_desc' => 'Date ↓',
130 'name_asc' => 'Name ↑',
131 'name_desc' => 'Name ↓',
132 'tags_asc' => 'Tags ↑',
133 'tags_desc' => 'Tags ↓',
136 /* Check necessary requirements */
137 if(!$this->check_requirements()) {
141 /******* Opening F-Spot's sqlite database *********/
143 /* Check if database file is writeable */
144 if(!is_writeable($this->cfg->fspot_db)) {
145 print $this->cfg->fspot_db ." is not writeable for user ". $this->getuid() ."\n";
149 /* open the database */
150 $this->db = new PHPFSPOT_DB($this, $this->cfg->fspot_db);
152 /* change sqlite temp directory, if requested */
153 if(isset($this->cfg->sqlite_temp_dir)) {
156 temp_store_directory = '". $this->cfg->sqlite_temp_dir ."'
160 $this->dbver = $this->getFspotDBVersion();
162 if(!is_writeable($this->cfg->base_path ."/templates_c")) {
163 print $this->cfg->base_path ."/templates_c: directory is not writeable for user ". $this->getuid() ."\n";
167 if(!is_writeable($this->cfg->thumb_path)) {
168 print $this->cfg->thumb_path .": directory is not writeable for user ". $this->getuid() ."\n";
172 /******* Opening phpfspot's sqlite database *********/
174 /* Check if directory where the database file is stored is writeable */
175 if(!is_writeable(dirname($this->cfg->phpfspot_db))) {
176 print dirname($this->cfg->phpfspot_db) .": directory is not writeable for user ". $this->getuid() ."\n";
180 /* Check if database file is writeable */
181 if(!is_writeable($this->cfg->phpfspot_db)) {
182 print $this->cfg->phpfspot_db ." is not writeable for user ". $this->getuid() ."\n";
186 /* open the database */
187 $this->cfg_db = new PHPFSPOT_DB($this, $this->cfg->phpfspot_db);
189 /* change sqlite temp directory, if requested */
190 if(isset($this->cfg->sqlite_temp_dir)) {
191 $this->cfg_db->db_exec("
193 temp_store_directory = '". $this->cfg->sqlite_temp_dir ."'
197 /* Check if some tables need to be created */
198 $this->check_config_table();
200 /* overload Smarty class with our own template handler */
201 require_once "phpfspot_tmpl.php";
202 $this->tmpl = new PHPFSPOT_TMPL();
204 $this->tmpl->assign('web_path', $this->cfg->web_path);
206 /* check if all necessary indices exist */
207 $this->checkDbIndices();
209 /* if session is not yet started, do it now */
210 if(session_id() == "")
213 if(!isset($_SESSION['tag_condition']))
214 $_SESSION['tag_condition'] = 'or';
216 if(!isset($_SESSION['sort_order']))
217 $_SESSION['sort_order'] = 'date_desc';
219 if(!isset($_SESSION['searchfor_tag']))
220 $_SESSION['searchfor_tag'] = '';
222 // if begin_with is still set but thumbs_per_page is now 0, unset it
223 if(isset($_SESSION['begin_with']) && $this->cfg->thumbs_per_page == 0)
224 unset($_SESSION['begin_with']);
228 public function __destruct()
234 * show - generate html output
236 * this function can be called after the constructor has
237 * prepared everyhing. it will load the index.tpl smarty
238 * template. if necessary it will registere pre-selects
239 * (photo index, photo, tag search, date search) into
242 public function show()
244 $this->tmpl->assign('searchfor_tag', $_SESSION['searchfor_tag']);
245 $this->tmpl->assign('page_title', $this->cfg->page_title);
246 $this->tmpl->assign('current_condition', $_SESSION['tag_condition']);
247 $this->tmpl->assign('template_path', 'themes/'. $this->cfg->theme_name);
250 if($this->is_user_friendly_url()) {
251 $content = $this->parse_user_friendly_url($_SERVER['REQUEST_URI']);
254 if(isset($_GET['mode'])) {
256 $_SESSION['start_action'] = $_GET['mode'];
258 switch($_GET['mode']) {
260 if(isset($_GET['tags'])) {
261 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
263 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
264 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
266 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
267 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
271 if(isset($_GET['tags'])) {
272 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
273 $_SESSION['start_action'] = 'showp';
275 if(isset($_GET['id']) && is_numeric($_GET['id'])) {
276 $_SESSION['current_photo'] = $_GET['id'];
277 $_SESSION['start_action'] = 'showp';
279 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
280 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
282 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
283 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
287 $this->tmpl->show("export.tpl");
291 $this->tmpl->show("slideshow.tpl");
295 if(isset($_GET['tags'])) {
296 $_SESSION['selected_tags'] = $this->extractTags($_GET['tags']);
298 if(isset($_GET['from_date']) && $this->isValidDate($_GET['from_date'])) {
299 $_SESSION['from_date'] = strtotime($_GET['from_date'] ." 00:00:00");
301 if(isset($_GET['to_date']) && $this->isValidDate($_GET['to_date'])) {
302 $_SESSION['to_date'] = strtotime($_GET['to_date'] ." 23:59:59");
310 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date']))
311 $this->tmpl->assign('date_search_enabled', true);
313 $this->tmpl->register_function("sort_select_list", array(&$this, "smarty_sort_select_list"), false);
314 $this->tmpl->assign('from_date', $this->get_calendar('from'));
315 $this->tmpl->assign('to_date', $this->get_calendar('to'));
318 $this->tmpl->assign('content_page', $this->tmpl->fetch('welcome.tpl'));
320 $this->tmpl->assign('content_page', $content);
322 $this->tmpl->show("index.tpl");
327 * get_tags - grab all tags of f-spot's database
329 * this function will get all available tags from
330 * the f-spot database and store them within two
331 * arrays within this class for later usage. in
332 * fact, if the user requests (hide_tags) it will
333 * opt-out some of them.
335 * this function is getting called once by show()
337 private function get_tags()
339 $this->avail_tags = Array();
342 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
345 DISTINCT t1.id as id, t1.name as name
348 INNER JOIN photo_tags
349 pt2 ON pt1.photo_id=pt2.photo_id
355 t2.name IN ('".implode("','",$this->cfg->show_tags)."')
357 t1.sort_priority ASC";
359 $result = $this->db->db_query($query_str);
363 $result = $this->db->db_query("
366 ORDER BY sort_priority ASC
370 while($row = $this->db->db_fetch_object($result)) {
372 $tag_id = $row['id'];
373 $tag_name = $row['name'];
375 /* if the user has specified to ignore this tag in phpfspot's
376 configuration, ignore it here so it does not get added to
379 if(in_array($row['name'], $this->cfg->hide_tags))
382 /* if you include the following if-clause and the user has specified
383 to only show certain tags which are specified in phpfspot's
384 configuration, ignore all others so they will not be added to the
386 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags) &&
387 !in_array($row['name'], $this->cfg->show_tags))
391 $this->tags[$tag_id] = $tag_name;
392 $this->avail_tags[$count] = $tag_id;
400 * extract all photo details
402 * retrieve all available details from f-spot's
403 * database and return them as object
404 * @param integer $idx
405 * @return object|null
407 public function get_photo_details($idx)
409 if($this->dbver < 9) {
411 SELECT p.id, p.name, p.time, p.directory_path, p.description
417 SELECT p.id, p.uri, p.time, p.description
422 /* if show_tags is set, only return details for photos which
423 are specified to be shown
425 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
427 INNER JOIN photo_tags pt
431 WHERE p.id='". $idx ."'
432 AND t.name IN ('".implode("','",$this->cfg->show_tags)."')";
436 WHERE p.id='". $idx ."'
440 if($result = $this->db->db_query($query_str)) {
442 $row = $this->db->db_fetch_object($result);
444 if($this->dbver < 9) {
445 $row['uri'] = "file://". $row['directory_path'] ."/". $row['name'];
454 } // get_photo_details
457 * returns aligned photo names
459 * this function returns aligned (length) names for
460 * an specific photo. If the length of the name exceeds
461 * $limit the name will be shrinked (...)
462 * @param integer $idx
463 * @param integer $limit
464 * @return string|null
466 public function getPhotoName($idx, $limit = 0)
468 if($details = $this->get_photo_details($idx)) {
469 if($long_name = $this->parse_uri($details['uri'], 'filename')) {
470 $name = $this->shrink_text($long_name, $limit);
480 * shrink text according provided limit
482 * If the length of the name exceeds $limit the
483 * text will be shortend and some content in between
484 * will be replaced with "..."
486 * @param integer $limit
489 private function shrink_text($text, $limit)
491 if($limit != 0 && strlen($text) > $limit) {
492 $text = substr($text, 0, $limit-5) ."...". substr($text, -($limit-5));
500 * translate f-spoth photo path
502 * as the full-qualified path recorded in the f-spot database
503 * is usally not the same as on the webserver, this function
504 * will replace the path with that one specified in the cfg
505 * @param string $path
508 public function translate_path($path)
510 return str_replace($this->cfg->path_replace_from, $this->cfg->path_replace_to, $path);
515 * control HTML ouput for a single photo
517 * this function provides all the necessary information
518 * for the single photo template.
519 * @param integer photo
521 public function showPhoto($photo)
523 /* get all photos from the current photo selection */
524 $all_photos = $this->getPhotoSelection();
525 $count = count($all_photos);
527 for($i = 0; $i < $count; $i++) {
529 // $get_next will be set, when the photo which has to
530 // be displayed has been found - this means that the
531 // next available is in fact the NEXT image (for the
533 if(isset($get_next)) {
534 $next_img = $all_photos[$i];
538 /* the next photo is our NEXT photo */
539 if($all_photos[$i] == $photo) {
543 $previous_img = $all_photos[$i];
546 if($photo == $all_photos[$i]) {
551 $details = $this->get_photo_details($photo);
558 $orig_path = $this->translate_path($this->parse_uri($details['uri'], 'fullpath'));
559 $thumb_path = $this->get_thumb_path($this->cfg->photo_width, $photo);
561 if(!file_exists($orig_path)) {
562 $this->_error("Photo ". $orig_path ." does not exist!<br />\n");
566 if(!is_readable($orig_path)) {
567 $this->_error("Photo ". $orig_path ." is not readable for user ". $this->getuid() ."<br />\n");
571 /* If the thumbnail doesn't exist yet, try to create it */
572 if(!file_exists($thumb_path)) {
573 $this->gen_thumb($photo, true);
574 $thumb_path = $this->get_thumb_path($this->cfg->photo_width, $photo);
577 /* get mime-type, height and width from the original photo */
578 $info = getimagesize($orig_path);
580 /* get EXIF information if JPEG */
581 if($info['mime'] == "image/jpeg") {
582 $meta = $this->get_meta_informations($orig_path);
585 /* If EXIF data are available, use them */
586 if(isset($meta['ExifImageWidth'])) {
587 $meta_res = $meta['ExifImageWidth'] ."x". $meta['ExifImageLength'];
589 $meta_res = $info[0] ."x". $info[1];
592 $meta_date = isset($meta['FileDateTime']) ? strftime("%a %x %X", $meta['FileDateTime']) : "n/a";
593 $meta_make = isset($meta['Make']) ? $meta['Make'] ." / ". $meta['Model'] : "n/a";
594 $meta_size = isset($meta['FileSize']) ? round($meta['FileSize']/1024, 1) ."kbyte" : "n/a";
596 $extern_link = "index.php?mode=showp&id=". $photo;
597 $current_tags = $this->getCurrentTags();
598 if($current_tags != "") {
599 $extern_link.= "&tags=". $current_tags;
601 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
602 $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
605 $this->tmpl->assign('extern_link', $extern_link);
607 if(!file_exists($thumb_path)) {
608 $this->_error("Can't open file ". $thumb_path ."\n");
612 $info_thumb = getimagesize($thumb_path);
614 $this->tmpl->assign('description', $details['description']);
615 $this->tmpl->assign('image_name', $this->parse_uri($details['uri'], 'filename'));
617 $this->tmpl->assign('width', $info_thumb[0]);
618 $this->tmpl->assign('height', $info_thumb[1]);
619 $this->tmpl->assign('ExifMadeOn', $meta_date);
620 $this->tmpl->assign('ExifMadeWith', $meta_make);
621 $this->tmpl->assign('ExifOrigResolution', $meta_res);
622 $this->tmpl->assign('ExifFileSize', $meta_size);
624 if($this->is_user_friendly_url()) {
625 $this->tmpl->assign('image_url', '/photo/'. $photo ."/". $this->cfg->photo_width);
626 $this->tmpl->assign('image_url_full', '/photo/'. $photo);
629 $this->tmpl->assign('image_url', 'phpfspot_img.php?idx='. $photo ."&width=". $this->cfg->photo_width);
630 $this->tmpl->assign('image_url_full', 'phpfspot_img.php?idx='. $photo);
633 $this->tmpl->assign('image_filename', $this->parse_uri($details['uri'], 'filename'));
635 $this->tmpl->assign('tags', $this->get_photo_tags($photo));
636 $this->tmpl->assign('current_page', $this->getCurrentPage($current, $count));
637 $this->tmpl->assign('current_img', $photo);
640 $this->tmpl->assign('previous_url', "javascript:showImage(". $previous_img .");");
641 $this->tmpl->assign('prev_img', $previous_img);
645 $this->tmpl->assign('next_url', "javascript:showImage(". $next_img .");");
646 $this->tmpl->assign('next_img', $next_img);
648 $this->tmpl->assign('mini_width', $this->cfg->mini_width);
649 $this->tmpl->assign('photo_width', $this->cfg->photo_width);
650 $this->tmpl->assign('photo_number', $i);
651 $this->tmpl->assign('photo_count', count($all_photos));
653 return $this->tmpl->fetch("single_photo.tpl");
658 * all available tags and tag cloud
660 * this function outputs all available tags (time ordered)
661 * and in addition output them as tag cloud (tags which have
662 * many photos will appears more then others)
664 public function getAvailableTags()
666 /* retrive tags from database */
671 $result = $this->db->db_query("
672 SELECT tag_id as id, count(tag_id) as quantity
682 while($row = $this->db->db_fetch_object($result)) {
683 $tags[$row['id']] = $row['quantity'];
686 // change these font sizes if you will
687 $max_size = 125; // max font size in %
688 $min_size = 75; // min font size in %
691 $max_sat = hexdec('cc');
692 $min_sat = hexdec('44');
694 // get the largest and smallest array values
695 $max_qty = max(array_values($tags));
696 $min_qty = min(array_values($tags));
698 // find the range of values
699 $spread = $max_qty - $min_qty;
700 if (0 == $spread) { // we don't want to divide by zero
704 // determine the font-size increment
705 // this is the increase per tag quantity (times used)
706 $step = ($max_size - $min_size)/($spread);
707 $step_sat = ($max_sat - $min_sat)/($spread);
709 // loop through our tag array
710 foreach ($tags as $key => $value) {
712 if(isset($_SESSION['selected_tags']) && in_array($key, $_SESSION['selected_tags']))
715 // calculate CSS font-size
716 // find the $value in excess of $min_qty
717 // multiply by the font-size increment ($size)
718 // and add the $min_size set above
719 $size = $min_size + (($value - $min_qty) * $step);
720 // uncomment if you want sizes in whole %:
723 $color = $min_sat + ($value - $min_qty) * $step_sat;
729 if(isset($this->tags[$key])) {
730 $output.= "<a href=\"javascript:Tags('add', ". $key .");\" class=\"tag\" style=\"font-size: ". $size ."%; color: #". $r.$g.$b .";\">". $this->tags[$key] ."</a>, ";
735 $output = substr($output, 0, strlen($output)-2);
738 } // getAvailableTags()
741 * output all selected tags
743 * this function output all tags which have been selected
744 * by the user. the selected tags are stored in the
745 * session-variable $_SESSION['selected_tags']
748 public function getSelectedTags($type = 'link')
750 /* retrive tags from database */
755 foreach($this->avail_tags as $tag)
757 // return all selected tags
758 if(isset($_SESSION['selected_tags']) && in_array($tag, $_SESSION['selected_tags'])) {
763 $output.= "<a href=\"javascript:Tags('del', ". $tag .");\" class=\"tag\">". $this->tags[$tag] ."</a>, ";
767 <div style=\"display: table-cell;\">
768 <div style=\"display: table-row; text-align: center;\">
769 <a href=\"javascript:Tags('del', ". $tag .");\" title=\"". $this->tags[$tag] ."\">
770 <img src=\"phpfspot_img.php?tagidx=". $tag ."\" />
773 <div style=\"display: table-row; text-align: center;\">
774 <a href=\"javascript:Tags('del', ". $tag .");\" title=\"". $this->tags[$tag] ."\">
775 <img src=\"resources/underbar.png\" />
786 $output = substr($output, 0, strlen($output)-2);
790 return "no tags selected";
793 } // getSelectedTags()
796 * add tag to users session variable
798 * this function will add the specified to users current
799 * tag selection. if a date search has been made before
800 * it will be now cleared
803 public function addTag($tag)
805 if(!isset($_SESSION['selected_tags']))
806 $_SESSION['selected_tags'] = Array();
808 if(isset($_SESSION['searchfor_tag']))
809 unset($_SESSION['searchfor_tag']);
811 // has the user requested to hide this tag, and still someone,
812 // somehow tries to add it, don't allow this.
813 if(!isset($this->cfg->hide_tags) &&
814 in_array($this->get_tag_name($tag), $this->cfg->hide_tags))
817 if(!in_array($tag, $_SESSION['selected_tags']))
818 array_push($_SESSION['selected_tags'], $tag);
825 * remove tag to users session variable
827 * this function removes the specified tag from
828 * users current tag selection
832 public function delTag($tag)
834 if(isset($_SESSION['searchfor_tag']))
835 unset($_SESSION['searchfor_tag']);
837 if(isset($_SESSION['selected_tags'])) {
838 $key = array_search($tag, $_SESSION['selected_tags']);
839 unset($_SESSION['selected_tags'][$key]);
840 sort($_SESSION['selected_tags']);
848 * reset tag selection
850 * if there is any tag selection, it will be
853 public function resetTags()
855 if(isset($_SESSION['selected_tags']))
856 unset($_SESSION['selected_tags']);
861 * returns the value for the autocomplet tag-search
864 public function get_xml_tag_list()
866 if(!isset($_GET['search']) || !is_string($_GET['search']))
867 $_GET['search'] = '';
872 /* retrive tags from database */
875 $matched_tags = Array();
877 header("Content-Type: text/xml");
879 $string = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n";
880 $string.= "<results>\n";
882 foreach($this->avail_tags as $tag)
884 if(!empty($_GET['search']) &&
885 preg_match("/". $_GET['search'] ."/i", $this->tags[$tag]) &&
886 count($matched_tags) < $length) {
888 $count = $this->get_num_photos($tag);
891 $string.= " <rs id=\"". $i ."\" info=\"". $count ." photo\">". $this->tags[$tag] ."</rs>\n";
894 $string.= " <rs id=\"". $i ."\" info=\"". $count ." photos\">". $this->tags[$tag] ."</rs>\n";
900 /* if we have collected enough items, break out */
901 if(count($matched_tags) >= $length)
905 $string.= "</results>\n";
909 } // get_xml_tag_list()
915 * if a specific photo was requested (external link)
916 * unset the session variable now
918 public function resetPhotoView()
920 if(isset($_SESSION['current_photo']))
921 unset($_SESSION['current_photo']);
923 } // resetPhotoView();
928 * if any tag search has taken place, reset it now
930 public function resetTagSearch()
932 if(isset($_SESSION['searchfor_tag']))
933 unset($_SESSION['searchfor_tag']);
935 } // resetTagSearch()
940 * if any name search has taken place, reset it now
942 public function resetNameSearch()
944 if(isset($_SESSION['searchfor_name']))
945 unset($_SESSION['searchfor_name']);
947 } // resetNameSearch()
952 * if any date search has taken place, reset
955 public function resetDateSearch()
957 if(isset($_SESSION['from_date']))
958 unset($_SESSION['from_date']);
959 if(isset($_SESSION['to_date']))
960 unset($_SESSION['to_date']);
962 } // resetDateSearch();
965 * return all photo according selection
967 * this function returns all photos based on
968 * the tag-selection, tag- or date-search.
969 * the tag-search also has to take care of AND
970 * and OR conjunctions
973 public function getPhotoSelection()
975 $matched_photos = Array();
976 $additional_where_cond = "";
978 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
979 $from_date = $_SESSION['from_date'];
980 $to_date = $_SESSION['to_date'];
981 $additional_where_cond.= "
982 p.time>='". $from_date ."'
984 p.time<='". $to_date ."'
988 if(isset($_SESSION['searchfor_name'])) {
989 if($this->dbver < 9) {
990 $additional_where_cond.= "
992 p.name LIKE '%". $_SESSION['searchfor_name'] ."%'
994 p.description LIKE '%". $_SESSION['searchfor_name'] ."%'
999 $additional_where_cond.= "
1001 basename(p.uri) LIKE '%". $_SESSION['searchfor_name'] ."%'
1003 p.description LIKE '%". $_SESSION['searchfor_name'] ."%'
1009 if(isset($_SESSION['sort_order'])) {
1010 $order_str = $this->get_sort_order();
1013 /* return a search result */
1014 if(isset($_SESSION['searchfor_tag']) && $_SESSION['searchfor_tag'] != '') {
1016 SELECT DISTINCT pt1.photo_id
1018 INNER JOIN photo_tags pt2
1019 ON pt1.photo_id=pt2.photo_id
1023 ON pt1.photo_id=p.id
1026 WHERE t.name LIKE '%". $_SESSION['searchfor_tag'] ."%' ";
1028 if(isset($additional_where_cond) && !empty($additional_where_cond))
1029 $query_str.= "AND ". $additional_where_cond ." ";
1031 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1032 $query_str.= "AND t2.name IN ('".implode("','",$this->cfg->show_tags)."')";
1035 if(isset($order_str))
1036 $query_str.= $order_str;
1038 $result = $this->db->db_query($query_str);
1039 while($row = $this->db->db_fetch_object($result)) {
1040 array_push($matched_photos, $row['photo_id']);
1042 return $matched_photos;
1045 /* return according the selected tags */
1046 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
1048 foreach($_SESSION['selected_tags'] as $tag)
1049 $selected.= $tag .",";
1050 $selected = substr($selected, 0, strlen($selected)-1);
1052 /* photo has to match at least on of the selected tags */
1053 if($_SESSION['tag_condition'] == 'or') {
1055 SELECT DISTINCT pt1.photo_id
1057 INNER JOIN photo_tags pt2
1058 ON pt1.photo_id=pt2.photo_id
1062 ON pt1.photo_id=p.id
1063 WHERE pt1.tag_id IN (". $selected .")
1065 if(isset($additional_where_cond) && !empty($additional_where_cond))
1066 $query_str.= "AND ". $additional_where_cond ." ";
1068 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1069 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags)."')";
1072 if(isset($order_str))
1073 $query_str.= $order_str;
1075 /* photo has to match all selected tags */
1076 elseif($_SESSION['tag_condition'] == 'and') {
1078 if(count($_SESSION['selected_tags']) >= 32) {
1079 print "A SQLite limit of 32 tables within a JOIN SELECT avoids to<br />\n";
1080 print "evaluate your tag selection. Please remove some tags from your selection.\n";
1084 /* Join together a table looking like
1086 pt1.photo_id pt1.tag_id pt2.photo_id pt2.tag_id ...
1088 so the query can quickly return all images matching the
1089 selected tags in an AND condition
1094 SELECT DISTINCT pt1.photo_id
1098 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1105 for($i = 0; $i < count($_SESSION['selected_tags']); $i++) {
1107 INNER JOIN photo_tags pt". ($i+2) ."
1108 ON pt1.photo_id=pt". ($i+2) .".photo_id
1113 ON pt1.photo_id=p.id
1115 $query_str.= "WHERE pt2.tag_id=". $_SESSION['selected_tags'][0]." ";
1116 for($i = 1; $i < count($_SESSION['selected_tags']); $i++) {
1118 AND pt". ($i+2) .".tag_id=". $_SESSION['selected_tags'][$i] ."
1121 if(isset($additional_where_cond) && !empty($additional_where_cond))
1122 $query_str.= "AND ". $additional_where_cond;
1124 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1125 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags). "')";
1128 if(isset($order_str))
1129 $query_str.= $order_str;
1133 $result = $this->db->db_query($query_str);
1134 while($row = $this->db->db_fetch_object($result)) {
1135 array_push($matched_photos, $row['photo_id']);
1137 return $matched_photos;
1140 /* return all available photos */
1142 SELECT DISTINCT p.id
1144 LEFT JOIN photo_tags pt
1150 if(isset($additional_where_cond) && !empty($additional_where_cond))
1151 $query_str.= "WHERE ". $additional_where_cond ." ";
1153 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
1154 if(isset($additional_where_cond) && !empty($additional_where_cond))
1155 $query_str.= "AND t.name IN ('".implode("','",$this->cfg->show_tags). "')";
1157 $query_str.= "WHERE t.name IN ('".implode("','",$this->cfg->show_tags). "')";
1160 if(isset($order_str))
1161 $query_str.= $order_str;
1163 $result = $this->db->db_query($query_str);
1164 while($row = $this->db->db_fetch_object($result)) {
1165 array_push($matched_photos, $row['id']);
1167 return $matched_photos;
1169 } // getPhotoSelection()
1172 * control HTML ouput for photo index
1174 * this function provides all the necessary information
1175 * for the photo index template.
1177 public function showPhotoIndex()
1179 $photos = $this->getPhotoSelection();
1181 $count = count($photos);
1183 /* if all thumbnails should be shown on one page */
1184 if(!isset($this->cfg->thumbs_per_page) || $this->cfg->thumbs_per_page == 0) {
1188 /* thumbnails should be splitted up in several pages */
1189 elseif($this->cfg->thumbs_per_page > 0) {
1191 if(!isset($_SESSION['begin_with']) || $_SESSION['begin_with'] == 0) {
1195 $begin_with = $_SESSION['begin_with'];
1198 $end_with = $begin_with + $this->cfg->thumbs_per_page;
1202 $images[$thumbs] = Array();
1203 $img_height[$thumbs] = Array();
1204 $img_width[$thumbs] = Array();
1205 $img_id[$thumbs] = Array();
1206 $img_name[$thumbs] = Array();
1207 $img_fullname[$thumbs] = Array();
1208 $img_title = Array();
1210 for($i = $begin_with; $i < $end_with; $i++) {
1212 if(isset($photos[$i])) {
1214 $images[$thumbs] = $photos[$i];
1215 $img_id[$thumbs] = $i;
1216 $img_name[$thumbs] = htmlspecialchars($this->getPhotoName($photos[$i], 15));
1217 $img_fullname[$thumbs] = htmlspecialchars($this->getPhotoName($photos[$i], 0));
1218 $img_title[$thumbs] = "Click to view photo ". htmlspecialchars($this->getPhotoName($photos[$i], 0));
1220 $thumb_path = $this->get_thumb_path($this->cfg->thumb_width, $photos[$i]);
1222 if(file_exists($thumb_path)) {
1223 $info = getimagesize($thumb_path);
1224 $img_width[$thumbs] = $info[0];
1225 $img_height[$thumbs] = $info[1];
1231 // +1 for for smarty's selection iteration
1234 if(isset($_SESSION['searchfor_tag']) && $_SESSION['searchfor_tag'] != '')
1235 $this->tmpl->assign('searchfor_tag', $_SESSION['searchfor_tag']);
1237 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1238 $this->tmpl->assign('from_date', $this->ts2str($_SESSION['from_date']));
1239 $this->tmpl->assign('to_date', $this->ts2str($_SESSION['to_date']));
1242 if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
1243 $this->tmpl->assign('tag_result', 1);
1246 /* do we have to display the page selector ? */
1247 if($this->cfg->thumbs_per_page != 0) {
1251 /* calculate the page switchers */
1252 $previous_start = $begin_with - $this->cfg->thumbs_per_page;
1253 $next_start = $begin_with + $this->cfg->thumbs_per_page;
1255 if($begin_with != 0)
1256 $this->tmpl->assign("previous_url", "javascript:showPhotoIndex(". $previous_start .");");
1257 if($end_with < $count)
1258 $this->tmpl->assign("next_url", "javascript:showPhotoIndex(". $next_start .");");
1260 $photo_per_page = $this->cfg->thumbs_per_page;
1261 $last_page = ceil($count / $photo_per_page);
1263 /* get the current selected page */
1264 if($begin_with == 0) {
1268 for($i = $begin_with; $i >= 0; $i-=$photo_per_page) {
1275 for($i = 1; $i <= $last_page; $i++) {
1277 if($current_page == $i)
1278 $style = "style=\"font-size: 125%; text-decoration: underline;\"";
1279 elseif($current_page-1 == $i || $current_page+1 == $i)
1280 $style = "style=\"font-size: 105%;\"";
1281 elseif(($current_page-5 >= $i) && ($i != 1) ||
1282 ($current_page+5 <= $i) && ($i != $last_page))
1283 $style = "style=\"font-size: 75%;\"";
1287 $select = "<a href=\"javascript:showPhotoIndex(". (($i*$photo_per_page)-$photo_per_page) .");\"";
1290 $select.= ">". $i ."</a> ";
1292 // until 9 pages we show the selector from 1-9
1293 if($last_page <= 9) {
1294 $page_select.= $select;
1297 if($i == 1 /* first page */ ||
1298 $i == $last_page /* last page */ ||
1299 $i == $current_page /* current page */ ||
1300 $i == ceil($last_page * 0.25) /* first quater */ ||
1301 $i == ceil($last_page * 0.5) /* half */ ||
1302 $i == ceil($last_page * 0.75) /* third quater */ ||
1303 (in_array($i, array(1,2,3,4,5,6)) && $current_page <= 4) /* the first 6 */ ||
1304 (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 */ ||
1305 $i == $current_page-3 || $i == $current_page-2 || $i == $current_page-1 /* three before */ ||
1306 $i == $current_page+3 || $i == $current_page+2 || $i == $current_page+1 /* three after */) {
1308 $page_select.= $select;
1316 $page_select.= "......... ";
1321 /* only show the page selector if we have more then one page */
1323 $this->tmpl->assign('page_selector', $page_select);
1327 $current_tags = $this->getCurrentTags();
1328 $extern_link = "index.php?mode=showpi";
1329 $rss_link = "index.php?mode=rss";
1330 if($current_tags != "") {
1331 $extern_link.= "&tags=". $current_tags;
1332 $rss_link.= "&tags=". $current_tags;
1334 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
1335 $extern_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
1336 $rss_link.= "&from_date=". $this->ts2str($_SESSION['from_date']) ."&to_date=". $this->ts2str($_SESSION['to_date']);
1339 $export_link = "index.php?mode=export";
1340 $slideshow_link = "index.php?mode=slideshow";
1342 $this->tmpl->assign('extern_link', $extern_link);
1343 $this->tmpl->assign('slideshow_link', $slideshow_link);
1344 $this->tmpl->assign('export_link', $export_link);
1345 $this->tmpl->assign('rss_link', $rss_link);
1346 $this->tmpl->assign('count', $count);
1347 $this->tmpl->assign('width', $this->cfg->thumb_width);
1348 $this->tmpl->assign('preview_width', $this->cfg->photo_width);
1349 $this->tmpl->assign('thumb_container_width', $this->cfg->thumb_width);
1350 $this->tmpl->assign('thumb_container_height', $this->cfg->thumb_height+20);
1351 $this->tmpl->assign('images', $images);
1352 $this->tmpl->assign('img_width', $img_width);
1353 $this->tmpl->assign('img_height', $img_height);
1354 $this->tmpl->assign('img_id', $img_id);
1355 $this->tmpl->assign('img_name', $img_name);
1356 $this->tmpl->assign('img_fullname', $img_fullname);
1357 $this->tmpl->assign('img_title', $img_title);
1358 $this->tmpl->assign('thumbs', $thumbs);
1359 $this->tmpl->assign('selected_tags', $this->getSelectedTags('img'));
1361 $result = $this->tmpl->fetch("photo_index.tpl");
1363 /* if we are returning to photo index from an photo-view,
1364 scroll the window to the last shown photo-thumbnail.
1365 after this, unset the last_photo session variable.
1367 if(isset($_SESSION['last_photo'])) {
1368 $result.= "<script language=\"JavaScript\">moveToThumb(". $_SESSION['last_photo'] .");</script>\n";
1369 unset($_SESSION['last_photo']);
1374 } // showPhotoIndex()
1377 * show credit template
1379 public function showCredits()
1381 $this->tmpl->assign('version', $this->cfg->version);
1382 $this->tmpl->assign('product', $this->cfg->product);
1383 $this->tmpl->assign('db_version', $this->dbver);
1384 $this->tmpl->show("credits.tpl");
1389 * create thumbnails for the requested width
1391 * this function creates image thumbnails of $orig_image
1392 * stored as $thumb_image. It will check if the image is
1393 * in a supported format, if necessary rotate the image
1394 * (based on EXIF orientation meta headers) and re-sizing.
1395 * @param string $orig_image
1396 * @param string $thumb_image
1397 * @param integer $width
1400 public function create_thumbnail($orig_image, $thumb_image, $width)
1402 if(!file_exists($orig_image)) {
1406 $mime = $this->get_mime_info($orig_image);
1408 /* check if original photo is a support image type */
1409 if(!$this->checkifImageSupported($mime))
1416 $meta = $this->get_meta_informations($orig_image);
1422 switch($meta['Orientation']) {
1423 case 1: /* top, left */
1424 /* nothing to do */ break;
1425 case 2: /* top, right */
1426 $rotate = 0; $flip_hori = true; break;
1427 case 3: /* bottom, left */
1428 $rotate = 180; break;
1429 case 4: /* bottom, right */
1430 $flip_vert = true; break;
1431 case 5: /* left side, top */
1432 $rotate = 90; $flip_vert = true; break;
1433 case 6: /* right side, top */
1434 $rotate = 90; break;
1435 case 7: /* left side, bottom */
1436 $rotate = 270; $flip_vert = true; break;
1437 case 8: /* right side, bottom */
1438 $rotate = 270; break;
1441 $src_img = @imagecreatefromjpeg($orig_image);
1447 $src_img = @imagecreatefrompng($orig_image);
1451 case 'image/x-portable-pixmap':
1453 $src_img = new Imagick($orig_image);
1454 $handler = "imagick";
1459 if(!isset($src_img) || empty($src_img)) {
1460 print "Can't load image from ". $orig_image ."\n";
1468 /* grabs the height and width */
1469 $cur_width = imagesx($src_img);
1470 $cur_height = imagesy($src_img);
1472 // If requested width is more then the actual image width,
1473 // do not generate a thumbnail, instead safe the original
1474 // as thumbnail but with lower quality. But if the image
1475 // is to heigh too, then we still have to resize it.
1476 if($width >= $cur_width && $cur_height < $this->cfg->thumb_height) {
1477 $result = imagejpeg($src_img, $thumb_image, 75);
1478 imagedestroy($src_img);
1485 $cur_width = $src_img->getImageWidth();
1486 $cur_height = $src_img->getImageHeight();
1488 // If requested width is more then the actual image width,
1489 // do not generate a thumbnail, instead safe the original
1490 // as thumbnail but with lower quality. But if the image
1491 // is to heigh too, then we still have to resize it.
1492 if($width >= $cur_width && $cur_height < $this->cfg->thumb_height) {
1493 $src_img->setCompressionQuality(75);
1494 $src_img->setImageFormat('jpeg');
1495 $src_img->writeImage($thumb_image);
1497 $src_img->destroy();
1504 // If the image will be rotate because EXIF orientation said so
1505 // 'virtually rotate' the image for further calculations
1506 if($rotate == 90 || $rotate == 270) {
1508 $cur_width = $cur_height;
1512 /* calculates aspect ratio */
1513 $aspect_ratio = $cur_height / $cur_width;
1516 if($aspect_ratio < 1) {
1518 $new_h = abs($new_w * $aspect_ratio);
1520 /* 'virtually' rotate the image and calculate it's ratio */
1521 $tmp_w = $cur_height;
1522 $tmp_h = $cur_width;
1523 /* now get the ratio from the 'rotated' image */
1524 $tmp_ratio = $tmp_h/$tmp_w;
1525 /* now calculate the new dimensions */
1527 $tmp_h = abs($tmp_w * $tmp_ratio);
1529 // now that we know, how high they photo should be, if it
1530 // gets rotated, use this high to scale the image
1532 $new_w = abs($new_h / $aspect_ratio);
1534 // If the image will be rotate because EXIF orientation said so
1535 // now 'virtually rotate' back the image for the image manipulation
1536 if($rotate == 90 || $rotate == 270) {
1547 /* creates new image of that size */
1548 $dst_img = imagecreatetruecolor($new_w, $new_h);
1550 imagefill($dst_img, 0, 0, ImageColorAllocate($dst_img, 255, 255, 255));
1552 /* copies resized portion of original image into new image */
1553 imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $new_w, $new_h, imagesx($src_img), imagesy($src_img));
1555 /* needs the image to be flipped horizontal? */
1557 $this->_debug("(FLIP)");
1558 $dst_img = $this->flipImage($dst_img, 'hori');
1560 /* needs the image to be flipped vertical? */
1562 $this->_debug("(FLIP)");
1563 $dst_img = $this->flipImage($dst_img, 'vert');
1567 $this->_debug("(ROTATE)");
1568 $dst_img = $this->rotateImage($dst_img, $rotate);
1571 /* write down new generated file */
1572 $result = imagejpeg($dst_img, $thumb_image, 75);
1574 /* free your mind */
1575 imagedestroy($dst_img);
1576 imagedestroy($src_img);
1578 if($result === false) {
1579 print "Can't write thumbnail ". $thumb_image ."\n";
1589 $src_img->resizeImage($new_w, $new_h, Imagick::FILTER_LANCZOS, 1);
1591 /* needs the image to be flipped horizontal? */
1593 $this->_debug("(FLIP)");
1594 $src_img->rotateImage(new ImagickPixel(), 90);
1595 $src_img->flipImage();
1596 $src_img->rotateImage(new ImagickPixel(), -90);
1598 /* needs the image to be flipped vertical? */
1600 $this->_debug("(FLIP)");
1601 $src_img->flipImage();
1605 $this->_debug("(ROTATE)");
1606 $src_img->rotateImage(new ImagickPixel(), $rotate);
1609 $src_img->setCompressionQuality(75);
1610 $src_img->setImageFormat('jpeg');
1612 if(!$src_img->writeImage($thumb_image)) {
1613 print "Can't write thumbnail ". $thumb_image ."\n";
1618 $src_img->destroy();
1625 } // create_thumbnail()
1628 * return all exif meta data from the file
1629 * @param string $file
1632 public function get_meta_informations($file)
1634 return exif_read_data($file);
1636 } // get_meta_informations()
1639 * create phpfspot own sqlite database
1641 * this function creates phpfspots own sqlite database
1642 * if it does not exist yet. this own is used to store
1643 * some necessary informations (md5 sum's, ...).
1645 public function check_config_table()
1647 // if the config table doesn't exist yet, create it
1648 if(!$this->cfg_db->db_check_table_exists("images")) {
1649 $this->cfg_db->db_exec("
1650 CREATE TABLE images (
1651 img_idx int primary key,
1657 } // check_config_table
1660 * Generates a thumbnail from photo idx
1662 * This function will generate JPEG thumbnails from provided F-Spot photo
1665 * 1. Check if all thumbnail generations (width) are already in place and
1667 * 2. Check if the md5sum of the original file has changed
1668 * 3. Generate the thumbnails if needed
1669 * @param integer $idx
1670 * @param integer $force
1671 * @param boolean $overwrite
1673 public function gen_thumb($idx = 0, $force = 0, $overwrite = false)
1677 $resolutions = Array(
1678 $this->cfg->thumb_width,
1679 $this->cfg->photo_width,
1680 $this->cfg->mini_width,
1684 /* get details from F-Spot's database */
1685 $details = $this->get_photo_details($idx);
1687 /* calculate file MD5 sum */
1688 $full_path = $this->translate_path($this->parse_uri($details['uri'], 'fullpath'));
1690 if(!file_exists($full_path)) {
1691 $this->_error("File ". $full_path ." does not exist\n");
1695 if(!is_readable($full_path)) {
1696 $this->_error("File ". $full_path ." is not readable for ". $this->getuid() ."\n");
1700 $this->_debug("Image [". $idx ."] ". $this->shrink_text($this->parse_uri($details['uri'], 'filename'), 20) ." Thumbnails:");
1702 /* If Nikon NEF format, we need to treat it another way */
1703 if(isset($this->cfg->dcraw_bin) &&
1704 file_exists($this->cfg->dcraw_bin) &&
1705 is_executable($this->cfg->dcraw_bin) &&
1706 preg_match('/\.nef$/i', $details['uri'])) {
1708 $ppm_path = preg_replace('/\.nef$/i', '.ppm', $full_path);
1710 /* if PPM file does not exist, let dcraw convert it from NEF */
1711 if(!file_exists($ppm_path)) {
1712 system($this->cfg->dcraw_bin ." -a ". $full_path);
1715 /* for now we handle the PPM instead of the NEF */
1716 $full_path = $ppm_path;
1720 $file_md5 = md5_file($full_path);
1723 foreach($resolutions as $resolution) {
1725 $generate_it = false;
1727 $thumb_sub_path = substr($file_md5, 0, 2);
1728 $thumb_path = $this->cfg->thumb_path ."/". $thumb_sub_path ."/". $resolution ."_". $file_md5;
1730 /* if thumbnail-subdirectory does not exist yet, create it */
1731 if(!file_exists(dirname($thumb_path))) {
1732 mkdir(dirname($thumb_path), 0755);
1735 /* if the thumbnail file doesn't exist, create it */
1736 if(!file_exists($thumb_path)) {
1737 $generate_it = true;
1739 /* if the file hasn't changed there is no need to regen the thumb */
1740 elseif($file_md5 != $this->getMD5($idx) || $force) {
1741 $generate_it = true;
1744 if($generate_it || $overwrite) {
1746 $this->_debug(" ". $resolution ."px");
1747 if(!$this->create_thumbnail($full_path, $thumb_path, $resolution))
1755 $this->_debug(" already exist");
1758 /* set the new/changed MD5 sum for the current photo */
1760 $this->setMD5($idx, $file_md5);
1763 $this->_debug("\n");
1768 * returns stored md5 sum for a specific photo
1770 * this function queries the phpfspot database for a
1771 * stored MD5 checksum of the specified photo
1772 * @param integer $idx
1773 * @return string|null
1775 public function getMD5($idx)
1777 $result = $this->cfg_db->db_query("
1780 WHERE img_idx='". $idx ."'
1786 $img = $this->cfg_db->db_fetch_object($result);
1787 return $img['img_md5'];
1792 * set MD5 sum for the specific photo
1793 * @param integer $idx
1794 * @param string $md5
1796 private function setMD5($idx, $md5)
1798 $result = $this->cfg_db->db_exec("
1799 REPLACE INTO images (img_idx, img_md5)
1800 VALUES ('". $idx ."', '". $md5 ."')
1806 * store current tag condition
1808 * this function stores the current tag condition
1809 * (AND or OR) in the users session variables
1810 * @param string $mode
1813 public function setTagCondition($mode)
1815 $_SESSION['tag_condition'] = $mode;
1819 } // setTagCondition()
1822 * invoke tag & date search
1824 * this function will return all matching tags and store
1825 * them in the session variable selected_tags. furthermore
1826 * it also handles the date search.
1827 * getPhotoSelection() will then only return the matching
1831 public function startSearch()
1833 if(isset($_POST['from']) && $this->isValidDate($_POST['from'])) {
1834 $from = $_POST['from'];
1836 if(isset($_POST['to']) && $this->isValidDate($_POST['to'])) {
1840 if(isset($_POST['for_tag']) && is_string($_POST['for_tag'])) {
1841 $searchfor_tag = $_POST['for_tag'];
1842 $_SESSION['searchfor_tag'] = $_POST['for_tag'];
1845 if(isset($_POST['for_name']) && is_string($_POST['for_name'])) {
1846 $searchfor_name = $_POST['for_name'];
1847 $_SESSION['searchfor_name'] = $_POST['for_name'];
1852 if(isset($from) && !empty($from))
1853 $_SESSION['from_date'] = strtotime($from ." 00:00:00");
1855 unset($_SESSION['from_date']);
1857 if(isset($to) && !empty($to))
1858 $_SESSION['to_date'] = strtotime($to ." 23:59:59");
1860 unset($_SESSION['to_date']);
1862 if(isset($searchfor_tag) && !empty($searchfor_tag)) {
1863 /* new search, reset the current selected tags */
1864 $_SESSION['selected_tags'] = Array();
1865 foreach($this->avail_tags as $tag) {
1866 if(preg_match('/'. $searchfor_tag .'/i', $this->tags[$tag]))
1867 array_push($_SESSION['selected_tags'], $tag);
1876 * updates sort order in session variable
1878 * this function is invoked by RPC and will sort the requested
1879 * sort order in the session variable.
1880 * @param string $sort_order
1883 public function updateSortOrder($order)
1885 if(isset($this->sort_orders[$order])) {
1886 $_SESSION['sort_order'] = $order;
1890 return "unkown error";
1892 } // updateSortOrder()
1897 * this function rotates the image according the
1899 * @param string $img
1900 * @param integer $degress
1903 private function rotateImage($img, $degrees)
1905 if(function_exists("imagerotate")) {
1906 $img = imagerotate($img, $degrees, 0);
1908 function imagerotate($src_img, $angle)
1910 $src_x = imagesx($src_img);
1911 $src_y = imagesy($src_img);
1912 if ($angle == 180) {
1916 elseif ($src_x <= $src_y) {
1920 elseif ($src_x >= $src_y) {
1925 $rotate=imagecreatetruecolor($dest_x,$dest_y);
1926 imagealphablending($rotate, false);
1931 for ($y = 0; $y < ($src_y); $y++) {
1932 for ($x = 0; $x < ($src_x); $x++) {
1933 $color = imagecolorat($src_img, $x, $y);
1934 imagesetpixel($rotate, $dest_x - $y - 1, $x, $color);
1940 for ($y = 0; $y < ($src_y); $y++) {
1941 for ($x = 0; $x < ($src_x); $x++) {
1942 $color = imagecolorat($src_img, $x, $y);
1943 imagesetpixel($rotate, $y, $dest_y - $x - 1, $color);
1949 for ($y = 0; $y < ($src_y); $y++) {
1950 for ($x = 0; $x < ($src_x); $x++) {
1951 $color = imagecolorat($src_img, $x, $y);
1952 imagesetpixel($rotate, $dest_x - $x - 1, $dest_y - $y - 1, $color);
1966 $img = imagerotate($img, $degrees);
1975 * returns flipped image
1977 * this function will return an either horizontal or
1978 * vertical flipped truecolor image.
1979 * @param string $image
1980 * @param string $mode
1983 private function flipImage($image, $mode)
1985 $w = imagesx($image);
1986 $h = imagesy($image);
1987 $flipped = imagecreatetruecolor($w, $h);
1991 for ($y = 0; $y < $h; $y++) {
1992 imagecopy($flipped, $image, 0, $y, 0, $h - $y - 1, $w, 1);
1996 for ($x = 0; $x < $w; $x++) {
1997 imagecopy($flipped, $image, $x, 0, $w - $x - 1, 0, 1, $h);
2007 * return all assigned tags for the specified photo
2008 * @param integer $idx
2011 private function get_photo_tags($idx)
2013 $result = $this->db->db_query("
2016 INNER JOIN photo_tags pt
2018 WHERE pt.photo_id='". $idx ."'
2023 while($row = $this->db->db_fetch_object($result)) {
2024 if(isset($this->cfg->hide_tags) && in_array($row['name'], $this->cfg->hide_tags))
2026 $tags[$row['id']] = $row['name'];
2031 } // get_photo_tags()
2034 * create on-the-fly images with text within
2035 * @param string $txt
2036 * @param string $color
2037 * @param integer $space
2038 * @param integer $font
2041 public function showTextImage($txt, $color=000000, $space=4, $font=4, $w=300)
2043 if (strlen($color) != 6)
2046 $int = hexdec($color);
2047 $h = imagefontheight($font);
2048 $fw = imagefontwidth($font);
2049 $txt = explode("\n", wordwrap($txt, ($w / $fw), "\n"));
2050 $lines = count($txt);
2051 $im = imagecreate($w, (($h * $lines) + ($lines * $space)));
2052 $bg = imagecolorallocate($im, 255, 255, 255);
2053 $color = imagecolorallocate($im, 0xFF & ($int >> 0x10), 0xFF & ($int >> 0x8), 0xFF & $int);
2056 foreach ($txt as $text) {
2057 $x = (($w - ($fw * strlen($text))) / 2);
2058 imagestring($im, $font, $x, $y, $text, $color);
2059 $y += ($h + $space);
2062 Header("Content-type: image/png");
2065 } // showTextImage()
2068 * check if all requirements are met
2071 private function check_requirements()
2073 if(!function_exists("imagecreatefromjpeg")) {
2074 print "PHP GD library extension is missing<br />\n";
2078 if($this->cfg->db_access == "native" && !function_exists("sqlite3_open")) {
2079 print "PHP SQLite3 library extension is missing<br />\n";
2083 /* Check for HTML_AJAX PEAR package, lent from Horde project */
2084 ini_set('track_errors', 1);
2085 @include_once 'HTML/AJAX/Server.php';
2086 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
2087 print "PEAR HTML_AJAX package is missing<br />\n";
2090 @include_once 'Calendar/Calendar.php';
2091 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
2092 print "PEAR Calendar package is missing<br />\n";
2095 @include_once 'Console/Getopt.php';
2096 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
2097 print "PEAR Console_Getopt package is missing<br />\n";
2100 @include_once $this->cfg->smarty_path .'/libs/Smarty.class.php';
2101 if(isset($php_errormsg) && preg_match('/Failed opening.*for inclusion/i', $php_errormsg)) {
2102 print "Smarty template engine can not be found in ". $this->cfg->smarty_path ."/libs/Smarty.class.php<br />\n";
2105 ini_restore('track_errors');
2112 } // check_requirements()
2114 private function _debug($text)
2116 if($this->fromcmd) {
2123 * check if specified MIME type is supported
2124 * @param string $mime
2127 public function checkifImageSupported($mime)
2129 $supported_types = Array(
2132 "image/x-portable-pixmap",
2136 if(in_array($mime, $supported_types))
2141 } // checkifImageSupported()
2145 * @param string $text
2147 public function _error($text)
2149 switch($this->cfg->logging) {
2152 print "<img src=\"resources/green_info.png\" alt=\"warning\" />\n";
2153 print $text ."<br />\n";
2159 error_log($text, 3, $his->cfg->log_file);
2163 $this->runtime_error = true;
2168 * output calendard input fields
2169 * @param string $mode
2172 private function get_calendar($mode)
2174 $year = isset($_SESSION[$mode .'_date']) ? date("Y", $_SESSION[$mode .'_date']) : date("Y");
2175 $month = isset($_SESSION[$mode .'_date']) ? date("m", $_SESSION[$mode .'_date']) : date("m");
2176 $day = isset($_SESSION[$mode .'_date']) ? date("d", $_SESSION[$mode .'_date']) : date("d");
2178 $output = "<input type=\"text\" size=\"3\" id=\"". $mode ."year\" value=\"". $year ."\"";
2179 if(!isset($_SESSION[$mode .'_date']))
2180 $output.= " disabled=\"disabled\"";
2182 $output.= "<input type=\"text\" size=\"1\" id=\"". $mode ."month\" value=\"". $month ."\"";
2183 if(!isset($_SESSION[$mode .'_date']))
2184 $output.= " disabled=\"disabled\"";
2186 $output.= "<input type=\"text\" size=\"1\" id=\"". $mode ."day\" value=\"". $day ."\"";
2187 if(!isset($_SESSION[$mode .'_date']))
2188 $output.= " disabled=\"disabled\"";
2196 * output calendar matrix
2197 * @param integer $year
2198 * @param integer $month
2199 * @param integer $day
2201 public function get_calendar_matrix($year = 0, $month = 0, $day = 0)
2203 if (!isset($year)) $year = date('Y');
2204 if (!isset($month)) $month = date('m');
2205 if (!isset($day)) $day = date('d');
2210 require_once CALENDAR_ROOT.'Month/Weekdays.php';
2211 require_once CALENDAR_ROOT.'Day.php';
2214 $month = new Calendar_Month_Weekdays($year,$month);
2217 $prevStamp = $month->prevMonth(true);
2218 $prev = "javascript:setMonth(". date('Y',$prevStamp) .", ". date('n',$prevStamp) .", ". date('j',$prevStamp) .");";
2219 $nextStamp = $month->nextMonth(true);
2220 $next = "javascript:setMonth(". date('Y',$nextStamp) .", ". date('n',$nextStamp) .", ". date('j',$nextStamp) .");";
2222 $selectedDays = array (
2223 new Calendar_Day($year,$month,$day),
2224 new Calendar_Day($year,12,25),
2227 // Build the days in the month
2228 $month->build($selectedDays);
2230 $this->tmpl->assign('current_month', date('F Y',$month->getTimeStamp()));
2231 $this->tmpl->assign('prev_month', $prev);
2232 $this->tmpl->assign('next_month', $next);
2234 while ( $day = $month->fetch() ) {
2236 if(!isset($matrix[$rows]))
2237 $matrix[$rows] = Array();
2241 $dayStamp = $day->thisDay(true);
2242 $link = "javascript:setCalendarDate(". date('Y',$dayStamp) .", ". date('n',$dayStamp).", ". date('j',$dayStamp) .");";
2244 // isFirst() to find start of week
2245 if ( $day->isFirst() )
2248 if ( $day->isSelected() ) {
2249 $string.= "<td class=\"selected\">".$day->thisDay()."</td>\n";
2250 } else if ( $day->isEmpty() ) {
2251 $string.= "<td> </td>\n";
2253 $string.= "<td><a class=\"calendar\" href=\"".$link."\">".$day->thisDay()."</a></td>\n";
2256 // isLast() to find end of week
2257 if ( $day->isLast() )
2258 $string.= "</tr>\n";
2260 $matrix[$rows][$cols] = $string;
2270 $this->tmpl->assign('matrix', $matrix);
2271 $this->tmpl->assign('rows', $rows);
2272 $this->tmpl->show("calendar.tpl");
2274 } // get_calendar_matrix()
2277 * output export page
2278 * @param string $mode
2280 public function getExport($mode)
2282 $pictures = $this->getPhotoSelection();
2283 $current_tags = $this->getCurrentTags();
2285 foreach($pictures as $picture) {
2287 $orig_url = $this->get_phpfspot_url() ."/index.php?mode=showp&id=". $picture;
2288 if($current_tags != "") {
2289 $orig_url.= "&tags=". $current_tags;
2291 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
2292 $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
2295 if($this->is_user_friendly_url()) {
2296 $thumb_url = $this->get_phpfspot_url() ."/photo/". $picture ."/". $this->cfg->thumb_width;
2299 $thumb_url = $this->get_phpfspot_url() ."/phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
2305 // <a href="%pictureurl%"><img src="%thumbnailurl%" ></a>
2306 print htmlspecialchars("<a href=\"". $orig_url ."\"><img src=\"". $thumb_url ."\" /></a>") ."<br />\n";
2310 // "[%pictureurl% %thumbnailurl%]"
2311 print htmlspecialchars("[".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
2314 case 'MoinMoinList':
2315 // " * [%pictureurl% %thumbnailurl%]"
2316 print " " . htmlspecialchars("* [".$orig_url." ".$thumb_url."&fake=1.jpg]") ."<br />\n";
2327 public function getRSSFeed()
2329 Header("Content-type: text/xml; charset=utf-8");
2330 print "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
2333 xmlns:media="http://search.yahoo.com/mrss/"
2334 xmlns:dc="http://purl.org/dc/elements/1.1/"
2337 <title>phpfspot</title>
2338 <description>phpfspot RSS feed</description>
2339 <link><?php print htmlspecialchars($this->get_phpfspot_url()); ?></link>
2340 <pubDate><?php print strftime("%a, %d %b %Y %T %z"); ?></pubDate>
2341 <generator>phpfspot</generator>
2344 $pictures = $this->getPhotoSelection();
2345 $current_tags = $this->getCurrentTags();
2347 foreach($pictures as $picture) {
2349 $orig_url = $this->get_phpfspot_url() ."/index.php?mode=showp&id=". $picture;
2350 if($current_tags != "") {
2351 $orig_url.= "&tags=". $current_tags;
2353 if(isset($_SESSION['from_date']) && isset($_SESSION['to_date'])) {
2354 $orig_url.= "&from_date=". $_SESSION['from_date'] ."&to_date=". $_SESSION['to_date'];
2357 $details = $this->get_photo_details($picture);
2359 if($this->is_user_friendly_url()) {
2360 $thumb_url = $this->get_phpfspot_url() ."/photo/". $picture ."/". $this->cfg->thumb_width;
2363 $thumb_url = $this->get_phpfspot_url() ."/phpfspot_img.php?idx=". $picture ."&width=". $this->cfg->thumb_width;
2366 $thumb_html = htmlspecialchars("
2367 <a href=\"". $orig_url ."\"><img src=\"". $thumb_url ."\" /></a>
2369 ". $details['description']);
2371 $orig_path = $this->translate_path($this->parse_uri($details['uri'], 'fullpath'));
2373 /* get EXIF information if JPEG */
2374 if($details['mime'] == "image/jpeg") {
2375 $meta = $this->get_meta_informations($orig_path);
2378 $meta_date = isset($meta['FileDateTime']) ? $meta['FileDateTime'] : filemtime($orig_path);
2382 <title><?php print htmlspecialchars($this->parse_uri($details['uri'], 'filename')); ?></title>
2383 <link><?php print htmlspecialchars($orig_url); ?></link>
2384 <guid><?php print htmlspecialchars($orig_url); ?></guid>
2385 <dc:date.Taken><?php print strftime("%Y-%m-%dT%H:%M:%S+00:00", $meta_date); ?></dc:date.Taken>
2387 <?php print $thumb_html; ?>
2389 <pubDate><?php print strftime("%a, %d %b %Y %T %z", $meta_date); ?></pubDate>
2404 * return all selected tags as one string
2407 private function getCurrentTags()
2410 if(isset($_SESSION['selected_tags']) && $_SESSION['selected_tags'] != "") {
2411 foreach($_SESSION['selected_tags'] as $tag)
2412 $current_tags.= $tag .",";
2413 $current_tags = substr($current_tags, 0, strlen($current_tags)-1);
2415 return $current_tags;
2417 } // getCurrentTags()
2420 * return the current photo
2422 public function getCurrentPhoto()
2424 if(isset($_SESSION['current_photo'])) {
2425 print $_SESSION['current_photo'];
2427 } // getCurrentPhoto()
2430 * tells the client browser what to do
2432 * this function is getting called via AJAX by the
2433 * client browsers. it will tell them what they have
2434 * to do next. This is necessary for directly jumping
2435 * into photo index or single photo view when the are
2436 * requested with specific URLs
2439 public function whatToDo()
2441 if(isset($_SESSION['current_photo']) && $_SESSION['start_action'] == 'showp') {
2443 elseif(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
2444 return "showpi_tags";
2446 elseif(isset($_SESSION['start_action']) && $_SESSION['start_action'] == 'showpi') {
2453 * return the current process-user
2456 private function getuid()
2458 if($uid = posix_getuid()) {
2459 if($user = posix_getpwuid($uid)) {
2460 return $user['name'];
2469 * returns a select-dropdown box to select photo index sort parameters
2470 * @param array $params
2471 * @param smarty $smarty
2474 public function smarty_sort_select_list($params, &$smarty)
2478 foreach($this->sort_orders as $key => $value) {
2479 $output.= "<option value=\"". $key ."\"";
2480 if($key == $_SESSION['sort_order']) {
2481 $output.= " selected=\"selected\"";
2483 $output.= ">". $value ."</option>";
2488 } // smarty_sort_select_list()
2491 * returns the currently selected sort order
2494 private function get_sort_order()
2496 switch($_SESSION['sort_order']) {
2498 return " ORDER BY p.time ASC";
2501 return " ORDER BY p.time DESC";
2504 if($this->dbver < 9) {
2505 return " ORDER BY p.name ASC";
2508 return " ORDER BY basename(p.uri) ASC";
2512 if($this->dbver < 9) {
2513 return " ORDER BY p.name DESC";
2516 return " ORDER BY basename(p.uri) DESC";
2520 return " ORDER BY t.name ASC ,p.time ASC";
2523 return " ORDER BY t.name DESC ,p.time ASC";
2527 } // get_sort_order()
2530 * return the next to be shown slide show image
2532 * this function returns the URL of the next image
2533 * in the slideshow sequence.
2536 public function getNextSlideShowImage()
2538 $all_photos = $this->getPhotoSelection();
2540 if(!isset($_SESSION['slideshow_img']) || $_SESSION['slideshow_img'] == count($all_photos)-1)
2541 $_SESSION['slideshow_img'] = 0;
2543 $_SESSION['slideshow_img']++;
2545 if($this->is_user_friendly_url()) {
2546 return $this->get_phpfspot_url() ."/photo/". $all_photos[$_SESSION['slideshow_img']] ."/". $this->cfg->photo_width;
2549 return $this->get_phpfspot_url() ."/phpfspot_img.php?idx=". $all_photos[$_SESSION['slideshow_img']] ."&width=". $this->cfg->photo_width;
2551 } // getNextSlideShowImage()
2554 * return the previous to be shown slide show image
2556 * this function returns the URL of the previous image
2557 * in the slideshow sequence.
2560 public function getPrevSlideShowImage()
2562 $all_photos = $this->getPhotoSelection();
2564 if(!isset($_SESSION['slideshow_img']) || $_SESSION['slideshow_img'] == 0)
2565 $_SESSION['slideshow_img'] = 0;
2567 $_SESSION['slideshow_img']--;
2569 if($this->is_user_friendly_url()) {
2570 return $this->get_phpfspot_url() ."/photo/". $all_photos[$_SESSION['slideshow_img']] ."/". $this->cfg->photo_width;
2573 return $this->get_phpfspot_url() ."/phpfspot_img.php?idx=". $all_photos[$_SESSION['slideshow_img']] ."&width=". $this->cfg->photo_width;
2575 } // getPrevSlideShowImage()
2577 public function resetSlideShow()
2579 if(isset($_SESSION['slideshow_img']))
2580 unset($_SESSION['slideshow_img']);
2582 } // resetSlideShow()
2587 * this function will get all photos from the fspot
2588 * database and randomly return ONE entry
2590 * saddly there is yet no sqlite3 function which returns
2591 * the bulk result in array, so we have to fill up our
2595 public function get_random_photo()
2604 /* if show_tags is set, only return details for photos which
2605 are specified to be shown
2607 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
2609 INNER JOIN photo_tags pt
2614 t.name IN ('".implode("','",$this->cfg->show_tags)."')";
2617 $result = $this->db->db_query($query_str);
2619 while($row = $this->db->db_fetch_object($result)) {
2620 array_push($all, $row['id']);
2623 return $all[array_rand($all)];
2625 } // get_random_photo()
2628 * get random photo tag photo
2630 * this function will get all photos tagged with the requested
2631 * tag from the fspot database and randomly return ONE entry
2633 * saddly there is yet no sqlite3 function which returns
2634 * the bulk result in array, so we have to fill up our
2638 public function get_random_tag_photo($tagidx)
2645 INNER JOIN photo_tags pt
2649 if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
2657 pt.tag_id LIKE '". $tagidx ."'
2660 /*if(isset($this->cfg->show_tags) && !empty($this->cfg->show_tags)) {
2663 t.name IN ('".implode("','",$this->cfg->show_tags)."')
2667 $result = $this->db->db_query($query_str);
2669 while($row = $this->db->db_fetch_object($result)) {
2670 array_push($all, $row['id']);
2673 return $all[array_rand($all)];
2675 } // get_random_tag_photo()
2678 * validates provided date
2680 * this function validates if the provided date
2681 * contains a valid date and will return true
2683 * @param string $date_str
2686 public function isValidDate($date_str)
2688 $timestamp = strtotime($date_str);
2690 if(is_numeric($timestamp))
2698 * timestamp to string conversion
2699 * @param integer $timestamp
2702 private function ts2str($timestamp)
2704 return strftime("%Y-%m-%d", $timestamp);
2708 * extract tag-names from $_GET['tags']
2709 * @param string $tags_str
2712 private function extractTags($tags_str)
2714 $not_validated = split(',', $tags_str);
2715 $validated = array();
2717 foreach($not_validated as $tag) {
2718 if(is_numeric($tag))
2719 array_push($validated, $tag);
2727 * returns the full path to a thumbnail
2728 * @param integer $width
2729 * @param integer $photo
2732 public function get_thumb_path($width, $photo)
2734 $md5 = $this->getMD5($photo);
2735 $sub_path = substr($md5, 0, 2);
2736 return $this->cfg->thumb_path
2744 } // get_thumb_path()
2747 * returns server's virtual host name
2750 private function get_server_name()
2752 return $_SERVER['SERVER_NAME'];
2753 } // get_server_name()
2756 * returns type of webprotocol which is currently used
2759 private function get_web_protocol()
2761 if(!isset($_SERVER['HTTPS']))
2765 } // get_web_protocol()
2768 * return url to this phpfspot installation
2771 private function get_phpfspot_url()
2773 return $this->get_web_protocol() ."://". $this->get_server_name() . $this->cfg->web_path;
2775 } // get_phpfspot_url()
2778 * returns the number of photos which are tagged with $tag_id
2779 * @param integer $tag_id
2782 public function get_num_photos($tag_id)
2784 if($result = $this->db->db_fetchSingleRow("
2785 SELECT count(*) as number
2788 tag_id LIKE '". $tag_id ."'")) {
2790 return $result['number'];
2796 } // get_num_photos()
2799 * check file exists and is readable
2801 * returns true, if everything is ok, otherwise false
2802 * if $silent is not set, this function will output and
2804 * @param string $file
2805 * @param boolean $silent
2808 private function check_readable($file, $silent = null)
2810 if(!file_exists($file)) {
2812 print "File \"". $file ."\" does not exist.\n";
2816 if(!is_readable($file)) {
2818 print "File \"". $file ."\" is not reachable for user ". $this->getuid() ."\n";
2824 } // check_readable()
2827 * check if all needed indices are present
2829 * this function checks, if some needed indices are already
2830 * present, or if not, create them on the fly. they are
2831 * necessary to speed up some queries like that one look for
2832 * all tags, when show_tags is specified in the configuration.
2834 private function checkDbIndices()
2836 $result = $this->db->db_exec("
2837 CREATE INDEX IF NOT EXISTS
2844 } // checkDbIndices()
2847 * retrive F-Spot database version
2849 * this function will return the F-Spot database version number
2850 * It is stored within the sqlite3 database in the table meta
2851 * @return string|null
2853 public function getFspotDBVersion()
2855 if($result = $this->db->db_fetchSingleRow("
2856 SELECT data as version
2859 name LIKE 'F-Spot Database Version'
2861 return $result['version'];
2865 } // getFspotDBVersion()
2868 * parse the provided URI and will returned the requested chunk
2869 * @param string $uri
2870 * @param string $mode
2873 public function parse_uri($uri, $mode)
2875 if(($components = parse_url($uri)) !== false) {
2879 return basename($components['path']);
2882 return dirname($components['path']);
2885 return $components['path'];
2895 * validate config options
2897 * this function checks if all necessary configuration options are
2898 * specified and set.
2901 private function check_config_options()
2903 if(!isset($this->cfg->page_title) || $this->cfg->page_title == "")
2904 $this->_error("Please set \$page_title in phpfspot_cfg");
2906 if(!isset($this->cfg->base_path) || $this->cfg->base_path == "")
2907 $this->_error("Please set \$base_path in phpfspot_cfg");
2909 if(!isset($this->cfg->web_path) || $this->cfg->web_path == "")
2910 $this->_error("Please set \$web_path in phpfspot_cfg");
2912 if(!isset($this->cfg->thumb_path) || $this->cfg->thumb_path == "")
2913 $this->_error("Please set \$thumb_path in phpfspot_cfg");
2915 if(!isset($this->cfg->smarty_path) || $this->cfg->smarty_path == "")
2916 $this->_error("Please set \$smarty_path in phpfspot_cfg");
2918 if(!isset($this->cfg->fspot_db) || $this->cfg->fspot_db == "")
2919 $this->_error("Please set \$fspot_db in phpfspot_cfg");
2921 if(!isset($this->cfg->db_access) || $this->cfg->db_access == "")
2922 $this->_error("Please set \$db_access in phpfspot_cfg");
2924 if(!isset($this->cfg->phpfspot_db) || $this->cfg->phpfspot_db == "")
2925 $this->_error("Please set \$phpfspot_db in phpfspot_cfg");
2927 if(!isset($this->cfg->thumb_width) || $this->cfg->thumb_width == "")
2928 $this->_error("Please set \$thumb_width in phpfspot_cfg");
2930 if(!isset($this->cfg->thumb_height) || $this->cfg->thumb_height == "")
2931 $this->_error("Please set \$thumb_height in phpfspot_cfg");
2933 if(!isset($this->cfg->photo_width) || $this->cfg->photo_width == "")
2934 $this->_error("Please set \$photo_width in phpfspot_cfg");
2936 if(!isset($this->cfg->mini_width) || $this->cfg->mini_width == "")
2937 $this->_error("Please set \$mini_width in phpfspot_cfg");
2939 if(!isset($this->cfg->thumbs_per_page))
2940 $this->_error("Please set \$thumbs_per_page in phpfspot_cfg");
2942 if(!isset($this->cfg->path_replace_from) || $this->cfg->path_replace_from == "")
2943 $this->_error("Please set \$path_replace_from in phpfspot_cfg");
2945 if(!isset($this->cfg->path_replace_to) || $this->cfg->path_replace_to == "")
2946 $this->_error("Please set \$path_replace_to in phpfspot_cfg");
2948 if(!isset($this->cfg->hide_tags))
2949 $this->_error("Please set \$hide_tags in phpfspot_cfg");
2951 if(!isset($this->cfg->theme_name))
2952 $this->_error("Please set \$theme_name in phpfspot_cfg");
2954 if(!isset($this->cfg->logging))
2955 $this->_error("Please set \$logging in phpfspot_cfg");
2957 if(isset($this->cfg->logging) && $this->cfg->logging == 'logfile') {
2959 if(!isset($this->cfg->log_file))
2960 $this->_error("Please set \$log_file because you set logging = log_file in phpfspot_cfg");
2962 if(!is_writeable($this->cfg->log_file))
2963 $this->_error("The specified \$log_file ". $log_file ." is not writeable!");
2967 /* remove trailing slash, if set */
2968 if($this->cfg->web_path == "/")
2969 $this->cfg->web_path = "";
2970 elseif(preg_match('/\/$/', $this->cfg->web_path))
2971 $this->cfg->web_path = preg_replace('/\/$/', '', $this->cfg->web_path);
2973 return $this->runtime_error;
2975 } // check_config_options()
2978 * cleanup phpfspot own database
2980 * When photos are getting delete from F-Spot, there will remain
2981 * remain some residues in phpfspot own database. This function
2982 * will try to wipe them out.
2984 public function cleanup_phpfspot_db()
2986 $to_delete = Array();
2988 $result = $this->cfg_db->db_query("
2991 ORDER BY img_idx ASC
2994 while($row = $this->cfg_db->db_fetch_object($result)) {
2995 if(!$this->db->db_fetchSingleRow("
2998 WHERE id='". $row['img_idx'] ."'")) {
3000 array_push($to_delete, $row['img_idx'], ',');
3004 print count($to_delete) ." unnecessary objects will be removed from phpfspot's database.\n";
3006 $this->cfg_db->db_exec("
3008 WHERE img_idx IN (". implode($to_delete) .")
3011 } // cleanup_phpfspot_db()
3014 * return first image of the page, the $current photo
3017 * this function is used to find out the first photo of the
3018 * current page, in which the $current photo lies. this is
3019 * used to display the correct photo, when calling showPhotoIndex()
3021 * @param integer $current
3022 * @param integer $max
3025 private function getCurrentPage($current, $max)
3027 if(isset($this->cfg->thumbs_per_page) && !empty($this->cfg->thumbs_per_page)) {
3028 for($page_start = 0; $page_start <= $max; $page_start+=$this->cfg->thumbs_per_page) {
3029 if($current >= $page_start && $current < ($page_start+$this->cfg->thumbs_per_page))
3035 } // getCurrentPage()
3040 * this function tries to find out the correct mime-type
3041 * for the provided file.
3042 * @param string $file
3045 public function get_mime_info($file)
3047 $details = getimagesize($file);
3049 /* if getimagesize() returns empty, try at least to find out the
3052 if(empty($details) && function_exists('mime_content_type')) {
3054 // mime_content_type is marked as deprecated in the documentation,
3055 // but is it really necessary to force users to install a PECL
3057 $details['mime'] = mime_content_type($file);
3060 return $details['mime'];
3062 } // get_mime_info()
3065 * return tag-name by tag-idx
3067 * this function returns the tag-name for the requested
3068 * tag specified by tag-idx.
3069 * @param integer $idx
3072 public function get_tag_name($idx)
3074 if($result = $this->db->db_fetchSingleRow("
3078 id LIKE '". $idx ."'")) {
3080 return $result['name'];
3089 * parse user friendly url which got rewritten by the websever
3090 * @param string $request_uri
3093 private function parse_user_friendly_url($request_uri)
3095 if(preg_match('/\/photoview\/|\/photo\/|\/tag\//', $request_uri)) {
3097 unset($_SESSION['start_action']);
3098 unset($_SESSION['selected_tags']);
3100 $options = explode('/', $request_uri);
3102 switch($options[1]) {
3104 if(is_numeric($options[2])) {
3105 $_GET['mode'] = 'showp';
3106 return $this->showPhoto($options[2]);
3110 if(is_numeric($options[2])) {
3111 require_once "phpfspot_img.php";
3112 $img = new PHPFSPOT_IMG;
3113 if(isset($options[3]) && is_numeric($options[3]))
3114 $img->showImg($options[2], $options[3]);
3116 $img->showImg($options[2]);
3121 if(is_numeric($options[2])) {
3122 $_GET['mode'] = 'showpi';
3123 $_SESSION['selected_tags'] = Array($options[2]);
3124 $this->tmpl->assign('preset_selected_tags', $this->getSelectedTags());
3125 $_GET['tags'] = $options[2];
3126 return $this->showPhotoIndex();
3132 } // parse_user_friendly_url()
3135 * check if user-friendly-urls are enabled
3137 * this function will return true, if the config option
3138 * $user_friendly_url has been set. Otherwise false.
3141 private function is_user_friendly_url()
3143 if(isset($this->cfg->user_friendly_url) && $this->cfg->user_friendly_url)
3148 } // is_user_friendly_url()