Particular/TI/Projetos/Galeria de Vídeos/index.php

De Cartola
<?php
/* --------------------------------------------------------------
 * Program Name: Ben's Picture Gallery (BPG)
 * Development Site: http://benspicgallery.sourceforge.net
 * Author: Benjamin Roy <bpg (at) 7373.us>
 * License: GPL v2
 * Version Release Date: October 2007
 * Version: 1.05
 * --------------------------------------------------------------
 *
 * Future Plans:
 * 
 * let user choose a prefered mirror or autochoose for them with Javascript
 * 
 * future versions may have a Javascript library dependancy (Prototype, Dojo, Mochikit)
 * to enable cross platform compatibility and new features
 * 
 * make CSS and XSLT for RSS feeds
 * 
 * color highlight for in-cart/out-of-cart status (blank/green)
 * 
 * add option to make new folders hidden to start with, until admin user sets the folder to be visible
 *   - add .hidden suffix to folder name
 * 
 * improve clarity of cart/downloading zip file
 * 
 * make comment editing overlay the whole screen rather than disturbing
 * the layout of the thumbnail grid (need to figure out the proper interface design)
 * 
 * watermarks
 * 
 * variables to control basic CSS styles, color/borders (or maybe allow the whole CSS to be overridden)
 * 
 * animated movie thumbnails
 * ffmpeg -y -i MVI_6693.AVI -s 160x120 -an -r 1 -t 7 -loop_output 0 test.[flv|gif|mp4]
 * another option is using javascript to rotate thru a few images
 * 
 * find a better way to center images for slideshow and single screen image.
 * (the javascript resize seems to interfere with the standard methods)
 * 
 * snipshot image editing, saving another copy of the original with a new name
 * the main reason for this would be for ordering prints
 * 
 */

///////////////////////////////////////////////////////////////////
// Configure these variables as needed
//   to preserve your settings between upgrades, copy this section to 
//   a file named config.php and it will override these values
///////////////////////////////////////////////////////////////////

// this is the real path on the server to the original photos, and
// it can be relative to this bpg.php script or absolute.
$original_photos_dir = 'originais'; // (no trailing slash)

// the name of your gallery
$gallery_name = 'Nossos Videos';

// name to put in the Copyright tag of the RSS feeds
$copyright_owner_name = 'Carlos E. G. Carvalho';

// the name to use for the top level breadcrumb and the RSS feed.
// links to the parent directory of this script.
$home_site_name = 'Videos de Carlos Eduardo e Juliana';

// sort the pictures in the browser by filename or EXIF Date
$sort_style = 'file_mtime';  // filename or file_mtime


// The location of the cached files, it needs to be writable by the webserver and browsable by visitors.
// It's location is relative to this script and it is where all the generated files are stored.
// You will need to create this directory if this script is not in a location writable by the webserver.
// go to the location where this script is, and do "mkdir _cache; chmod 777 _cache;"
$cache_dir = '_cache'; //  (no trailing slash)

// the max size for the cached files, ie 1024 for a 1024x768 pixel image size.
$screen_image_dimension = '1024';    // largest dimension for screen sized images
$thumbnail_image_dimension = '150';  // largest dimension for thumbnail images

// lower quality = smaller file size, 70 seems like a good balance
$jpeg_image_quality = '90';  // the jpeg compression quality 0-100


// external commands that this program depends on
$ffmpeg_cmd = '/usr/local/bin/ffmpeg';  // this converts AVI videos to the Flash FLV format

$flvtool2_cmd = '/usr/local/bin/flvtool2';  // this adds the metadata to the Flash videos for the progress bar to work during playback
$cat_cmd = '/bin/cat'; // this is needed by flvtool2

$zip_cmd = '/usr/local/bin/zip'; // this is used to make a downloadable zip file from the files in the cart


// enable the "buy prints" feature in the cart screen to use digibug
$buy_prints_feature_enabled = FALSE;  // TRUE or FALSE

// URL that digibug will use to access the copies of the original photos for printing.
// Original files are temporarily copied to ./$cache_dir/_orders/ when buying prints, 
// this URL needs to be accessible to Digibug's servers without authentication.
$digibug_orders_dir_url = 'http://localhost/digibug-orders'; // (no trailing slash)
$digibug_company_id = '1312';
$digibug_event_id = '4191';
$digibug_event_id_authuser = '4191';


// To edit jpeg comments or delete the original files the user name must be in this $admin_users array 
// (the original files must be writable by the webserver for this to work).
// The admin users also use a seperate $digibug_event_id so they can get different/wholesale pricing when buying prints.
// The user name is identified by the by the web server's basic auth (.htaccess), so you'll need to use
// Apache's htpasswd and .htaccess files to make these users login
$admin_users = array('cartola'); // example: array( 'alice', 'bob' )

$jhead_cmd = '/usr/local/bin/jhead';  // this program is what does the jpeg comment editing


// enable the load balancing feature
$load_balancing_feature_enabled = FALSE;  // TRUE or FALSE

// the list of sites to use for load balancing
$load_balance_hosts = array( 'http://localhost/photos1', 'http://localhost/photos2' );


// extra lines for the html head section of the do_browser
// useful for loading extra javascript like a visitor stats tracking script
$extra_head_lines = "";


/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
//
// internationalization: translate expressions below to your language
//
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
$lang_add_to_cart = "selecionar";
$lang_all_photos_in_cart = "selecionar todas essas fotos";
$lang_cart = "selecionadas";
$lang_back_to_gallery = "voltar &agrave; galeria";
$lang_download_zip_file = "baixar arquivos num zip";
$lang_no_photos_in_cart = "Voc&ecirc; n&atilde;o possui fotos selecionadas";
$lang_current_cart_options = "Suas op&ccedil;&otilde;es s&atilde;o:";
$lang_buy_prints = "Comprar impress&otilde;es dessas fotos";
$lang_remove_cart = "Desfazer todas as sele&ccedil;&otilde;es";
$lang_photos_in_cart = "foto(s) selecionada(s)";
$lang_remove_from_cart = "desfazer sele&ccedil;&atilde;o";
$lang_refresh = "atualizar";

/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
//
// don't mess with stuff below here unless you know what you are doing
//
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////

// override the variables above so settings can be saved between upgrades
if ( file_exists('config.php') ) {
	include('config.php');
}

// identify the URL of this script for the RSS and buy prints features
if ($_SERVER['HTTPS']) {
	$URLprotocol = 'https://';
	if ($_SERVER['SERVER_PORT'] != '443') $URLport = ':'.$_SERVER['SERVER_PORT'];
	else $URLport = '';
} else {
	$URLprotocol = 'http://';
	if ($_SERVER['SERVER_PORT'] != '80') $URLport = ':'. $_SERVER['SERVER_PORT'];
	else $URLport = '';
}
$site_main_url = $URLprotocol . $_SERVER['SERVER_NAME'] . $URLport . $_SERVER['PHP_SELF'];
$site_main_dir_url = $URLprotocol . $_SERVER['SERVER_NAME'] . $URLport . dirname($_SERVER['PHP_SELF']);

// read the shopping cart cookies from the user's browser
//$cart = $_COOKIE['cart'];

session_start(); // use PHP session to track users shopping cart
$cart = $_SESSION['cart'];

$balance_iterator = 0; //placeholder for which load balancing host to use next

function authorizedUser() {  //decide if the current user has admin priviledges
	global $admin_users;
	$is_admin = FALSE;
	foreach( $admin_users as $user ) {
		if( $_SERVER[PHP_AUTH_USER] == $user ){
			$is_admin = TRUE;
			break;
		}
	}
	return $is_admin;
}

if(!function_exists('scandir')) {  // may only need this function for php4 compatability
	function scandir($dir = './', $sort = 0) {
		$dir_open = @opendir($dir);
		if (! $dir_open) return false;
		while (($dir_content = readdir($dir_open)) !== false) $files[] = $dir_content;
		if ($sort == 1) rsort($files, SORT_STRING);
		else sort($files, SORT_STRING);
		return $files;
	}
}

function specific_filetype( $file ) { //return the specific file type if it is supported, or false if not
 	$type = strtolower( substr($file, -4, 4) );
	switch ($type) {
	case '.jpg':
		$type = '.jpg';
		$handled = TRUE;
		break;
	case 'jpeg':
		$type = '.jpg';
		$handled = TRUE;
		break;
	case '.avi':
		$handled = TRUE;
		break;
	default:
		$handled = FALSE;
		break;
	}
	if ($handled) return $type;
	else return FALSE;
}
 
function handled_filetype( $file ) { //return the file type if it is supported, or false if not
	$type = strtolower( substr($file, -4, 4) );
	switch ($type) {
	case '.png':
		$type = 'image';
		$handled = TRUE;
		break;
	case '.bmp':
		$type = 'image';
		$handled = TRUE;
		break;
	case '.gif':
		$type = 'image';
		$handled = TRUE;
		break;
	case 'jpeg':
		$type = 'image';
		$handled = TRUE;
		break;
	case '.jpg':
		$type = 'image';
		$handled = TRUE;
		break;
	case '.ogg':
		$type = 'video';
		$handled = TRUE;
		break;
	case 'mpeg':
		$type = 'video';
		$handled = TRUE;
		break;
	case '.mov':
		$type = 'video';
		$handled = TRUE;
		break;
	case '.mpg':
		$type = 'video';
		$handled = TRUE;
		break;
	case '.avi':
		$type = 'video';
		$handled = TRUE;
		break;
	default:
		$handled = FALSE;
		break;
	}
	if ($handled) return $type;
	else return FALSE;
}

function safe_path( $path ) {  // scrub a path provided by the browser to make it safe
/* data provided by a user can't be trusted so we need to check it here
   the rules we enforce here are
	1. no '..' allowed in path
	2. don't start with /
*/
	$path = stripslashes (urldecode( stripslashes($path) ));
	$path = trim ( $path, '/\\' );

	if ( strpos($path, '..') !== false ) {
		$path = '';  // don't allow ..
		print "don't mess with the dir parameter!\n";
	}
	if ( substr($path, 0, 1) == '/' ) {
		$path = ''; // don't start with /
		print "Don't mess with the dir parameter!\n";
	}
	return $path;
}

function urlencode_path( $string ) { // encode a file path so it can be used in URLs
//	$result = rawurlencode($string);
//	$result = str_replace("%2F","/",$string);
//	$result = addslashes($string);
	$result = implode("/", array_map("rawurlencode", explode("/", $string)));
	return $result;
}

function file_mtime_sorter($a, $b) {
    global $current_path;
	$a_filepath = "$current_path/$a";
	$b_filepath = "$current_path/$b";

    $a_time = filemtime( $a_filepath );
    $b_time = filemtime( $b_filepath );

    if ($a_time == $b_time) {
        return 0;
    }
    else {
        return ($a_time < $b_time) ? -1 : 1;
    }
}

function get_files_and_dirs( $path, $only_handled_filetypes=TRUE ) { // get all the files and folders in the path requested
	global $cache_dir, $sort_style, $current_path;
	$files = array();
	$dirs = array();
	$files_and_dirs = array();

	if($path == '' || !$path) $path = '.'; // don't allow an empty path

	if( is_dir($path) ) {
		$files = scandir( $path ); // get the directory list for a path
	}

	if (is_array($files)) {
		foreach( $files as $i => $file ) { // separate the file and dirs
			if( substr($file, 0, 1)=="." ) { // ignore files and dirs that start with '.'
				unset( $files[$i] );
			}elseif( is_dir("$path/$file") ) { // dirs
				if ( $file != $cache_dir ) $dirs[] = $file ;
				unset( $files[$i] );
			}elseif( $only_handled_filetypes && (!handled_filetype($file)) ) {
				// we only want handled file types, and this isn't one of them 
				unset( $files[$i] );
			}
		}
	}

    $current_path = $path; // set this global variable for use in the sort function
    //default sort method is alphabetic by filename
    if ($sort_style == "file_mtime") {
        usort($files, "file_mtime_sorter");        
    }

	$files_and_dirs['dirs'] = $dirs;
	$files_and_dirs['files'] = $files;
	return $files_and_dirs;
}

function get_jpg_files( $files ) { // return just the JPEG files from the provided file list
	$jpg_files = array();

	foreach( $files as $file ) {
		if (specific_filetype($file) == '.jpg' ) {
			$jpg_files[] = $file;
		}
	}
	return $jpg_files;
}

function mkdir_r($dirName, $rights=0777){ // take a path and make all the directories if they don't exist yet
	$dirs = explode('/', $dirName);
	$dir='';
	foreach ($dirs as $part) {
		$dir.=$part.'/';
		if (!is_dir($dir) && strlen($dir)>0)
			mkdir($dir, $rights);
	}
}

