Location: PHPKode > scripts > Weatimages > weatimages/index.php
<?php
////////////////////////////////////////////////////////////////////////////////////
//
// Weatimages 1.7.2, powerful easy to use albums publishing script
// Copyright (c) 2003-2007 Vladimir Nazarkin
// http://nazarkin.name/projects/weatimages/
// hide@address.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
//
// $Id: index.php,v 1.47 2007/04/15 08:23:06 Vova Exp $
//
////////////////////////////////////////////////////////////////////////////////////

//Do some initializations
error_reporting(E_ALL ^ E_NOTICE);
$limit_cpu = ini_get('max_execution_time');
$limit_mem = ini_get('memory_limit');
if ($limit_cpu && ($limit_cpu < 60)) { @ini_set('max_execution_time', '60'); }
if ($limit_mem && (rtrim($limit_mem, 'M') < 64)) { @ini_set('memory_limit', '64M'); }

//Langpack strings
$langpack['albums'] = 'Albums';
$langpack['nested_albums_available'] = 'Nested albums available at the first page';
$langpack['additional_items'] = 'Additional items';
$langpack['additional_items_available'] = 'Additional items available at the first page';
$langpack['album_zip'] = 'Download entire album in single archive';
$langpack['page'] = 'page';
$langpack['next_image'] = 'next image';
$langpack['previous_image'] = 'previous image';
$langpack['return_to_album'] = 'return to album';
$langpack['first_image'] = 'first image';
$langpack['last_image'] = 'last image';
$langpack['close_window'] = 'close window';
$langpack['slideshow_start'] = 'start slideshow';
$langpack['slideshow_stop'] = 'stop slideshow';
$langpack['original'] = 'Original';
$langpack['resized'] = 'Resized';
$langpack['switch_size_bottomhelp'] = 'Click image to switch between full-size view and resized view';
$langpack['switch_size_toresized'] = 'Click to view resized image';
$langpack['switch_size_tofullsize'] = 'Click to view full size image';
$langpack['thumbnail_hint'] = 'Click to view big image';
$langpack['kilobytes'] = 'Kb';
$langpack['powered_by'] = 'Powered by';

//kill oneself if user trying to access resource with '/../' in path
if (strstr(urldecode($_SERVER['REQUEST_URI']), '/../')) { fatal_error('Suspicious query rejected'); }

//$_SERVER['PATH_INFO'] and $_SERVER['PHP_SELF'] variables is very unstable with different php versions and with different web servers
//so it is better to compute them manually
if ( preg_match('|('.$_SERVER['SCRIPT_NAME'].'([^\?]*))\???|', urldecode($_SERVER['REQUEST_URI']), $matches) ) {
	//PATH_INFO is the text between SCRIPT_NAME and QUERY_STRING.
	//$_SERVER['REQUEST_URI'] is not urldecode'd by default on Apache (unlike IIS).
	$SERVER_PHP_SELF = rtrim($matches[1], '/') . '/'; //ensure that we have trailing slash
	$REQUEST_PATH = trim($matches[2], '/');//cut hampering slashes
}
else {
	$SERVER_PHP_SELF = $_SERVER['SCRIPT_NAME'] . '/';
}
if (!$REQUEST_PATH) {
	if ($_GET['path']) { //compatibility mode enabled and we have some path
		$REQUEST_PATH = $_GET['path'];
		$SERVER_PHP_SELF = $_SERVER['SCRIPT_NAME'] . '/' . $REQUEST_PATH . '/';
	}
	else { //we are in the root directory
		$REQUEST_PATH = '.';
	}
}
//$REQUEST_PATH never has starting and trailing slashes
//$SERVER_PHP_SELF always has starting and trailing slashes

//ini file name
$ini_ini_filename = 'weatimages.ini';
//read ini file if it present
if (@is_readable($ini_ini_filename)) {
	$ini = parse_ini_file($ini_ini_filename, FALSE);
}
else {
	unset($ini);
}

//process nested configs
if ($ini['enable_nested_ini'] && '.' != $REQUEST_PATH) {
	$possible_ini_places = explode('/' , $REQUEST_PATH);
	$current_search_path = '.';
	while (count($possible_ini_places)) {
		$current_search_path .= '/' . array_shift($possible_ini_places);
		$current_config = $current_search_path . '/' . $ini_ini_filename;
		if (@is_readable($current_config)) {
			$ini_override = parse_ini_file($current_config, FALSE);
			foreach ($ini_override as $key => $value) {
				$ini[$key] = $value;
			}
			unset($ini_override);
		}//if (@is_readable(
	}//while (count($possible_ini_places
	unset($possible_ini_places, $current_search_path, $current_config);
}//if ($ini['enable_nested_ini']

//set default options if it absent in ini file of file doesn't exists
if (!isset($ini['cols'])) { $ini['cols'] = 4; }
if (!isset($ini['rows'])) { $ini['rows'] = 6; }
if (!isset($ini['enable_albums_listing'])) { $ini['enable_albums_listing'] = 1; }
if (!isset($ini['enable_albums_thumbs'])) { $ini['enable_albums_thumbs'] = 1; }
if (!isset($ini['albums_thumbs_index'])) { $ini['albums_thumbs_index'] = "index"; }
if (!isset($ini['enable_index_image_hide'])) { $ini['enable_index_image_hide'] = 1; }
if (!isset($ini['albums_cols'])) { $ini['albums_cols'] = 2; }
if (!isset($ini['enable_albums_mtime_sort'])) { $ini['enable_albums_mtime_sort'] = 0; }
if (!isset($ini['enable_albums_reverse_sort'])) { $ini['enable_albums_reverse_sort'] = 0; }
if (!isset($ini['enable_files_mtime_sort'])) { $ini['enable_files_mtime_sort'] = 0; }
if (!isset($ini['enable_files_reverse_sort'])) { $ini['enable_files_reverse_sort'] = 0; }
if (!isset($ini['albums'])) { $ini['albums'] = 50; }
if (!isset($ini['enable_additional_listing'])) { $ini['enable_additional_listing'] = 1; }
if (!isset($ini['additionals'])) { $ini['additionals'] = 20; }
if (!isset($ini['enable_album_zip'])) { $ini['enable_album_zip'] = 0; }
if (!isset($ini['enable_new_window'])) { $ini['enable_new_window'] = 0; }
if (!isset($ini['enable_size_lookup'])) { $ini['enable_size_lookup'] = 1; }
if (!isset($ini['enable_description'])) { $ini['enable_description'] = 1; }
if (!isset($ini['enable_exif'])) { $ini['enable_exif'] = 1; }
if (!isset($ini['enable_exif_date'])) { $ini['enable_exif_date'] = 0; }
if (!isset($ini['enable_cell_border'])) { $ini['enable_cell_border'] = 1; }
if (!isset($ini['enable_albums_edging'])) { $ini['enable_albums_edging'] = -1; }
if (!isset($ini['description_filename'])) { $ini['description_filename'] = 'desc.txt'; }
if (!isset($ini['description_delimiter'])) { $ini['description_delimiter'] = ' '; }
if (!isset($ini['enable_omit_ext'])) { $ini['enable_omit_ext'] = 1; }
if (!isset($ini['enable_filename_display'])) { $ini['enable_filename_display'] = 1; }
if (!isset($ini['enable_filename_cleaning'])) { $ini['enable_filename_cleaning'] = 1; }
if (!isset($ini['enable_html_container'])) { $ini['enable_html_container'] = 1; }
if (!isset($ini['enable_slideshow'])) { $ini['enable_slideshow'] = 1; }
if (!isset($ini['slideshow_delay'])) { $ini['slideshow_delay'] = 3; }
if (!isset($ini['charset'])) { $ini['charset'] = 'windows-1251'; }
if (!isset($ini['jpeg_quality'])) { $ini['jpeg_quality'] = 80; }
if (!isset($ini['hidden_prefix'])) { $ini['hidden_prefix'] = '.'; }
if (!isset($ini['enable_custom_container'])) { $ini['enable_custom_container'] = 0; }
if (!isset($ini['cache_dir'])) { $ini['cache_dir'] = "weatimages-cache"; }
if (!isset($ini['external_css'])) { $ini['external_css'] = ''; }
if (!isset($ini['langpack'])) { $ini['langpack'] = ''; }
if (!isset($ini['enable_compatibility_mode'])) { $ini['enable_compatibility_mode'] = 0; }

if (!isset($ini['thumb_size'])) { $ini['thumb_size'] = 150; }
if (!isset($ini['enable_thumbs_cache'])) { $ini['enable_thumbs_cache'] = 1; }

if (!isset($ini['enable_resize'])) { $ini['enable_resize'] = 1; }
if (!isset($ini['resize_size'])) { $ini['resize_size'] = 800; }
if (!isset($ini['enable_smart_resize'])) { $ini['enable_smart_resize'] = 1; }
if (!isset($ini['default_size_resize'])) { $ini['default_size_resize'] = 1; }
if (!isset($ini['enable_resize_cache'])) { $ini['enable_resize_cache'] = 1; }

