<?php
/* Barbara Post (postb99 at yahoo dot com), released under the terms of GPL version 2 or later (http://www.gnu.org).

0. History :
25 June 2006, version 5.1 - XHTML 1.0 conformance : removal of 'target="_blank"'
11 August 2005, version 5.0 - important security fix with 'include'...
12 March 2005, version 4.1.0 - bug fix with current gallery number no set when viewing multi-gallery, bug fix for having
	next and previous picture links when only more than one picture
05 March 2005, version 4.1 - minor XHTML 1.0 well-formedness corrections
09 December 2004, version 4.0.2 - tiny bug fix with layout number 1 (missing clearer div, but displayed correctly at 1024*768
	resolution)
18 October 2004, version 4.0.1 - tiny bug fix for multipage gallery
17 October 2004, version 4.0 - Multi-page gallery, finally !
23 September 2004, version 3.3 - Centers images in black boxes of layout 2 thanks to additional data in gallery data file
	(layout will be a bit less beautiful if this data misses)
19 September 2004, version 3.2.2 - Correction of stupid bug on last image "previous" link, and repeated gallery description
14 September 2004, version 3.2 - addition of "next"/"previous" link when in fullsize picture mode
13 September 2004, version 3.1.0.1 - default $indexl to 2, not 1.
12 September 2004, version 3.1 - addition of linked URLs support
September 2004, version 3.0 - full refactoring (function calls, optimizations, documentation)
August 2004. version 2.1 - some refactoring
March-April 2004. version 1.0

1. Purpose :

Script permettant d'afficher une galerie simple de photos 
à  partir d'une autre page et de sous-répertoires "big" et "thumbnails".
Il utilise des styles CSS2.

This script allows to build a photo gallery from another page and its
BIG and THUMBS subdirectories. It uses CSS2 styles.

The essential data file will be created by using the same author's gallery management web interface.

If you want to include one gallery in the page, call gallery(), but if you want to include several galleries in 
the same html or php page, use rather mgallery(), once for each gallery you want to show. 
This limitation is due to the way the "showpicture" 
action is handled.


2. Data and parameters :

2.1. Parameters of function call :

gallery() :
$url, $titre, $picdir, $layout, $hide_desc

mgallery() :
$url, $titre, $picdirs, $layout, $gnum, $hide_desc, $no_footer


- $url : url of the page to link to from a full-sized picture display page (return to the gallery link) ($url parameter)
- $titre used by footer (statistics)
- $picdir : name of folder containing BIG and THUMBS directories. 
  or $picdirs when using mgallery() : array of picture directories names.
- $layout : the layout for displaying thumbnails. Several layouts are available.
- $gnum : gallery order number, when using mgallery()
- $no_footer : only useful when using mgallery(). Should be set to true excepted for last call of mgallery() in the page.
- $hide_desc : hide the description when using layout 2 (or else what is used for the ALT attribute will be shown right
  below the picture in its black box (see 3.2 below).


additional in HTTP request :
- $fichier : name of wanted file for thumbnail view ($fichier parameter)

additional constant you should define somewhere :
- $_SESSION['lang'] : language, depending on the user-agent string or any other choice you make :)
Don't forget to initialize the session with session_start() function.


2.2. Data file :

Variables found in DATAFILE file :
$gal_desc, $fichiers, $legendes, $descriptions
- $gal_desc : array of gallery descriptions, indexed by language
- $fichiers : array of file names
- $legendes : array of arrays (text for "alt" image attribute) 
  one per language (below fr and en)
- $descriptions : array of arrays (text for image description, one per language (below fr and en))
- $urls_keys : array of arrays indexed by picture name (without extension). Each array is an array of URLs related to a picture.
	For each URL, its data is represented by an array : URL, fr description, en description.
	An exception is done for gallery description which key is 'gallery_desc'.
	So the scheme is : array(pic1=>array(array(url1, desc1fr, desc1en), array(url2, desc2fr, desc2en)), pic2=>...)
- $margin_top : array of pixels numbers, useful to define margin-top css property when using layout 2 (centered pictures in black
	boxes, and vertically-centering using css can be a pain, so I defined variable margin tops.
$picperpage : blank or unlimited, or some value. Number of thumbnails on a page.

The DATAFILE file can be easily created and edited using another script I created to edit gallery. Check this website for "gallery management".


3. CSS :

Since the <head> tag has already been sent off when calling this gallery creation function, you need to add these CSS excerpts
to you own stylesheet(s).

3.0. General CSS :

div.gallerypage {background-color:#FFFFFF; width:80%; margin-left:auto; margin-right:auto;padding-right:20px; padding-left:20px; padding-top:20px; padding-bottom:20px; }

This one above is used for thumbnails view.

div.bigpage{background-color:#FFFFFF; width:100%; margin-left:auto; margin-right:auto; padding-right:20px; padding-left:20px; padding-top:20px; padding-bottom:20px;}

This one above is used for the full-sized picture.

div.clearer{clear:both;}

This is a CSS trick to "clear" th flow of floating divs.

3.1. CSS for layout 1 (created March 2004) :

div.left {float:left; width:40%; margin-top:0.5em; margin-bottom:0.5em;clear:left;}
div.right{float:left; width:60%;margin-top:0.5em; margin-bottom:0.5em; clear:right;}div.clearer{clear:both;}
img.cadre {border:solid 1px; border-color:#000000;}

This one is rather simple, one left-aligned thumb per line, and its right-aligned description, then a separator.

3.2. CSS for layout 2 (created April 2004, then refactored) : 

div.tiers {float:left; width:33.3%; text-align:center; margin-top:10px;margin-bottom:10px;}
div.noir {background-color:black; width:245px; height:245px;margin-right:auto; margin-left:auto;text-align:center;padding-left:1px; padding-right:1px;}
p.reduit {font-size:9pt; color:#FFFFFF; }
div.noir img{padding:0px;}

Still perfectible, this will show three pictures per line, each in a black square. I had troubles
with vertical alignment of images into black divs so played with margin-top of images... This render fine under 1024*768 resolution.
You can have some short description below each picture.


4. Additional notes :

I have an additional footer() function that allows me to include some stuff to get 
statistics on my web pages (the require statement to include the code of xiti() function is somewhere else). Feel free to remove it, then you can remove the "titre" parameter as well. Or have your own footer instead.


5. Acknowledgments :

Many thanks to Photo Gallery script that gave me a boost to go and create my own one, from :
http://tuma.stc.cx/gallery.php
Tuomas Airaksinen <tuomas.airaksinen@tuma.stc.cx> (Maintainer & original author)
*/