// due to a Debian bug http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=298061
// the imagerotate function isn't available by default
// http://us3.php.net/manual/en/function.imagerotate.php
if(!function_exists('imageRotate')) {
	function imageRotate($src, $angle, $dummy) {
		$width = imagesx($src);
		$height = imagesy($src);
		if ($angle == 90 || $angle == 270) $dst = imageCreateTruecolor($height, $width);
		else $dst = imageCreateTrueColor($width, $height);
		for ( $y=0 ; $y < $height; $y++ ) {
			for( $x=0; $x < $width; $x++ ) {
				switch ($angle) {
				case 90:
					imagecopy($dst, $src, $y, $width-$x-1, $x, $y, 1, 1);
					break;
				case 180:
					imagecopy($dst, $src, $x, $y, $width-$x-1, $height-$y-1, 1, 1);
					break;
				case 270:
					imagecopy($dst, $src, $height-$y-1, $x, $x, $y, 1, 1);
					break;
				default:
					imagecopy($dst, $src, $x, $y, $x, $y, 1, 1);
				}
			}
		}
		imagedestroy($src);
		return($dst);
	}
}

function makeScaled($im, $size, $new_size, $rotation=0) { // resize the image keeping the same aspect ratio
	$width = $size[0];
	$height = $size[1];

        if($width<=$new_size && $height<=$new_size) return $im;

        if($width>$height) { //fat images, normal landscape format
                $ratio = $width/$new_size;
                $newWidth=$new_size;
                $newHeight = round($height/$ratio,0);
        }elseif($width<$height) {  //tall images, portrait format
                $ratio = $height/$new_size;
                $newHeight = $new_size;
                $newWidth= round($width/$ratio,0);
        }else { //a square image
                $newWidth = $new_size;
                $newHeight = $new_size;
        }

        //make the new image
        $destImage = ImageCreateTrueColor( $newWidth, $newHeight);

        //copy the passed image into the new image at the proper scale
	// Resized is about 30% faster, Resampled is better quality
	ImageCopyResized( $destImage, $im, 0, 0, 0, 0, $newWidth+1, $newHeight+1, $width, $height );
//	// Resampled is better quality but about 30% slower
//	ImageCopyResampled( $destImage, $im, 0, 0, 0, 0, $newWidth+1, $newHeight+1, $width, $height );
//
// ImageMagik is about 10% slower than PHP/GD Resized
//exec("/usr/bin/convert -size 800x800 \"$filepath\" -resize 800x800 \"$cached_screenfile\"");
//if ($rotation > 0)
//	exec("/usr/bin/convert -rotate $rotation \"$cached_screenfile\" \"$cached_screenfile\"");
//exec("/usr/bin/convert -size 160x160 \"$cached_screenfile\" -resize 160x160 \"$cached_thumbfile\"");

	if ($rotation>0) {
		$color = ImageColorAllocate($destImage,255,255,255);
		$destImage = ImageRotate($destImage,$rotation,$color);
	}

	return $destImage;
}

function get_cache_path( $filepath, $size='_thumbnails' ) { // get the path for a _screen or _thumbnail image in the cache
    global $cache_dir, $original_photos_dir;
    $file = basename($filepath);
    $dir = dirname($filepath);

    if ($size == 'original' ) {
        $path = "$original_photos_dir/$dir/$file";
    }
    else {
        $path = "$cache_dir/$dir/$size/$file";
    }

    if (handled_filetype($filepath) == 'video' ) {
        if ($size == '_thumbnails') {
            $path = substr_replace($path, '.jpg', -4);
        }elseif ($size == '_screen') {
            $path = substr_replace($path, '.flv', -4);
        }
    }
    return $path;
}

function get_load_balanced_url( $filepath ) { // returns a verified load balanced URL
	global $load_balancing_feature_enabled;
	global $load_balance_hosts;
	global $balance_iterator;

	if( $load_balancing_feature_enabled ) {
		$url = $load_balance_hosts[$balance_iterator] .'/'. $filepath;
		$balance_iterator++;
		if( $balance_iterator > count($load_balance_hosts)-1 ) {
 			$balance_iterator = 0;
		}
	} else {
		return urlencode_path($filepath);
	}
	return urlencode_path($url);
}


function generate_cached_avi_files( $filepath, $cached_screenfile, $cached_thumbfile ) { // make versions of AVI files for the cache
	global $original_photos_dir;
	global $jpeg_image_quality;
	global $ffmpeg_cmd, $file_cmd, $cat_cmd, $flvtool2_cmd;
	$filepath = "$original_photos_dir/$filepath";

	// use the camera's thm files for movies if possible
	// check for lower or upper case file names
	if ( is_file(preg_replace('/\.[0-9a-zA-Z]+$/','.thm',$filepath)) ) {
		$thmfile = preg_replace('/\.[0-9a-zA-Z]+$/','.thm',$filepath);
	} elseif ( is_file(preg_replace('/\.[0-9a-zA-Z]+$/','.THM',$filepath)) ) {
		$thmfile = preg_replace('/\.[0-9a-zA-Z]+$/','.THM',$filepath);
	} else {
		// no .THM file so need to use ffmpeg to get tumbnail image
		$command = "$ffmpeg_cmd -y -v 0 -i " . escapeshellarg($filepath) .
		    " -s 160x120 -f mjpeg -t 0.001 " . escapeshellarg($cached_thumbfile);
		$command .= " 2>&1";
		$return = exec($command);
		$thmfile = $cached_thumbfile;
	}

	// add the filmstrip border to the thumbnail in the cache
//	$filmstrip = imageCreateFromPNG('filmstrip.png');
	$image = 'iVBORw0KGgoAAAANSUhEUgAAABQAAAB4CAYAAADyv9IsAAAACXBIWXMAAAsT
AAALEwEAmpwYAAAAYElEQVRo3u3UMQ7AIBADwXOU/3/Z+UAKCrobSiSmwNJm
ZjoXzzOXz0Lw/btsm5PHSeoPgSvAyBdQYIFAgQUKrFGAAmsUgRVYIFBggQIL
BAosUGCNAhRYowiswAKBWwP7AQXJJO+EVoJJAAAAAElFTkSuQmCC';
	$image = base64_decode($image);
	$filmstrip = imageCreateFromString($image);

	$filmstrip_width = imagesx($filmstrip);
	$filmstrip_height = imagesy($filmstrip);
	$image = imageCreateFromJpeg($thmfile);
	$size = getimagesize($thmfile);
	$dest_x = $size[0] - $filmstrip_width;
	$dest_y = $size[1] - $filmstrip_height;
	imagecopymerge($image, $filmstrip, 0, 0, 0, 0, $filmstrip_width, $filmstrip_height, 50);
	imagecopymerge($image, $filmstrip, $dest_x, $dest_y, 0, 0, $filmstrip_width, $filmstrip_height, 50);
	ImageJpeg($image, $cached_thumbfile, $jpeg_image_quality);
	imagedestroy($image);
	imagedestroy($filmstrip);

	// generate the Flash FLV version of the file
	$command = "$file_cmd " . escapeshellarg($filepath);
	$width = exec($command);
	// Take the width and hight from an output like this:
	// file_name.avi: RIFF (little-endian) data, AVI, 480 x 640, 23.98 fps, video: XviD, audio: MPEG-1 Layer 3 (mono, 32000 Hz)
	$height = preg_replace("/.*, [0-9]+ x ([0-9]+),.*/", "$1", $width);
	$width = preg_replace("/.*, ([0-9]+) x [0-9]+,.*/", "$1", $width);
	// cif = 352x288
	if ( $width > $height ) {
		$command = "$ffmpeg_cmd -y -v 0 -i ". escapeshellarg($filepath) ." -s cif -ar 44100 -r 24000/1001 -b 500k ". escapeshellarg($cached_screenfile);
	}else {
		$command = "$ffmpeg_cmd -y -v 0 -i ". escapeshellarg($filepath) ." -s cif -ar 44100 -r 24000/1001 -b 500k ". escapeshellarg($cached_screenfile);
	}
	$command .= " 2>&1";
	$return = exec($command);

	// add video duration to flv files metatdata using flvtool2
	$command = "$cat_cmd ". escapeshellarg($cached_screenfile) ." | $flvtool2_cmd -U stdin ". escapeshellarg($cached_screenfile);
	$command .= " 2>&1";
	$return = exec($command);
}

function generate_cached_image_files( $filepath, $cached_screenfile, $cached_thumbfile ) { // make versions of JPEG files for the cache
	global $original_photos_dir;
	global $screen_image_dimension, $thumbnail_image_dimension;
	global $jpeg_image_quality;
	$filepath = "$original_photos_dir/$filepath";

	// find out how the image needs to be rotated on jpeg files
	if ( specific_filetype($filepath) == ".jpg" ) {
	    $exif = exif_read_data($filepath);
	    if(!empty($exif['Orientation'])) {
		switch($exif['Orientation']) {
		    case 1: $rotation = 0; break;
		    case 3: $rotation = 180; break;
		    case 8: $rotation = 90; break;
		    case 6: $rotation = 270; break;
		    default: $rotation = 0; break;
		}
	    }
	} else {
	    $rotation = 0;
	}

	// read the image into memory
	switch (specific_filetype($filepath)) {
	    case '.gif':
		$im = ImageCreateFromgif($filepath);
		break;
	    case '.png':
		$im = ImageCreateFrompng($filepath);
		break;
	    case '.bmp':
		$im = ImageCreateFromwbmp($filepath);
		break;
	    case '.jpg':
		$im = ImageCreateFromJpeg($filepath);
		break;
	}
	$size = GetImageSize($filepath);

	// create the cached screen file and rotate it
	$im = makeScaled($im, $size, $screen_image_dimension, $rotation);
	// save the image file
	ImageJpeg($im, $cached_screenfile, $jpeg_image_quality);
	$size = GetImageSize($cached_screenfile);

	// now reduce it again to the cached thumbnail file
	$im = makeScaled($im,  $size, $thumbnail_image_dimension);
	// save the image file
	ImageJpeg($im, $cached_thumbfile, $jpeg_image_quality);

        ImageDestroy($im); //clean up the old image
}

function generate_cached_files( $filepath ) { // make the cached version of the file
	$file = basename($filepath);
	$dir = dirname($filepath);
	$cached_thumbfile = get_cache_path( $filepath, '_thumbnails' );
	$cached_screenfile = get_cache_path( $filepath, '_screen' );

	if( !is_file($cached_thumbfile) || !is_file($cached_screenfile) ) {

		if ( !is_dir(dirname($cached_thumbfile)) ) mkdir_r(dirname($cached_thumbfile));
		if ( !is_dir(dirname($cached_screenfile)) ) mkdir_r(dirname($cached_screenfile));

	        switch ( handled_filetype($file) ) {
	        case 'image':
			generate_cached_image_files( $filepath, $cached_screenfile, $cached_thumbfile );
	                break;
	        case 'video':
			generate_cached_avi_files( $filepath, $cached_screenfile, $cached_thumbfile );
	                break;
		}
	}
}

function read_exif_name_and_date( $filepath ) { // get the exif file name and photo date from the jpeg file
	global $original_photos_dir;
	$filepath = "$original_photos_dir/$filepath";

	$result = '';
	if ( specific_filetype($filepath) == '.jpg') {
		$exif = exif_read_data( $filepath );
		$result = $exif['FileName'] ." - ". $exif['DateTimeOriginal'];
	}
	return $result;
}

function timestamp_from_exif_DateTimeOriginal( $filepath ) { // get a UNIX timestamp formated time from EXIF data
	$result = '';
	if ( specific_filetype($filepath) == '.jpg') {
		$exif = exif_read_data( $filepath );
        list ($yyyy, $mm, $dd, $h, $m, $s, $junk) = preg_split( '/[: ]/', $exif['DateTimeOriginal']);
		$result = mktime( $h, $m, $s, $mm, $dd, $yyyy);
	}
	return $result;
}

function read_jpeg_comment( $filepath ) { // get the JPEG comment from a file
	global $original_photos_dir, $ffmpeg_cmd;
	$filepath = "$original_photos_dir/$filepath";

	$comments = '';

	// save comments for movies in the thumbnail jpeg file.
	if ( handled_filetype($filepath) == 'video' ) {
	    if( is_file(preg_replace('/\.[0-9a-zA-Z]+$/','.thm',$filepath)) ) {
		$filepath = preg_replace('/\.[0-9a-zA-Z]+$/','.thm',$filepath);
	    } elseif( is_file(preg_replace('/\.[0-9a-zA-Z]+$/','.THM',$filepath)) ) {
		$filepath = preg_replace('/\.[0-9a-zA-Z]+$/','.THM',$filepath);
	    }else {
		// create a thumbnail file if doesnt exist yet
		$command = "$ffmpeg_cmd -y -v 0 -i " . escapeshellarg($filepath) .
		    " -s 160x120 -f mjpeg -t 0.001 " .  substr_replace($filepath, '.thm', -4);
		$command .= " 2>&1";
		exec($command);
		if( is_file(preg_replace('/\.[0-9a-zA-Z]+$/','.thm',$filepath)) ) {
		    $filepath = preg_replace('/\.[0-9a-zA-Z]+$/','.thm',$filepath);
		}
	    }
	}

	if ( specific_filetype($filepath) == '.jpg' || strtolower(substr($filepath, -4, 4)) == ".thm") {
		$exif = exif_read_data( $filepath );
		if (is_array($exif['COMMENT'])) {
			foreach( $exif['COMMENT'] as $comment ) {
				$comments .= "$comment\n";
			}
		}
	}
	return trim($comments);
}