//proccess options dependences
// if 'enable_resize' disabled, we should to disable remaining resizing options
if (!$ini['enable_resize']) {
	$ini['resize_size'] = 0;
	$ini['enable_smart_resize'] = 0;
	$ini['default_size_resize'] = 0;
	$ini['enable_resize_cache'] = 0;
}
//'enable_smart_resize' feature requires 'enable_size_lookup' option enabled
if (!$ini['enable_size_lookup']) {
	$ini['enable_smart_resize'] = 0;
}
//'enable_omit_ext' feature is reasonable only when descriptions enabled
if (!$ini['enable_description']) {
	$ini['enable_omit_ext'] = 0;
}
//turn off exif lookup if exif module not found
if ($ini['enable_exif'] && !extension_loaded('exif')) {
	$ini['enable_exif'] = 0;
	$ini['enable_exif_date'] = 0;
}
if (!$ini['enable_html_container']) {
	$ini['enable_slideshow'] = 0;
}

//Check for GD2 lib
if (!function_exists(imagecopyresampled)) {
	echo "Fatal error: GD2 library is not presented";
	exit;
}

//advanced options which aren't included in ini file
//Assume that thumbnail creation supported for next file extensions
$ini['thumbnailable_exts'] = 'jpg|jpeg|gif|png';
//Always ignore files with next extensions
$ini['ignore_exts'] = 'php|css|htm|html|sem';
//Array containing list of filenames which should be omitted during directory loading. Wildcards aren't allowed.
$ini['ignore_files'] = array('.', '..', $ini_ini_filename, $ini['description_filename'], $ini['cache_dir'], basename($_SERVER['SCRIPT_NAME']), '.htaccess', '.htpasswd', 'Thumbs.db', 'error_log', 'access_log', 'cgi-bin', '_notes');
//EXIF comment strings which must be not shown.
$ini['exif_comment_ignore_strings'] = array('MINOLTA DIGITAL CAMERA', 'KONICA MINOLTA DIGITAL CAMERA', 'OLYMPUS DIGITAL CAMERA');
//Formatting of the timestamp taken from EXIF tags
$ini['exif_date_format'] = 'd.m.Y H:i';

//Load langpack file
if ('' != $ini['langpack'] && 'thumb' != $_GET['action'] && 'resize' != $_GET['action']) {
	@include($ini['langpack']);
}

//begin html page
function html_begin($title, $start, $header, $comment) {
	global $ini, $langpack;
	if (!$title || '.' == $title) {
		$title = $langpack['albums'];
	}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title><?php echo $title ?></title>
<meta http-equiv="Content-Type" content="text/html; charset=<?php echo $ini['charset'] ?>"/>
<meta name="Generator" content="Weatimages"/>
<?php
	if ('' != $ini['external_css'] && is_readable($ini['external_css'])) {
		print('<link href="' . ( ('/' != dirname($_SERVER['SCRIPT_NAME'])) ? dirname($_SERVER['SCRIPT_NAME']) : '' ) . '/' . $ini['external_css'] . '" rel="stylesheet" type="text/css">');
	}
	else {
?>
<style type="text/css">
<!--
body {
	font-family: "Trebuchet MS", Verdana, Helvetica, Arial, sans-serif;
	color: #333333;
	font-size: 11px;
	text-align: center;
	margin-top: 0px;
	padding-top: 0px;
	margin-bottom: 2px;
	margin-left: 0px;
	margin-right: 0px;
	padding: 0px;
	background-color: #FFFFFF;
}
a, a:link, a:visited {
	color: #002277;
	text-decoration: underline;
}
a:hover {
	color: #EE5500;
}
a:active {
	color: #FF0000;
}
.weatimages_thumbnail_cell {/* cell displayed in album view and containing image thumbnail, filename, description */
	font-family: Helvetica, Arial, sans-serif;
	padding: 4px 4px 8px 4px;
	border-style: solid;
	border-color: #DDDDDD;
	text-align: center;
	vertical-align: top;
}
.weatimages_thumb_border {/* border of thumbnail */
	padding: 0px;
	border-width: 1px;
	border-style: solid;
	border-color: #999999;
	margin: 6px 6px 2px 6px;
}
.weatimages_link_size {/* links to original/resized image displayed under thumbnail in album */
	font-size: 9px;
	text-decoration: underline;
	color: #333366;
	text-align: center;
}
.weatimages_filename {/* filename displayed under image thumbnail in album */
	font-size: 9px;
	color: #666666;
	font-weight: bold;
	text-align: center;
}
.weatimages_image_desc {/* description (from textfile or exif) displayed under image thumbnail in album */
	color: #555555;
	text-align: center;
}
.weatimages_pages_navigator {/* pager */
	font-size: 12px;
	color: #003366;
	text-align: center;
}
.weatimages_header {/* page title line - album/image name (or description) */
	font-size: 15px;
	color: #333333;
	margin-top: 4px;
	margin-bottom: 2px;
	margin-left: 20px;
	margin-right: 20px;
}
.weatimages_comment {/* string under page title - album/image description */
	font-size: 12px;
	color: #555555;
	margin-bottom: 3px;
	margin-left: 20px;
	margin-right: 20px;
}
.weatimages_thumb_album_name {/* album name shown on the right of album thumbnail */
	font-size: 14px;
	color: #333333;
}
.weatimages_thumb_album_desc {/* album decsription shown on the right of album thumbnail */
	font-size: 12px;
	color: #555555;
}
.weatimages_bigimage {/* style for big version of image */
	padding: 0px;
	border-width: 1px;
	border-style: solid;
	border-color: #444444;
	margin: 5px;
	text-align: center;
}
.weatimages_container_navig {/* links to next/previous images displayed at the page vith big version of image */
	font-size: 11px;
	text-decoration: underline;
}
.weatimages_toppest_navig {/* style for a div containing top navigational links - to parent albums and next/prev images */
	color: #555555;
	background-color: #FAFBFB;
	padding-left: 20px;
	padding-right: 20px;
	margin-bottom: 5px;
}
.weatimages_hotkey_tip {/* tips beside links to next/previous images */
	font-size: 11px;
	color: #BBBBBB;
}
-->
</style>
<?php
	}//if ($ini['enable_external_css']) { ... } else {
?>
<script language="javascript" type="text/javascript">
<!--
var slideshow_onload = null; //should be implemented as a function later in this document if it must be called onload
var slideshow = null; //should be implemented as a function later in this document when this function is needle

function go_link(link_object) {
	location.href = link_object.href;
}
function ev(e) { //process window events
	if (!e) var e = window.event;
	var key = (e.keyCode)? e.keyCode : ((e.which)?e.which:0);
	link_id = false;
	link_obj = null;
	if ((35 == key) && (true == e.ctrlKey)) { //ctrl + end
		link_id = 'page_last';
	}
	else if ((36 == key) && (true == e.ctrlKey)) { //ctrl + home
		link_id = 'page_first';
	}
	else if ((37 == key) && (true == e.ctrlKey)) { //ctrl + arrow left
		link_id = 'page_previous';
	}
	else if ((38 == key) && (true == e.ctrlKey)) { //ctrl + arrow up
		link_id = 'page_up';
	}
	else if ((39 == key) && (true == e.ctrlKey)) { //ctrl + arrow right
		link_id = 'page_next';
	}
	else if ((40 == key) && (true == e.ctrlKey)) { //ctrl + arrow down
		if (slideshow) {
			slideshow();
		}
	}
	if (link_id) link_obj = document.getElementById(link_id);
	if (link_obj) go_link(link_obj);
}
document.onkeydown = ev;

function onload_init() {
	if (slideshow_onload) {
		slideshow_onload();
	}
}
//-->
</script>
</head>
<body onload="onload_init();">
<?php
	if ($ini['enable_custom_container']) {
		@include('weatimages_top.inc.php');
	}
	print($start);
	if ($header && '.' != $header) {
		print('<div align="center" class="weatimages_header">' . $header . '</div>');
	}
	if ($comment) {
		print('<div align="center" class="weatimages_comment">' . $comment . '</div>');
	}
}//function html_begin(


function html_end() {
	global $ini, $langpack;
//You should not to remove the following software signature
?>
<div align="right" style="font-size:9px; color:#909090; margin:15px;"> <?php echo $langpack['powered_by'] ?> <a href="http://nazarkin.name/projects/weatimages/">Weatimages</a></div>
<?php
	if ($ini['enable_custom_container']) {
		@include('weatimages_bottom.inc.php');
	}
?>
</body>
</html>
<?php
}//function html_end(

function fatal_error($title = 'Unknown error', $comment = '') {
	html_begin($title, '', $title, $comment);
	html_end();
	exit();
}

//calculate size of image after resizing
function calc_size_after_resize($imagesize, $max_size) {
	//$imagesize - array containing size of source image: $imagesize[0] - width, $imagesize[1] - height
	//$max_size - maximal dimension of resulting image in pixels, or in percents
	//returns $resizedsize - size of image after resizing: $resizesize[0] - width, $resizesize[1] - height
	if (0 == $imagesize[0] || 0 == $imagesize[1]) { return array(0, 0); }
	if (preg_match('/([\.\d]+)\%$/', $max_size, $matches)) {
		$scale_factor = $matches[1] / 100;
		$resizedsize[0] = ceil( $imagesize[0] * $scale_factor );
		$resizedsize[1] = ceil( $imagesize[1] * $scale_factor );
		return $resizedsize;
	}
	if ($imagesize[0] > $imagesize[1]) { //if width > height
		$resizedsize[0] = $max_size; //width
		$resizedsize[1] = ceil( ($imagesize[1] / $imagesize[0]) * $resizedsize[0] ); //calculate height
	}
	else { //if height > width
		$resizedsize[1] = $max_size;
		$resizedsize[0] = ceil( ($imagesize[0] / $imagesize[1]) * $resizedsize[1] );
	}
	return $resizedsize;
}//function calc_size_after_resize(


