#! /usr/bin/perl -w
# $Id: picpage.cgi,v 1.25 2004/01/09 04:44:32 ddb Exp $
use Date::Format;
use URI::Escape;
use File::stat;
use Fcntl ':flock'; # import LOCK_* constants
my $debug = 0;
# Easy lookup index of image files we'll handle
my %imagetypes = (
'jpg', 1,
'jpeg', 1,
'JPG', 1,
'JPEG', 1,
'gif', 1,
'GIF', 1,
'png', 1,
'PNG', 1
);
# This script is intended to work in conjunction with image-index. It
# makes a custom page for the given image, and brings in possible
# associated data for that page. Put picpage in /cgi-bin; it expects
# the path to the file in PATH_INFO.
# It's to be invoked with additional path info leading to the actual
# image; $PATH_TRANSLATED must point there.
# This extended version should be backwards-compatible with the old
# one, and also work (rather more featurefully) with galpage.pl
# pages.
# Newform is used if the galinfo.yaml file is present and doesn't
# contain . In newform, you specify the
# album directory as additional path info, and the photo ID as a
# parameter (id=).
$newform = 0;
$ENV{PATH} = "/bin:/usr/bin:/usr/local/bin";
# Config add comments (overridden by galcfg in galinfo for newform)
my $AddCommentsScript = 'GalleryAddComment.pl';
#my $AddCommentsScript = 'gac.cgi'; # ZZZ for testing
my $AddCommentsText = 'To add a comment to this photo, enter it here and click submit.';
my $AddCommentsFromPrompt = 'Who is commenting?';
# Get directory part of path info only, even if filename is there too.
$ENV{'PATH_TRANSLATED'} =~ qr|^(.*?)(/[^/]+\..+)?$|;
my $picdir = $1;
chdir ($picdir) || die "Can't chdir to $picdir";
my $galinfo;
my $picid;
if (-r "galinfo.yaml") {
use YAML qw (LoadFile);
$galinfo = LoadFile ("galinfo.yaml");
if (! $galinfo) {
die "Failed to load galinfo.yaml";
}
if ($galinfo->{OLDPICPAGE}) {
$newform = $galinfo->{OLDPICPAGE};
} else {
$newform = 1;
}
undef $galinfo unless $newform;
}
# Missing id can override above decision, however
# Note this isn't fully general!
if ($ENV{QUERY_STRING} =~ /id=(.*)/i) {
$picid = uri_unescape($1);
} else {
$newform = 0;
}
if ($newform) {
# Show a single picture in the context of a gallery; meaning links
# back to the gallery, and forward and backward links, and title
# and info information and comments.
use strict;
use warnings;
use Data::Dumper;
my ($title, $picurl, $picfile, $picnav, $previd,
$nextid, $debinfo, $descr, $piccomments, $mtimestr,
$entercmt, $style, $picbottomtext);
my $error = '';
$debinfo = '';
eval { # Trap errors to make error page
# Get data
my $picobj;
# Photo ID must be present
if (! defined ($picid)) {
die "No picture id defined in query string";
}
if (! exists ($galinfo->{OBJINFO}->{$picid})) {
die "Invalid picture id $picid";
}
$picobj = $galinfo->{OBJINFO}->{$picid};
$picurl = $ENV{PATH_INFO};
if ($picurl =~ /(\.\.)/) {
die "Attempt to leave current directory in picture path $picurl";
}
$picfile = $picobj->{file};
if ($picfile =~ /(\.\.)|\//) {
die "Attempt to leave current directory in picture file $picfile";
}
if (! -r $picfile) {
die "No readable file for picture $picfile";
}
my $ext;
if ($picfile =~ /^.*\.(.+)$/) {
$ext = $1;
die "$picfile not a picture type I understand" unless $imagetypes{$ext};
} else {
die "No file extension in $picfile";
}
# Allow local config of comment prompts and handling
$AddCommentsScript = $galinfo->{GALCFG}->{ADDCOMMENTSSCRIPT} || $AddCommentsScript;
$AddCommentsText = $galinfo->{GALCFG}->{ADDCOMMENTSTEXT} || $AddCommentsText;
$AddCommentsFromPrompt = $galinfo->{GALCFG}->{ADDCOMMENTSFROMPROMPT} ||
$AddCommentsFromPrompt;
# Make ordered list
my @order = sort {$a->[1] <=> $b->[1] || $a->[0] cmp $b->[0]} map [$_,$galinfo->{OBJINFO}->{$_}->{sort}], keys %{$galinfo->{OBJINFO}};
$debinfo .= " order " . Dumper (@order);
# Find our current one ($picid). Only once, so no point bulding hash.
for (my $i=0; $i<$#order; $i++) {
if ($order[$i]->[0] eq $picid) {
if ($i > 0) {
# There's a previous, get it
$previd = $order[$i-1]->[0];
} else {
undef $previd;
}
if ($i < $#order) {
# There's a next, get it
$nextid = $order[$i+1]->[0];
} else {
undef $nextid;
}
last;
}
}
# Assemble the navigation elements
$picnav = "";
$picnav .= "[prev]" if $previd;
$picnav .= "[up]";
$picnav .= "[next]" if $nextid;
if ($picobj->{title}) {
$title = $picobj->{title};
} else {
$title = $picid;
}
$descr = $picobj->{descr};
# Get comment block, if any
my ($commentfn, $commentts);
$commentfn = "$picid.comments";
eval { # Protect from blowouts
$piccomments = "";
$commentts = 0;
my $if;
open ($if, $commentfn) and
flock ($if, LOCK_SH) and
($commentts = stat($if)->mtime) and
($piccomments = join (" ", <$if>)) and
flock ($if, LOCK_UN);
close $if;
};
if ($@) {
# It's legal to not have this stuff
$piccomments = '';
$commentts = 0;
}
# Decide if we're allowing comments, and generate html block
# to allow users to do so, or else blank block.
$entercmt = '';
if ($galinfo->{GALCFG}->{COMMENTS} &&
(-w "$picid.comment" || -f ".mkcomment")) {
$entercmt = qq|
\n|;
$entercmt .= "$AddCommentsText
\n";
$entercmt .= "\n";
}
# Figure out what lie we're going to tell about last-modified time
# Check actual image file
my $imagets;
$imagets = stat($picobj->{file})->mtime or 0;
my $mtime;
$mtime = $imagets > $commentts ? $imagets : $commentts;
$mtimestr = time2str ("%a, %d %b %Y %H:%M:%S %z", $mtime, "GMT");
# Grab proper local stylesheet from config in info
$style = $galinfo->{GALCFG}->{STYLESHEET} || "local.css";
# Very bottom text (bottom nav, usually)
$picbottomtext = $galinfo->{GALCFG}->{PICBOTTOMTEXT};
};
if ($@) {
$error = $@;
# Display error page
print <
Picture display error
Picture Display Error
$error