function write_jpeg_comment( $filepath, $comment ) { // save a description in the JPEG comment
    if ( authorizedUser() ) {
	global $original_photos_dir;
	global $jhead_cmd, $ffmpeg_cmd;
	$filepath = "$original_photos_dir/$filepath";

	// save comments for movies in the thumbnail jpeg file.
	if ( handled_filetype($filepath) == 'video' ) {
	    if( is_file(preg_replace('/\.[0-9a-zA-Z]+$/','.thm',$filepath)) ) {
		$filepath = preg_replace('/\.[0-9a-zA-Z]+$/','.thm',$filepath);
	    } elseif( is_file(preg_replace('/\.[0-9a-zA-Z]+$/','.THM',$filepath)) ) {
		$filepath = preg_replace('/\.[0-9a-zA-Z]+$/','.THM',$filepath);
	    }
	}

	list($width, $height, $type, $attr) = getimagesize($filepath);

	if (! file_exists($filepath) ) {
	    return "error: file does not exist.";
	}elseif (! is_writable($filepath) ) {
	    exec("echo $filepath >> log.txt");
	    return "error: file -$filepath- is not writable (try: chmod a+w filename)";
	}elseif ( image_type_to_mime_type( $type ) == "image/jpeg") {
	    // check the file extension and make sure it's really a jpeg
	    // save a description within the JPEG file
	    // jhead -cl "test comment" img_4695.jpg
	    $command = "$jhead_cmd -cl ". escapeshellarg($comment) ." ". escapeshellarg($filepath);
	    $output = exec($command, $full_output, $return_var);
	    if ( $return_var != 0 ) {
		return $output;
	    }else {// successful completion
		chmod($filepath, 0666);
		// keep the file mtime the same for sorting
		touch( $filepath, timestamp_from_exif_DateTimeOriginal($filepath) );
		return 0;
	    }
	}else {
	    if ( preg_match("/\.avi$/i",$filepath) ) {
		// In case of a video avi file will record description on thumbnail
		$thumbnail = get_cache_path($filepath);
		$thumbnail = preg_replace("/$original_photos_dir\//","",$thumbnail);
		$command = "$jhead_cmd -cl ". escapeshellarg($comment) ." ".
		    escapeshellarg($thumbnail);
		$output = exec($command, $full_output, $return_var);
		if ( $return_var != 0 ) {
		    return $output;
		}else {// successful completion
		    return 0;
		}
	    }else {
		print "error: the file does not look like a jpeg or avi";
	    }
	}
    }
}

function purge_abandoned_cache_files( $path ) { // delete cache files that are no longer in the originals
	global $original_photos_dir;
    
	$local_path = "$original_photos_dir/$path";
	$files_and_dirs = get_files_and_dirs( $local_path );
	$original_files = $files_and_dirs['files'];

	$screen_path = dirname(get_cache_path( "$path/.", '_screen' )) ."/";
	$cache_files_and_dirs = get_files_and_dirs( $screen_path, FALSE );
	$files_to_delete = $cache_files_and_dirs['files'];
	$files_to_delete = @array_diff( $cache_files_and_dirs['files'], $original_files);  // this makes it up to 30% faster
	if (is_array($files_to_delete)) {
		foreach ($files_to_delete as $i => $old_file) { // look at each file we are about to delete
			foreach ($original_files as $cur_file) { // compare it to each file that is still in the original path
				if ( substr($old_file, 0, -4) == substr($cur_file, 0, -4) ) { // if the names match without extensions
					unset( $files_to_delete[$i] ); // take it off the list of files to delete
				}
			}
		}
		foreach ( $files_to_delete as $file_to_delete ) {
			unlink("$screen_path$file_to_delete");
		}
	}

	$thumb_path = dirname(get_cache_path( "$path/.", '_thumbnails' )) ."/";
	$cache_files_and_dirs = get_files_and_dirs( $thumb_path, FALSE );
	$files_to_delete = $cache_files_and_dirs['files'];
	$files_to_delete = @array_diff( $cache_files_and_dirs['files'], $original_files);  // this makes it up to 30% faster
	if (is_array($files_to_delete)) {
		foreach ($files_to_delete as $i => $old_file) { // look at each file we are about to delete
			foreach ($original_files as $cur_file) { // compare it to each file that is still in the original path
				if ( substr($old_file, 0, -4) == substr($cur_file, 0, -4) ) { // if the names match without extensions
					unset( $files_to_delete[$i] ); // take it off the list of files to delete
				}
			}
		}
		foreach ( $files_to_delete as $file_to_delete ) {
			unlink("$thumb_path$file_to_delete");
		}
	}

/*
    $original_dirs = $files_and_dirs['dirs'];
	$cache_path = dirname(get_cache_path($path));
	$cache_files_and_dirs = get_files_and_dirs( $cache_path, FALSE );
	$dirs_to_delete = @array_diff( $cache_files_and_dirs['dirs'], $original_files);  // this makes it up to 30% faster
	if (is_array($dirs_to_delete)) {
		foreach ($dirs_to_delete as $i => $old_dir) { // look at each dir we are about to delete
			foreach ($original_dirs as $cur_dir) { // compare it to each dir that is still in the original path
				if ( $old_dir == $cur_dir ) { // if the names match
					unset( $dirs_to_delete[$i] ); // take it off the list of dirs to delete
				}
			}
		}
		foreach ( $dirs_to_delete as $dir_to_delete ) {
//			print "removing dir $cache_path/$dir_to_delete/";
			rmdir_r("$cache_path/$dir_to_delete");
		}
	}
*/
}
function rmdir_r($path) {
  if (!is_dir($path)) {return false;}
  $stack = Array($path);
  while ($dir = array_pop($stack)) {
    if (@rmdir($dir)) {continue;}
    $stack[] = $dir;
    $dh = opendir($dir);
    while (($child = readdir($dh)) !== false) {
      if ($child[0] == '.') {continue;}
      $child = $dir . '/' . $child;
      if (is_dir($child)) {$stack[] = $child;}
      else {unlink($child);}
    }
  }
  return true;
}
function delete_file( $filepath ) { // delete a file
	global $original_photos_dir;
	$path = dirname($filepath);
	$filepath = "$original_photos_dir/$filepath";
	if ( authorizedUser() ) {
		if ( unlink($filepath) ) {
			if ( handled_filetype( $filepath ) == "video" ) {
				if( is_file(preg_replace('/\.[0-9a-zA-Z]+$/','.thm',$filepath)) ) {
					$filepath = preg_replace('/\.[0-9a-zA-Z]+$/','.thm',$filepath);
				}
				elseif( is_file(preg_replace('/\.[0-9a-zA-Z]+$/','.THM',$filepath)) ) {
					$filepath = preg_replace('/\.[0-9a-zA-Z]+$/','.THM',$filepath);
				}
				unlink( $filepath );// convert to .thm file to delete it also
			}
			
			purge_abandoned_cache_files( "$path/" );
			return "0";
		}
	}
	return "error: unable to delete file.";
}

function add_to_cart( $filepath ) {
    $_SESSION['cart'][$filepath] = 1;
    return "0";
}
function remove_from_cart( $filepath ) {
    unset( $_SESSION['cart'][$filepath] );
    return "0";
}
function empty_cart() {
    unset( $_SESSION['cart'] );
    return "0";
}
function add_all_to_cart( $path ) {
	global $original_photos_dir;
	$local_path = "$original_photos_dir/$path";
	$files_and_dirs = get_files_and_dirs( $local_path );
	$files = $files_and_dirs['files'];
	sort($files);
	foreach( $files as $filename ) {
		add_to_cart( "$path/$filename" );
	}
    return "0";
}

function create_rss_icon( $filepath ) {
	$image = imageCreateFromString( base64_decode( 
"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/
AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH1gIMEQohk8eI
2QAAAnZJREFUOMulk0tsTGEcxX/fzDcv01Y7VY+2UqrasfC2ICpILQRBgsRO
JDa1tWgtEDbEBhskQmLlEQsrsWsixnNaiQWpejTDYGY6r87r3rnfvZ/FVBQh
Ev/1yS/n/HOO0FrzPycnrodDVjwRqabzYcuowcQfxB6/QDY3vIkWGzbuOv0x
pbW2pRX7HPEHdNi1YSee0Do8UhCURXT8Pj4rjtslfgLmxvPdy725CNArhEjK
aqIQnrN2Nu/LAbp2D0yTnsL49JDKs2MEK69xTVFmzptB/nGyE2gE0lKZIKqK
+kqE5+e2YDsa39xldPQeINTRi799iMy9furjt/DImhtl1uIDuHBAWIpmkafd
fMwC6ynh9FWsm+uJ3T2CUcwR2naJZNMeHENBVYHzw6cLBRiKiZTJvMEScweL
sPcBgc7tzBq7ROxyH0YhS9veKxQ8PWhDgZoOcICqjbQV2ddDJMZGCLSuoGHf
bcpLB2itvCR57yQA3s1nsQ3rFwcOYFo0ezT+m32YF1czdHQ9lUKWWVtPUGnb
ji96gcy7EQKLNlES7b8DtOlglh0m85rWIKzTj3h5dhsAgb7j1Akwnl6rdWTx
jt8BpSKIw8PMOa8R/SNIG+annpAcHaauYxXZHMgvLwAo6wb0r4CE04Jv/ioA
3G0ryeSgyQ3SyAHwNQ11LhsAx7J/eqKUDvgyKQpvo9R3rcH8MEw94LUhfWUf
ZksnPY1gxcd4deMMjak3uKfVTcT3MxqAbgWMZ2FJCwS9tT18n5kAHA2mglIV
8jaxrjvsAEZldJKNy/w8EoqFIS8k8n9ZngDlJnboCQeZCiIANzB7qtvyH1es
gByQ/AZxvww2gh/aWQAAAABJRU5ErkJggg=="
) );
	imageAlphaBlending($image, true);
	imageSaveAlpha($image, true);
	imagePNG($image, $filepath);
}

function render_thumbnail_area_html( $filepaths ) {
	global $cart, $lang_add_to_cart, $lang_remove_from_cart;
	
	print "<div class='thumbnail-area'>\n";

	foreach( $filepaths as $filepath ) {
		$filename = basename($filepath);
		
		print "<div class='thumbnail-cell'>";

		print "<div class='thumbnail'>\n";
		$jspath = urlencode_path( addslashes($filepath) );
		generate_cached_files("$filepath");
		// link to larger version with exif info, add to cart, etc
		print "<a class='image' href=\"?dir=". urlencode_path($filepath) ."&amp;view=image\">";
		// load balance the <img src= links between available mirrors
		// display a thumbnail image
		$thumb_path = get_cache_path( $filepath, '_thumbnails' ); 
		// It seems Firefox needs this becuase the inline-block CSS rendering is buggy.
		list($w, $h) = getimagesize($thumb_path);
		$title = read_exif_name_and_date($filepath);
		print "<img src=\"". get_load_balanced_url($thumb_path) . "\"";
		print " title=\"$title\" alt='' width='$w' height='$h'";
		print " onerror=\"javascript:this.onerror='';this.src='". urlencode_path($thumb_path) ."';\" />";
		print "</a>\n";
		print "</div>"; //end of thumbnail div

		// print the cart control button
		print "<div class='cartcontrol'>";
		if ( $cart[$filepath]  ) { // file is in the cart
			print "<a id='cartcontrol$filename' title='remove this picture from your cart' href=\"javascript:remove_from_cart('$jspath','cartcontrol$filename');\">$lang_remove_from_cart</a>";
		}else { // not in cart
			print "<a id='cartcontrol$filename' title='put this picture in your cart to buy prints or download it' href=\"javascript:add_to_cart('$jspath','cartcontrol$filename');\">$lang_add_to_cart</a>";
		}
		print "</div>\n";
		
		// print jpeg comments with the tumbnail image;
		print "<div class='comment' id='comment$filename'>". read_jpeg_comment($filepath) . "</div>\n";
		// print the comment editing button
		if ( authorizedUser() ) {
			print "<div class='comment-edit' id='CTRLcomment$filename'\">";
			print "<a href='javascript:void(0);' title='edit the description of this picture' onclick='editComment(\"comment$filename\",\"CTRLcomment$filename\",\"$jspath\")'>edit</a>";
			print "<a href='javascript:void(0);' title='delete the original picture' onclick='deleteFile(\"CTRLcomment$filename\",\"$jspath\")'>delete</a>";
			print "</div>\n";
		}
		
		print "</div>\n"; //end of thumbnail-cell div

		// try to force the browser to display everything available so far
		ob_flush();
		flush();
	}
	print "<div class='spacer'>&nbsp;</div>\n";
	print "</div>\n"; // end of thumbnail-area div
}