//immediate image resizing function
function resize_image ($image_input, $image_output, $max_size, $jpeg_quality) {
	//$image_input - path to file with original image
	//$image_output - path to file in which this function must to save resized image. if it empty then output image directly to browser
	//$max_size - maximal dimension of resulting image in pixels
	//$jpeg_quality - quality of resulting jpeg image
	$imagesize = getimagesize($image_input);
	if (!$imagesize) { fatal_error("Fatal error: getimagesize($image_input) failed"); }
	if (0 == $imagesize[0] || 0 == $imagesize[1]) { fatal_error("Fatal error: zero size happened"); }
	$resizedsize = calc_size_after_resize($imagesize, $max_size);
	//create image from source file
	switch ($imagesize[2]) { //find out a format of source image
		case 1: //gif
			$image = imagecreatefromgif($image_input);
			break;
		case 2: //jpg
			$image = imagecreatefromjpeg($image_input);
			break;
		case 3: //png
			$image = imagecreatefrompng($image_input);
			break;
		default: //unknown image type
			fatal_error("Fatal error: unsupported file type");
	}
	if (!$image) { fatal_error("Fatal error: cannot create image from source"); }
	$resized = imagecreatetruecolor($resizedsize[0], $resizedsize[1]);
	imagecopyresampled($resized, $image, 0, 0, 0, 0, $resizedsize[0], $resizedsize[1], $imagesize[0], $imagesize[1]);
	if (!$image_output) { //in this case we output image directly to the browser
		header('Content-Type: image/jpeg');
	}
	@imagejpeg($resized, $image_output, $jpeg_quality);
}//function resize_image (


//manages images resizing proccess and perform caching of resized images
function resize_manager($image_input, $max_size, $cache_suffix, $is_cache_enabled) {
	//$image_input - path to file with original image
	//$max_size - maximal dimension of resulting image in pixels
	//$cache_suffix - suffix used to get filename of cached thumbnail from source image filename
	//$is_cache_enabled - indicates enabled or disabled caching of resized images
	global $ini;
	if (!@is_readable($image_input)) { fatal_error("Fatal error: requested image is not readable"); }
	$is_resized_sent = FALSE;
	if ($is_cache_enabled) {
		$file_cache = $ini['cache_dir'] . '/' . $image_input . $cache_suffix;
		if (!@is_readable($file_cache)) { //thumbnail file still don't exists
			$file_cache_dir = dirname($file_cache);
			if (!@is_dir($file_cache_dir)) {
				//we need to create a copy of directories tree under cache directory
				$dirs_must_exist = array($file_cache_dir);
				while ('.' != $dirs_must_exist[count($dirs_must_exist)-1] && '/' != $dirs_must_exist[count($dirs_must_exist)-1]) {
					array_push( $dirs_must_exist, dirname($dirs_must_exist[count($dirs_must_exist)-1]) );
				}
				array_pop($dirs_must_exist);
				while (count($dirs_must_exist) > 0) {
					$tmp_dir_new = array_pop($dirs_must_exist);
					if (@is_dir($tmp_dir_new)) {
						continue;
					}
					@mkdir($tmp_dir_new, 0777);
					@chmod($tmp_dir_new, 0777);
					clearstatcache();
				}
			}
			if (@is_writable(dirname($file_cache))) {
				$file_mutex = $ini['cache_dir'] . '/' . 'weatimages-mutex';//we allow only single image resizing proccess in a time to avoid memory issues on the server
				$FP = @fopen($file_mutex, 'r');
				if (FALSE === $FP) {
					$FP = @fopen($file_mutex, 'w');
					@chmod($file_mutex, 0666);
				}
				@flock($FP, LOCK_EX);
				resize_image($image_input, $file_cache, $max_size, $ini['jpeg_quality']);
				@chmod($file_cache, 0666);
				@flock($FP, LOCK_UN);
				@fclose($FP);
			}
			clearstatcache();
		}//if (!@is_readable($file_cache)) {
		if (@is_readable($file_cache)) { //check that we successfully created thumbnail file at the previous step
			header('Content-Type: image/jpeg');
			readfile($file_cache);
			$is_resized_sent = TRUE;
		}//if (@is_readable($file_cache)) {
	 }
	if (!$is_resized_sent) { //we still don't have cached image. Let's resize image and output result to user's browser
		resize_image($image_input, '', $max_size, $ini['jpeg_quality']);
	}
}//function resize_manager(


//show pages-navigation-bar on thumbnails page if there are more then one page
function show_pages_navigator($objects_count, $objects_on_page, $page_current, $page_query_string) {
	//$objects_count - total objects amount
	//$objects_on_page - amount of objects on a single page
	//$page_current - current page number
	//$page_query_string - string used as pagenumber variable name in http query
	global $ini, $langpack, $SERVER_PHP_SELF;
	if ($objects_count > $objects_on_page) {
		print('<div class="weatimages_pages_navigator"><span style="font-size:12px; color:#333333;">' . $langpack['page'] . ':&nbsp;&nbsp;</span>');
		//print link to previous page if current page isn't first
		if (1 != $page_current) {
			print('<a href="'
				. url_compat( $SERVER_PHP_SELF . '?' . $page_query_string . '=' . ($page_current-1) )
				. '" style="font-size:15px; font-weight:bold;">&lsaquo;&nbsp;&nbsp;</a>');
		}
		for ($i = 1; $objects_count > ($i-1)*$objects_on_page; $i++) {
			if ($i != $page_current) {
				print('<a href="'
					. url_compat($SERVER_PHP_SELF . '?' . $page_query_string . '=' . $i)
					. '">&nbsp;' . $i . ' </a>');
			}
			else {
				print('<font style="font-size: 14px; color:#555555; background-color:#F2F2F2; text-decoration:underline;">&nbsp;' . $i . '&nbsp;</font>');
			}
		}
		//print link to next page if current page isn't last
		if ( $objects_count > ($page_current*$objects_on_page) ) {
			print('<a href="'
				. url_compat($SERVER_PHP_SELF . '?' . $page_query_string . '=' . ($page_current+1))
				. '" style="font-size:15px; font-weight:bold;">&nbsp;&nbsp;&rsaquo;</a>');
		}
		print('</div>');
	}
}//function show_pages_navigator(


//load descriptions from desc file if feature enabled and file exists
function load_descriptions($REQUEST_PATH) {
	global $ini;
	$descs = array();
	if ($ini['enable_description']) {
		$desc_filefullname = $REQUEST_PATH . '/' . $ini['description_filename'];
		if (@is_readable($desc_filefullname)) {
			$desc_file = file($desc_filefullname);
			if (is_array($desc_file)) {
				foreach ($desc_file as $line) {
					list($filename, $desc) = split($ini['description_delimiter'], trim($line), 2);
					$descs[$filename] = $desc;
				}//foreach ($desc_file as $line) {
				unset($desc_file);
			}//if (!is_array($desc_file) {
		}//if (@is_readable($desc_filefullname)) {
	}//if ($ini['enable_description']) {
	return $descs;
}