// some constants 
function init_params(){
	// constants
	define('BIG', 'big');
	define('THUMBS', 'thumbnails');
	define('DATAFILE', 'galerie_data.php');
	init_lang();
}

// localization
function init_lang(){
	// warn if language wasn't set !
	if($_SESSION['lang']==''){
		echo('<p>Gallery initialization warning : no $_SESSION[\'lang\'] constant defined before calling function !</p>');
		// fallback
		$_SESSION['lang']='en';
	}
	switch($_SESSION['lang']){
		case 'en' :
			define('CLICK_ON_PIC', 'Click on pictures to see them larger');
			define('PAGE', 'Page');
			define('UNEXISTANT', 'does not exist');
			define('CLICK_BACK_GAL', 'Click here to go back to gallery');
			define('LIB_PREVIOUS', 'Previous');
			define('LIB_NEXT', 'Next');
			define('LIB_START', 'Start of gallery');
			define('LIB_END', 'Last picture of gallery');
		break;
		
		case 'fr' :
			define('CLICK_ON_PIC', 'Cliquez sur les images pour les voir en grande taille');
			define('PAGE', 'Page');
			define('UNEXISTANT', 'n\'existe pas');
			define('CLICK_BACK_GAL', 'Cliquez ici pour revenir à la galerie');
			define('LIB_PREVIOUS', 'Précédent');
			define('LIB_NEXT', 'Suivant');
			define('LIB_START', 'Début de la galerie');
			define('LIB_END', 'Dernière image de la galerie');
		break;
	}
}

// function that is to use when one wants ONE gallery on the page
// $url, $titre, $picdir, $layout, $hide_desc
function gallery($url, $titre, $picdir, $layout, $hide_desc){
	init_params();
	$action=$_REQUEST['action'];
	$fichier = $_REQUEST['fichier'];

	 switch($action) {
                case "showpicture" :
                        echo('<div class="bigpage">');
                        showpicture($url, $picdir, $fichier, null);
                        footer(trim_extension($fichier));
                        echo('</div>');
                        break;
                default :
                        echo('<div class="gallerypage">');
                        thumbnails($url, $picdir, $layout, $hide_desc, false, 0);
                        footer($titre);
                        echo('</div>');
                        break;
        }		
}