function do_browser( $path ) { // display the thumbnail browser interface
	global $gallery_name, $home_site_name, $cache_dir, $site_main_dir_url, $cart;
	global $extra_head_lines, $lang_all_photos_in_cart, $lang_cart;

	test_dependancies(); // display the diagnostics page if needed

	global $original_photos_dir;
	$local_path = "$original_photos_dir";
	if ($path) { $local_path .= "/$path"; }

	$files_and_dirs = get_files_and_dirs( $local_path );
	$files = $files_and_dirs['files'];
	$dirs = $files_and_dirs['dirs'];

	$filepaths = array();
	$photo_count = 0;
	foreach( $files as $filename ) {
		if ( handled_filetype($filename) == 'image' ) { $photo_count++; }
		if ( $path ) { $filepath = "$path/$filename"; }
		else { $filepath = "$filename"; }
		$filepaths[] = $filepath;
	}
	
	purge_abandoned_cache_files( $path );

	$rss_link = FALSE;
	if ( $photo_count > 0 ) {
		$rss_link = "?dir=$path&amp;view=rss";
		$rss_link_alt = "RSS feed";
	}elseif ($path == '' ){
		$rss_link = "?view=rssnew";
		$rss_link_alt = "RSS link to most recent photos";
	}

	print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
	print "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n";
	print "<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>\n";

	print "<head>\n";
	print "<link rel='stylesheet' href='?view=css' type='text/css' />\n";
	if ( $rss_link ) {
		print "<link rel='alternate' href=\"$rss_link\" title=\"$rss_link_alt\" type='application/rss+xml' />\n";
	}
	print "<title>$gallery_name</title>\n";
	print $extra_head_lines;
	print "<script type=\"text/javascript\" src=\"?view=js\"></script>\n";
	print "</head>\n";
	print "<body>\n";

	print "<div class='header'>\n";

	$site_parent_dir_url = dirname($site_main_dir_url) .'/';
	print "<div class='breadcrumbs'>";
	$parts = explode( "/", (trim($path,"/")) );
	if ( !$path || $path=='/' ) {
		print "<a href=\"$site_parent_dir_url\">$home_site_name</a>/";
	}else {
		print "<a href=\"?dir=\">$home_site_name</a>/";
	}

	$crumbpath = "";
	for ( $i=0; $i<count($parts); $i++) {
		$part = $parts[$i];
		if ( !$part ) { break; }
		$crumbpath .= "$part/";
		if ( $i == count($parts)-1 ) { print "<span class='foldername'>$part</span>/"; }
		else { print "<a href=\"?dir=$crumbpath\">$part</a>/"; }
	}
	print "</div>\n";

	print "<div class='links'>\n";

	if ( authorizedUser() ) {
		if ( $_COOKIE['view_admin_controls'] == "show" ) {
			print "<a id='view_admin_controls' href=\"javascript:writeCookie('view_admin_controls','hide','90','/');";
			print "UpdateAdminControls('view_admin_controls','hide');\">";
			print "hide admin controls</a>\n";
		}else { // hide or no cookie set
			print "<a id='view_admin_controls' href=\"javascript:writeCookie('view_admin_controls','show','90','/');";
			print "UpdateAdminControls('view_admin_controls','show');\">";
			print "show admin controls</a>\n";
		}
	}

	if ( $photo_count > 0 ) {
		$jspath = urlencode_path( addslashes($path) );
		print "<a href=\"javascript:void(0);\" onclick=\"window.open('?dir=$jspath&amp;view=slideshow', 'Slideshow', 'scrollbars=0,status=0,resizable=1,width='+screen.width+',height='+screen.height+',top=0,left=0'); return false;\">";
		print "slideshow</a>";
	}

	print "<span id='cartlink'>";
	print "<a href=\"?dir=$path&amp;view=cart\">$lang_cart</a>";
	print "</span>";

	print "</div>\n";
	// add the rss icon for programs like iPhoto
	if ( $rss_link ) {
		$rss_icon_file = "$cache_dir/rss.png";
		if ( !file_exists($rss_icon_file) ) {
			if ( !is_dir($cache_dir) ) mkdir_r($cache_dir);
//			copy("http://benspicgallery.sourceforge.net/rss.png", $rss_icon_file);
			create_rss_icon($rss_icon_file);
		}
		print "<span class='rsslink'><a href=\"$rss_link\">";
//		print "<img src='$rss_icon_file' alt='$rss_link_alt' title='$rss_link_alt' border='0' />";
		print "<img src='$rss_icon_file' alt='$rss_link_alt' title='$rss_link_alt' />";
		print "</a></span>";
	}
	print "</div>\n";  // end of header div
	
	// print out the directory and files
	foreach( $dirs as $dir ) {
		print "<div class='folder'>\n";
		if ($path) { $dir_link = "$path/$dir"; }
		else { $dir_link = "$dir"; }
		print "<a href=\"?dir=$dir_link\">$dir</a>\n";
		print "</div>\n";
	}

	render_thumbnail_area_html( $filepaths );

	print "<div class='footer'>";
	if ( count($files) > 0 ) {
		print "<a href=\"";
		$jspath = urlencode_path( addslashes( dirname($filepath) ) );
		print "javascript:add_all_to_cart( '$jspath' );\">$lang_all_photos_in_cart</a>\n";
	}
	print "</div>\n";

	print "<div class='project-link'><a href='http://benspicgallery.sourceforge.net/'>Powered by BPG</a></div>\n";

	print "</body></html>\n";
} // end of do_browser

function do_screen_image( $filepath ) { // display a single file
	global $gallery_name;
	global $cart, $lang_add_to_cart;
	$filename = basename($filepath);
	$jspath = urlencode_path( addslashes($filepath) );
	
	print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
	print "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n";
	print "<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>\n";
	
	print "<head>\n";
	print "<link rel='stylesheet' href='?view=css' type='text/css' />\n";
	print "<title>$gallery_name</title>\n";
	print "<script type=\"text/javascript\" src=\"?view=js\"></script>\n";
	print "</head>\n";
	print "<body class='singleImage'>\n";
	
	print "<div class='screenImage'>";
	$screen_path = get_cache_path( $filepath, '_screen' );
	$thumbnail = preg_replace("/screen/","thumbnails",$screen_path);
	$thumbnail = preg_replace("/flv/","jpg",$thumbnail);
	
	if ( handled_filetype($filepath) == 'video' ) {
		$flvurl = get_load_balanced_url( $screen_path );
		print "
		<script type='text/javascript' src='swfobject.js'></script>
		<p id='player1'>
		<a href='http://www.macromedia.com/go/getflashplayer'>Get the Flash Player</a> to see this player.</p>
		<script type='text/javascript'>
		//movie size 352x288 + space for user controls
        var s1 = new SWFObject('flvplayer.swf','single','352','310','7');
        s1.addParam('allowfullscreen','true');
        s1.addVariable('file','$flvurl');
        s1.addVariable('autostart','true');
        s1.addVariable('image','$thumbnail');
        s1.write('player1');
		</script>
		";

	}else {
		list($w, $h) = getimagesize( $screen_path );
		print "<img id='screenimage' src=\"". get_load_balanced_url($screen_path) ."\" width='$w' height='$h' alt='large image' onload=\"shrinkImageToScreen(getObjectByID('screenimage'));\" />";
	}
	print "</div>\n";

	// print jpeg comments with the tumbnail image;
	if ( authorizedUser() ) {
		print "<div class='comment' id='comment' onclick='edit(\"comment\")'>";
	}else {
		print "<div class='comment' id='comment'>";
	}
	$comments = read_jpeg_comment( $filepath );
	if ( strlen($comments) > 0 ) {
		print $comments;
	}
	print "</div>\n";

	print "<div class='cartcontrol'>";
	if ( $cart[$filepath]  ) { // file is in the cart
		print "<a id='cartcontrol' title='remove this picture from your cart' href=\"javascript:remove_from_cart('$jspath','cartcontrol');\">remove from cart</a>";
	}else { // not in cart
		print "<a id='cartcontrol' title='put this picture in your cart to buy prints or download it' href=\"javascript:add_to_cart('$jspath', 'cartcontrol');\">$lang_add_to_cart</a>";
	}
    print "<a id='exif_display' title='display details about this picture' href=\"?file=$filepath&amp;view=exif_display\">EXIF details</a>";
	print "</div>\n";

	print "</body></html>\n";
} // end of do_screen_image

function do_exif_display( $filepath ) {
	$file = get_cache_path( $filepath, 'original' );
	
	print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
	print "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n";
	print "<html>\n";
	print "<head>\n";
	print "<link rel='stylesheet' href='?view=css' type='text/css' >\n";
	print "<title>Image Details</title>\n";
	print "</head>\n";
	
	print "<body>\n";
	
	print "<table align='center' border='0' cellpadding='0' cellspacing='15'>\n";
	
	if ( handled_filetype($filepath) == 'video' ) {
	    if( is_file(preg_replace('/\.[0-9a-zA-Z]+$/','.thm',$filepath)) ) {
		    $filepath = preg_replace('/\.[0-9a-zA-Z]+$/','.thm',$filepath);
	    }
	    elseif( is_file(preg_replace('/\.[0-9a-zA-Z]+$/','.THM',$filepath)) ) {
		    $filepath = preg_replace('/\.[0-9a-zA-Z]+$/','.THM',$filepath);
	    }
	    $file = get_cache_path( $filepath, 'original' );
	} else {
		print "<tr><td colspan=2><img src=\"?view=exif_thumbnail&amp;file=$filepath\" alt=''></td></tr>\n";
	}

	$exif = @exif_read_data($file, 0, true);
	if ( $exif !== FALSE ) {
		print "<tr><td>Date/Time: </td><td>".$exif['EXIF']['DateTimeOriginal']."</td></tr>\n";
		print "<tr><td>Filename: </td><td>".$exif['FILE']['FileName']."</td></tr>\n";
		print "<tr><td>Size: </td><td>".round($exif['FILE']['FileSize']/1024/1000, 1)." Mb</td></tr>\n";
		print "<tr><td>Width x Height: </td><td>".$exif['EXIF']['ExifImageWidth']." x ".$exif['EXIF']['ExifImageLength']."</td></tr>\n";

		print "<tr><td>Camera: </td><td>".$exif['IFD0']['Model']."</td></tr>\n";

		print "<tr><td>Aperture: </td><td>".$exif['COMPUTED']['ApertureFNumber']."</td></tr>\n";

		$val = $exif['EXIF']['ExposureTime'];
		if( strpos($val, '/') ) {
			list ($dividend, $divisor) = split('/', $val);
			if ( is_numeric($dividend) && is_numeric($divisor) ) {
				$cval = $dividend/$divisor;
			}
		}
		if ( substr($dividend, -1, 1)=='0' && substr($divisor, -1, 1)=='0' ) {
			$dividend = trim($dividend, '0');
			$divisor = trim($divisor, '0');
		}
		print "<tr><td>Exposure: </td><td>$dividend/$divisor sec</td></tr>\n";

		$val = $exif['EXIF']['FocalLength'];
		if( strpos($val, '/') ) {
			list ($dividend, $divisor) = split('/', $val);
			if ( is_numeric($dividend) && is_numeric($divisor) ) {
				$val = $dividend/$divisor;
			}
		}
		print "<tr><td>Focal Length: </td><td>".$val;
		if ($exif['EXIF']['FocalLengthIn35mmFilm']) {
			print " (FocalLengthIn35mmFilm = ".$exif['EXIF']['FocalLengthIn35mmFilm'].")";
		}
		print "</td></tr>\n";

		print "<tr><td>ISO Sensitivity: </td><td>".$exif['EXIF']['ISOSpeedRatings']."</td></tr>\n";

		if ($exif['EXIF']['Flash']) $val = 'yes';
		else $val = 'no';
		print "<tr><td>Flash: </td><td>".$val."</td></tr>\n";

		//Exposure program that the camera used when image was taken. '1' means manual control, '2' program normal, '3' aperture priority, '4' shutter priority, '5' program creative (slow program), '6' program action(high-speed program), '7' portrait mode, '8' landscape mode.
		switch ($exif['EXIF']['ExposureProgram']) {
			case '0': $val = 'Automatic'; break;
			case '1': $val = 'Manual control (M)'; break;
			case '2': $val = 'Auto shutter and aperture (P)'; break;
			case '3': $val = 'Aperture Priority (A)'; break;
			case '4': $val = 'Shutter Priority (S)'; break;
			case '5': $val = 'program creative'; break;
			case '6': $val = 'program action'; break;
			case '7': $val = 'portrait'; break;
			case '8': $val = 'landscape'; break;
			default: $val = $exif['EXIF']['ExposureProgram'];
		}
		print "<tr><td>Shooting Mode: </td><td>".$val."</td></tr>\n";

		//Exposure metering method. '0' means unknown, '1' average, '2' center weighted average, '3' spot, '4' multi-spot, '5' multi-segment, '6' partial, '255' other.
		switch ($exif['EXIF']['MeteringMode']) {
			case '1': $val = 'Average'; break;
			case '2': $val = 'Center-weighted'; break;
			case '3': $val = 'Spot'; break;
			case '4': $val = 'Multi-spot'; break;
			case '5': $val = 'Matrix (multi-segment)'; break;
			case '6': $val = 'Partial'; break;
			default: $val = $exif['EXIF']['MeteringMode'];
		}
		print "<tr><td>Metering mode: </td><td>".$val."</td></tr>\n";

		switch ($exif['IFD0']['Orientation']) {
			case 1: $val = 'Landscape (horizontal)'; break;
			case 3: $val = 'Inverted Landscape'; break;
			case 8: $val = 'Portrait (vertical)'; break;
			case 6: $val = 'Portrait (vertical)'; break;
		}
		print "<tr><td>Orientation: </td><td>".$val."</td></tr>\n";
	}
	else {
		print "<tr><td>no exif data available for this file type</td></tr>\n";
	}
	print "</table>\n";
	print "</body>\n";
	print "</html>\n";
}