//read directory contents and descriptions
function load_directory($REQUEST_PATH, $include_index_image) {
	global $ini;
	if ( FALSE == ($dir = opendir($REQUEST_PATH)) ) {
		fatal_error("Fatal error: path cannot be loaded");
	}
	$pictures = $others = $dirs = array();
	$pictures_mtime = $others_mtime = $dirs_mtime = array();
	$descs = load_descriptions($REQUEST_PATH);
	//read directory - get arrays with names of objects situated in that directory
	$pictures_count = 0;
	$others_count = 0;
	$dirs_count = 0;
	while (FALSE !== ($file = readdir($dir))) { //sift out directory record which are not necessary images
		if ('.' == $file || '..' == $file) { continue; } //sift out current directory and parental directory
		if (in_array($file, $ini['ignore_files'])) { continue; } //sift out descriptions file
		//don't include hidden objects
		if ( $ini['hidden_prefix'] == substr($file, 0, strlen($ini['hidden_prefix'])) ) { continue; }
		if (is_dir($REQUEST_PATH . '/' . $file)) { //we got an directory in directory contents listing
			if ($ini['enable_albums_mtime_sort']) {
				$dirs_mtime[$dirs_count] = filemtime($REQUEST_PATH.'/'.$file);
			}
			$dirs[$dirs_count++] = $file;
			continue;
		}
		//try to find image description (for file without extension) for substituting to absent description (for file with extension)
		if ($ini['enable_omit_ext']) {
			$filename_without_ext = preg_replace('/\.[^\.]+$/', '', $file);
			if (!array_key_exists($file, $descs)) {
				if (array_key_exists($filename_without_ext, $descs)) {
					$descs[$file] = $descs[$filename_without_ext];
				}
			}
			if (!array_key_exists($file.'.', $descs)) {
				if (array_key_exists($filename_without_ext.'.', $descs)) {
					$descs[$file.'.'] = $descs[$filename_without_ext.'.'];
				}
			}
		}//if ($ini['enable_description'] && !array_key_exists($pictures[$i], $descs)) {
		if (preg_match('/\.(' . $ini['thumbnailable_exts'] . ')$/i', $file)) {//include files with image extensions only
			if ($ini['enable_files_mtime_sort']) {
				$pictures_mtime[$pictures_count] = filemtime($REQUEST_PATH.'/'.$file);
			}
			if ((!$include_index_image && $ini['enable_index_image_hide']) && ($ini['albums_thumbs_index'].'.jpg' == $file || $ini['albums_thumbs_index'].'.jpeg' == $file || $ini['albums_thumbs_index'].'.png' == $file || $ini['albums_thumbs_index'].'.gif' == $file) ) {
				continue;
			}
			$pictures[$pictures_count++] = $file;
			continue;
		}
		if (preg_match('/\.(' . $ini['ignore_exts'] . ')$/i', $file)) {//ignore files with always-dont-show extensions
			continue;
		}
		if ($ini['enable_files_mtime_sort']) {
			$others_mtime[$others_count] = filemtime($REQUEST_PATH.'/'.$file);
		}
		$others[$others_count++] = $file; //we got an non-image (not thumbnailable) and non-directory item
	}//while (FALSE !== ($file = readdir($dir))) {
	closedir($dir);
	//sort images and other files
	if ($ini['enable_files_mtime_sort']) {
		array_multisort($pictures_mtime, SORT_NUMERIC, (!$ini['enable_files_reverse_sort'])?SORT_ASC:SORT_DESC, $pictures, SORT_STRING, SORT_ASC);
		array_multisort($others_mtime, SORT_NUMERIC, (!$ini['enable_files_reverse_sort'])?SORT_ASC:SORT_DESC, $others, SORT_STRING, SORT_ASC);
	}
	else {
		if (!$ini['enable_files_reverse_sort']) {
			sort($pictures, SORT_STRING);
			sort($others, SORT_STRING);
		} else {
			rsort($pictures, SORT_STRING);
			rsort($others, SORT_STRING);
		}
	}
	//sort albums
	if ($ini['enable_albums_mtime_sort']) {
		array_multisort($dirs_mtime, SORT_NUMERIC, (!$ini['enable_albums_reverse_sort'])?SORT_ASC:SORT_DESC, $dirs, SORT_STRING, SORT_ASC);
	}
	else {
		if (!$ini['enable_albums_reverse_sort']) {
			sort($dirs, SORT_STRING);
		} else {
			rsort($dirs, SORT_STRING);
		}
	}
	return array($pictures, $others, $dirs, $descs);
}//function load_directory($REQUEST_PATH) {


//checks exif comment text
function is_exif_text_bad(&$exif_text) {
	global $ini;
	$exif_text = preg_replace('/^[\x00\s]+/', '', $exif_text);//cut spaces at the beginning
	$exif_text = preg_replace('/[\x00\s]+$/', '', $exif_text);//cut trailing spaces
	$search_result = array_search($exif_text, $ini['exif_comment_ignore_strings']);
	if ( false !== $search_result && NULL !== $search_result) { $exif_text = ''; }//array_search in php<4.2 returns NULL instead of false if not found
	if ( preg_match('/[\.,:\-\?\S\x00]/', $exif_text) ) { return false; } else { return true; }
}


//get image size, size after resize, resize expediency, and EXIF data
//returns array($filesize_kb, $imagesize, $resizesize, $is_resize_senseless);
function get_image_sizes($image_path) {
	global $ini;
	$exif_string = '';
	$filesize_kb = 0;
	$imagesize = array();
	if ($ini['enable_exif'] && preg_match('/\.(jpg|jpeg|tif|tiff)$/i', $image_path)){
		$exif_desc = '';
		$exif_comment = '';
		$exif_data = @exif_read_data($image_path, false, true, false);
		//try to get description from exif. it may be contained in various exif sections
		if ( is_exif_text_bad($exif_desc) && isset($exif_data['IFD0']['Title']) && extension_loaded('mbstring') ) {
			//Title given by Windows Explorer, UNICODE
			$exif_desc = @mb_convert_encoding($exif_data['IFD0']['Title'], strtoupper($ini['charset']), 'UCS-2LE');
		}
		if ( is_exif_text_bad($exif_comment) && isset($exif_data['IFD0']['Comments']) && extension_loaded('mbstring') ) {
			//Comment given by Windows Explorer, UNICODE
			$exif_comment = @mb_convert_encoding($exif_data['IFD0']['Comments'], strtoupper($ini['charset']), 'UCS-2LE');
		}
		if ( is_exif_text_bad($exif_comment) && isset($exif_data['EXIF']['UserComment']) && extension_loaded('mbstring') ) {
			//UserComment given by ACDSee, UNICODE
			$comment_field = $exif_data['EXIF']['UserComment'];
			if (preg_match('/^([^\0]+?)\0(.+)$/', $comment_field, $matches) ) {
				//now $matches[1] contains encoding of the comment (unicode most likely), $matches[2] - comment in this encoding
				if ('UNICODE' == $matches[1]) { $matches[1] = 'UCS-2LE'; }
				$exif_comment = @mb_convert_encoding($matches[2], strtoupper($ini['charset']), $matches[1]);
			}
		}
		if ( is_exif_text_bad($exif_desc) && isset($exif_data['IFD0']['ImageDescription']) ) {
			//ImageDescription given by ACDSee, non-UNICODE, international characters saved
			$exif_desc = $exif_data['IFD0']['ImageDescription'];
		}
		if ( is_exif_text_bad($exif_desc) && isset($exif_data['WINXP']['Title']) ) {
			//Title given by Windows Explorer, non-UNICODE
			$exif_desc = $exif_data['WINXP']['Title'];
		}
		if ( is_exif_text_bad($exif_comment) && isset($exif_data['WINXP']['Comments']) ) {
			//Comment given by Windows Explorer, non-UNICODE
			$exif_comment = $exif_data['WINXP']['Comments'];
		}
		if ( is_exif_text_bad($exif_comment) && isset($exif_data['COMPUTED']['UserComment']) ) {
			//UserComment given by ACDSee, autoconverted to ASCII probably with national characters loss
			$exif_comment = $exif_data['COMPUTED']['UserComment'];
		}
		
		if (!is_exif_text_bad($exif_desc) && !is_exif_text_bad($exif_comment)) {
			$exif_string = $exif_desc . '<br/>' . $exif_comment;
		}
		else if (!is_exif_text_bad($exif_desc)) { $exif_string = $exif_desc; }
		else if (!is_exif_text_bad($exif_comment)) { $exif_string = $exif_comment; }
		
		//try to get filesize from exif
		if ( isset($exif_data['FILE']['FileSize']) ) {
			$filesize_kb = $exif_data['FILE']['FileSize'];
		}
		//try to get image dimensions from exif
		if ( isset($exif_data['COMPUTED']['Width']) && isset($exif_data['COMPUTED']['Height']) ) {
			$imagesize[0] = $exif_data['COMPUTED']['Width'];
			$imagesize[1] = $exif_data['COMPUTED']['Height'];
		}
		//try to get date picture taken
		if ( $ini['enable_exif_date'] && isset($exif_data['EXIF']['DateTimeOriginal'])
			&& preg_match('/^(\d\d\d\d):(\d\d):(\d\d) (\d\d):(\d\d):(\d\d)$/', $exif_data['EXIF']['DateTimeOriginal'], $matches) ) {
			$unixtime = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
			if ($unixtime > 0) {
				$exif_string = (is_exif_text_bad($exif_string)?'':$exif_string.'<br/>') . date($ini['exif_date_format'], $unixtime);
			}
		}
	}
	if (!$filesize_kb) {
		$filesize_kb = @filesize($image_path);
	}
	$filesize_kb = ceil($filesize_kb / 1024);
	if (0 == $imagesize[0] || 0 == $imagesize[1]) {
		$imagesize = @getimagesize($image_path);
	}
	$resizesize = calc_size_after_resize($imagesize, $ini['resize_size']);
	$is_resize_senseless = FALSE;
	if (($resizesize[0] >= $imagesize[0]) && $ini['enable_smart_resize']) {
		$is_resize_senseless = TRUE;
	}
	return array($filesize_kb, $imagesize, $resizesize, $is_resize_senseless, $exif_string);
}//function get_image_sizes(


