#!/usr/bin/perl -- # Location of config file ###### CHANGE THIS ###### $configfile="http://www.hasta-pronto.net/cgi-bin/album/album.cfg"; ###### CHANGE THIS ###### # Program Version $ver="4.4"; # NOTE: The doucmentation shown below in the POD (Plain Old Documentation) section # is meant to be read through album.html. # # The POD formatting shown here makes it hard to read, so try album.html instead. ######################## START OF POD ######################## =head1 NAME Photo Album - A dynamically generated web based photo album. =head1 SYNOPSIS http://www.hasta-pronto.net/cgi-bin/album/album.pl http://www.hasta-pronto.net/cgi-bin/album/album.pl?function=config http://www.hasta-pronto.net/cgi-bin/album/album.pl?function=enter_desc http://www.hasta-pronto.net/cgi-bin/album/album.pl?function=upload http://www.hasta-pronto.net/cgi-bin/album/album.pl?slideshow=x http://www.hasta-pronto.net/cgi-bin/album/album.pl?configfile=/home/user/www/album.cfg =head1 DESCRIPTION Photo Album is a simple web based program that allows you to simply drop new photo files into a directory, and they will automatically be accessible via the web. It does this by building the photo album on the fly. It can also be used to create static HTML files for certain situations. (This mode is not updated automatically, but is useful for creating a photo CD or viewing pictures without a web server. Users may upload photos directly into your album, if you permit it. To get a feel for all the features and functions, you should see the Revision History section of this document. =head1 INFORMATION Author: Mike Bobbitt (Bobbitt@CdnArmy.ca) For updates, instructions and examples see http://perl.CdnArmy.ca/album on the web. Sometimes this site is a bit out of date. Try contacting me for the latest version if it's been a while since it was updated. Please also note that this is a personal project. I work on it in my spare time, on weekends and evenings, so I may not be able to respond immediately to questions or comments. =head1 MAILING LIST There is a mailing list set up for discussion of album.pl matters. I would recommend that anyone with a support question try sending to the list first. That way, if I am unable to respond right away, it's entirely likely that a peer user will be able to help out. To subscribe, simply send an e-mail to majordomo@cdnarmy.ca with "subscribe album-list" in the message body (quotes not required). To send a message to the list, simply send it to album-list@cdnarmy.ca, however I recommend you subscribe first, so you can receive all responses. =head1 FILES Below is a list of the files and directories that are used by this script, their purpose, and their preferred permissions. The items listed here are the files and directories used by default. Your specific configuration is probably different, but this will give you an idea of what is involved. Each of these paths are web paths. That is, they are as if they were from the web root, not from the file system root. =begin html
File | Description | Permissions |
---|---|---|
/Photo_Album.css | The cascading style sheet for the album. [Optional, set by style_sheet] | World Readable |
/cgi-bin/album.pl | The script itself. | World Executable |
/cgi-bin/album.cfg | The config file. You need to edit this. | World Readable, or writable to your web server if you intend to use the function=config feature. |
/cgi-bin/album.tml | The album template file. You may want to edit this. | World Readable |
/cgi-bin/album_header.tml | The album header sub-template file. You may want to edit this. It's automatically included into album.tml and photo.tml. | World Readable |
/cgi-bin/album_footer.tml | The album footer sub-template file. You may want to edit this. It's automatically included into album.tml and photo.tml. | World Readable |
/cgi-bin/photo.tml | The photo template file. You may want to edit this. | World Readable |
/cgi-bin/album_upload.tml | The upload form template file. You may want to edit this. | World Readable |
/cgi-bin/album_rating.tml | The rating form template file. You may want to edit this. | World Readable |
/img/thmb_photo.gif | The icon for a photo. [Optional, set by icons=1] | World Readable | /img/thmb_album.gif | The icon for an album. [Optional, set by icons=1] | World Readable |
/img/thmb_movie.gif | The icon for a movie. [Optional, set by icons=1] | World Readable |
/Photo_Album/ | Your actual photo album root directory. Images put in here will show up as photos in your gallery. | World Writable |
/Photo_Album/descriptions.txt | Used to describe the photos and albums in your gallery. For formatting rules see below. [Optional] | World Writable |
/Photo_Album/views.txt | Created automatically by this script. Used to keep track of the number of times each photo in this album has been viewed. [Optional, set by viewfile] | World Writable |
/Photo_Album/subdir | A sub album. Can contain more photos and a descriptions.txt file, as desired. | World Writable |
/Photo_Album/somephoto.jpg | A photo in your album. | World Readable |
/Photo_Album/thmb_somephoto.jpg | A thumbnail for a photo in your album. | World Readable |
../logs/gallery.log | Log file to log all photo uploads. Should be above the web root, so people can't browse to it. | World Writable |
../auth_db | Authorization database. Should be above the web root, so people can't browse to it. [Optional, set by authentication_type=0] | World Readable |
Tag | Description |
---|---|
####TITLE#### | The object's short title. As defined in descriptions.txt. |
####DESCRIPTION#### | The object's long description. As defined in descriptions.txt. |
####OBJECT#### | The object itself. This is either the photo (for photos), or the list of photos/albums (for albums). |
####NAV#### | The navigation bar. (Buttons or text links to next, previous and parent objects.) |
####STYLESHEET#### | The complete reference to the style sheet. This will substitute with the entire <link rel="stylesheet" type="text/css" href="$style_sheet"> tag. NOTE: This tag must be in the HEAD section of your HTML. |
####SLIDESHOW#### | Used to replace the slideshow directive, you really don't need to mess with this. NOTE: This tag must be in the HEAD section of your HTML. |
####LEGEND#### | The icon legend, if you elect to show it at all. |
####NOTIFY#### | The e-mail notification form, if you elect to show it at all. |
####ENTERDESC#### | The form that allows you to enter object titles and descriptions, if you're using "function=enter_desc". |
####VIEWS#### | Displays the number of times the photo has been viewed and the date it was last viewed, if using a viewfile. |
####RATINGS#### | Displays the user ratings given for a photo, and a link to add ratings of your own. Only present if using a ratingfile. |
####ALBUMPROG#### | The web path to album.pl. Meant to be used for linking back to your album. |
####FILE=filename.html#### | Automatically inserts the contents of "filename.html" into the template. (Note that it doesn't have to be a HTML file.) Used for SSI like behaviour, common headers/footers, or even nesting templates. |
####STOPSLIDESHOW#### | The "Stop Slideshow" button. Only displayed during a slide show. |
####STOPDEBUG#### | The "Stop Debugging" button. Only displayed when debugging is on. |
####PAGES#### | The multi-page link set. Only displayed when photos_per_page is non-zero, and the number of photos on the current page is greater than that value. |
Tag | Description |
---|---|
####FORMAT#### | The list of valid file formats accepted. Taken from imgexts and/or movieexts as appropriate. |
####SIZE#### | The maximum size allowed for uploaded files. |
####UPLOAD#### | The actual upload form. |
Tag | Description |
---|---|
####RATING#### | Inserts the rating form. |
",2,__LINE__); # Drop the proceeding path (for UNIX) - don't change this $albumprog=~s/.*\/(.*)/$1/; # No change? Then this must be a Win32 machine... - don't change this if ($albumprog eq $0) { $albumprog=~s/.*\\(.*)/$1/; } # Check for command-line parameter to set static mode - don't change this if ($ARGV[0] eq "static") { $create_html_flag=2; } # Explicitly turn off buttons, jump station and multi-paging if creating static HTML if ($create_html_flag) { $usebuttons=0; $jump_to=0; $photos_per_page=0; } if (!$authentication_type) { $protect_album=0; } $albumprog=$webroot."/".$relalbum."/".$albumprog; debug("Web Path to Album (albumprog): $albumprog
\n",2,__LINE__); # Set location of album.pl $homedir=$rootdir; # Load these down into a variable, so we can modify them $username=$form->param('username'); $password=$form->param('password'); # Was a slideshow timer value passed in from the web? if ($form->param('slideshow')) { $slide_timer=$form->param('slideshow'); # Set flag to keep the slide timer in the URL... $slide_timer_passed=1; } # Load this down into a variable, so we can modify it $function=$form->param('function'); # Load this down into a variable, so we can modify it $page=$form->param('page'); # Set default page if (!$page) { $page=1; } ######################## END OF SETUP ######################## ######################## START OF MAIN ######################## # Are we displaying the config screen? if ($function eq $config) { showConfig(); } # Are we actually updating the configuration? if ($function eq $updateconfig) { updateConfig(); } # Check to see we're creating static HTML files if ($create_html_flag) { # *** Temporary action to remove icons and legend for static html... (notify is OK) $icons=$legend=$notify=0; # Copy CSS into root photo album and reference it from there *** # copy(x,"$rootdir$style_sheet"); # *** Title is wrong for photos with no desc (it's last desc in album) - now I forget what that means... print "
This mode is meant to be used to prepare the photo album to be read offline. For example, when a web server is not practical or available, or if you want to burn your album onto a CD-ROM.
This will create an HTML file in each directory (album), and one for each photo. This will allow you to view the photos through this static HTML. (Normally this HTML is built on the fly by the web server). The down side to doing this is that you will have to re-run this process if new photos are added.
HTML print "Generating Static HTML for..."; print "
";
print "$rootdir...";
print "
";
debug("Calling photoAlbum($rootdir)",4,__LINE__);
photoAlbum($rootdir);
debug("Back from photoAlbum($rootdir) call",4,__LINE__);
debug("Calling recursiveScan($rootdir)",4,__LINE__);
&recursiveScan($rootdir);
debug("Back from recursiveScan($rootdir) call",4,__LINE__);
print "
"; print "Created HTML for $static_photos_done photo(s)"; # Any movies? if ($static_movies_done) { print " and $static_movies_done movie(s)"; } print " in $static_albums_done album(s).\n"; if ($static_photos_thumb) { print "
"; print "$static_photos_thumb photo thumbnails were found.\n"; } if ($static_movies_thumb) { print "
"; print "$static_movies_thumb movie thumbnails were found.\n"; } if ($static_albums_thumb) { print "
"; print "$static_albums_thumb album thumbnails were found.\n"; } } else { # Show Login Screen if not already logged in if (($album_password && ($password ne $album_password)) || ($protect_album && !Authenticate($username,$password))) { login(); } &photoAlbum(); } ######################## END OF MAIN ######################## ######################## START OF SUBROUTINES ######################## ########################################################################## =head3 photoAlbum() photoAlbum($manual_override); $manual_override - Start in this album or with this photo (optional) Does the majority of the processing for the photo album =cut sub photoAlbum { my $manual_override=shift; debug("Entered photo_album subroutine
",4,__LINE__); if ($manual_override) { debug("\$manual_override=$manual_override",2,__LINE__); } # Read web environment variables debug("REMOTE_HOST: $ENV{REMOTE_HOST}",3,__LINE__); debug("REMOTE_USER: $ENV{REMOTE_USER}",3,__LINE__); debug("REMOTE_IDENT: $ENV{REMOTE_IDENT}",3,__LINE__); debug("HTTP_USER_AGENT: $ENV{HTTP_USER_AGENT}",3,__LINE__); debug("REQUEST_METHOD: $ENV{REQUEST_METHOD}",3,__LINE__); debug("QUERY_STRING: $ENV{QUERY_STRING}",3,__LINE__); debug("CONTENT_LENGTH: $ENV{CONTENT_LENGTH}",3,__LINE__); #debug("SSL_CLIENT_CN: $ENV{SSL_CLIENT_CN}",3,__LINE__); #debug("SSL_CLIENT_IO: $ENV{SSL_CLIENT_IO}",3,__LINE__); # Check to see if we're being called with function=$upload if ($function eq "$upload") { uploadPhoto(); exit(); } # Check to see if the user is updating a description if ($function eq "$update_desc") { updateDesc($form->param('object'),$form->param('desc_file_loc'),$form->param('title'),$form->param('description')); } # Check to see if the user is adding a rating if ($function eq "$rating_form") { $shortdesc="Add a Rating: ".$form->param('object'); $object=buildTemplate(); display($object); exit(); } # Check to see if the user is adding a rating if ($function eq "$update_rating") { if ($form->param('comments')) { $object="Comment from "; if ($form->param('name')) { $object.=$form->param('name'); } else { $object.="Anonymous"; } $object.=": ".$form->param('comments'); } updateRating($form->param('object'),$form->param('rating_file_loc'),$form->param('rating'),$object); } # Have we been told to stop adding descriptions? if ($form->param('stop_add_desc') eq "stop") { $function=""; } # Translate into shorter variable names if ($form->param('album')) { $album=$rootdir."/".$form->param('album'); } if ($form->param('photo')) { $photo=$form->param('photo'); } # Override album (for creating static HTML) if ($manual_override) { debug("Manual Override is [$manual_override]",2,__LINE__); if (isAPhoto($manual_override)) { $photo=$manual_override; debug("Setting photo to [$photo]",2,__LINE__); $static_filename_to_use="$full_directory.html"; $album=""; } else { $album=$manual_override; debug("Setting album to [$album]",2,__LINE__); if ($full_directory) { # For photo albums to be scanned $static_filename_to_use="$full_directory/$static_html_filename"; } else { # For root photo album $static_filename_to_use="$rootdir/$static_html_filename"; } $photo=""; } } # Is this the top level? if (!($photo || $album)) { $album="$rootdir"; } if ($album) { $middle=$album; } if ($photo) { $middle=$photo; } if ($middle=~/^$rootdir$/i) { $middle=""; } else { $middle=~s/$rootdir\/(.*)/$1/; # No change? Then this must be a Win32 machine... if ($middle eq $rootdir) { $middle=~s/.*\\(.*)/$1/; } } # Open static HTML file... if ($create_html_flag) { # Open the static HTML file open(STATIC,">$static_filename_to_use") || error("not_writable","$static_filename_to_use"); debug("Creating static HTML file at [$static_filename_to_use]",2,__LINE__); } debug("The album is: $album",2,__LINE__); debug("The middle bit is: $middle
",2,__LINE__); $goback=$middle; # Drop the proceeding path (for UNIX) $goback=~s/(.*)\/.*/$1/; # No change? Then this must be a Win32 machine... if ($goback eq $middle) { $goback=~s/.*\\(.*)/$1/; } if ($goback=~/^$middle$/) { $goback=""; } # Keep a copy, so you don't have all the funny web stuff when you do a compare $realgoback=$goback; if (!$usebuttons) { $goback.=passVars(0); } debug("GoBack: $goback
",2,__LINE__); if ($photo) { $descfile=$rootdir."/"; if ($goback) { $descfile.=$goback."/"; } } if ($album) { #$shortalbum=$rootdir."/".$album; $shortalbum=$album; if ($realgoback) { $shortalbum=~s/(.*$realgoback).*/$1\//; } else { $shortalbum=$rootdir."/"; } debug("ShortAlbum: $shortalbum
",2,__LINE__); # If you're updating descriptions, this is the file you want. $desc_to_update="$shortalbum"; openDescfile($shortalbum); if ($album=~/^$rootdir$/i) { $shortalbum="$rootalbumname"; } else { if ($realgoback) { $shortalbum=$middle; $shortalbum=~s/(.*)$realgoback\//$1/; } else { $shortalbum=$middle; } } debug("ShortAlbum: $shortalbum
",2,__LINE__); $shortobject=$shortalbum; getDescription($shortalbum); close(DESC); # Set the description to pass as a default for editing $existing_shortdesc=$shortdesc; if (!$shortdesc) { if ($shortalbum eq $rootalbumname) { $shortdesc="Photo Album"; } else { $shortdesc=$shortalbum; } } $descfile="$rootdir/$middle/"; } # Select directory to read all entries from if ($album) { $dir_to_read="$rootdir/$goback"; } if ($photo) { $dir_to_read="$descfile"; $shortphoto=$photo; $shortphoto=~s/^$realgoback\/(.*)/$1/; } # find next and previous pictures/albums as appropriate debug("Looking for next and previous objects in [$dir_to_read]...",2,__LINE__); @file_list=&readDirectory($dir_to_read); debug("Done Directory Scan, comparing for $shortphoto or $shortalbum...",3,__LINE__); # clear re-used vars $prev_obj_desc=""; $next_obj_desc=""; $this_is_it=0; $next_obj=""; # Prep the "jump station" for the footer if ($jump_to && $middle && $album && $contains_dir) { $jump_station="
",2,__LINE__);
$shortobject=$shortphoto;
$shortdesc="";
$longdesc="";
getDescription($shortphoto);
# Set the description to pass as a default for editing
$existing_shortdesc=$shortdesc;
if (!$shortdesc)
{
$shortdesc=$shortphoto;
}
# If you're updating descriptions, this is the file you want.
$desc_to_update="$descfile";
}
debug("ShortObject: $shortobject",2,__LINE__);
# Make a "text" (not html) version of the long description
$textlongdesc=$longdesc;
$textlongdesc=~s/
//g;
$textlongdesc=~s/\r//g;
$textlongdesc=~s/\n+$//g;
# Build the "next photo" url
if ($create_html_flag)
{
$next_photo_link="$next_obj.html";
}
else
{
$next_photo_link="$albumprog?photo=$realgoback/$next_obj";
}
$next_photo_link.=passVars(0);
# Build navigation buttons/links
$nav_footer=buildNavFooter();
# When a photo is displayed, it is in an HTML page, with a reference to the actual photo.
# The short description is the photo's title, and the long description is displayed below it.
# Description information is read out of $descfile file, in the photo album.
# Save off descriptions
$temp_shortdesc=$shortdesc;
$temp_longdesc=$longdesc;
$actual_object=buildObject();
# Restoredescriptions
$shortdesc=$temp_shortdesc;
$longdesc=$temp_longdesc;
$object_template=buildTemplate();
$object_template=parseLinks($object_template);
debug("Object template is built! [$object_template]",4,__LINE__);
display("$object_template");
# Scan for files and directories under the root directory. Each directory is considered an album.
# Each photo file (.bmp, .gif or .jpg) is considered an photo.
# Display an HTML page listing all albums and photos in given directory.
# Each album's link will call album.pl with the name of the album as an environment variable.
# (album=01 - The Beginning)
# Each picture's link will call album.pl with the name of the photo file as an environment variable.
# Each picture's short description is displayed as the link text.
# (photo=001.jpg)
debug("Leaving photo_album subroutine
",4,__LINE__); if ($usedesc) { close(DESC); } if ($create_html_flag) { close(STATIC); } } ########################################################################## =head3 openDescfile() openDescfile($descfilename); $descfilename - Path to the album you want to read descriptions from. Opens up $descfilename so that photo/album titles/descriptions can be loaded. =cut sub openDescfile { my $descfilename=shift; #$descfilename.="/".$descname; $descfilename.=$descname; debug("Looking for DescFile: [$descfilename]
",3,__LINE__); if (-r $descfilename) { $usedesc=1; open(DESC,"$descfilename"); debug("Using DescFile: [$descfilename]
",3,__LINE__);
}
}
##########################################################################
=head3 getDescription()
getDescription($desctoget);
$desctoget - Photo or album to get description of
Retrieves the title and description of the provided photo or album. Puts the title in $shortdesc and the description in $longdesc, if present.
=cut
sub getDescription
{
my $desctoget=shift;
debug("Entering getDescription",3,__LINE__);
debug("Getting Description for [$desctoget] ==> \$usedesc=[$usedesc]",3,__LINE__);
# Clear variables, in case they're being re-used
$shortdesc="";
$longdesc="";
# Haven't found a description yet.
$founddesc=0;
# See if description exists
if ($usedesc && $desctoget)
{
# Rewind description file
seek(DESC,0,0);
while ($descline= \nYou probably need to make the directory world writable (chmod 777 for unix).";
}
elsif ($error eq "not_readable")
{
$errstring="Cannot open file: @error_fields\n";
}
elsif ($error eq "not_writable")
{
$errstring="Cannot write to file: @error_fields\n";
}
elsif ($error eq "sanity")
{
$errstring="Failed basic sanity test: @error_fields\n";
}
elsif ($error eq "upload_error")
{
$errstring="Error uploading photo: @error_fields\n";
}
elsif ($error eq "open_db")
{
$errstring="Cannot open authentication database: @error_fields\n";
}
elsif ($error eq "cant_append")
{
$errstring="Cannot append to file: @error_fields\n";
}
elsif ($error eq "upload_dir")
{
$errstring="Cannot create directory to upload photo into: @error_fields\n";
}
elsif ($error eq "conf_error")
{
$errstring="Error in configuration file: Line @error_fields\n";
}
elsif ($error eq "no_config")
{
$errstring="Invalid configuration file specified (@error_fields).\n Please edit $0 and modify the \"\$configfile=...\" line to point to your configuration file.\n";
}
else
{
# Handle error codes not listed above
$errstring="Unknown error code: $error (@error_fields)\n";
}
# Print error info
display("$errstring \n");
display(" ",2,__LINE__);
opendir(ENTRIES,"$scan_directory") or error("not_readable","$scan_directory");
# Change Grep
@file_list=grep !/^\.\.?$/,readdir ENTRIES;
close(ENTRIES);
# clear directory flag
$contains_dir=0;
foreach $shortfile (@file_list)
{
# Check to see if it's a movie, picture or album
debug("Checking to see if $scan_directory/$shortfile is a photo/movie/album...",4,__LINE__);
if (isAPhoto($shortfile) || isAMovie($shortfile) || (-d "$scan_directory/$shortfile"))
{
push @final_file_list,$shortfile;
debug("It's one of the above...",4,__LINE__);
# Set the flag if we've seen at least one dir
if (!$contains_dir || (-d "$scan_directory/$shortfile"))
{
$contains_dir=1;
}
}
}
# Here's where to add in different sorting options
@final_file_list=sort(@final_file_list);
debug("All Entries: @final_file_list",4,__LINE__);
return (wantarray) ? @final_file_list : shift(@final_file_list);
}
##########################################################################
=head3 recursiveScan()
recursiveScan($dir_to_read,$already_scanned);
$dir_to_read - Directory to search recursively
$already_scanned - Path of directories above this one (optional)
Walks the directory tree recursively
=cut
sub recursiveScan
{
my @all_dirs;
my $single_directory,$photo_filename,$directory_only;
my $scan_directory=shift;
my $already_scanned=shift;
debug("Performing recursive scan of $scan_directory...",2,__LINE__);
debug("\$already_scanned=$already_scanned",2,__LINE__);
@all_dirs=&readDirectory($scan_directory);
foreach $single_directory (@all_dirs)
{
$full_directory="$rootdir/";
if ($already_scanned)
{
debug("Concatenating \$already_scanned ($already_scanned) to \$full_directory ($full_directory) because \$already_scanned has a value.",2,__LINE__);
$full_directory.="$already_scanned/";
}
$full_directory.=$single_directory;
debug("\$full_directory=$full_directory",2,__LINE__);
if (-d "$full_directory")
{
# Increment "scan depth" counter
$scan_depth++;
debug("$single_directory is a directory.",2,__LINE__);
$static_albums_done++;
$directory_only=$single_directory;
if ($already_scanned)
{
debug("Prepending $already_scanned to $single_directory because \$already_scanned has a value.",2,__LINE__);
$single_directory="$already_scanned/$single_directory";
}
# Do any per directory processing here
if ($doing_upload)
{
debug("Building upload category list [$single_directory]...",3,__LINE__);
# Get description
openDescfile("$rootdir/$already_scanned/");
getDescription($directory_only);
close(DESC);
$object.="\n";
}
else
{
print "$full_directory...
The site administrator has disabled the upload photo function. Please return to $shortdesc.
HTML
exit(0);
}
# same as debug=3
if ($debug gt 2)
{
print "Displaying all form values: ";
my @all=$query->param;
my $name;
foreach $name (@all)
{
print " Uploaded by $displayname.");
# Log upload
$sysdate=&setDate(time,1);
open(UPLOADLOG,">>$upload_logfile") || error("cant_append","$upload_logfile: $!");
print UPLOADLOG "$sysdate $ENV{'REMOTE_ADDR'} $q::userid $category/$filename\n";
close(UPLOADLOG);
}
}
##########################################################################
=head3 showFooter()
$footer=showFooter($show);
$show - If set to 0, the footer simply returned, if set to 1, it is displayed and returned.
Rerturns or displays the HTML footer for all pages.
=cut
sub showFooter
{
my @allinfo;
my $revdate;
my $show=shift;
if ($create_html_flag)
{
$revdate=setDate();
$revdate="Built on $revdate";
}
else
{
@allinfo=stat($0);
$revdate=localtime($allinfo[9]);
}
my $footer=<
Album V$ver [$revdate]
HTML
if ($show)
{
display($footer);
}
return($footer);
}
##########################################################################
=head3 setDate()
$datestr=setDate($convtime,$return_seconds);
$datestr - date and time
$convtime - unixtime value which is used to set $datestr (optional)
$return_seconds - 1=YYYY/MM/DD HH:MM:SS, 0=YYYY/MM/DD HH:MM
Converts $convtime into a human readable format and returns it as $datestring.
If $convtime is not provided, the current time is returned. If $return_seconds
has a value, then the time includes seconds.
=cut
sub setDate
{
my $convtime=shift;
my $return_seconds=shift;
$convtime=time if (!$convtime);
debug("Convtime: [$convtime]",2,__LINE__);
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime($convtime);
$year+=1900;
$mon++;
$mday = "0$mday" if ($mday < 10);
$mon = "0$mon" if ($mon < 10);
$hour = "0$hour" if ($hour < 10);
$min = "0$min" if ($min < 10);
$sec = "0$sec" if ($sec < 10);
$sysdate="$year/$mon/$mday $hour:$min";
$sysdate.=":$sec" if ($return_seconds);
debug("Sysdate: [$sysdate]",2,__LINE__);
return($sysdate);
}
##########################################################################
=head3 sanityTest()
sanityTest();
Runs some basic tests to make sure the environment is clean and secure before the script starts. Right now it's pretty lame, but I intend to add some new tests in to make installation/configuration/troubleshooting easier.
=cut
sub sanityTest
{
my $errstr="";
if (($cfgver ne $ver) && (($form->param('function') ne "$config") && ($form->param('function') ne "$updateconfig")))
{
$errstr="Config file is version $cfgver but you are running version $ver of this program. Please fix!";
}
# Check for security holes
# Relative paths
if ($form->param('album')=~/^\\*\./)
{
$errstr="Sorry, you can't use a relative path for the album.";
}
if ($form->param('photo')=~/^\\*\./)
{
$errstr="Sorry, you can't use a relative path for the photo.";
}
if ($form->param('album')=~/^\/*\./)
{
$errstr="Sorry, you can't use a relative path for the album.";
}
if ($form->param('photo')=~/^\/*\./)
{
$errstr="Sorry, you can't use a relative path for the photo.";
}
# Special chars
if ($form->param('album')=~/[|><]/)
{
$errstr="Sorry, you can't use special characters in the album name.";
}
if ($form->param('photo')=~/[|><]/)
{
$errstr="Sorry, you can't use special characters in the photo name.";
}
if ($errstr)
{
error("sanity","$errstr");
}
}
##########################################################################
=head3 buildTemplate()
$object_template=buildTemplate();
$object_template = variable to pass the template back into
Builds the object template, and returns it.
=cut
sub buildTemplate
{
my $object_template,$shortdesctitle;
# Album template
if ($album)
{
open(TEMPLATE,"$album_template") || error("not_readable","$album_template: $!");
debug("Using Template File: [$album_template]",2,__LINE__);
}
# Photo template
if ($photo)
{
open(TEMPLATE,"$photo_template") || error("not_readable","$photo_template: $!");
debug("Using Template File: [$photo_template]",2,__LINE__);
}
# Upload Template
if ($function eq $upload)
{
open(TEMPLATE,"$upload_template") || error("not_readable","$upload_template: $!");
debug("Using Template File: [$upload_template]",2,__LINE__);
}
# Rating Template
if ($function eq $rating_form)
{
open(TEMPLATE,"$rating_template") || error("not_readable","$rating_template: $!");
debug("Using Template File: [$rating_form]",2,__LINE__);
}
$object_template=join("",);
close(TEMPLATE);
debug("Loaded object_template: [$object_template]",4,__LINE__);
# Cut out HTML for title
$shortdesctitle=$shortdesc;
$shortdesctitle=~s/<([^>]|\n)*>//g;
if (!$shortdesctitle)
{
$shortdesctitle="Photo Album";
}
# Substitute tags for actual data
$object_template=substituteData($object_template);
# Add correct style sheet link *** Broken
# if ($create_html_flag)
# {
# $album_header.="$rootdir$style_sheet";
# }
# else
# {
# $album_header.="$style_sheet";
# }
# $album_header.="\">\n";
return($object_template);
}
##########################################################################
=head3 buildNavFooter()
$nav_footer=buildNavFooter();
Builds the navigaction footer, and returns it. (The navigation footer is the buttons/links that allow you to visit the next/previous photo or album.)
=cut
sub buildNavFooter
{
my $nav_footer,$temp;
$nav_footer="
Name (optional):
Comments (optional):
HTML
$function=$update_rating;
$ratings.=passVars(1);
$temp=$form->param('rating_file_loc');
$ratings.=<
HTML
$temp=$form->param('object');
$ratings.=<
HTML
}
$html_data=~s/####RATING####/\n\n$ratings\n\n/g;
debug("Data after substitution: [$html_data]",4,__LINE__);
# Return data
return($html_data);
}
##########################################################################
=head3 buildObject()
$output_data=buildObject();
$output_data - The HTML for displaying the object is build and returned.
Builds the "object" to be displayed. For a photo, it builds the HTML to display the photo, and for an album, it builts the list of objects in that album (photos and sub-albums).
=cut
sub buildObject
{
my $actual_object,$relpath,$multi_page,$num_pics,$num_page_pics,$total_objects,$temppage,$starting_number,$ending_number,$temppage2,$pages_html2;
if ($function eq "about")
{
$actual_object=<
zurück zum Album
HTML
return($actual_object);
}
if ($photo)
{
# If the next file is also a photo, make a link to it
if (isAPhoto($next_obj))
{
$relpath=$next_obj;
$relpath=webifyLinks($relpath);
$actual_object.="";
}
$actual_object.="\n";
# Close off link for next pic
if (isAPhoto($next_obj))
{
$actual_object.="";
}
}
if ($album)
{
$actual_object=" ",3,__LINE__);
# Check to see if file has photo extension
$isimage=isAPhoto($file);
# If it's not a photo, check to see if it's a movie
if (!$isimage)
{
$isimage=isAMovie($file);
}
debug("Checking to see if $file is a directory",4,__LINE__);
if (-d "$file")
{
debug("$file is a directory",4,__LINE__);
$isimage=0;
$isalbum=1;
}
# Cheap way to do debug("XX",2,__LINE__);
if ($debug gt 2)
{
display("
";
}
$founddesc=1;
}
}
if (!$founddesc)
{
$shortdesc=$longdesc="";
debug("No description found.",3,__LINE__);
}
debug("ShortDesc: [$shortdesc]",3,__LINE__);
debug("LongDesc: [$longdesc]",3,__LINE__);
}
debug("Leaving getDescription",3,__LINE__);
}
##########################################################################
=head3 error()
error($error_code,$extra_info);
$error_code - Pre-defined error code that prints a canned message.
$extra_info - Additional information that can be passed in
Displayes the error message associated with $error_code along with the $extra_info. Then halts execution.
=cut
sub error
{
# Pull error code and error fields
($error,@error_fields)=@_;
$error_header="ERROR!
\n";
# Print error header
display($error_header);
# Build error info, depending on error code
if ($error eq "tempdesc_not_writable")
{
$errstring="Cannot open temp file for writing: @error_fields
\n");
if ($line)
{
display("$line: ");
}
display("$debug_message
\n");
}
}
##########################################################################
=head3 readDirectory()
readDirectory($dir_to_read);
$dir_to_read - Directory to read all values from
Reads all entries in specified directory, returns as list
=cut
sub readDirectory
{
my @file_list;
my @final_file_list;
my $scan_directory=shift;
my $shortfile;
# Clear arrays, because otherwise they appear to have a null element, which really buggers things up
while (@final_file_list)
{
shift @final_file_list;
}
while (@file_list)
{
shift @file_list;
}
debug("Attempting to read entries in [$scan_directory]
\n\n";
# Generate static HTML for $full_directory
debug("Calling photoAlbum($full_directory)",4,__LINE__);
&photoAlbum($full_directory);
debug("Back from photoAlbum($full_directory) call.",4,__LINE__);
}
$debug_num_recurses++;
# Un comment to stop recursing (added when testing started to run away)
# if ($debug_num_recurses lt 3)
# {
debug("Calling recursiveScan($full_directory,$single_directory)",4,__LINE__);
&recursiveScan($full_directory,$single_directory);
debug("Back from recursiveScan($full_directory,$single_directory) call.",4,__LINE__);
debug("Recursion $debug_num_recurses...",2,__LINE__);
# }
# else
# {
# debug("Recursion Stopped.",2,__LINE__);
# }
# Pop back up a level
$scan_depth--;
}
# Generate HTML for pictures too
elsif (!$doing_upload && (-s "$full_directory") && (isAPhoto($full_directory)))
{
$photo_filename=$full_directory;
# strip off all but the filename
$photo_filename=~s/.*\/(.*)/$1/;
$photo_and_path=$full_directory;
# strip off the rootdir
$photo_and_path=~s/$rootdir\/(.*)/$1/;
if ($already_scanned)
{
# This used to be a typo so $photo_filename wasn't being set, and everything seemed to work. If something is broken, take this out. (I haven't tested it)
# $photo_filename="Picture: $already_scanned/$photo_filename";
# Maybe this is what I meant:
$photo_filename="$already_scanned/$photo_filename";
}
# Do any per file processing here
debug("Generating photo HTML for $photo_filename",2,__LINE__);
print "
\n";
}
}
##########################################################################
=head3 isAPhoto()
isAPhoto($photo_name);
$photo_name - name of picture file
Returns 1 if the filename passed in is that of a valid "photo", 0 otherwise.
=cut
sub isAPhoto
{
my $flag=0;
my $photo_name=shift;
debug("Checking to see if $photo_name is a photo...",4,__LINE__);
# *** I may want to add a test to see if $photo_name is a readable file as well, but that might cause problems for relative paths, if they're used
if ($photo_name=~/^$thumbprefix/i)
{
$flag=0;
}
else
{
foreach $imgext (@imgexts)
{
if ($photo_name=~/.*\.$imgext$/i)
{
$flag=1;
debug("Yep, it's a photo.",4,__LINE__);
}
}
}
return $flag;
}
##########################################################################
=head3 isAMovie()
isAMovie($movie_name);
$movie_name - name of movie file
Returns 1 if the filename passed in is that of a valid "movie", 0 otherwise.
=cut
sub isAMovie
{
my $flag=0;
my $movie_name=shift;
debug("Checking to see if $movie_name is a movie...",4,__LINE__);
# *** I may want to add a test to see if $movie_name is a readable file as well, but that might cause problems for relative paths, if they're used
if ($movie_name=~/^$thumbprefix/i)
{
$flag=0;
}
else
{
foreach $movieext (@movieexts)
{
if ($movie_name=~/.*\.$movieext$/i)
{
$flag=1;
debug("Yep, it's a movie.",4,__LINE__);
}
}
}
return $flag;
}
##########################################################################
=head3 readConfig()
readConfig($configfile);
$configfile - path and filename of the config file
Reads configuration information from the specified config file.
=cut
sub readConfig
{
my $confile=shift;
my $data;
my $line=0;
my $confopen=0;
my $couldbe=$0;
# Set all config vars to null, just so they exist. (Was causing some setup issues)
# String variables
$rootdir=$webroot=$relalbum=$notify_file=$photo_icon=$movie_icon=$album_icon=$file_photo_icon=$file_movie_icon=$file_album_icon=$style_sheet=$descname=$upload_logfile=$membersdir=$auth_db=$static_html_filename=$thumbprefix=$rootalbumname=$desc_delim=$album_password=$enter_desc=$update_desc=$upload=$viewfile=$album_template=$photo_template=$updateconfig=$config=$update_rating=$ratingfile=$rating_form=$rating_template=$upload_template=$debug_code="";
# Numeric variables
$cfgver=$columns=$column_spacing=$descloc=$usebuttons=$showcount=$showmoviecount=$icons=$legend=$notify=$allow_uploads=$upload_overwrite=$upload_size_limit=$authentication_type=$per_member_upload=$create_html_flag=$slide_timer=$nextprevthumb=$constrain_thumbs=$showsubalbumcount=$photos_per_page=0;
# Array variables
@imgexts=("");
@movieexts=("");
debug("Reading configuration information from $confile...",2,__LINE__);
# Trying to open the provided config file
if (open(CONFIG,"$confile"))
{
debug("Opened config file at $confile",2,__LINE__);
$confopen=1;
}
else
{
$confopen=0;
}
# Nope. Try just album.cfg
if (!$confopen)
{
debug("Trying to read configuration information from album.cfg...",2,__LINE__);
if (open(CONFIG,"album.cfg"))
{
debug("Opened config file at album.cfg",2,__LINE__);
$confopen=1;
$configfile="album.cfg";
}
else
{
$confopen=0;
}
}
# Nope. Try the same directory as album.pl explicitly
if (!$confopen)
{
# Drop the proceeding path (for UNIX) - don't change this
$couldbe=~s/(.*\/).*/$1/;
# No change? Then this must be a Win32 machine... - don't change this
if ($couldbe eq $0)
{
$couldbe=~s/(.*\\).*/$1/;
}
$couldbe.="album.cfg";
debug("Trying to read configuration information from $couldbe...",2,__LINE__);
if (open(CONFIG,"$couldbe"))
{
debug("Opened config file at $couldbe",2,__LINE__);
$confopen=1;
$configfile=$couldbe;
}
else
{
$confopen=0;
}
}
# Just couldn't find the bloody thing!
if (!$confopen)
{
error("no_config","$confile");
}
while ($data=
\n";
$static_photos_done++;
debug("Calling photoAlbum($photo_and_path)",4,__LINE__);
&photoAlbum("$photo_and_path");
debug("Back from photoAlbum($photo_and_path) call.",4,__LINE__);
}
}
debug("Done with $scan_directory...",2,__LINE__);
if (!$doing_upload)
{
print "Form Data: $name ->", $query->param($name),"
\n";
}
}
$object=buildTemplate();
if ($query->param('upload_file'))
{
debug("A photo is being uploaded.",2,__LINE__);
my $em='';
# import the paramets into a series of variables in 'q' namespace
$query->import_names('q');
# check if the necessary fields are empty or not
$em .= "
You must specify your Userid!
" if !$q::userid;
if (!$q::upload_password && $authentication_type)
{
$em .= "You must specify your Password!
"
}
$em .= "You must select a file to upload!
" if !$q::upload_file;
print $object;
if ($em)
{
error("upload_error",$em);
}
if (!&Authenticate($query->param('userid'),$query->param('upload_password')))
{
error("upload_error","Will not upload! Could not validate Userid: $q::userid");
}
# now upload file
fileUpload();
}
else
{
debug("No photo is being uploaded.",2,__LINE__);
print $object;
}
}
##########################################################################
=head3 Authenticate()
$authenticated=Authenticate($username,$password);
$username - the username of the user
$password - the password for the user
Authenticates the username/password against a UBB member. Returns 1 for a successful authentication, otherwise 0.
=cut
sub Authenticate
{
my $username=shift;
my $password=shift;
my $data="";
my $auth="";
my $storedpass="";
$usernumber="";
# UBB authorization
if ($authentication_type eq 2)
{
$memberslist="$membersdir/memberslist.cgi";
open (FILE,"$memberslist") || error("not_readable","$memberslist: $!");
while ($data=\n";
$upload_form.=$query->start_multipart_form,"\n";
# userid field
$upload_form.="
\n";
return($upload_form);
}
##########################################################################
=head3 fileUpload()
fileUpload();
Handles the nitty gritty file upload stuff.
=cut
sub fileUpload
{
my $bytes_read=0;
my $size='';
my $buff='';
my $start_time,$time_taken;
my $filepath='';
my $filename='';
my $write_file='';
$filepath=$query->param('upload_file');
my $category=$query->param('category');
my $photo_title=$query->param('title');
my $photo_desc=$query->param('description');
if ($filepath =~ /([^\/\\]+)$/)
{
$filename="$1";
}
else
{
$filename="$filepath";
}
# if there's any space in the filename, get rid of them
$filename=~s/\s+//g;
# Is $per_member_upload on? If so, change the category, and create the directory if it's not already there.
if ($category eq "per_member_upload")
{
# UBB categories are user numbers, all others are display names
if ($authentication_type eq 2)
{
$category=$usernumber;
}
else
{
$category=$displayname;
}
$dirtomk="$rootdir"."/"."$category";
if (!(-d $dirtomk))
{
mkdir($dirtomk,777) || error("upload_dir","$dirtomk");
if (!chmod(0777,$dirtomk))
{
error("upload_dir","$dirtomk");
}
}
# Update the description for this new album
updateDesc("$category","$rootdir/",$displayname,"Photos uploaded by $displayname.");
}
# Check for any fooling around
if (!(-d "$rootdir/$category"))
{
error("sanity","Naughty naughty! Are you trying to hack me?");
}
$write_file="$rootdir"."/"."$category"."/"."$filename";
debug("Filename=$filename",2,__LINE__);
debug("Writefile=$write_file",2,__LINE__);
debug("Checking to see if $write_file is an photo.",2,__LINE__);
$object=0;
if (!(isAPhoto($write_file) || (isAMovie($write_file) && $movie_upload)))
{
error("upload_error","File $filename is not a supported file type. Please see the upload rules for more information.");
}
if (!$upload_overwrite)
{
if (-e $write_file)
{
error("upload_error","Photo $filename exists, will not overwrite!");
}
}
if (!open(WFD,">$write_file"))
{
error("upload_error","Error opening $write_file file for writing");
return;
}
$start_time=time();
while ($bytes_read=read($filepath,$buff,2096))
{
$size+=$bytes_read;
binmode WFD;
print WFD $buff;
}
debug("size=$size",2,__LINE__);
close(WFD);
# Check to see if file exceeds set limit
if ($size>($upload_size_limit*1024))
{
unlink($write_file);
error("upload_error","Cannot load files larger than $upload_size_limit kilobytes.");
}
if ((stat $write_file)[7] <= 0)
{
unlink($write_file);
error("upload_error","Could not upload file: $filename");
return;
}
else
{
$time_taken=time()-$start_time;
print<
\n";
$upload_form.=" \n";
# Don't display password field if we're using anonymous uploads
if ($authentication_type)
{
# password field
$upload_form.="\n";
# Display name/userid depending on if we're using anonymous uploads or not
if ($authentication_type)
{
$upload_form.="Userid:\n";
}
else
{
$upload_form.="Name:\n";
}
$upload_form.=" \n";
$upload_form.="\n";
$upload_form.=$query->textfield(-name=>'userid',-size=>20);
$upload_form.=" \n";
$upload_form.="\n";
$upload_form.=" \n";
}
# file field
$upload_form.="\n";
$upload_form.="Password:\n";
$upload_form.=" \n";
$upload_form.="\n";
$upload_form.=$query->password_field(-name=>'upload_password',-size=>20);
$upload_form.=" \n";
$upload_form.="\n";
$upload_form.=" \n";
$upload_form.=<
HTML
}
else
{
$upload_form.=<
\n";
$upload_form.="File:\n";
$upload_form.=" \n";
$upload_form.="\n";
$upload_form.=$query->filefield(-name=>'upload_file',-size=>30,-maxlength=>80);
$upload_form.=" \n";
$upload_form.="
Category:
HTML
}
$upload_form.=<
Title:
HTML
$upload_form.="
Description:
\n";
$upload_form.=" \n";
$upload_form.=<
HTML
$upload_form.=$query->endform,"\n";
$upload_form.="\n";
$upload_form.=" \n";
$upload_form.="
\n";
$upload_form.=$query->submit(-label=>'Upload',-value=>'Upload',-onClick=>"return ValidateAllFields(this.form)"),"\n";
$upload_form.="
Photo $filename of size $size bytes is uploaded successfully!
\n";
}
##########################################################################
=head3 passVars()
$vars=passVars($format);
$vars = variable to pass the formed variables back into
$format = 0: pass in web URL format (&debug=1&configfile=file, etc); 1: pass in button format (\n";
}
else
{
$vars.="&function=$function";
}
}
if ($slide_timer_passed)
{
if ($usebuttons)
{
$vars.="\n";
}
else
{
$vars.="&slideshow=$slide_timer";
}
}
if ($configfilepassed)
{
if ($usebuttons)
{
$vars.="\n";
}
else
{
$vars.="&configfile=$configfile";
}
}
if ($debug)
{
if ($usebuttons)
{
$vars.="\n";
}
else
{
$vars.="&$debug_code=$debug";
}
}
if ($password)
{
if ($usebuttons)
{
$vars.="\n";
}
else
{
$vars.="&password=$password";
}
}
if ($username)
{
if ($usebuttons)
{
$vars.="\n";
}
else
{
$vars.="&username=$username";
}
}
}
return($vars);
}
##########################################################################
=head3 printHeader()
$header=printHeader();
$header - The formed header, with style sheet or body colour tags, is returned.
Prints out either the style sheet or a generic body tag.
=cut
sub printHeader
{
my $html;
if ($style_sheet)
{
$html="\n";
}
$html.="\n\n";
return($html);
}
##########################################################################
=head3 updateDesc()
updateDesc($object,$desc_file_loc,$title,$description);
$object - The object whose description is being updated
$desc_file_loc - The location of the descfile to update
$title - The new title to apply to the object
$description - The new long description to apply to the object
Updates the $descfile located in $desc_file_loc for the item $object, with the information passed in through the web form.
=cut
sub updateDesc
{
my $tempfilename,$added_desc,$data,$skip;
my $object=shift;
my $desc_file_loc=shift;
my $title=shift;
my $description=shift;
# Yep, so update the description file, and then display everything normally
debug("Updating description for $object in $desc_file_loc. Title is [$title], description is [$description].",2,__LINE__);
if (!$object || !$desc_file_loc)
{
error("sanity","Not enough info to update description.");
}
# Open the description file specified
openDescfile($desc_file_loc);
$tempfilename=$desc_file_loc."$descname.$$";
# Open a temp file for writing
open(TEMPFILE,">$tempfilename") || error("tempdesc_not_writable","$tempfilename");
# have not added desc
$added_desc=0;
# am not skipping
$skip=0;
while ($data= ";
# Display jump station
if ($jump_to)
{
$nav_footer.=$jump_station;
}
$nav_footer.="\n";
# Display the "previous photo" link/button
if ($prev_obj)
{
# Text link and prev photo thumbnail
if (!$usebuttons || $nextprevthumb)
{
$nav_footer.="";
# Show previous photo thumbnail
if ($nextprevthumb && $photo)
{
$temp=$static_photos_thumb;
$nav_footer.=showThumb($prev_obj);
$static_photos_thumb=$temp;
# Align description
if ($descloc eq 1)
{
$nav_footer.="
\n";
}
}
if (!$usebuttons)
{
if ($prev_obj_desc)
{
$nav_footer.="$prev_obj_desc";
}
else
{
$nav_footer.="Previous";
}
}
$nav_footer.="\n";
}
if ($usebuttons)
{
$nav_footer.="";
}
}
$nav_footer.="\n";
# Display the "back to album" link/button
if ($middle)
{
if ($usebuttons)
{
$nav_footer.="";
}
else
{
$nav_footer.="\">\n";
if ($back_desc)
{
# if ($create_html_flag)
# {
# $nav_footer.="Back To Album";
#### TODO This doesn't work for static, for some reason...
# }
# else
# {
$nav_footer.="$back_desc";
# }
}
else
{
$nav_footer.="Back To Album";
}
$nav_footer.="\n";
}
}
$nav_footer.=" \n";
# Display the "next photo" link/button
if ($next_obj)
{
# Text link and next photo thumbnail
if (!$usebuttons || $nextprevthumb)
{
$nav_footer.="\n";
# Show next photo thumbnail
if ($nextprevthumb && $photo)
{
$temp=$static_photos_thumb;
$nav_footer.=showThumb($next_obj);
$static_photos_thumb=$temp;
# Align description
if ($descloc eq 1)
{
$nav_footer.="
\n";
}
}
if (!$usebuttons)
{
if ($next_obj_desc)
{
$nav_footer.="$next_obj_desc";
}
else
{
$nav_footer.="Next";
}
}
$nav_footer.="\n";
}
if ($usebuttons)
{
$nav_footer.="";
}
}
$nav_footer.="
\n";
if (-e $file_album_icon)
{
$legend_html.=" = Album";
}
if (-e $file_photo_icon)
{
$legend_html.=" ";
$legend_html.=" = Photo\n";
}
if (-e $file_movie_icon)
{
$legend_html.=" ";
$legend_html.=" = Movie\n";
}
}
if ($notify)
{
$notify_html="If you want to be notified when pictures are added to $shortdesc, please enter your e-mail address below.
\n";
$notify_html.="\n";
}
}
if ($form->param('email_notify') && $notify)
{
open(NOTIFY,">>$notify_file") || error("not_writable","$notify_file");
print NOTIFY $form->param('email_notify');
print NOTIFY "\n";
close(NOTIFY);
$notify_html.="
\n";
$notify_html.="
\n";
}
$html_data=~s/####LEGEND####/\n\n$legend_html\n\n/g;
$html_data=~s/####NOTIFY####/\n\n$notify_html\n\n/g;
# Check to see if we are adding a description
if ($function eq $enter_desc)
{
# Form for entering a new description
$add_desc_footer="\n";
}
$html_data=~s/####ENTERDESC####/\n\n$add_desc_footer\n\n/g;
# Are we tracking the number of photo views?
if ($viewfile && !$create_html_flag && !$album)
{
$views=trackView();
}
$html_data=~s/####VIEWS####/\n\n$views\n\n/g;
# Are we rating photos?
if ($ratingfile && !$create_html_flag && !$album)
{
$ratings=getRatings();
}
$html_data=~s/####RATINGS####/\n\n$ratings\n\n/g;
if ($function eq $rating_form)
{
$ratings=<
HTML
$shortphoto=$object;
if ($ratingfile)
{
$ratings.=getRatings(1,$rating_file_loc);
}
$ratings.=<
Version $ver written by Mike Bobbitt ( http://perl.CdnArmy.ca/album ).
\n";
# Display total number of pages...
if ($multi_page)
{
$pages_html="";
$num_page_pics=$total_objects;
$temppage=1;
while ($num_page_pics > 0)
{
$num_page_pics-=$photos_per_page;
$pages_html.=" ";
if ($page ne $temppage)
{
$pages_html.="";
}
$pages_html.="$temppage";
if ($page ne $temppage)
{
$pages_html.="";
}
$temppage++;
}
$temppage--;
debug("Total pages: $temppage",2,__LINE__);
debug("Current page: $page",2,__LINE__);
# Print "Previous" page link
if (($temppage > 1) && ($page > 1))
{
$pages_html2.=" << ";
$pages_html2.="Previous";
$pages_html="$pages_html2 $pages_html";
}
# Print "Next" page link
if (($temppage > 1) && ($page < $temppage))
{
$pages_html.=" ";
$pages_html.="Next >> ";
}
$pages_html="Page: $pages_html";
}
}
return($actual_object);
}
##########################################################################
=head3 parseLinks()
$object_template=parseLinks($object_template);
$object_template - Data is passed in, made web safe, and passed out.
Checks the data passed and converts special characters within any links into web safe characters.
=cut
sub parseLinks
{
my $object_template=shift;
# Replace any spaces in the links to %20
while ($object_template=~s/ (src|href)="([^"]*?) ([^"]*)"/ $1="$2%20$3"/g)
{
}
return($object_template);
}
##########################################################################
=head3 showThumb()
$thumbnail_html=showThumb($object);
$object - Object to search for thumbnail of.
$thumbnail_html - HTML for the thumbnail.
Returns the proper HTML for the thumbnail of the passed object, honouring all configfile settings.
=cut
sub showThumb
{
my $object=shift;
my $thumbnail_html,$object_no_ext,$imgext;
my $thumb_album=$album;
my $middlebit=$middle;
debug("showthumb($object) called.",4,__LINE__);
if ($photo)
{
$isimage=1;
$thumb_album=$dir_to_read;
$middlebit=$goback;
}
if ($isimage)
{
# Set photo thumbnail to search for.
$object_no_ext=$object;
$object_no_ext=~s/(.+)\..+/$1/;
}
if ($isalbum)
{
$object_no_ext=$object;
}
foreach $imgext (@imgexts)
{
# Check upper case extensions
$imgext="\U$imgext";
if (-e "$thumb_album/$thumbprefix$object_no_ext.$imgext")
{
$alb_thumb_ext=$imgext;
}
# Check lower case extensions
$imgext="\L$imgext";
if (-e "$thumb_album/$thumbprefix$object_no_ext.$imgext")
{
$alb_thumb_ext=$imgext;
}
}
if ($alb_thumb_ext)
{
$image_thumb="$thumb_album/$thumbprefix$object_no_ext.$alb_thumb_ext";
debug("Looking for thumbnail ($image_thumb) ([$thumb_album][/][$thumbprefix][$object_no_ext][.][$alb_thumb_ext])",2,__LINE__);
}
else
{
debug("No file thimbnail found.",2,__LINE__);
}
if (($icons && ((-e $file_photo_icon && $photo) || (-e $file_album_icon && $thumb_album))) || (-e "$image_thumb") || $constrain_thumbs)
{
$thumbnail_html.="";
}
return($thumbnail_html);
}
##########################################################################
=head3 showConfig()
showConfig();
Displays the configuration items from $configfile in a web submittable form.
=cut
sub showConfig
{
my $data,$section,$first_section,$paramsize,$prevline,$var,$value,$line,$help,$sect_header;
print "\n";
# Reset the number of pictures in the current row and on the current page
$num_pics=$num_page_pics=$multi_page=$total_objects=0;
$starting_number=$photos_per_page*$page-$photos_per_page;
$ending_number=$photos_per_page*$page+1;
debug("Displaying pictures in range: $starting_number to $ending_number",2,__LINE__);
foreach $shortfile (@file_list)
{
# Keep count of total objects
if ($shortfile)
{
$total_objects++;
}
debug("\$num_page_pics: $num_page_pics",2,__LINE__);
debug("\$total_objects: $total_objects (out of $photos_per_page, exclusive range $starting_number to $ending_number)",2,__LINE__);
# Is this page full?
if ($shortfile && (!$photos_per_page || (($starting_number < $total_objects) && ($ending_number > $total_objects))))
{
debug("\Going to display $shortfile",3,__LINE__);
getDescription($shortfile);
$isimage=0;
$isalbum=0;
$file="$rootdir";
if ($middle)
{
$file.="/$middle";
}
$file.="/$shortfile";
$webfile="$webroot";
if ($middle)
{
$webfile.="/$middle";
}
$webfile.="/$shortfile";
debug("\$File: $file",3,__LINE__);
debug("\$WebFile: $webfile",3,__LINE__);
# Find relative path
$relpath=$file;
$relpath=~s/$rootdir\/(.*)/$1/;
$relpath=webifyLinks($relpath);
debug("Relpath: $relpath \nUNKNOWN: $file");
if ($isimage)
{
display(" is a photo (so says \$isimage)");
}
if ($isalbum)
{
display(" is an album (so says \$isalbum)");
}
display("
");
}
if (!$founddesc)
{
$shortdesc=$shortfile;
}
# New cell in the table
$actual_object.="";
if ($isimage)
{
$actual_object.=" \n";
# Start a new row?
if ($num_pics eq $columns)
{
$num_pics=0;
$actual_object.="
\n";
}
# use $shortfile if no desc avail
$actual_object.="$shortdesc";
# Is there a long description too?
if ($founddesc && $longdesc)
{
$actual_object.=" *";
}
$actual_object.="";
# Show ratings and long descriptions for movies.
if (isAMovie($file))
{
$actual_object.="
\n";
if ($longdesc)
{
$actual_object.="$longdesc
\n";
}
if ($ratingfile)
{
$actual_object.=getRatings();
}
}
$actual_object.="
";
}
else
{
$actual_object.=" ";
}
# use $shortfile if no desc avail
$actual_object.="$shortdesc";
if ($showcount || $showmoviecount || $showsubalbumcount)
{
opendir(ENTRIES,"$file") or error("not_readable","$file");
# Change Grep
@count_file_list=grep !/^\.\.?$/,readdir ENTRIES;
close(ENTRIES);
$photocount=0;
$moviecount=0;
$subalbumcount=0;
foreach $eachfile (@count_file_list)
{
if (isAPhoto($eachfile))
{
$photocount++;
}
if (isAMovie($eachfile))
{
$moviecount++;
}
if (-d "$file/$eachfile")
{
$subalbumcount++;
}
}
$actual_object.=" (";
if ($showcount)
{
$actual_object.="$photocount";
}
if ($showcount && $showmoviecount)
{
$actual_object.=", ";
}
if ($showmoviecount)
{
$actual_object.="$moviecount";
}
if ($showmoviecount && $showsubalbumcount)
{
$actual_object.=", ";
}
if ($showsubalbumcount)
{
$actual_object.="$subalbumcount";
}
$actual_object.=")";
}
$actual_object.="";
}
}
# Are we looking at multiple pages?
elsif ($photos_per_page eq $num_page_pics || ($page > 1))
{
$multi_page=1;
}
}
$actual_object.="