function get_exif_embedded_thumbnail( $filepath ) {
    $file = get_cache_path( $filepath, 'original' );
	$image = exif_thumbnail($file, $width, $height, $type);
	if ($image!==false) {
	    header('Content-type: ' .image_type_to_mime_type($type));
	    echo $image;
	    exit;
	} else {
	    echo 'No thumbnail available';
	}
}

function do_rss( $path ){ // return an rss version of the browser page
	global $original_photos_dir;
	global $home_site_name;
	global $site_main_url, $site_main_dir_url;
	global $copyright_owner_name;
	$local_path = "$original_photos_dir/$path";
	$files_and_dirs = get_files_and_dirs( $local_path );
	$files = $files_and_dirs['files'];	
	$original_path = "$original_photos_dir/$path";
	$title = basename($path);
	
	header("Content-Type: text/xml");
	header("Pragma: no-cache");
	print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
	
	print "<rss version=\"2.0\">\n";
	print "<channel>\n";
	print "  <title>$home_site_name photocast $title</title>\n";
	
	// the rest of these are optional for iPhoto's photocast
	print "  <link>$site_main_url</link>\n";
	print "  <language>en-US</language>\n";
	print "  <generator>$site_main_url</generator>\n";
	print "  <lastBuildDate>". date(r, filemtime( $original_path )) ."</lastBuildDate>\n";
	print "  <copyright>". date(Y, filemtime( $original_path )) ." $copyright_owner_name</copyright>\n";
//	print "  <description>$home_site_name photos from $path</description>\n";
//	print "  <ttl>1440</ttl>";


	foreach( $files as $file ) {
		$screen_path = $site_main_dir_url .'/'. urlencode_path( get_cache_path( "$path/$file", '_screen' ) );
		print "<item>\n";

		// these all work with iPhoto
//		print "<description>&lt;p>&lt;a href=\"$screen_path\">&lt;img src=\"$screen_path\" alt=\"photo\" title=\"\" style=\"float:left; padding-right:10px; padding-bottom:10px;\"/>&lt;/a>&lt;/p>&lt;br clear=all></description>";
//		print "  <description><![CDATA[<img src=\"$screen_path\" alt=\"\" />]]></description>\n";
		print "  <description>&lt;img src=\"$screen_path\"/&gt;</description>\n";
		
		print "  <title>$file</title>\n";
		print "  <link>$site_main_url?dir=$path</link>\n";
		print "  <pubDate>". date(r, filemtime("$local_path$file")) ."</pubDate>\n";
		// the rest of these are optional for iPhoto's photocast
		//print "  <guid isPermaLink=\"true\">$screen_path</guid>\n";
		//print "  <category>photocast_test_category</category>\n";
		print "</item>\n\n";
	}
	print "</channel>\n";
	print "</rss>\n";
} // end of do_rss

function most_recent_photo_folder_rss() { // rss feed for the most recent folder of files
	global $original_photos_dir;
	$local_path = $original_photos_dir;

	$files_and_dirs = get_files_and_dirs( $local_path );
	$files = $files_and_dirs['files'];
	$dirs = $files_and_dirs['dirs'];

	// get the most recent year directory
	sort($dirs);
	$mostrecentdir = $dirs[count($dirs)-1];

	$yeardir = $mostrecentdir;
	$local_path .= "/$mostrecentdir";
	$files_and_dirs = get_files_and_dirs( $local_path );
	$files = $files_and_dirs['files'];
	$dirs = $files_and_dirs['dirs'];

	$mostrecentdir = $dirs[0];
	foreach ($dirs as $dir) {
		if (filemtime( "$local_path/$dir" ) > filemtime( "$local_path/$mostrecentdir" )) {
			$mostrecentdir = $dir;
		}
	}
	$mostrecentdir = "$yeardir/$mostrecentdir";

	do_rss( "$mostrecentdir/" );
}

function do_slideshow( $path ) { // display the slideshow page
	global $original_photos_dir, $gallery_name;
	$path = stripslashes($path);
	$local_path = "$original_photos_dir/$path";
	$files_and_dirs = get_files_and_dirs( $local_path );
	$files = $files_and_dirs['files'];
	$files = get_jpg_files($files);
	
	print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
	print "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n";
	print "<html>\n";
	
	print "<head>\n";
	print "<link rel='stylesheet' href='?view=css' type='text/css' >\n";
	print "<title>$gallery_name Slideshow $path</title>\n";
	print "<script type=\"text/javascript\" src=\"?view=js\"></script>\n";
	print "<script type='text/javascript'>\n";
	print "<!-- you need a browser that has Javascript for this slideshow\n";
	
	foreach( $files as $i => $file ) {
		$files[$i] = "$path/$file";
	}
	print "imageFiles = new Array (\n";
	foreach( $files as $i => $filepath ) {
		$screen_path = get_load_balanced_url( get_cache_path( "$filepath", '_screen' ) );
		print "\"$screen_path\"";
		if ( $i+1 < count($files) ) print ",";
		print "\n";
	}
	print ");\n";
	
	print "imageWidths = new Array(\n";
	foreach( $files as $i => $filepath ) {
		$screen_path = get_cache_path( "$filepath", '_screen' );
		list($width, $height) = @getimagesize($screen_path);
		print "\"$width\"";
		if ( $i+1 < count($files) ) print ",";
		print "\n";
	}
	print ");\n";
	
	print "imageHeights = new Array(\n";
	foreach( $files as $i => $filepath ) {
		$screen_path = get_cache_path( "$filepath", '_screen' );
		list($width, $height) = @getimagesize($screen_path);
		print "\"$height\"";
		if ( $i+1 < count($files) ) print ",";
		print "\n";
	}
	print ");\n";
?>	
	
	var delay = 5000; //default time delay between slides in milliseconds
	
	var playing;
	var nextSlide;
	var fileIndex = 0;
	var imageFilesCount = imageFiles.length - 1;
	var mouseMovementTimer = 3000;

	function imageDimensions(w, h) { /* an object to hold a reference to the image Dimensions*/
		this.width = w
		this.height = h
	}
	function getFileIndex(direction) {
		i = fileIndex + direction;
		if (i > imageFilesCount) {
			i = 0;
		}
		if ( 0 > i ) {
			i = imageFilesCount;
		}
        return(i);
	}
	function changeImage(direction) {
//		if (document.images) {
			fileIndex = getFileIndex(direction);
			var imageDim = new imageDimensions( imageWidths[fileIndex], imageHeights[fileIndex] );
			shrinkImageToScreen( imageDim );
			var screenimage_div = getObjectByID('screenimage_div');
			screenimage_div.innerHTML = "<img src='" + imageFiles[fileIndex] + "' width='"+ imageDim.width +"' height='"+ imageDim.height +"'>";

//			if (direction == '0') { direction++; }
			n = getFileIndex(direction);
			var preloadImage = new Image();
			preloadImage.src = imageFiles[n];
//		}
		updatePlayPauseButton();
		hideControls();
	}
	function playAndPause() {
		if (playing == true) {
			stop();
		}
		else {
			playing = true;
			nextSlide = setInterval('changeImage(1)', delay);
		}
		updatePlayPauseButton();
	}
	function updatePlayPauseButton() {
		var button_obj = getObjectByID('PlayPauseButton');
		if (playing == true) {
			button_obj.innerHTML = 'Playing (press to pause)';
		}
		else {
			button_obj.innerHTML = 'Paused (press to play)';
		}
	}
	function stop() {
		if (playing == true) {
			playing = false;
			window.clearInterval(nextSlide);
		}
	}
	function changeSpeed() {
		var speedForm = document.forms[0].speedMenu.selectedIndex;
		if (speedForm == 0) {
			delay = 15000; // Very Slow
		} else if (speedForm == 1) {
			delay = 7000;  // Slow
		} else if (speedForm == 2) {
			delay = 5000;  // Medium is the default
		} else if (speedForm == 3) {
			delay = 3000;  // Fast
		} else {
			//unknown speed
		}
		stop();
		playAndPause();
	}


	var mouseMovement = setInterval('hideControlsCountdown()', 200);
	document.onmousemove=showControls;
	document.onmousedown=showControls;
	document.onkeyup=showControls;
	function showControls(event){
		mouseMovementTimer = 3000;
		document.getElementById('slidecontrols').style.display = "block";
		if (event.type == 'keyup') {
			keyCode = event.keyCode;
			if (keyCode == 39) { // right arrow
				stop();
				changeImage(1);
			}else if (keyCode == 37) { // left arrow
				stop();
				changeImage(-1);
			}else if (keyCode == 32) { // spacebar
				playAndPause();
			}else if (keyCode == 8) { // backspace
				window.close();
			}else if (keyCode == 27) { // escape
				window.close();
			}
		}
	}
	function hideControls() {
		if (1 > mouseMovementTimer) {
			document.getElementById('slidecontrols').style.display = "none";
		}
	}
	function hideControlsCountdown() {
		if (mouseMovementTimer > 0) {
			mouseMovementTimer = mouseMovementTimer - 200;
		}
	}


	//  end of hiding from old broswers -->
	</script>

	</head>
	<body class='slideshow' onload='changeImage(0);playAndPause();'>

	<div class='slideshow_page'>
	<div class='slideshow_page_vcenter'>

	<div class='slideshow_controls' id='slidecontrols'>
		<form action='javascript::void(0);'>
		<a href='javascript:window.close();'><?php print "$lang_back_to_gallery"; ?></a>
		<a href='javascript:stop();changeImage(-1)'>&lt;-- Previous</a>
		<a id='PlayPauseButton' href='javascript:playAndPause()'>Play/Pause</a>
		<a href='javascript:stop();changeImage(1)'>Next --&gt;</a>
		Speed: <select name='speedMenu' onchange='changeSpeed();'>
		<option>Very Slow <option>Slow <option selected>Medium <option>Fast
		</select>
		</form>
	</div>
	
	<div class='slideshow_image' id='screenimage_div'>
	<!-- img src='' name='screenimage' id='screenimage' -->
	</div>

	</div>
	</div>
	
	</body></html>
<?php
} // end of do_slideshow