//output cell with thumbnail and image info
function show_thumbnail_cell($uri_original, $uri_resize, $uri_thumb, $filesize_kb, $imagesize, $resizesize, $is_resize_senseless, $filename, $desc) {
	global $ini, $langpack;
	$thumbsize = 0;
	if ($ini['enable_size_lookup']) {//get thumbnail width and height
		$thumbsize = calc_size_after_resize($imagesize, $ini['thumb_size']);
	}
	if ($ini['enable_size_lookup'] && $ini['default_size_resize'] && $is_resize_senseless) { $uri_original .= '&amp;preferredsize=resize'; }
	print('<td align="center" valign="top" class="weatimages_thumbnail_cell" width="' . ($ini['thumb_size'] + 14) . '"'
		. ' style="border-width: ' . ($ini['enable_cell_border'] ? '1' : '0') . 'px;">'
		. '<a name="' . $filename . '" href="'
		. (($ini['default_size_resize'] && !$is_resize_senseless) ? $uri_resize : $uri_original) . '"'
		. ($ini['enable_new_window']?' target="blank"':'') .'>'
		. '<img src="' . $uri_thumb . '"'
		. (($ini['enable_size_lookup'])?' width="' . $thumbsize[0] . '" height="' . $thumbsize[1] . '"':'')
		. ' class="weatimages_thumb_border" title="' . $langpack['thumbnail_hint'] . '" alt="' . $filename . '"/>'
		. '</a>'
		. ($ini['enable_filename_display'] ? '<div class="weatimages_filename">' . wordwrap(clean_filename($filename), 30, '<br/>', 1) . '</div>' : '')
		. ( ($ini['enable_resize'] || $ini['enable_size_lookup']) ?
			'<div align="center">'
			. '<a href="' . $uri_original . '"'. ($ini['enable_new_window']?' target="blank"':'') .' class="weatimages_link_size">'
			. (($ini['enable_resize'] && !$is_resize_senseless) ? $langpack['original'] : '')
			. ($ini['enable_size_lookup']?' '.$imagesize[0].'x'.$imagesize[1].' ('.$filesize_kb.$langpack['kilobytes'].')':'')
			. '</a>'
			. ( (!$is_resize_senseless && $ini['enable_resize']) ?
				($ini['enable_size_lookup']?'<br/>':'<font class="weatimages_link_size" style="text-decoration:none;"> | </font>')
				. '<a href="' . $uri_resize . '"'. ($ini['enable_new_window']?' target="blank"':'') .' class="weatimages_link_size">'
				. $langpack['resized']. ($ini['enable_size_lookup']?' '.$resizesize[0].'x'.$resizesize[1]:'')
				. '</a>' : ''
			)//( (!$is_resize_senseless && $ini['enable_resize']) ?
			. '</div>' : ''
		)//( ($ini['enable_resize'] || $ini['enable_size_lookup']) ?
		. (($ini['enable_description'] && $desc) ? '<div class="weatimages_image_desc">' . $desc . '</div>' : '')
		. '</td>'
	);//print('<td
}//function show_thumbnail_cell(

//calculate image urls. returns array($uri_original, $uri_resize, $uri_thumb)
function get_image_urls($relative_dir, $filename, $is_need_container) {
	global $ini;
	$uri_thumb = $_SERVER['SCRIPT_NAME'] . '/' . $relative_dir . '/' . $filename . '?action=thumb';
	
	if ($is_need_container) {
		$uri_original = $_SERVER['SCRIPT_NAME'] . '/' . $relative_dir . '/' . $filename . '?action=big&amp;size=original';
		$uri_resize = $_SERVER['SCRIPT_NAME'] . '/' . $relative_dir . '/' . $filename . '?action=big&amp;size=resize';
	}
	else {
		$current_relative_directory = dirname($_SERVER['SCRIPT_NAME']); //current directory relative to web root
		if ('/' == $current_relative_directory || '\\' == $current_relative_directory) { $current_relative_directory = '/.'; }
		//link to original current image
		$uri_original = $current_relative_directory . '/' . $relative_dir . '/' . $filename;
		//link to resized current image
		$uri_resize = $_SERVER['SCRIPT_NAME'] . '/' . $relative_dir . '/' . $filename . '?action=resize';
		//link to the thumb of current image
	}
	if ($is_need_container) { $uri_original = url_compat($uri_original); }
	$uri_resize = url_compat($uri_resize);
	$uri_thumb = url_compat($uri_thumb);
	return array($uri_original, $uri_resize, $uri_thumb);
}//function get_image_urls(

//returns filename without extension, '_' symbols replaced by spaces
function clean_filename($filename) {
	global $ini;
	if ($ini['enable_filename_cleaning']) {
		$filename = preg_replace('/\.('.$ini['thumbnailable_exts'].')$/i', '', $filename);
		$filename = preg_replace('/_/', ' ', $filename);
	}
	return $filename;
}//function clean_filename(

//find thumbnail image for album and return array ([0]:uri of thumbnail; [1]:array([0]:thumb width; [1]:thumb height)) or return FALSE if album hasn't thumbnails
function get_album_thumb($album_dir) {
	global $ini;
	$album_thumb[0] = 0;
	list($nested_pictures, /*$others*/, $nested_dirs, $descs) = load_directory($album_dir, TRUE);
	$nested_dirs_count = count($nested_dirs);
	if (0 == count($nested_pictures)) {
		for ($i = 0; $i < $nested_dirs_count; $i++) {
			$album_thumb = get_album_thumb($album_dir.'/'.$nested_dirs[$i]);
			if ($album_thumb[0]) { break; }
		}
	} //if (0 == count($nested_pictures)) {
	else {
		if (in_array($ini['albums_thumbs_index'].'.jpg', $nested_pictures)) {
			$album_index_image = $ini['albums_thumbs_index'].'.jpg';
		}
		elseif (in_array($ini['albums_thumbs_index'].'.jpeg', $nested_pictures)) {
			$album_index_image = $ini['albums_thumbs_index'].'.jpeg';
		}
		elseif (in_array($ini['albums_thumbs_index'].'.png', $nested_pictures)) {
			$album_index_image = $ini['albums_thumbs_index'].'.png';
		}
		elseif (in_array($ini['albums_thumbs_index'].'.gif', $nested_pictures)) {
			$album_index_image = $ini['albums_thumbs_index'].'.gif';
		}
		else {
			$album_index_image = $nested_pictures[0];
		}
		list(/*$uri_original*/, /*$uri_resize*/, $album_thumb[0]) = get_image_urls($album_dir, $album_index_image, 0);
		list(/* $filesize_kb */, $album_thumb_size, /*$resizesize*/, /*$is_resize_senseless*/, /*$exif_comment*/)
			= get_image_sizes($album_dir.'/'.$album_index_image);
		$album_thumb[1] = calc_size_after_resize($album_thumb_size, $ini['thumb_size']);
	} //if (0 == count($nested_pictures)) { ELSE
	return $album_thumb;
}

//Converts url which use virtual path to url which don't use it
//Source url must be relative to site root
//Return the unchanged url if compatibility mode is disabled
function url_compat($url) {
	global $ini;
	if (!$ini['enable_compatibility_mode']) {
		return $url;
	}
	if ( !preg_match ('|^'.$_SERVER['SCRIPT_NAME'].'([^?]*)\??([^?]*)$|', $url, $matches) ) {
		return $url;
	}
	$path = rawurlencode(trim($matches[1], '/'));
	$query_string = $matches[2];
	$url_compatible = $_SERVER['SCRIPT_NAME'];
	if ($path) { $url_compatible .= '?path=' . $path; }
	if ($query_string) { $url_compatible .= (($path)?'&amp;':'?') . $query_string; }
	return $url_compatible;
}

//Get url for navigational link in expanded view (links to neighbour images - previous , next, etc)
//First parameter - path to image, relative to this script
//Returns url to page with image
function get_expanded_navig_url($path_to_image) {
	global $ini;
	if ($ini['enable_size_lookup']) {
		list($filesize_kb, $imagesize, $resizesize, $is_resize_senseless, /*$exif_comment*/) = get_image_sizes($path_to_image);
	}//if ($ini['enable_size_lookup']) {
	list($uri_original, $uri_resize, $uri_thumb) = get_image_urls(dirname($path_to_image), basename($path_to_image), TRUE);
	//if current page contains resized image, but next image cannot be resized, we'll remember that user prefers resized images and when some of next images will be resizeable, we'll show it resized
	if (('resize' == $_GET['size'] || 'resize' == $_GET['preferredsize']) && $is_resize_senseless) {
		$uri_original .= '&amp;preferredsize=resize';
	}
	if (('resize' == $_GET['size'] || 'resize' == $_GET['preferredsize']) && !$is_resize_senseless) {
		$result = $uri_resize;
	}
	else {
		$result = $uri_original;
	}
	return $result;
}//function get_expanded_navig_url(

//Prints link to album on expanded view
function print_expanded_album_link($album_path, $album_page, $album_picture) {
	//$album_path - relative path to album link to which is wanted
	//$album_page - page of the album
	//$album_picture - picture which should be focused when user clicks this link
	global $ini, $langpack;
	if ($ini['enable_new_window']) { //create link for closing this window
?>
<script language="javascript" type="text/javascript">
<!--
document.write('<a id="page_up" href="javascript:window.close();" class="weatimages_container_navig"><?php echo $langpack['close_window'] ?></a>');
//-->
</script><noscript><?php print('<a id="page_up" href="' . url_compat($_SERVER['SCRIPT_NAME'] . '/' . $album_path . '?page=' . $album_page . '#' . $album_picture) . '" class="weatimages_container_navig">' . $langpack['return_to_album'] . '</a>'); ?></noscript>
<?php
	}//if ($ini['enable_new_window']) {
	elseif ('true' == $_GET['fromthumbnail']) { //create link for return to thumbnails page
?><script language="javascript" type="text/javascript">
<!--
if (history.length > 0) {
document.write('<a id="page_up" href="javascript:history.back();" class="weatimages_container_navig"><?php echo $langpack['return_to_album'] ?></a>');
}
else {
document.write('<?php print('<a id="page_up" href="' . url_compat($_SERVER['SCRIPT_NAME'] . '/' . $album_path . '?page=' . $album_page . '#' . $album_picture) . '" class="weatimages_container_navig">' . $langpack['return_to_album'] . '</a>'); ?>');
}
//-->
</script><noscript><?php print('<a id="page_up" href="' . url_compat($_SERVER['SCRIPT_NAME'] . '/' . $album_path . '?page=' . $album_page . '#' . $album_picture) . '" class="weatimages_container_navig">' . $langpack['return_to_album'] . '</a>'); ?></noscript><?php
	}
	else {
		print('<a id="page_up" href="' . url_compat($_SERVER['SCRIPT_NAME'] . '/' . $album_path . '?page=' . $album_page . '#' . $album_picture) . '" class="weatimages_container_navig">' . $langpack['return_to_album'] . '</a>');
	}
}//function print_expanded_album_link(

