#!/usr/bin/perl -Tw
use strict;
use warnings;
use CGI qw( :standard );
use POSIX;
require HTML::TokeParser;
# set some vars to help defend against DoS attacks
$CGI::POST_MAX=1024 * 10; # max 10K posts
$CGI::DISABLE_UPLOADS = 1; # no uploads
#
# Copyright Tim F. Rayner, 2003
#
# This is a CGI script to convert Apple iPhoto-exported
# thumbnail galleries into a slicker-looking XHTML/CSS based
# layout. Minor editing by the user is required: The DATA
# section at the bottom of this script holds values for each
# gallery in a |-delimited table format. Required parameters
# include: (1) a keyword identifier, matching the name of
# the directory which holds the three "-Pages",
# "-Thumbnails" and "-Images" directories produced by
# iPhoto; (2) the actual title of the gallery to be used in
# the generated HTML; (3) the total number of photos in the
# gallery (this seems safer than automatically detecting the
# number of images available); (4) the background colour
# to use (I prefer a centralised location for such things)
# in the standard #nnnnnn hexadecimal form (other forms
# usable in CSS should also work, but are untested); and
# (5) a 'subdirectory' term, for when the individual gallery
# page is held in a subdirectory of the top-level directory.
# An example of the directory organisation:
#
# /var/www/htdocs/photos/spain/madrid
# /var/www/htdocs/photos/spain/barcelona
# /var/www/htdocs/photos/wedding
# /var/www/htdocs/photos/vacation
# /var/www/htdocs/styles/photos.css
#
# You should also set the variables $docroot, $galleryroot
# and $stylesheet.
# For the example above:
#
# my $docroot = "/var/www/htdocs";
# my $galleryroot = "/photos";
# my $stylesheet = "/styles/photos.css";
#
# In this case, the wedding and vacation galleries are in
# the top level and so do not require subdirectory
# information; however, the various spain galleries are in
# the spain subdirectory and therefore require entries in
# the DATA section such as:
#
# madrid|Photos of Madrid|24|#fdffbc|spain
#
# Finally, the script is called as:
#
# http://your.domain.org/photos/index.pl?page=madrid&index=1
#
# This assumes you call the script index.pl and put it in
# the /photos directory; you can call it anything you want
# and put it anywhere you like, however.
#
# (From there, the rest should be obvious - I hope!)
#
### BEGIN USER CONFIG ###
my $docroot = "/var/www/htdocs"; # Path to webpages on the serve
+r
my $galleryroot = "/photos"; # Path from $docroot to where t
+he galleries are
my $stylesheet = "/styles/photos.css"; # Path from $docroot to where t
+he stylesheet is
my $rowno = 5; # Number of rows in the thumbnail galleries
my $colno = 3; # Number of columns in the thumbnail galleries
### END USER CONFIG ### - But also see DATA section at end of script!
sub parsedata{
# Get the relevant <DATA>
# Takes: $cgi->param("page"), as passed to it
# Gives: hashref containing all the data parsed from <DATA> for the
+given page
my $target=shift;
while (my $line=<DATA>){
chomp $line;
my %data;
($data{page},$data{title},$data{number},$data{bkgd},$data{subd
+ir})=split /\|/,$line;
return(\%data) if ($target eq $data{page});
}
}
sub drawindex{
# Draw an index page
# Takes a CGI object, a data hashref (originally from &parsedata),
# the number of columns and rows desired in the index table (this
+is
# trucated as necessary to match the total number of pictures in
# $data{number}.
my ($cgi,$dataref,$colno,$rowno)=splice(@_,0,4);
my %data = %{$dataref};
my $idxno = POSIX::ceil($data{number}/($colno * $rowno));
my $index = $cgi->param("index");
my $prev = $index-1;
my $next = $index+1;
my $pageroot = "$galleryroot/$data{subdir}/$data{page}"; # Where t
+he thumbnail, page and image dirs are
my $url = $cgi->url();
# Check our index is in range
unless ($index > 0 && $index <= $idxno){
print $cgi->h4("Error in CGI input: index out of range.");
return 0;
}
# Get the thumbnail titles
my @alt;
for (my $i=1; $i <= $idxno+1 ; $i++){
my $tmpidx = $i - 1;
my $indexfile = ($i == 1) ? "$data{page}.html" : "Page$tmpidx.
+html";
open (PAGE, "<$docroot$pageroot/$indexfile") or die("$!\n");
my $p = HTML::TokeParser->new(\*PAGE) or die ("Can't open: $!\
+n");
while (my $token = $p->get_token) {
if ((${$token}[0] eq "S") && (${$token}[1] eq "img")){
push @alt, ${$token}[2]->{alt};
}
}
close (PAGE) or die ("$!\n");
last if ($#alt >= ($data{number}-1));
}
# Start the page content
print $cgi->h1($data{title}); # level 1 header
# Navigation bar
# (new version using $" trick to insert spacer characters)
my @navbar;
for (my $i=1; $i <= $idxno; $i++){
push @navbar, a({href => "$url?page=$data{page}&index=".$i
+}, "Page ".$i)
}
{
local($") = ' | ';
print $cgi->h3(@navbar),hr;
}
# Build the table
my @table;
for (my $r=0; $r < $rowno; $r++){
my @row;
for (my $c=0; $c < $colno; $c++){
my $item = (($index - 1) * $colno * $rowno) + ($colno * $r
+) + $c;
last if ($item >= $data{number});
push @row, h5(a({ href => "$url?page=$data{page}&image
+=".$item } ,
img({ src => "$pageroot/$data{page}-Thumbn
+ails/$item.jpg",
alt => "$alt[$item]",
} ),br,"$alt[$item]"
));
}
push @table, td(\@row);
}
# Print the table
print $cgi->table( { -width => "100%",
-align => "center",
},
Tr( { -align => "center",
-valign => "bottom",
},
\@table
)
);
# Finish off nicely
print $cgi->hr,h5(a({href => "$galleryroot/"},"Back to Galleries p
+age"));
}
sub drawimage{
# Draw an image page
# Takes a CGI object, a data hashref (originally from &parsedata),
# the number of columns and rows desired in the index table (this
+is
# trucated as necessary to match the total number of pictures in
# $data{number}.
my ($cgi,$dataref,$colno,$rowno)=splice(@_,0,4);
my %data = %{$dataref};
my $pageroot = "$galleryroot/$data{subdir}/$data{page}";
my $url = $cgi->url();
my $image = $cgi->param("image");
my $prev = $image-1;
my $next = $image+1;
# Check our image is in range
unless ($image >= 0 && $image < $data{number}){
print $cgi->h4("Error in CGI input: image number out of range.
+");
return 0;
}
# Get the relevant photo title, from the iPhoto HTML files
my $imgtitle;
open (PAGE, "<$docroot$pageroot/$data{page}-Pages/Image$image.html
+") or die("$!\n");
my $p = HTML::TokeParser->new(\*PAGE) or die ("Can't open: $!\n");
while (my $token = $p->get_token) {
if ((${$token}[0] eq "S") && (${$token}[1] eq "title")){ # fi
+nd the <title> tag
$token = $p->get_token; # ge
+t the next token (containing the title text)
if (${$token}[0] eq "T"){ # ch
+eck it's the right one
$imgtitle = ${$token}[1];
last; # fo
+r what little efficiency it affords us
}
}
}
close (PAGE) or die ("$!\n");
# Start the page content
print h2($data{title}); # level 2 header
if ($prev >= 0){
print $cgi->div({id => "list1",
class => "link-list"
},
h5(a({-href => "$url?page=$data{page}&imag
+e=$prev"},
img({src => "$pageroot/$data{page}-Thu
+mbnails/$prev.jpg",
alt => "Previous image",
align => "left",
width => "100%",
}),"Previous"
)
)
);
}
if ($next < $data{number}){
print $cgi->div({id => "list2",
class => "link-list"
},
h5(a({-href => "$url?page=$data{page}&imag
+e=$next"},
img({src => "$pageroot/$data{page}-Thu
+mbnails/$next.jpg",
alt => "Next image",
align => "right",
width => "100%",
}),"Next"
)
)
);
}
if ($image >= $data{number}){
print $cgi->h4("Error: image number out of range.");
}else{
print $cgi->div({id => "main",
align => "center"
},
h3($imgtitle),
img({src => "$pageroot/$data{page}-Images/$i
+mage.jpg",
alt => "$imgtitle",
})
);
}
my $index = POSIX::floor($image/($colno * $rowno))+1;
print $cgi->h5(a({-href=>"$url?page=$data{page}&index=$index"}
+,"Back to index"));
}
### MAIN ###
my $cgi = new CGI;
# create the HTTP header
print $cgi->header;
# Check that the script was passed a page keyword parameter
unless (defined $cgi->param("page")){
print $cgi->h4("Error in CGI input: \"page\" parameter undefined.\
+n"),end_html;
exit;
}
# Get the relevant data from <DATA>, check that there's a match
my $dataref=&parsedata($cgi->param("page"));
unless ($dataref){
print $cgi->h4("Error in CGI input: requested page not found in in
+dex.\n"),end_html;
exit;
}
my %data = %{$dataref};
# Start the HTML
print $cgi->start_html(-title => $data{title},
-style => {'src' => "$stylesheet",
'code' => "html,body {background-c
+olor: $data{bkgd}}",
},
);
if (defined $cgi->param("index")){ # Draw an index page, if re
+quired
&drawindex($cgi,\%data,$colno,$rowno);
}elsif (defined $cgi->param("image")){ # Draw an image page, if re
+quired
&drawimage($cgi,\%data,$colno,$rowno);
}else{
print $cgi->h4("Error in CGI input: Neither index nor image page r
+equested.\n");
}
# end the HTML
print $cgi->end_html;
# DATA is in the form:
# page|title|total no. of photos|background colour|subdirectory
# Note: page param and $page should be identical to each
# other and the the name of the relevant subdirectory
__DATA__
wedding|Wedding Photos|30|#daffcc|
madrid|Photos of Madrid|30|#fdffbc|spain
barcelona|Photos of Barcelona|34|#fdffbc|spain
vacation|Holiday Pics|28|#fdffbc|
|