function do_css( $layout_type ) { // return the css page for controling the layout
	header('Content-type: text/css');
	$tomorrow = time() + (1 * 24 * 60 * 60);
	header("Expires: ". date('D, d M Y', $tomorrow) . " 00:00:00 GMT");
	header('Cache-Control: maxage=86400');
	header('Pragma: public');
print "

body {
	background-color: LightGrey;
}
body.cart {
	line-height: 170%;
}
body.cart a:hover {
	background-color: #FFA500;
	border:0px;-moz-border-radius:8px;
}
div.cart_options {
	display: block;
	float: left;
	margin:20px;
	padding: 0px 10px 0px 0px;
	border: 1px solid black;
}
body.singleImage {
	background-color: LightGrey;
	text-align: center;
}

/*html { height: 100%; }*/
body.slideshow {
	background-color: black;
	display: table;
	text-align: center;
	width: 100%;
	height: 100%;
/*	border:solid 3px; color: red; */
}
div.slideshow_page {
	display: table-cell;
	height: 100%;
	vertical-align: middle;
/*	border:solid 3px; color: green; */
}
div.slideshow_page_vcenter {
	text-align: center;
	vertical-align: middle;
	height: 95%; /* this isn't great but it makes the image a bit more vertically centered*/
/*	border:solid 3px; color: grey; */
}
div.slideshow_image {
/*	border:solid 3px; color: orange; */
}
div.slideshow_controls {
	position: absolute; top: 0px; left: 0px; right: 0px;
	color: white;  /* for plain text */
	background-color: black;
	margin:0px;
	padding:6px;
	opacity:.85;
}
div.slideshow_controls a:link { 
	color: white;
	text-decoration: none;
	border:solid 1px;
	margin:20px;
	padding: 2px;
}
div.slideshow_controls a:visited { /* IE6 needs this, in addition to the a:link section */
	color: white;
	text-decoration: none;
	border:solid 1px;
	margin:20px;
	padding: 2px;
}
div.slideshow_controls a:hover { 
	color: #CCCCCC;
	background-color: #333333;
	text-decoration: none;
	border:solid 1px;
	margin:18px;
	padding: 4px;
}

div.folder a{
	display: table;
	border:solid 1px;-moz-border-radius:20px;
	background-color: MintCream;
	width: 70%;
	line-height: 170%;
	padding-left: 5%;
	padding-right: 5%;
}
div.folder a:hover {
	background-color: #FFA500;
}
div.folder a:link {
	color: #000000;
}
div.folder a:visited {
	color: #000000;
}


div.header {
	display:table;
	background-color: WhiteSmoke;
	width:100%;
        padding:4px;
}
div.header div.breadcrumbs {
	display:table-cell;
	text-align: left;
	vertical-align: middle;
}
div.header div.breadcrumbs a:link {
	color: #000000;
        padding:4px;
}
div.header div.breadcrumbs a:visited {
	color: #000000;
        padding:4px;
}
div.header div.breadcrumbs a:hover {
	color: #000000;
        padding:4px;
	background-color: #FFA500;
	border:0px;-moz-border-radius:8px;
}
div.header span.foldername {
        padding:4px;
}
div.header div.links {
	display:table-cell;
	text-align: right;
	vertical-align: middle;
}
div.header div.links a:link{
	color: #000000;
        text-decoration: none;
        border:solid LightGrey 1px;-moz-border-radius:8px;
        margin:10px;
        padding:2px;
}
div.header div.links a:visited{
	color: #000000;
        text-decoration: none;
        border:solid LightGrey 1px;-moz-border-radius:8px;
        margin:10px;
        padding:2px;
}
div.header div.links a:hover{
	color: #000000;
	background-color: #FFA500;
	text-decoration: none;
	border:solid 1px;-moz-border-radius:8px;
	margin:8px;
	padding:4px;
}
div.header span.rsslink {
        margin-left:10px;
}
div.header span.rsslink img {
        border:0px;
}


div.footer {
	text-align: center;
        padding:15px;
}
div.footer a:link{
	background-color: WhiteSmoke;
	text-decoration: none;
        border:solid Grey 1px;-moz-border-radius:8px;
        margin:10px;
        padding:2px;
}
div.footer a:visited{
	background-color: WhiteSmoke;
	text-decoration: none;
        border:solid Grey 1px;-moz-border-radius:8px;
        margin:10px;
        padding:2px;
}
div.footer a:hover{
	background-color: #FFA500;
	text-decoration: none;
	border:solid 1px;-moz-border-radius:8px;
	margin:8px;
	padding:4px;
}


.thumbnail-area {
	text-align: center;
}
.thumbnail-area div.thumbnail-cell {
	float: left;  /* may be able to take out width/height now with float: left*/
/*	display: -moz-inline-box;/* causes problems with image sizes in Firefox
				solution is to add width/height to images*/
/*	display: inline-block; */
	vertical-align: top;
	margin: 7px 7px 15px 7px;  /*top right bottom left*/
	padding: 0px;
}
div.spacer {
	clear: both; /* makes a blank line between floating objects */
}
.thumbnail-area div.thumbnail {
	display: block; 
	width: 160px;
	height: 160px;
	padding: 5px;
}
.thumbnail-area a.image {
	display:table-cell;
	text-align: center;
	vertical-align: middle;
	width: 160px;
	height: 160px;
	padding: 4px;
}
.thumbnail-area span.deleted-thumb {
/* this is what replaces an image when it is deleted */
	display:table-cell;
	text-align: center;
	vertical-align: middle;
	width: 160px;
	height: 160px;
}
.thumbnail-area div.comment {
	display:block;
	font-size: .9em;
	line-height: 1.1;
	width: 165px;  /**/
/*	width: 200px; /**/
	height: 50px;
}
.thumbnail-area a:hover {
	background-color: #FFA500;
	border:0px;-moz-border-radius:8px;
}
.thumbnail-area img {
	border: solid 1px #000;
}

div.comment {
	display: table;
/*	border: solid 1px #000; /* if authorizedUser() then make the comment area clickable */
	width:100%;
}
div.comment textarea{
	float:left;
	display: table-cell;
	border: solid 1px #000;
	width:100%;
	background-color: #FFFFFF;
}
div.cartcontrol a{
	display: inline;
	line-height: 170%;
	padding: 5px;
	margin: 10px;
}
div.cartcontrol a:hover {
	background-color: #FFA500;
	border:0px;-moz-border-radius:8px;
}

div.project-link {
	display: block;
	text-align: center;
	font-size: xx-small;
}
div.project-link a:hover{
        color: #000000;
        background-color: #FFA500;
        text-decoration: none;
        border:solid 1px;-moz-border-radius:8px;
        margin:8px;
        padding:4px;
}

div.comment-edit a{
        margin:10px;
        padding:2px;
}
";

	if ( $_COOKIE['view_admin_controls'] == "show" ) {
	print "
div.comment-edit{
	display: inline;
	line-height: 170%;
	padding: 5px;
}
	";
	}else {
	print "
div.comment-edit{
	display: none;
	line-height: 170%;
	padding: 5px;
}
	";
	}

print "
.diagnostics p {
	line-height: 170%;
	font-size: large;
	padding: 4px;
}
.diagnostics div.good {
	padding: 2px;
}
.diagnostics div.error {
	background-color: #FFE4E1;
	padding: 2px;
}
";
} // end of do_css

function do_javascript() { // return the javascript page for client side controls
	$tomorrow = time() + (1 * 24 * 60 * 60);
	header("Expires: ". date('D, d M Y', $tomorrow) . " 00:00:00 GMT");
	header('Cache-Control: maxage=86400');
	header('Pragma: public');
?>
var winW;
var winH;
if (document.documentElement && document.documentElement.clientWidth) {
	winW = document.documentElement.clientWidth;
	winH = document.documentElement.clientHeight;
} else if (document.body && document.body.clientWidth) {
	winW = document.body.clientWidth;
	winH = document.body.clientHeight;
} else {
	winW = window.innerWidth;
	winH = window.innerHeight;
}
//alert( navigator.appName + " window size is " + winW +" x "+ winH );

var ajax;
var isIE = false;
if (window.XMLHttpRequest) { // branch for native XMLHttpRequest object
	ajax = new XMLHttpRequest();
} else if (window.ActiveXObject) { // branch for IE/Windows ActiveX version
	isIE = true;
	ajax = new ActiveXObject('MSXML2.XMLHTTP.3.0'); // this is what Microsoft recommends for IE5/IE6 (abort() method is not available)
}
if (!ajax) {
  alert("Error initializing XMLHttpRequest!");
}

function getObjectByID(objectId) { // get an object by it's tag ID value
	if (document.getElementById && document.getElementById(objectId)) {
		return document.getElementById(objectId);
	} else if (document.all && document.all(objectId)) {
		return document.all(objectId);
	} else {
		return false;
	}
}
function addslashes(str) {
	str=str.replace(/\'/g,'\\\'');
	return str;
}
function stripslashes(str) {
	str=str.replace(/\\'/g,'\'');
	return str;
}
function trim(myString) {
	return myString.replace(/^\s*|\s*$/g,"");
}

function editComment(comment_div, ctrl_div, filepath) {
	var comment_obj = getObjectByID(comment_div);
	var currentText = comment_obj.innerHTML;
	if (currentText == '' ) currentText = 'put your description here';
	comment_obj.innerHTML = '<textarea name=comments>' + currentText + '<\/textarea>';
	var ctrl_obj = getObjectByID(ctrl_div);
	ctrl_obj.innerHTML = '<a href="javascript:void(0);" onclick="saveComment(\'' + comment_div + '\',\'' + ctrl_div + '\',\'' + filepath + '\')" >[save]<\/a>';
}
function saveComment(comment_div, ctrl_div, filepath) {
	// get the new text
	var comment_obj = getObjectByID(comment_div);
	var textarea_obj = comment_obj.firstChild;
	var currentText = textarea_obj.value;

	// update the comment display
	comment_obj.innerHTML = currentText;

	// update the comment controls
	var ctrl_obj = getObjectByID(ctrl_div);
	ctrl_obj.innerHTML = '<a href="javascript:void(0);" onclick="editComment(\'' + comment_div + '\',\'' + ctrl_div + '\',\'' + filepath + '\')" >[edit]<\/a>';

	// submit the change to the server for saving
	if (!isIE) ajax.abort;
	ajax.open('POST', '?view=ajax');
	ajax.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
	ajax.send('cmd=writecomment&filepath=' + filepath +'&comment=' + currentText);
	ajax.onreadystatechange = function () { alertXMLresponse() };
}

function deleteFile(ctrl_div, filepath) {
	var ctrl_obj = getObjectByID(ctrl_div);
	if (confirm('This file will be permanently deleted, are you sure?')) { 
		// submit the change to the server for saving
		if (!isIE) ajax.abort;
		ajax.open('POST', '?view=ajax');
		ajax.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
		ajax.send('cmd=deletefile&filepath=' + filepath );
		ajax.onreadystatechange = function () { deleteFileXMLresponse(ctrl_obj) };
	}
}
function deleteFileXMLresponse(ctrl_obj) {
	if(ajax.readyState == 4){ //finished loading the response
		var response = ajax.responseText;
		if ( response != 0) {
			alert( response );
		}else {
			ctrl_obj.parentNode.innerHTML = "<span class='deleted-thumb'>deleted</span>";
		}
	}
}

function shrinkImageToScreen( image ) { // scale an image to fit within the browser window
	var ratio;
	var w = winW -50;
	var h = winH -50;
	if (image.width > image.height) { // landscape format
		if (image.width > w) { // shrink if it is too wide
			ratio = image.width / w;
			image.width = w;
			image.height = Math.round(image.height / ratio);
		}
		if (image.height > h) { // shrink again if it is still too tall
			ratio = image.height / h;
			image.height = h;
			// for some reason the makes vertical portrait images too skinny
			image.width = Math.round(image.width / ratio);
		}
	} else if (image.height > image.width) { // portrait format
		if (image.height > h) { // shrink if it is too tall
			ratio = image.height / h;
			image.height = h;
			// for some reason this makes vertical portrait images too skinny
			image.width = Math.round(image.width / ratio);
		}
		if (image.width > w) { // shrink again if it is still too wide
			ratio = image.width / w;
			image.width = w;
			image.height = Math.round(image.height / ratio);
		}
	}
}

function UpdateAdminControls( view_admin_controls_linkname, state ) {
	var view_admin_controls_link_obj = getObjectByID(view_admin_controls_linkname);
	var rule_position = 0;
	var num_rules = document.styleSheets[0].cssRules.length;
	for (var i=0; num_rules > i; i++ ) {
		if ( 'div.comment-edit' == document.styleSheets[0].cssRules[i].selectorText ) {
			rule_position = i;
		}
	}
	if ( state == 'hide' ) {
		view_admin_controls_link_obj.innerHTML = "show admin controls";
		view_admin_controls_link_obj.href = "javascript:writeCookie('view_admin_controls','show','90','/');UpdateAdminControls('view_admin_controls','show');";
		document.styleSheets[0].cssRules[rule_position].style.setProperty('display','none','')
	} else if ( state == 'show' ) {
		view_admin_controls_link_obj.innerHTML = "hide admin controls";
		view_admin_controls_link_obj.href = "javascript:writeCookie('view_admin_controls','hide','90','/');UpdateAdminControls('view_admin_controls','hide');";
		document.styleSheets[0].cssRules[rule_position].style.setProperty('display','inline','')
	}
}

function readCookie( name ) {
	var cookie_array = document.cookie.split(';');
	for(var i=0; cookie_array.length > i; i++) {
		var cookie = cookie_array[i];
		cookie = trim(cookie);
		var cookie_parts = cookie.split('=');
		var cookie_name = cookie_parts[0];
		var cookie_value = cookie_parts[1];
		if (cookie_name.indexOf(name) == 0) {
			if ( !cookie_value || cookie_value == ' ' || cookie_value == '') {
				return null;
			}else {
				return unescape( cookie_value );
			}
		}
	}
	return null; // cookie was not found
}
function writeCookie( name, value, expires, path ) {
	// name == cookie name
	// value == cookie value
	// expires == number of days until cookie is deleted, when the browser closes if not specified
	// path == the path below which the browser will make this cookie available
	var expireTime = new Date();
	if ( expires ) expires = expires * 1000 * 60 * 60 * 24;
	var expires_date = new Date( expireTime.getTime() + expires );
	document.cookie = name + '=' +escape( value ) + ( ( expires ) ? ';expires=' + expires_date.toGMTString() : '' ) + ( ( path ) ? ';path=' + path : '' );
}
function deleteCookie( name ) {
	if ( readCookie( name ) ) {
		document.cookie = name +'=;path=/;expires=Thu, 01-Jan-1970 00:00:01 GMT';
	}
}

function add_to_cart( filepath, ctrl_link_id ) {
	if (!isIE) ajax.abort;
	ajax.open('POST', '?view=ajax');
	ajax.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
	ajax.send('cmd=add_to_cart&filepath=' + filepath );
	ajax.onreadystatechange = function () { alertXMLresponse() };
	
	filepath = addslashes(filepath);
	var obj = getObjectByID(ctrl_link_id);
	obj.href = "javascript:remove_from_cart('"+filepath+"', '"+ctrl_link_id+"');";
	obj.innerHTML = 'remove from cart';
	obj.title = 'remove this picture from your cart';
}
function remove_from_cart( filepath, ctrl_link_id ) {
	if (!isIE) ajax.abort;
	ajax.open('POST', '?view=ajax');
	ajax.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
	ajax.send('cmd=remove_from_cart&filepath=' + filepath );
	ajax.onreadystatechange = function () { alertXMLresponse() };
	
	filepath = addslashes(filepath);
	var obj = getObjectByID(ctrl_link_id);
	obj.href = "javascript:add_to_cart('"+filepath+"', '"+ctrl_link_id+"');";
	obj.innerHTML = 'add to cart';
	obj.title = 'put this picture in your cart to buy prints or download it';
}
function empty_cart() {
	if (!isIE) ajax.abort;
	ajax.open('POST', '?view=ajax');
	ajax.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
	ajax.send('cmd=empty_cart' );
	ajax.onreadystatechange = function () { alertXMLresponse() };
	window.location.reload();
}
function add_all_to_cart( path ) {
	if (!isIE) ajax.abort;
	ajax.open('POST', '?view=ajax');
	ajax.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
	ajax.send('cmd=add_all_to_cart&dir='+path );
	ajax.onreadystatechange = function () { alertXMLresponse() };
	window.location.reload();
}
function alertXMLresponse() {
	if(ajax.readyState == 4){ //response from webserver has finished loading
		var response = ajax.responseText;
		if ( response != 0) {
			alert( response );
		}
	}
}


<?php
} // end of do_javascript function