//Prints navigation bar for expanded view
function print_expanded_navigation($album_path, &$pictures, $i) {
	//$album_path - relative path to album
	//&$pictures - referencr to array containing picture filenames
	//$i - index of current image in array
	global $ini, $langpack;
	//show links to first and last images, and to thumbnail page
	print('<div align="center" class="weatimages_toppest_navig"><table border="0" cellspacing="0" cellpadding="0"><tr>');
	//create link to first image in album, only if current image isn't first
	if ($ini['enable_slideshow']) {
		echo '<td align="right" width="200" style="padding-right:10px;">';
		if (0 != $i) {//if current image is not the first image, we'll create link to first
			print('<script language="javascript" type="text/javascript"><!--'."\r\n".'document.write(\'<span class="weatimages_hotkey_tip">(Ctrl Home)&nbsp;</span>\');'."\r\n".'//--></script>');
			print('<a id="page_first" href="' . get_expanded_navig_url($album_path.'/'.$pictures[0]) . '" class="weatimages_container_navig"><strong style="font-size:12px; line-height:11px;">&lsaquo;&lsaquo;&nbsp;</strong> ' . $langpack['first_image'] . '</a> ');
		}//if (0 != $i) {
		echo '</td>';
		//create link to thumbnail page (exactly to page number on which located current image)
		echo '<td align="center">';
		$album_page = ceil(($i+1) / ($ini['cols']*$ini['rows'])); //number of album page which contains thumbnail of current image
		print_expanded_album_link($album_path, $album_page, $pictures[$i]);
		echo '</td>';
		//create link to last image in album, if current image isn't last
		echo '<td align="left" width="200" style="padding-left:10px;">';
		$i_last = count($pictures) - 1;
		if ($i < $i_last) {
			print(' <a id="page_last" href="' . get_expanded_navig_url($album_path.'/'.$pictures[$i_last]) . '" class="weatimages_container_navig">' . $langpack['last_image'] . ' <strong style="font-size:12px; line-height:11px;">&nbsp;&rsaquo;&rsaquo;</strong></a>');
			print('<script language="javascript" type="text/javascript"><!--'."\r\n".'document.write(\'<span class="weatimages_hotkey_tip">&nbsp;(Ctrl End)</span>\');'."\r\n".'//--></script>');
		}//if ($pictures[$i+1]) {
		echo '</td>';
		echo '</tr><tr>';
	}//if ($ini['enable_slideshow']) {
	//create link to previous image, if exists
	echo '<td align="right" width="200" style="padding-right:10px;">';
	if ($pictures[$i-1]) {//if previous image exists, we'll create link to it
		print('<script language="javascript" type="text/javascript"><!--'."\r\n".'document.write(\'<span class="weatimages_hotkey_tip">(Ctrl &larr;)&nbsp;</span>\');'."\r\n".'//--></script>');
		print('<a id="page_previous" href="' . get_expanded_navig_url($album_path.'/'.$pictures[$i-1]) . '" class="weatimages_container_navig"><strong style="font-size:12px; line-height:11px;">&lsaquo;&nbsp;</strong> ' . $langpack['previous_image'] . '</a> ');
	}//if ($pictures[$i-1]) {
	echo '</td>';
	//container for slideshow controller
	if ($ini['enable_slideshow']) {
		echo '<td id="slideshow_container" align="center">&nbsp;</td>';
	}
	else {//create link to thumbnail page 
		echo '<td align="center">';
		$album_page = ceil(($i+1) / ($ini['cols']*$ini['rows'])); //number of album page which contains thumbnail of current image
		print_expanded_album_link($album_path, $album_page, $pictures[$i]);
		echo '</td>';
	}
	//create link to next image, if it exists
	echo '<td align="left" width="200" style="padding-left:10px;">';
	if ($pictures[$i+1]) {
		print(' <a id="page_next" href="' . get_expanded_navig_url($album_path.'/'.$pictures[$i+1]) . '" class="weatimages_container_navig">' . $langpack['next_image'] . ' <strong style="font-size:12px; line-height:11px;">&nbsp;&rsaquo;</strong></a>');
		print('<script language="javascript" type="text/javascript"><!--'."\r\n".'document.write(\'<span class="weatimages_hotkey_tip">&nbsp;(Ctrl &rarr;)</span>\');'."\r\n".'//--></script>');
	}//if ($pictures[$i+1]) {
	echo '</td>';
	print('</tr></table></div>');
}//function print_expanded_navigation(

//Output slideshow javascript code to the browser
function print_slideshow() {
	global $ini, $langpack;
	if ($ini['enable_slideshow']) {
?>
<script language="javascript" type="text/javascript">
<!--
var LANGPACK_SLIDESHOW_START = "<?php echo $langpack['slideshow_start'] ?>";
var LANGPACK_SLIDESHOW_STOP = "<?php echo $langpack['slideshow_stop'] ?>";
var SLIDESHOW_INTERVAL = 1000 * <?php echo $ini['slideshow_delay'] ?>;
var strUrlMarker = 'slideshow=true';
var iTimerId = 0;
var bSlideshowRunning = ((location.href.length-strUrlMarker.length) == location.href.lastIndexOf(strUrlMarker)) ? true : false;
var next_obj = null;
var first_obj = null;

function slideshow_init() {
	next_obj = document.getElementById('page_next');
	first_obj = document.getElementById('page_first');
	if (next_obj || first_obj) {
		document.getElementById('slideshow_container').innerHTML = '<a id="slideshow_control" onclick="javascript:slideshow();" style="cursor:pointer">' + ( (bSlideshowRunning && next_obj) ? LANGPACK_SLIDESHOW_STOP : LANGPACK_SLIDESHOW_START ) + '</a>';
	}
	if (bSlideshowRunning && !next_obj) {
		bSlideshowRunning = false;
	}
}

function slideshow_go() {
	location.href = ( (next_obj) ? next_obj.href : first_obj.href ) + '&amp;' + strUrlMarker;
}
function slideshow_start() {
	iTimerId = setTimeout('slideshow_go();', SLIDESHOW_INTERVAL);
	bSlideshowRunning = true;
	document.getElementById('slideshow_control').innerHTML = LANGPACK_SLIDESHOW_STOP;
}
function slideshow_stop() {
	clearTimeout(iTimerId);
	bSlideshowRunning = false;
	document.getElementById('slideshow_control').innerHTML = LANGPACK_SLIDESHOW_START;
}
function slideshow() {
	if (!bSlideshowRunning) slideshow_start();
	else slideshow_stop();
}
function slideshow_onload() {
	if (bSlideshowRunning && next_obj) {
		slideshow_start();
	}
}

slideshow_init();
//-->
</script>
<?php
	}
}//function print_slideshow(