// function that is to use when one wants SEVERAL galleries on the page
// $url, $titre, $picdirs, $layout, $gnum, $hide_desc, $no_footer
function mgallery($url, $titre, $picdirs, $layout, $gnum, $hide_desc, $no_footer){
	// init only for first call
	if($gnum==0){
		init_params();
	}
	$action=$_REQUEST['action'];
	$fichier = $_REQUEST['fichier'];
	// currently seen gallery
	$current_gnum=$_REQUEST['gnum'];
	 
	 switch($action) {
                case 'showpicture' :
			// then only once
			if($gnum == 0) {
	                        echo('<div class="bigpage">');
        	                showpicture($url, $picdirs[$current_gnum], $fichier, $current_gnum);
                     		footer(trim_extension($fichier));
                	        echo('</div>');
			}
                        break;
                default :
                        echo('<div class="gallerypage">');
			thumbnails($url, $picdirs[$gnum], $layout, $hide_desc, true, $gnum);
  			if(! $no_footer){
                       		footer($titre);
			}
                        echo('</div>');
                        break;
        }
}

// thumbnail function
// $hide_desc is only useful when using layout 2
// $multiple is set to true when using mgallery(), false when using gallery()
// gnum indicates gallery order number when using mgallery()

function thumbnails($url, $picdir, $layout, $hide_desc, $multiple, $gnum){
	
	// security check
	if(isset($picdir) and (strpos($picdir, '://'))){
		$picdir='';
	}
	
	include($picdir . '/' . DATAFILE); // this will throw an error on its own if the file is missing	
	/* création de la page */
	// description - not that '\n' string encountered will give <br/>, while '\n\n' will give a new paragraph
	// first, explode in paragraphs, then, explode with <br/>
	$exploded_desc = explode('\n\n', normalize_my_output($gallery_desc[$_SESSION['lang']]));
	
	foreach($exploded_desc as $para) {
		echo('<p>');
		// second, explode in strings with line breaks. the last output string isn't followed by <br/>
		$exploded_desc2= explode('\n', $para);
		$size = count($exploded_desc2);
		$count_s = 1;
		foreach($exploded_desc2 as $count_s => $string) {
			if($count_s < $size) {
				echo($string . '<br/>');
			}
			else {
				echo($string);
			}
		}
		echo('</p>');
	}
	echo_linked_urls('gallery_desc', $urls_keys);

	echo('<p class="b">'. CLICK_ON_PIC .'</p>');	
if($_SESSION['lang']=='fr'){
	$indexl=0;
}
else{
	$indexl=1;
}

$multipage = false;
$maxpage=0;

if(isset($picperpage) and $picperpage != 'unlimited'){
	// multipage
	$multipage = true;
	$total=count($fichiers);
	// adjustment if maximum set per pages picture > $total
	if($picperpage > $total){
		$picperpage = $total;
		$multipage = false;
	}
	if($multipage) {
	$firstpic=0;
	$lastpic=$total -1;
	$page=0;
	$maxpage = ceil($total / $picperpage);

	if(isset($_REQUEST['page'])){
		$page=$_REQUEST['page'];
	}
	else{
		$page =1;
	}
	$firstpic= ($page -1) * $picperpage;
	$lastpic=($page * $picperpage) -1;
	// lastpic control
	if($lastpic > ($total -1)){
		$lastpic=$total -1;
	}
	// firstpic control
	if($firstpic > ($total -1)) {
		$firstpic=($maxpage -1) * $picperpage;
		$lastpic=$total -1;
		echo('<p>' . PAGE . ' . $page . ' . NON_EXISTANT.'</p>');
	}
	// now we extract the part we want and keep the key for later use
	$fichiers_temp = array();
	foreach($fichiers as $key => $val){
		if($key >= $firstpic and $key <= $lastpic){
			$fichiers_temp[$key] = $val;
		}
	}
	if($maxpage ==1){
	// a single-paged gallery is not a multipage one !
		$multipage = false;
	}
	$fichiers=$fichiers_temp;
	}
} 

if($multipage){
	links_page($url, $page, $maxpage);
	echo('<div class="clearer">&nbsp;</div>');
}

// two different layouts
switch($layout) {
	case 1 :
		// layout number one - the simple one
		foreach($fichiers as $counter => $fichier){
			$temp=getimagesize($picdir . '/' .THUMBS . '/' . $fichier);
			echo('
			<div class="left">
			<div class="center">');
			// if we are in multiple mode, we add a gnum parameter to the link
			if($multiple){
				echo('<a href="'.checkurl($url).'action=showpicture&amp;lang='.$_SESSION['lang'].'&amp;fichier='.trim_extension($fichier).'&amp;gnum=' . $gnum.'">');
			}
			else {
				echo('<a href="'.checkurl($url).'action=showpicture&amp;lang='.$_SESSION['lang'].'&amp;fichier='.trim_extension($fichier).'">');
			}
			echo('<img class="cadre" src="'.$picdir.'/'. THUMBS .'/'.$fichier.'" alt="'.normalize_my_output($legendes[$counter][$indexl]).'" ' .
			$temp[3] .'/></a>
			</div>
			</div>
			<div class="right"><p>'.normalize_my_output($descriptions[$counter][$indexl]).'</p>');
			echo_linked_urls(trim_extension($fichier), $urls_keys);
			echo('</div>
			<div class="clearer">&nbsp;</div>
			');
		}
	break;
	case 2 :
	// layout number two, the black boxes one, with three pics per line - with short description or not
	// count up to three pictures
		$filecounter=0;
		foreach($fichiers as $counter => $fichier){
			$filecounter=$filecounter+1;
			$temp=getimagesize($picdir . '/' . THUMBS . '/' . $fichier);
			echo('
			<div class="tiers">
			<div class="noir">');
			// if we are in multiple mode, we add a gnum parameter to the link
			if($multiple){
				echo('<a href="'.checkurl($url).'action=showpicture&amp;lang='.$_SESSION['lang'].'&amp;fichier='.trim_extension($fichier).'&amp;gnum=' .$gnum.'">');
			}
			else{
				echo('<a href="'.checkurl($url).'action=showpicture&amp;lang='.$_SESSION['lang'].'&amp;fichier='.trim_extension($fichier).'">');
			}
			echo('<img class="noir" src="'.$picdir.'/'. THUMBS .'/'.$fichier.'" alt="'.normalize_my_output($legendes[$counter][$indexl]).'" ' . 
				$temp[3]);
				if(isset($margin_top)){
				// shift from top of div
					// if description, rectify
					if(!$hide_desc){
						$rectified_margin= $margin_top[$counter] - 10;
						echo(' style="margin-top:' . $rectified_margin  . 'px;margin-bottom:auto;"');
					}
					else{
						echo(' style="margin-top:' . $margin_top[$counter] . 'px;margin-bottom:auto;"');
					}
				}
				else{
				// some default
					echo(' style="margin-top:22px;margin-bottom:auto;"');
				}				
			echo('/></a>');
				
			// only when some description is wanted
			if(! $hide_desc){
				echo(' <p class="reduit">'.normalize_my_output($legendes[$counter][$indexl]).'</p>');
			}
			echo('</div></div>');
			if($filecounter=='3'){
				// break next line
				echo('<div class="clearer">&nbsp;</div>');
				$filecounter=0;
			}
		}
		// when exiting loop, break...
		echo('<div class="clearer">&nbsp;</div>');
	}
	if($multipage){
		links_page($url, $page, $maxpage);
		echo('<div class="clearer">&nbsp;</div>');
	}
}

// to show links to previous and next page
function links_page($url, $page, $maxpage){
switch($page){
	case 1 :
		$previous_page=$maxpage;
		$next_page=2;
		$lib_previous=LIB_END;
		$lib_next=LIB_NEXT;
		break;
	case $maxpage :
		$previous_page= $maxpage -1;
		$next_page= 1;
		$lib_previous=LIB_PREVIOUS;
		$lib_next=LIB_START;
		break;
	default :
		$previous_page=$page -1;
		$next_page=$page +1;
		$lib_previous=LIB_PREVIOUS;
		$lib_next=LIB_NEXT;
		break;
	}
	echo('<div class="left"><p><a href="' . checkurl($url) . 
	'page=' . $previous_page .'" title="' .$lib_previous. '">&lt;&lt;</a></p></div>
	<div class="right"><p><a href="' . checkurl($url) . 'page=' . $next_page . '" title="'. $lib_next.'">&gt;&gt;</a></p></div>');
}

// to show a full-sized picture
// $gnum is set in case of multi-gallery, and is set to currently visited gallery number
function showpicture($url, $picdir, $fichier, $gnum){

	// security check
	if(isset($picdir) and (strpos($picdir, '://'))){
	$picdir='';
	}

include($picdir. '/' . DATAFILE); // this will throw an error on its own if the file is missing
	$counter=0;
	$filename='';
		
	// search for the file exact name
	while($key=current($fichiers)){
		if(strpos($key, $fichier . '.') ===false){
			$counter = $counter +1;
			next($fichiers);
		}
		else {
			$filename=$fichiers[$counter];
			break;
		}

	}

echo('');
echo('<p class="b"><a href="'.checkurl($url).'lang='.$_SESSION['lang'].'">');
// setting of language-specific variables
if($_SESSION['lang']=='fr'){
	$indexl=0;
}
else{
	$indexl=1;
}
echo(CLICK_BACK_GAL .'</a></p>');

// image description, if any
if(isset($descriptions[$counter][$indexl])){
    echo('
	<p>'.normalize_my_output($descriptions[$counter][$indexl]).'</p>');
}
	echo_linked_urls(trim_extension($filename), $urls_keys);

// if more than one picture !
$max=count($fichiers);
if($max > 1) {
// set previous and next pictures index

switch($counter){
	case 0 :
		$ind_previous=$max -1;
		$ind_next=1;
		$lib_previous=LIB_END;
		$lib_next=LIB_NEXT;
		break;
	case $max -1 :
		$ind_previous=$max -2;
		$ind_next=0;
		$lib_previous=LIB_PREVIOUS;
		$lib_next=LIB_START;
		break;
	default :
		$ind_previous=$counter -1;
		$ind_next=$counter + 1;
		$lib_previous=LIB_PREVIOUS;
		$lib_next=LIB_NEXT;
		break;
}
}
// now picture surrounded with links at the corners
$temp=getimagesize($picdir . '/' . BIG . '/' . $filename);

if($max > 1) {
 linked_pics($fichiers, $url, $max, $ind_previous, $ind_next, $lib_previous, $lib_next, $gnum);
}

echo('
<div class="center">
<img style="padding:0;margin:0;" src="'.$picdir.'/'. BIG .'/'.$filename.'" alt="'.normalize_my_output($legendes[$counter][$indexl]).'" ' .
$temp[3].'/>
 </div>
');

if($max > 1) {
 linked_pics($fichiers, $url, $max, $ind_previous, $ind_next, $lib_previous, $lib_next, $gnum);
 }
 
 echo('<div class="clearer">&nbsp;</div>');
}

// $gnum is set to currently visited gallery number when using multi-galleries
function linked_pics($fichiers, $url, $max_nb, $ind_previous, $ind_next, $lib_previous, $lib_next, $gnum){
// shown numbers shifted by 1 to the left from index
$nb_previous = $ind_previous + 1;
$nb_next = $ind_next + 1;
// left link
echo('
	<div style="float:left;">
	<p style="font-size:0.75em;"><a href="' . checkurl($url) . 'action=showpicture&amp;fichier='
	 . trim_extension($fichiers[$ind_previous]));
	 if(isset($gnum)){
	 	echo('&amp;gnum=' . $gnum);
	}
	echo('" title="' . $lib_previous . '">&lt;&lt;</a></p>
	<p style="font-size:0.75em;">[ ' . $nb_previous . '/' .$max_nb . ' ]</p>
	</div>
	');

// right link
echo('
	<div style="float:right;">
	<p style="font-size:0.75em;"><a href="' . checkurl($url) . 'action=showpicture&amp;fichier=' . trim_extension($fichiers[$ind_next]));
	if(isset($gnum)){
	 	echo('&amp;gnum=' . $gnum);
	}
	echo('" title="' . $lib_next . '">&gt;&gt;</a></p>
	<p style="font-size:0.75em;">[ ' . $nb_next .  '/' .$max_nb . ' ]</p>
	</div>
	');
}

function echo_linked_urls($key, $urls_keys){
	switch($_SESSION['lang']){
		case 'en' :
			$indexl = 2;
			break;
		case 'fr' :
			$indexl = 1;
			break;
		}
	$data=$urls_keys[$key];
	if(isset($data)){
		foreach($data as $url){
			echo('<p><a href="' . $url[0] . '" title="' . normalize_my_output($url[$indexl]) . '">' . normalize_my_output($url[$indexl]) . '</a></p>');
		}
	}
}

function checkurl($url){
if(is_string(strstr($url,'?'))){
  return $url.'&amp;';
}
else{
  return $url.'?';
}

}

function footer($titre){
    xiti($titre);
}
// removes extension
function trim_extension($string){
	$length=strlen($string);
	$pos=strpos($string, '.');
	return substr($string, 0, $pos);
}
// this changes \" to &quot;
function  normalize_my_output($string) {
	return str_replace('\\"', '&quot;', $string);
}
?>