function do_cart( $referer_path ) { // display the files in the user's cart
	global $cart, $buy_prints_feature_enabled, $lang_back_to_gallery, $lang_download_zip_file,
	       $lang_no_photos_in_cart, $lang_current_cart_options, $lang_buy_prints, $lang_remove_cart,
	       $lang_photos_in_cart, $lang_refresh;

	print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
	print "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n";
	print "<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>\n";

	print "<head>\n";
	print "<link rel='stylesheet' href='?view=css' type='text/css' />\n";
	print "<title>$gallery_name Shopping Cart</title>\n";
	print "<script type=\"text/javascript\" src=\"?view=js\"></script>\n";

	print "<script type='text/javascript'>
		writeCookie('cookieTest', 'cookiesEnabled','','/');
		if( !readCookie('cookieTest') ) alert('You must allow cookies for the cart to work.');
		deleteCookie('cookieTest');
	</script>\n";

	print "</head>\n";
	print "<body class='cart'>\n";

	print "<div class='header'>\n";

	print "<div class='breadcrumbs'>";
	print "<a href=\"?dir=$referer_path\">&lt;-- $lang_back_to_gallery</a>\n";
	print "</div>\n";

	print "<div class='links'>\n";
	if (enabled_zip_downloads()) {
		print "<a href='?view=downloadzip'>&nbsp; $lang_download_zip_file &nbsp;</a>";
		print "&nbsp;&nbsp;";
	}
	if ( $buy_prints_feature_enabled ) {
		delete_old_order_files();
		print "<a href='?view=buyprints'>&nbsp; buy prints &nbsp;</a>";
	}
	print "</div>\n";
	print "</div>\n";  // end of header div

	$itemCount = count($cart);
	if ($itemCount > 0 ) {
		print "<h3>$itemCount $lang_photos_in_cart. (<a href='javascript:window.location.reload();'>$lang_refresh</a>) </h3>";
		$filepaths = array();
		foreach ( $cart as $filepath => $quantity ) {
			$filepath = stripslashes($filepath);
			$filepaths[] = $filepath;
		}
		sort( $filepaths );
		render_thumbnail_area_html( $filepaths );
	}
	else {
		print "<h3>$lang_no_photos_in_cart</h3>";
	}

	print "<div class='cart_options'>\n";
	print "$lang_current_cart_options\n";
	print "<ul>\n";
	if (count($cart) > 0 ) {
		if (enabled_zip_downloads()) {
			print "<li><a href='?view=downloadzip'>$lang_download_zip_file</a> </li>";
		}
		if ( $buy_prints_feature_enabled ) {
			print "<li><a href='?view=buyprints'>$lang_buy_prints</a> </li>";
		}
		print "<li><a href=\"javascript:empty_cart();\">$lang_remove_cart</a> </li>";
	}
	print "<li>&lt;-- <a href=\"?dir=$referer_path\"> $lang_back_to_gallery</a> </li>\n";
	print "</ul>\n";
	print "</div>\n";

	print "</body></html>";
} // end of do_cart function

function delete_old_order_files(){ // remove order files that are no longer needed
	global $cache_dir;

	// clear old originals
	$orderdir = "$cache_dir/_orders/originals/";
	$files_and_dirs = get_files_and_dirs( $orderdir );
	$files = $files_and_dirs['files'];
	$dirs = $files_and_dirs['dirs'];
	if (is_array($files)) {
		foreach ($files as $file) {
			// delete files that are older than 30 days, digibug requires 5 days so theres a bit extra
			if ( filemtime( "$orderdir$file" ) < (time() - (30 * 24 * 60 * 60)) ) {
				@unlink ("$orderdir$file");
			}
		}
	}

	// clear old thumbnails
	$orderdir = "$cache_dir/_orders/thumbnails/";
	$files_and_dirs = get_files_and_dirs( $orderdir );
	$files = $files_and_dirs['files'];
	$dirs = $files_and_dirs['dirs'];
	if (is_array($files)) {
		foreach ($files as $file) {
			// delete files that are older than 7 days, digibug requires 5 days so theres a bit extra
			if ( filemtime( "$orderdir$file" ) < (time() - (7 * 24 * 60 * 60)) ) {
				@unlink ("$orderdir$file");
			}
		}
	}
} // end of delete_old_order_files function
function do_buyprints() { // submit the cart to digibug for printing
	global $cache_dir;
	global $cart;
	global $original_photos_dir, $site_main_url, $digibug_orders_dir_url;
	global $digibug_company_id, $digibug_event_id, $digibug_event_id_authuser;

	$orderdir = "$cache_dir/_orders";

	mkdir_r( $orderdir );  // make sure the _orders directory exists
	mkdir_r( "$orderdir/originals" );  // make sure the _orders/originals directory exists
	mkdir_r( "$orderdir/thumbnails" );  // make sure the _orders/thumbnails directory exists

	if (count($cart) < 1 ) {
		print "sorry, you need to put at least 1 file in your cart before ordering prints";
		return FALSE;
	}

	$html = '';
	$html .= "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">
	<html>
	<head>
	  <title>digibug order submit</title>
	  <script type='text/javascript'>
	    // <![CDATA[
	    function go() {
		document.getElementById('digibugForm').submit();
	    }
	   // ]]>
	  </script>
	</head>";
	$html .= "<body onload='go()'>\n";

	// post the order to the digibug site
	// redirect the user to digibug to complete the order
	$html .= "<form id='digibugForm' action=\"http://www.digibug.com/event/order_bug.php\" method=\"post\">\n";
	$html .= "Your files are ready for printing.  Press 'continue' to proceed with your order.\n";
	$html .= "<input type='submit' value='Continue'/>\n";
	$html .= "<input type='hidden' name='digibug_api_version' value='100'>\n";
	$html .= "<input type='hidden' name='company_id' value='$digibug_company_id'>\n";
	if ( authorizedUser() ) {
		$html .= "<input type='hidden' name='event_id' value='$digibug_event_id_authuser'>\n";
	}else {
		$html .= "<input type='hidden' name='event_id' value='$digibug_event_id'>\n";
	}
	$html .= "<input type='hidden' name='cmd' value='addimg'>\n";
	//$html .= "<input type='hidden' name='partner_code' value=''>\n";
	$html .= "<input type='hidden' name='return_url' value=\"$site_main_url\">\n";
	$html .= "<input type='hidden' name='num_images' value=\"". count($cart) ."\">\n";

	// copy all the files to the orders dir
	$i = 0;
	foreach ( $cart as $filepath => $quantity ) {
		$i++;
		$filepath = stripslashes($filepath);
		$filename = basename($filepath);

		// *** Pending correct the treatment of file type after changing function handled_filetype
		if (specific_filetype($filepath) != '.jpg') {
			continue; // skip this file, digibug only accepts JPEG files
		}

		//copy the originals
		$original = "$original_photos_dir/$filepath";
		$destination = "$orderdir/originals/$filename";
		if (!@copy($original, $destination)) {
			if ( !file_exists($destination) ) {
				$html .= "failed to copy $original to $destination\n";
			}
		}
		$original_url = "$digibug_orders_dir_url/originals/$filename";// . urlencode_path($filepath);
		$original_file = "$orderdir/originals/$filename";

		//copy the thumbnails
		$original = get_cache_path( $filepath, '_thumbnails' );
		$thumbname = substr_replace($filename, "thm.jpg", -3, 3);
		$destination = "$orderdir/thumbnails/$thumbname";
		if (!@copy($original, $destination)) {
			if (!file_exists($destination)) {
				$html .= "failed to copy $original to $destination\n";
			}
		}

		$thumb_url = "$digibug_orders_dir_url/thumbnails/$thumbname"; //. urlencode_path(get_cache_path($filepath,'_thumbnails'));
		$thumb_file = "$orderdir/thumbnails/$thumbname";

		//add image to digibug posting
		list ($orig_width, $orig_height) = getimagesize($original_file);
		list ($thumb_width, $thumb_height) = getimagesize($thumb_file);

		$html .= "<input type='hidden' name='image_$i' value=\"$original_url\">\n";
		$html .= "<input type='hidden' name='image_height_$i' value='$orig_height'>\n";
		$html .= "<input type='hidden' name='image_width_$i' value='$orig_width'>\n";

		$html .= "<input type='hidden' name='thumb_$i' value=\"$thumb_url\">\n";
		$html .= "<input type='hidden' name='thumb_height_$i' value='$thumb_height'>\n";
		$html .= "<input type='hidden' name='thumb_width_$i' value='$thumb_width'>\n";
		$html .= "<input type='hidden' name='title_$i' value=\"$filename\">\n";

		$html .= "<input type='hidden' name='backtext_$i' value=\"". substr(read_jpeg_comment($filepath), 0, 64) ."\">\n";
	}
	$html .= "</form>\n";
	$html .= "</body></html>\n";

	// save a copy of this order locally for future reference
	$saved_order_file = "$cache_dir/". $_SERVER['REMOTE_ADDR'] ."-". time();
	file_put_contents ( $saved_order_file, $html );

	print $html;
} // end of do_buyprints function