//Output html container with big image
function page_big() {
	global $ini, $langpack, $REQUEST_PATH;
	list($pictures, $others, $dirs, $descs) = load_directory(dirname($REQUEST_PATH), FALSE);
	$i = array_search(basename($REQUEST_PATH), $pictures);
	list(/* $filesize_kb_current */, $imagesize_current, $resizesize_current, $is_resize_senseless_current, $exif_comment_current) = get_image_sizes($REQUEST_PATH);
	if (!$descs[$pictures[$i]]) {
		$descs[$pictures[$i]] = $exif_comment_current;
	}
	//show page header depending on prefences
	if ($ini['enable_filename_display']) {
		html_begin(clean_filename($pictures[$i]), '', '', '');
	}
	else {
		html_begin(($descs[$pictures[$i]])?$descs[$pictures[$i]]:clean_filename($pictures[$i]), '', '', '');
	}
	//print navigational panel	
	print_expanded_navigation(dirname($REQUEST_PATH), $pictures, $i);
	print_slideshow(); //all navigational links just created, now we can initialize slideshow 
	//show title and description
	if ($ini['enable_filename_display']) {
		print('<div align="center" class="weatimages_header">' . clean_filename($pictures[$i]) . '</div>');
		print('<div align="center" class="weatimages_comment">' . $descs[$pictures[$i]] . '</div>');
	}
	else {
		print('<div align="center" class="weatimages_header">' . $descs[$pictures[$i]] . '</div>');
	}
	//show big image
	if (!$ini['enable_resize']) { $is_resize_senseless_current = TRUE; }//resize really senseless when resize completely disabled
	list($uri_original, $uri_resize, /* $uri_thumb */) = get_image_urls(dirname($REQUEST_PATH), basename($REQUEST_PATH), FALSE);
	list($uri_original_contained, $uri_resize_contained, /* $uri_thumb */) = get_image_urls(dirname($REQUEST_PATH), basename($REQUEST_PATH), TRUE);
	print('<div align="center">');
	if ('original' == $_GET['size']) {
		if (!$is_resize_senseless_current) { print('<a href="' . $uri_resize_contained . '">'); }
		print('<img src="' . $uri_original . '" class="weatimages_bigimage"' . ((!$is_resize_senseless_current)?' title="' . $langpack['switch_size_toresized'] . '"':'') . ' alt="' . $pictures[$i] . '" width="'.$imagesize_current[0].'" height="'.$imagesize_current[1].'"/>');
		if (!$is_resize_senseless_current) { print('</a>'); }
	}
	else {
		if (!$is_resize_senseless_current) { print('<a href="' . $uri_original_contained . '">'); }
		print('<img src="' . $uri_resize . '" class="weatimages_bigimage"' . ((!$is_resize_senseless_current)?' title="' . $langpack['switch_size_tofullsize'] . '"':'') . ' alt="' . $pictures[$i] . '" width="'.$resizesize_current[0].'" height="'.$resizesize_current[1].'"/>');
		if (!$is_resize_senseless_current) { print('</a>'); }
	}
	print('</div>');
	if (!$is_resize_senseless_current) {
		print('<div style="font-size:9px; color:#999999;">' . $langpack['switch_size_bottomhelp'] . '</div>');
	}
	//Show last description
	if ($descs[$pictures[$i].'.']) {
		print('<div align="center" class="weatimages_comment">' . $descs[$pictures[$i].'.'] . '</div>');
	}
	html_end();
}//function page_big(

function zip_directory($path) {
	global $ini;
	if ('.' != $path) {
		$zip_filename = preg_replace('|/|', '-', $path) . '.zip';
	}
	else {
		$zip_filename = 'Album.zip';
	}
	$zip_fullpath = dirname(__FILE__) . '/' . $ini['cache_dir'] . '/' . $zip_filename;
	$zip_url = 'http://' . $_SERVER["HTTP_HOST"] . dirname($_SERVER['SCRIPT_NAME']) . '/' . $ini['cache_dir'] . '/' . $zip_filename;
	if (!is_file($zip_fullpath)) {
		if (is_writable($ini['cache_dir'])) {
			exec('zip -1Dj "' . $zip_fullpath . '" "' . dirname(__FILE__) . '/' . $path . '/"* -x \*.php \*.css \*.ini \*.db');
		}
		else {
			fatal_error('Cannot create archive within cache directory.');
		}
	}
	header('Location: ' . $zip_url);
}//function zip_directory($path) {


if ('thumb' == $_GET['action']) {
	//expected that in $REQUEST_PATH variable relative path to source image stored
	resize_manager($REQUEST_PATH, $ini['thumb_size'], '.thumb_' . $ini['thumb_size'] . '_' . $ini['jpeg_quality'] . '.cache', $ini['enable_thumbs_cache']);
}//if ('thumb' == $_GET['action']) {

if ('resize' == $_GET['action']) {
	//expected that in $REQUEST_PATH variable relative path to source image stored
	if (!$ini['enable_resize']) { fatal_error("Fatal error: operation not permitted"); }
	resize_manager($REQUEST_PATH, $ini['resize_size'], '.resize_' . $ini['resize_size'] . '_' . $ini['jpeg_quality'] . '.cache', $ini['enable_resize_cache']);
}//if ('resize' == $_GET['action']) {

if ('noimage' == $_GET['action']) {
	$image = imagecreatetruecolor($ini['thumb_size'], floor(0.75*$ini['thumb_size']));
	$color_bg = imagecolorallocate($image, 255, 255, 255);
	imagefill($image, 0, 0, $color_bg);
	header("Content-Type: image/png");
	imagepng($image);
	imagedestroy($image);
}//if ('noimage' == $_GET['action']) {

//show big image inside html page
if ('big' == $_GET['action']) {
	page_big();
}//if ('big' == $_GET['action']) {

if ('zip' == $_GET['action']) {
	if ($ini['enable_album_zip'] && is_dir($REQUEST_PATH)) {
		zip_directory($REQUEST_PATH);
	}
	else {
		fatal_error('Operation not permitted');
	}
}//if ('zip' == $_GET['action']) {