function do_download_zipped_cart( ) { // download a zip file with of all the files in the cart
	global $cart;
	global $cache_dir;
	global $original_photos_dir;
	global $zip_cmd;
	$local_path = "$original_photos_dir/$path";
	$ipaddr = $_SERVER['REMOTE_ADDR'];

	if (!enabled_zip_downloads()) {
		print "the zip download feature is not available";
		return FALSE;
	}
	if (count($cart) < 1 ) {
		print "sorry, you need to put at least 1 file in your cart before requesting a zip download";
		return FALSE;
	}
	if (count($cart) > 50 ) {
		print "sorry, you can only download 50 files at a time"; // put a cap on the download size since this is very CPU & bandwidth intensive
		return FALSE;
	}
	
	$zipfile = "$cache_dir/$ipaddr.zip";
	// delete any old file before creating a new one for this user
	if ( is_file($zipfile) ) {
		unlink($zipfile);
	}
	$myfiles = "";
	foreach ( $cart as $filepath => $quantity ) {
		// add file to zip archive
		$filepath = safe_path( $filepath );
		$filename = "$local_path$filepath";
		$myfiles .= "\"$filename\" ";
	}
	// 10 seconds for 45 files 154 MB
	// 22 seconds for 101 files 358 MB
	// 80 seconds for 280 files 1158 MB
	$command = "$zip_cmd -j -0 \"$zipfile\" $myfiles";
	$return = exec($command);
	
/*	// 120 seconds for 45 files 154 MB
	foreach ( $cart as $filepath => $quantity ) {
		// add file to zip archive
		$filepath = safe_path( $filepath );
		$filename = "$local_path$filepath";
		$command = "$zip_cmd -j -0 \"$zipfile\" \"$filename\"";
		$return = exec($command);
	}
*/
/*	// 80 seconds for 45 files 154MB
	$zip = new ZipArchive();
	if ($zip->open($zipfile, ZIPARCHIVE::CREATE)!==TRUE) {
		exit("cannot open <$zipfile>\n");
	}
	foreach ( $cart as $filepath => $quantity ) {
		// add file to zip archive
		$filepath = safe_path( $filepath );
		$filename = "$local_path$filepath";
		$zip->addFile($filename);
	}
	$zip->close();
*/

	//return zip archive to user
	if ($fd = fopen ($zipfile, "r")) {
		$size= filesize($zipfile);
		header("Content-Description: File Transfer");
		header("Content-Type: application/force-download");
		header("Content-Disposition: attachment; filename=\"photos.zip\"");
		header("Content-Length: ".$size);
		header("Cache-control: private"); //use this to open files directly
		//@readfile($zipfile);
		while(!feof($fd)) {
			$buffer = fread($fd, 2048);
			echo $buffer;
		}
		fclose ($fd);
		// delete the file after it's been transfered
		unlink($zipfile);
	}
} // end of do_download_zipped_cart function

function enabled_flv_conversion(){
	global $ffmpeg_cmd;
	if ( $ffmpeg_cmd == '' ) return FALSE;
	else return TRUE;
}
function enabled_flv_progress_metadata(){
	global $flvtool2_cmd, $cat_cmd;
	if ( $flvtool2_cmd == '' && $cat_cmd == '' ) return FALSE;
	else return TRUE;
}
function enabled_jpeg_comment_writing(){
	global $jhead_cmd;
	if ( $jhead_cmd == '' ) return FALSE;
	else return TRUE;
}
function enabled_zip_downloads(){
	global $zip_cmd;
	if ( $zip_cmd == '' ) return FALSE;
	else return TRUE;
}
function test_ffmpeg_cmd(){
	global $ffmpeg_cmd;
	if ( is_executable($ffmpeg_cmd) ) return TRUE;
	else return FALSE;
}
function test_flvtool2_cmd() {
	global $flvtool2_cmd, $cat_cmd;
	if ( is_executable($flvtool2_cmd) && is_executable($cat_cmd) ) return TRUE;
	else return FALSE;
}
function test_jhead_cmd(){
	global $jhead_cmd;
	if ( is_executable($jhead_cmd) ) return TRUE;
	else return FALSE;
}
function test_zip_cmd(){
	global $zip_cmd;
	if ( is_executable($zip_cmd) ) return TRUE;
	else return FALSE;
}
function test_exif_features(){
	if( function_exists('exif_read_data') ) return TRUE;
	else return FALSE;
}
function test_gd2_features(){
	if( function_exists('imageCreateFromString') && 
	    function_exists('imageCreateTrueColor')  &&
	    function_exists('imageCreateFromJpeg') ) 
	return TRUE;
	else return FALSE;
}
function test_readable_photo_dir(){
	global $original_photos_dir;
	if ( is_dir($original_photos_dir) ) return TRUE;
	else return FALSE;
}
function test_writable_cache_dir(){
	global $cache_dir;
	if ( is_dir($cache_dir)  && is_writable($cache_dir) ) {
		return TRUE;
	}
	else {
		mkdir_r($cache_dir);
		if ( is_dir($cache_dir) && is_writable($cache_dir) ) return TRUE;
		else return FALSE;
	}
}

function test_dependancies() {
	// test for the dependancies and display the diagnostics page if there are any failures
	// if it's enabled, test for it and don't proceed until it's manually disabled
	// if it's disabled, ignore it.
	if ( 	!test_gd2_features() 	||
		!test_exif_features() 	||
		!test_readable_photo_dir() 	||
		!test_writable_cache_dir() 	||
		( enabled_flv_conversion() && !test_ffmpeg_cmd() ) ||
		( enabled_flv_progress_metadata() && !test_flvtool2_cmd() ) ||
		( enabled_jpeg_comment_writing() && !test_jhead_cmd() ) || 
		( enabled_zip_downloads() && !test_zip_cmd() )
	   ) {
 		do_diagnostics();
		exit(0);
	}
}
function do_diagnostics() {
	global $gallery_name, $original_photos_dir, $cache_dir;
	global $ffmpeg_cmd, $flvtool2_cmd, $cat_cmd, $jhead_cmd, $zip_cmd;

	print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
	print "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n";
	print "<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>\n";

	print "<head>\n";
	print "<link rel='stylesheet' href='?view=css' type='text/css' />\n";
	print "<title>$gallery_name Configuration Diagnostics</title>\n";
	print "</head>\n";
	print "<body class='diagnostics'>\n";
	
	print "<h2>Configuration diagnostic page for Ben's Picture Gallery</h2>\n";
	print "It looks like you need to configure a few things to make this gallery work.\n";
	print "<br>To fix these issues, you need to edit the configuration variables at the beginning of the bpg.php file.\n";
	print "<br>For more information goto the project site at <a href='http://benspicgallery.sourceforge.net/'>http://benspicgallery.sourceforge.net/</a>.\n";
	print "<hr>\n";
/*
 * On Mac OS 10.4 install PHP from http://www.entropy.ch/software/macosx/php/
 * then install macports and use it to install ffmpeg and jhead
 * sudo port -d selfupdate
 * sudo port install ffmpeg
 * sudo port install jhead
 * /opt/local/bin/ffmpeg
 * /opt/local/bin/jhead
 */
	
	if ( !test_readable_photo_dir() ) {
		print "<p>You must configure the location for your original photos:</p>\n";
		print "<ol>\n";
		print "<div class=error>\"$original_photos_dir/\" does not exist</div>\n";
		print "</ol>\n";
	}
	if ( !test_writable_cache_dir() ) {
		print "<p>The \$cache_dir must be writable:</p>\n";
		print "<ol>\n";
		print "<div class=error>\"$cache_dir/\" must be writable by the web server</div>\n";
		print "</ol>\n";
	}
	
	if( !test_gd2_features() ) {
		print "<p>PHP needs GD2 installed:</p>\n";
		print "<ol>\n";
		print "<div class=error>Your PHP does not appear to have GD2 installed.</div>\n";
		print "</ol>\n";
	}

	if( !test_exif_features() ) {
		print "<p>PHP needs EXIF installed:</p>\n";
		print "<ol>\n";
		print "<div class=error>Your PHP does not appear to have EXIF installed.</div>\n";
		print "</ol>\n";
	}

	if ( !test_ffmpeg_cmd() && enabled_flv_conversion() ) {
		print "<p>ffmpeg is required for converting movies to the flv format:</p>\n";
		print "<ol>\n";
		if (file_exists($ffmpeg_cmd)) {
			print "<div class=error>ffmpeg is not executable by the webserver (try \"chmod 777 $ffmpeg_cmd\" to fix this)</div>\n";
		}else {
			print "<div class=error>missing file \"$ffmpeg_cmd\", please install it or set the \$ffmpeg_cmd variable to the correct location.  To disable this feature set the variable to ''</div>\n";
		}
		print "</ol>\n";
	}

	if ( !test_flvtool2_cmd() && enabled_flv_progress_metadata() ) {
		print "<p>flvtool2 and cat are required for progress bar to work when playing flv files:</p>\n";
		print "<ol>\n";
		if ( !is_executable($flvtool2_cmd) ) {
			if (file_exists($flvtool2_cmd)){
				print "<div class=error>flvtool2 is not executable by the webserver (try \"chmod 777 $flvtool2_cmd\" to fix this)</div>\n";
			}else {
				print "<div class=error>missing file \"$flvtool2_cmd\", please install it or set the \$flvtool2_cmd variable to the correct location.  To disable this feature set the variable to ''</div>\n";
			}
		}
		if ( !is_executable($cat_cmd) ) {
			if (file_exists($cat_cmd)){
				print "<div class=error>cat is not executable by the webserver (try \"chmod 777 $cat_cmd\" to fix this)</div>\n";
			}else {
				print "<div class=error>missing file \"$cat_cmd\", please install it or set the \$cat_cmd variable to the correct location.  To disable this feature set the variable to ''</div>\n";
			}
		}
		print "</ol>\n";
	}

	if ( !test_jhead_cmd() && enabled_jpeg_comment_writing() ) {
		print "<p>jhead is needed for saving comments in the jpeg files:</p>\n";
		print "<ol>\n";
		if (file_exists($jhead_cmd)){
			print "<div class=error>jhead is not executable by the webserver (try \"chmod 777 $jhead_cmd\" to fix this)</div>\n";
		}else {
			print "<div class=error>missing file \"$jhead_cmd\", please install it or set the \$jhead_cmd variable to the correct location.  To disable this feature set the variable to ''</div>\n";
		}
		print "</ol>\n";
	}

	if ( !test_zip_cmd() && enabled_zip_downloads() ) {
		print "<p>zip is needed for downloading photos:</p>\n";
		print "<ol>\n";
		if (file_exists($zip_cmd)){
			print "<div class=error>zip is not executable by the webserver (try \"chmod 777 $zip_cmd\" to fix this)</div>\n";
		}else {
			print "<div class=error>missing file \"$zip_cmd\", please install it or set the \$zip_cmd variable to the correct location.  To disable this feature set the variable to ''</div>\n";
		}
		print "</ol>\n";
	}
	
	print "</body>\n</html>";
}

///////////////////////////////////////////////////////////
$path = safe_path( $_REQUEST['dir'] );
$file = safe_path( $_REQUEST['file'] );

//print "<pre>"; print_r ($_REQUEST); print "</pre>";

// choose an execution route based on _GET URL variable 'view'
if ( $_REQUEST['view'] == 'rss' ) { // do an rss feed for these images
	do_rss( $path );
}
elseif ( $_REQUEST['view'] == 'rssnew' ) { // do an rss feed for these images
	most_recent_photo_folder_rss();
}
elseif ( $_REQUEST['view'] == 'image' ) { // do a single screen sized image page
//	$file = safe_path($_GET['file']);
	do_screen_image( $path, $file );
}
elseif ( $_REQUEST['view'] == 'exif_display' ) {
	do_exif_display( "$file" );
}
elseif ( $_REQUEST['view'] == 'exif_thumbnail' ) {
	get_exif_embedded_thumbnail( "$file" );
}
elseif ( $_REQUEST['view'] == 'css' ) { // return the css that will format the layout
	$layout_type = $_REQUEST['layout'];
	do_css( $layout_type );
}
elseif ( $_REQUEST['view'] == 'js' ) { // return the javascript library
	do_javascript();
}
elseif ( $_REQUEST['view'] == 'ajax' ) { // respond to the XMLHttpRequest
	$filepath = safe_path( $_REQUEST['filepath'] );
	$path = safe_path( $_REQUEST['dir'] );
	$comment = stripslashes($_REQUEST['comment']);

	if ($_REQUEST['cmd'] == 'add_to_cart' ) {
		add_to_cart( $filepath );
	}elseif ($_REQUEST['cmd'] == 'remove_from_cart' ) {
		remove_from_cart( $filepath );        
	}elseif ($_REQUEST['cmd'] == 'empty_cart' ) {
		empty_cart();
	}elseif ($_REQUEST['cmd'] == 'add_all_to_cart' ) {
		add_all_to_cart( $path );
	}elseif ($_REQUEST['cmd'] == 'writecomment' && authorizedUser() ) {
		print write_jpeg_comment( $filepath, $comment );
	}elseif ($_REQUEST['cmd'] == 'deletefile' && authorizedUser()) {
		print delete_file( $filepath );
	}else {
		print "error: that is not a recognized command.";
	}
}
elseif ( $_REQUEST['view'] == 'slideshow' ) { // do a slideshow for this album
	do_slideshow( $path );
}
elseif ( $_REQUEST['view'] == 'cart' ) { // do the shopping cart
	do_cart( $path );
}
elseif ( $_REQUEST['view'] == 'downloadzip' ) { // download the cart in a zip file
	do_download_zipped_cart();
}
elseif ( $_REQUEST['view'] == 'buyprints' ) { // buy prints thru digibug's api
	do_buyprints();
}
else {
	do_browser( $path ); // do the dir & thumbnail file browser
}

?>