//show page with thumbnails if correct path requested
if ('' == $_GET['action']) {
	//do some simple checks
	if (!is_dir($REQUEST_PATH)) {
		fatal_error('Album not found', $ini['enable_albums_listing'] ? 'Try to start browsing from the <a href="' . $_SERVER['SCRIPT_NAME'] . '">root album</a>.' : 'Check the album name and then try again.');
	}

	//read directory contents and descriptions
	list($pictures, $others, $dirs, $descs) = load_directory($REQUEST_PATH, FALSE);
	$pictures_count = count($pictures);
	$others_count = count($others);
	$dirs_count = count($dirs);
	if ('.' != $REQUEST_PATH && !$descs['.'] && !$descs['..']) {//try to get album description from descs-file in parental directory
		$parent_descs = load_descriptions(dirname($REQUEST_PATH));
		$descs['.'] = $parent_descs[basename($REQUEST_PATH)];
	}
	
	//show navigational links to all parental directories
	if ($ini['enable_albums_listing'] && '.' != $REQUEST_PATH) {
		$link = ' &nbsp;/&nbsp; ' . clean_filename(basename($REQUEST_PATH));
		for ($path = dirname($REQUEST_PATH); '.' != $path; $path = dirname($path)) {
			$link = ' &nbsp;/&nbsp; <a href="' . url_compat($_SERVER['SCRIPT_NAME'] . '/' . $path) . '">' . clean_filename(basename($path)) . '</a> ' . $link;
		}
		$link = ' <a href="' . $_SERVER['SCRIPT_NAME'] . '">' . $langpack['albums'] . '</a> ' . $link;
		$link = '<div align="center" class="weatimages_toppest_navig" style="text-decoration:underline;">' . $link;
		$link .= '</div>';
	}//if ('.' != $REQUEST_PATH)
	
	html_begin($descs['.'] ? $descs['.'] : basename($REQUEST_PATH), $link, ($descs['.'] || $ini['enable_albums_listing']) ? $descs['.'] : basename($REQUEST_PATH), $descs['..']);
	
	 //show nested albums
	if ($ini['enable_albums_listing'] && $dirs_count > 0) {
		if ($_GET['page'] < 2 && $_GET['addspage'] < 2) {//show other items only if it is first thumbnails page
			$albumspage = ($_GET['albumspage'] > 0) ? $_GET['albumspage'] : 1;
			show_pages_navigator($dirs_count, $ini['albums'], $albumspage, 'albumspage');
			$bound_low = $ini['albums'] * ($albumspage - 1); //lowest index of $pictures[] which should be shown on current page
			$bound_high = ($ini['albums'] * $albumspage) - 1; //highest index of $pictures[] which should be shown on current page
			print('<table border="0" cellspacing="0" cellpadding="0" align="center" width="100%" style="margin-top:5px; margin-bottom:5px;">');
			print('<tr><td colspan="' . $ini['cols'] . '" align="center" valign="top">'
				. '<table border="0" cellspacing="0" cellpadding="0" align="center" width="'. $ini['cols']*$ini['thumb_size'] .'">'
				. '<tr><td align="left" style="font-size:12px; padding-left:5px;">' . $langpack['albums'] .'<a name="weatimagesdirsblock" style="visibility:hidden;">&nbsp;</a></td></tr>'
				. '<tr><td align="center" valign="top" style="padding-left:5px;'
				. ($ini['enable_albums_edging'] ? ' border-color:#AAAAAA; border-top-width:1px; border-top-style:dashed;' : '') . '">'
			);//print('
			print('<table border="0" cellspacing="0" cellpadding="0" align="center" style="font-size:13px;'
				. ((1 == $ini['enable_albums_edging']) ? ' border-color:#AAAAAA; border-left-width:1px; border-left-style:dashed;' : '')
				. '">');
			for ($i = 0; $i < $dirs_count; $i++) {
				if ($i < $bound_low) { continue; } //we still don't reached file which must be first on current page
				if ($i > $bound_high) { break; } //last file on current page was shown on previous iteration
				$uri_target = url_compat($SERVER_PHP_SELF . $dirs[$i]);
				
				if (0 == $i%$ini['albums_cols']) { print('<tr>'); }
				
				if ($ini['enable_albums_thumbs']) {
				     $nested_uri_thumb = get_album_thumb('./'.$REQUEST_PATH.'/'.$dirs[$i]);
				     if (!$nested_uri_thumb[0]) {
					     $nested_uri_thumb[0] = $SERVER_PHP_SELF . '?action=noimage';
					     $nested_uri_thumb[1][0] = $ini['thumb_size'];
					     $nested_uri_thumb[1][1] = ceil(0.75*$ini['thumb_size']);
				     }
				     print('<td align="right" valign="top" style="padding-left:10px; padding-right:0px; padding-top:10px;">'
					     . '<a href="'.$uri_target.'"><img src="' . $nested_uri_thumb[0]
					     . '" style="border-color:#CCCCCC; border-width:1px; border-style:solid;"'
					     . 'width="'.$nested_uri_thumb[1][0].'" height="'.$nested_uri_thumb[1][1].'" alt="'.$dirs[$i].'"/></a>'
					     . '</td><td align="left" valign="top" style="padding-left:10px; padding-right:30px; padding-top:20px;"><span class="weatimages_thumb_album_name">'.clean_filename($dirs[$i]).'</span><br/><span class="weatimages_thumb_album_desc">'.$descs[$dirs[$i]].'</span></td>'
					     );//print(
				} //if (!$ini['enable_albums_thumbs']) {
				else {    
				print('<td align="left" style="padding-left:5px; padding-top:2px; padding-right:10px;">'
					. '<table border="0" cellspacing="0" cellpadding="0"><tr>'
					. '<td align="right" valign="top"><strong>&raquo;</strong>&nbsp;<a href="' . $uri_target . '">' . clean_filename($dirs[$i]) . '</a></td>'
					. ( $descs[$dirs[$i]] ? '<td align="left" valign="top">&nbsp;<strong>:</strong>&nbsp;</td><td align="left" valign="top">'
					. $descs[$dirs[$i]] . '</td>' : '')
					. '</tr></table>'
					. '</td>'
				);//print(
				} //if (!$ini['enable_albums_thumbs']) { ELSE
				
				if ((0 == ($i+1)%$ini['albums_cols']) || ($i == $dirs_count-1)) { print('</tr>'); }
			}//for ($i = 0; $i < $others_count; $i++) {
			print('</table>'
				. '</td></tr></table>'
				. '</td></tr>'
			);//print(
			print('</table>');
			show_pages_navigator($dirs_count, $ini['albums'], $albumspage, 'albumspage');
			print('<br/>');
		}//if ($_GET['page'] < 2)
		else {//it is not first thumbnails page, so we only mention about other items existence
			print('<table border="0" cellspacing="0" cellpadding="0" align="center" width="100%" style="margin-top:5px; margin-bottom:5px;">');
			print('<tr><td colspan="' . $ini['cols'] . '" align="center" valign="top" style="color:#777777;">'
				. '<a href="' . url_compat($SERVER_PHP_SELF . '?' . (($_GET['page'] > 1)?'page':'addspage') . '=1#weatimagesdirsblock') . '">' . $langpack['nested_albums_available'] . '</a>'
				. '</td></tr>'
			);//print(
			print('</table>');
		}//if ($_GET['page'] < 2) else
	}//if ($ini['enable_albums_listing'] && $dirs_count > 0) {
	
	//show thumbnails
	if ($pictures_count > 0) {
		$page = ($_GET['page'] > 0) ? $_GET['page'] : 1;
		$images_on_page = $ini['cols']*$ini['rows'];
		show_pages_navigator($pictures_count, $images_on_page, $page, 'page');
		
		print('<table align="center" cellspacing="10" border="0">');
		$bound_low = $images_on_page * ($page - 1); //lowest index of $pictures[] which should be shown on current page
		$bound_high = ($images_on_page * $page) - 1; //highest index of $pictures[] which should be shown on current page
		$new_row_indicator = 0; //counter for decision when new row must be started
		for ($i = 0; $i < $pictures_count; $i++) {
			if ($i < $bound_low) { continue; } //we still don't reached file which must be first on current page
			if ($i > $bound_high) { break; } //last file on current page was shown on previous iteration
			if (0 == $new_row_indicator++) {//we need to begin new table row
				print('<tr>');
			}
			
			//get image sizes if size indication enabled
			if ($ini['enable_size_lookup']) {
				list($filesize_kb, $imagesize, $resizesize, $is_resize_senseless, $exif_comment) = get_image_sizes($REQUEST_PATH . '/' . $pictures[$i]);
			}//if ($ini['enable_size_lookup']) {
			
			if (!$descs[$pictures[$i]] && $exif_comment) {
				$descs[$pictures[$i]] = $exif_comment;
			}
			
			list($uri_original, $uri_resize, $uri_thumb) = get_image_urls($REQUEST_PATH, $pictures[$i], $ini['enable_html_container']);
			if ($ini['enable_html_container']) {//tell html container that it can return to thumbnails page simply using history.back() javascript call
				$uri_original .= '&amp;fromthumbnail=true';
				$uri_resize .= '&amp;fromthumbnail=true';
			}
			show_thumbnail_cell($uri_original, $uri_resize, $uri_thumb, $filesize_kb, $imagesize, $resizesize, $is_resize_senseless, $pictures[$i], $descs[$pictures[$i]]);

			if ($new_row_indicator == $ini['cols'] || $i == $pictures_count - 1) { //we need to close row if number of columns reached or it was last image
				print('</tr>');
				$new_row_indicator = 0;
			}
		}//for ($i = 0; $i < $pictures_count; $i++) {
		print('</table>');
		show_pages_navigator($pictures_count, $images_on_page, $page, 'page');
	}//if ($pictures_count > 0) {
	
	if ($ini['enable_album_zip'] && ($pictures_count > 0 || $others_count > 0)) {
		print ('<div align="center" style="width:100%;"><a href="'
			. url_compat($SERVER_PHP_SELF . '?action=zip')
			. '">' . $langpack['album_zip'] . '</a></div>'
		);
	}
	
	//show links to non-thumbnailable items
	if ($ini['enable_additional_listing'] && $others_count > 0) {
		print('<table border="0" cellspacing="0" cellpadding="0" align="center" width="100%" style="margin-top:5px; margin-bottom:5px;">');
		if ($_GET['page'] < 2 && $_GET['albumspage'] < 2) {//show other items only if it is first thumbnails page
			$addspage = ($_GET['addspage'] > 0) ? $_GET['addspage'] : 1;
			$bound_low = $ini['additionals'] * ($addspage - 1); //lowest index of $pictures[] which should be shown on current page
			$bound_high = ($ini['additionals'] * $addspage) - 1; //highest index of $pictures[] which should be shown on current page
			print('<tr><td colspan="' . $ini['cols'] . '" align="center" valign="top">'
				. '<table border="0" cellspacing="0" cellpadding="0" align="center" width="'. $ini['cols']*$ini['thumb_size'] .'">'
				. '<tr><td align="left" style="font-size:12px; padding-left:5px;">' . $langpack['additional_items'] . '<a name="weatimagesothersblock" style="visibility:hidden;">&nbsp;</a></td></tr>'
				. '<tr><td align="center" valign="top" style="padding-left:5px;'
				. ($ini['enable_albums_edging'] ? ' border-color:#AAAAAA; border-top-width:1px; border-top-style:dashed;' : '') . '">'
			);//print('
			print('<table border="0" cellspacing="0" cellpadding="0" align="center" style="'
				. ((1 == $ini['enable_albums_edging']) ? ' border-color:#AAAAAA; border-left-width:1px; border-left-style:dashed;' : '')
				. '">');
			for ($i = 0; $i < $others_count; $i++) {
				if ($i < $bound_low) { continue; } //we still don't reached file which must be first on current page
				if ($i > $bound_high) { break; } //last file on current page was shown on previous iteration
				list($uri_original, /* $uri_resize */, /* $uri_thumb */) = get_image_urls($REQUEST_PATH, $others[$i], FALSE);
				$filesize_kb = ceil(filesize($REQUEST_PATH . '/' . $others[$i]) / 1024);
				print('<tr><td align="left" style="padding-left:5px;">'
					. '<table border="0" cellspacing="0" cellpadding="0"><tr>'
					. '<td align="right" valign="top"><strong>&raquo;</strong>&nbsp;<a href="' . $uri_original . '">' . $others[$i] . '&nbsp;(' . $filesize_kb . $langpack['kilobytes'] . ')' . '</a></td>'
					. ( $descs[$others[$i]] ? '<td align="left" valign="top">&nbsp;<strong>:</strong>&nbsp;</td><td align="left" valign="top">'
					. $descs[$others[$i]] . '</td>' : '')
					. '</tr></table>'
					. '</td></tr>'
				);//print(
			}//for ($i = 0; $i < $others_count; $i++) {
			print('</table>'
				. '</td></tr></table>'
				. '</td></tr>'
			);//print(
		}//if ($_GET['page'] < 2 && $_GET['albumspage'] < 2) {
		else {//it is not first thumbnails page, so we only mention about other items existence
			print('<tr><td colspan="' . $ini['cols'] . '" align="center" valign="top" style="color:#777777;">'
				. '<a href="' . url_compat($SERVER_PHP_SELF . '?' . (($_GET['page'] > 1)?'page':'albumspage') . '=1#weatimagesothersblock') . '">' . $langpack['additional_items_available'] . '</a>'
				. '</td></tr>'
			);//print(
		}//if (2 > $_GET['page']) else
		print('</table>');
		if ($_GET['page'] < 2 && $_GET['albumspage'] < 2) { show_pages_navigator($others_count, $ini['additionals'], $addspage, 'addspage'); }
	}//if ($ini['enable_additional_listing'] && $others_count > 0) {
	
	html_end();
}//if ('' == $_GET['action']) {
?>

Return current item: Weatimages