Perl CGI picture-of-the-day script not behaving as expected after migration to new server












1














I have a perl cgi script that has been working perfectly for me on a FreeBSD 5.4 Apache 1.3 webserver for many years without trouble. It's a picture of the day script that randomly selects a picture from a given directory for inclusion on an shtml page with the server side include



<!--#exec cgi="/cgi-bin/pod/pod.cgi"-->


I recently migrated to a new server on Google Cloud Platform - Debian 9 (Stretch), Apache 2.4. And the script broke. After setting the server configurations to execute cgi perl scripts correctly, and re-uploading the script in ASCII, the script began working again, but now with an anomalous behavior. Instead of displaying one image (the same image) all day long and then changing the image at midnight (the desired behavior) it is now changing the image every time the page is reloaded in a web browser.



The script uses a flat-file log that keeps track of which images have been used from the source directory, and doesn't repeat displaying of any images until all images from the target directory have been used (logged in pod.log). When working correctly, it will display a new image every day (changing at midnight), which will remain the same for all users, whether the page is reloaded or not, until the following midnight.



Permissions have all been set on the necessary files as specified in the comments of the script. The script has been uploaded to the server in ASCII format (will not work at all if uploaded in binary). The script is displaying an image from the correct directory. BUT..... every time the page is refreshed, a new images is loaded and logged to the pod.log file.



One thing that I thought might be affecting the script was where it was getting the time for the date/time function of the script. When I entered the "date" command from the debian command prompt the server returned the correct time that I had configured the server to - America/Los_Angeles. But I noticed that when files on my webserver were touched or changed, it was time-stamping them with UTC time, which is 8 hours later. Thinking that Apache might be causing the different time-stamp, I tried changing the time-zone in php.ini for apache2. This didn't seem to change anything (after apache2ctl restart), so I thought, maybe I'll change the server timezone to UTC. If you can't beat 'em, join 'em. Right? Well that made it so the "date" command from the debian command line returned the time in UTC. Also noted: files on the webserver were still time-stamping with UTC time zone. All was looking good! But then I checked the time that was being used by perl/cgi with this little gem, which returns the date and time in a human-readable format...



#!/usr/bin/perl
print "Content-type: text/htmlnn";
@months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
@weekDays = qw(Sun Mon Tue Wed Thu Fri Sat Sun);
($second, $minute, $hour, $dayOfMonth, $month, $yearOffset, $dayOfWeek, $dayOfYear, $daylightSavings) = localtime();
$year = 1900 + $yearOffset;
$theTime = "$hour:$minute:$second, $weekDays[$dayOfWeek] $months[$month] $dayOfMonth, $year";
print $theTime;


...And this script was returning the time in the time zone America/Los_Angeles, rather than UTC. Now I don't know if this discrepancy could be the thing causing the bug in my pic of the day script. But my guess, with my very limited experience is telling me that it's at least possible. But I've taken this debugging/troubleshooting of the script about as far as my technical abilities will take me.



I need to know:




  1. what is causing the script to return a new picture and update the log file on every reload, rather than remaining static for 1 day?

  2. is it caused by an unintentional (fat finger) error in the script?

  3. is it caused by some different way my new server and/or its configuration are handling the script?

  4. is it caused by the time-stamp/time-zone issues I mentioned in the previous paragraph?

  5. or is this a result of something I'm completely missing?


Next I'll provide the source code for the script and my apache configuration files. EXAMPLE.COM should be replaced by your domain name wherever it appears and paths to files should be adjusted to your locations.



#!/usr/bin/perl

##############################################################
# POD (Picture of the Day) Version 1.30
##############################################################

package VAR;
use strict;

##############################################################
# Installation
##############################################################

# 1. Edit path to Perl at top of script (pod.cgi) if it
# differs on your server. Usual and default path it
# [/usr/bin/perl]. However, on some servers it may be
# /usr/local/bin/perl. If in doubt, then refer to a script on
# your server that does work, or ask your web host. Edit
# variables below. Ensure you edit (and save) the script using
# an ASCII editor like Notepad.
#
# 2. Via FTP, create directory on server in CGI-BIN called
# pod. No need to CHMOD - you can leave set to server
# default directory permissions.
#
# 3. Via FTP, create subdirectory in 'pod' directory
# called data and CHMOD 777 (drwxrwxrwx).
#
# 4. FTP upload the pod.cgi script to the 'pod'
# directory in ASCII (text) and CHMOD 755 (rwxr-xr-x). You may
# need to rename the scripts with the .pl extension if your
# server uses the .pl extension for CGI-Perl scripts.
#
# images/ 755 (drwxr-xr-x)
# cgi-bin/pod/
# pod.cgi 755 (rwxr-xr-x)
# data/ 777 (drwxrwxrwx)
#

##############################################################
# Operation
##############################################################
#
# METHOD 1: SSI Method
# ====================
# Call the script via SSI (Server-Side Includes). The image
# is embedded in the page. Insert the following SSI tag in
# the desired page:
#
# <!--#exec cgi="/cgi-bin/pod/pod.cgi"-->
#
# In either case, ensure to replace the cgi-bin/pod/ portion
# of the SSI tag with your path to the script.
#
# If you get the [an error occurred while processing this
# directive] error message or no image / message displays,
# make sure (a) the path to Perl is correct, (b) the script
# was uploaded in ASCII, (c) the script is chmod 755
# (rwxr-xr-x) and (d) the path to the script in the SSI tag
# is correct - if in doubt, then ask your web host. If still
# problematic then try the following:
#
# 1. On most servers, the page with a SSI tag must be named
# with the SHTML extension in order for the server to parse
# and execute the SSI tag. Check the page source. If you
# still see the SSI tag, then it was not parsed. Try
# renaming the page with the SHTML extension. If the SSI tag
# is still not parsed (and still visible), then SSI may not
# be enabled on your server - ask your web host.
#
# 2. Try calling the script directly from the browser. If
# you get a server 500 error, then check your server error
# logs.
#
# 3. You can also try the following SSI tag:
#
# <!--#include virtual="/cgi-bin/pod/pod.cgi"-->
#
# METHOD 1: Non-SSI Method
# ====================
# You can also call the script directly from the browser:
#
# http://www.yourdomain.com/cgi-bin/pod/pod.cgi
#
# The image is NOT embedded, but is instead displayed in a
# script generated HTML page.

##############################################################
# Configuration
##############################################################

# Full (absolute) server directory path of directory holding
# image files for the POD script to draw from. Create this
# directory in advance and upload images (in Binary) to this
# directory. No need to chmod. NO trailing slash at end of
# path.
$VAR::image_dir = "/var/www/EXAMPLE.COM/httpdocs/pod";

# URL of directory holding image files for the POD script to
# draw from. NO trailing slash at end of URL.
$VAR::image_url = "http://www.EXAMPLE.COM/pod";

# Full (absolute) server directory path for script data files
# (pod.log, pod.err). Create this directory in advance and
# chmod (777 or drwxrwxrwx). NO trailing slash at end of path.
$VAR::data_dir = "/var/www/EXAMPLE.COM/httpdocs/pod/data";

# Output template - how POD image (or error message) is
# displayed. Feel free to change the HTML but (1) the MS link
# back MUST be retained and (2) the <%image%> tag MUST be
# retained as the tag is replaced with the image (or error
# message) HTML code.
$VAR::template = qq~
<center>
<table border="1">
<th>
<%image%>
</th>
</table>
</center>
~;

##########################################################################
# Do NOT change or alter the code below!
##########################################################################

eval {
($0 =~ m,(.*)/[^/]+,) && unshift (@INC, "$1");
require 5.004;
};
if ($@) {
print "Content-type: text/htmlnn";
print "Server Error Message: $@n";
exit;
}

eval { &main; };
if ($@) { &error ("[Error 01]: $@"); }
exit;

###############################################
# Main
###############################################
sub main {

my ($time, $date) = &get_time_stamp();
my $num;

if (-e "$VAR::data_dir/pod.log") {
open (LOG, "$VAR::data_dir/pod.log") ||
&error ("Error [02]: Cannot open pod.log file - $!");
my @entries = <LOG>;
close (LOG);
chomp (@entries);

my @match = grep (/^$date/, @entries);
if (@match) {
foreach (@match) {
split (/|/);
if ($_[0] eq $date) {
$num = $_[1];
last;
}
}
}
}

opendir (DIR, "$VAR::image_dir") || &error ("Error [03]: Cannot open $VAR::image - $!");
my @files = sort (grep { m/.*.gif|.jpg/ } readdir (DIR));
closedir (DIR);

if ($num eq "") { $num = int (rand @files); }
my $image = @files[$num];
if (! -e "$VAR::image_dir/$image") { &error ("Error [04]: Cannot find image file [$image]"); }

my $tag = "<img src="$VAR::image_url/$image">";
$VAR::template =~ s/<%image%>/$tag/gis;
print $VAR::template;

my ($found, $newfile);
if (-e "$VAR::data_dir/pod.log") {
open (LOG, "$VAR::data_dir/pod.log") ||
&error ("Error [05]: Cannot open pod.log file - $!");
my @entries = <LOG>;
close (LOG);
chomp (@entries);

foreach (@entries) {
split (/|/);
if ($_[0] eq $date) {
$_[2]++;
$newfile .= "$date|$_[1]|$_[2]|$_[3]n";
$found++;
}
else { $newfile .= "$_n"; }
}
if (! $found) { $newfile .= "$date|$num|1|$imagen"; }

open (LOG, ">$VAR::data_dir/pod.log") ||
&error ("Error [06]: Cannot open pod.log file - $!");
flock (LOG, 2) || &error ("Error [07]: Cannot lock pod.log file - $!");
print LOG $newfile;
close (LOG);
}
else {
open (LOG, ">$VAR::data_dir/pod.log") ||
&error ("Error [08]: Cannot open pod.log file - $!");
print LOG "$date|$num|1|$imagen";
close (LOG);
chmod (0666, "$VAR::data_dir/pod.log") ||
&error ("Error [09]: Cannot chmod pod.log file - $!");
}
}

###############################################
# Get Time Stamp
###############################################
sub get_time_stamp {

my (@tb) = localtime (time);
my ($ap) = "am";

$tb[4]++;
for (0..4) { $tb[$_] = sprintf ("%02d", $tb[$_]); }
$tb[5] += 1900;
$ap = "pm" if ($tb[2] >= 12);
$tb[2] -= 12 if ($tb[2] > 12);

my $date = "$tb[4]/$tb[3]/$tb[5]";
return ("$tb[2]:$tb[1]:$tb[0]$ap $date", $date);
}

###############################################
# Error Handler
###############################################
sub error {

my $error = shift;
my ($time, $date) = &get_time_stamp();

my $tag = "Cannot display image";
$VAR::template =~ s/<%image%>/$tag/gis;

print $VAR::template;

open (ERR, ">>$VAR::data_dir/pod.err");
print ERR "$time | $ENV{'REMOTE_ADDR'} | $errorn";
close (ERR);
chmod (0666, "$VAR::data_dir/pod.err");
exit;
}
########################################
#end of Picture of the Day script
########################################


This is my apache2.conf (again, I've changed my domain name to EXAMPLE.COM wherever my domain name appears...



# configuration directives that give the server its instructions.
# See http://httpd.apache.org/docs/2.4/ for detailed information about
# the directives and /usr/share/doc/apache2/README.Debian about Debian specific
# hints.
#
#
# Summary of how the Apache 2 configuration works in Debian:
# The Apache 2 web server configuration in Debian is quite different to
# upstream's suggested way to configure the web server. This is because Debian's
# default Apache2 installation attempts to make adding and removing modules,
# virtual hosts, and extra configuration directives as flexible as possible, in
# order to make automating the changes and administering the server as easy as
# possible.

# It is split into several files forming the configuration hierarchy outlined
# below, all located in the /etc/apache2/ directory:
#
# /etc/apache2/
# |-- apache2.conf
# | `-- ports.conf
# |-- mods-enabled
# | |-- *.load
# | `-- *.conf
# |-- conf-enabled
# | `-- *.conf
# `-- sites-enabled
# `-- *.conf
#
#
# * apache2.conf is the main configuration file (this file). It puts the pieces
# together by including all remaining configuration files when starting up the
# web server.
#
# * ports.conf is always included from the main configuration file. It is
# supposed to determine listening ports for incoming connections which can be
# customized anytime.
#
# * Configuration files in the mods-enabled/, conf-enabled/ and sites-enabled/
# directories contain particular configuration snippets which manage modules,
# global configuration fragments, or virtual host configurations,
# respectively.
#
# They are activated by symlinking available configuration files from their
# respective *-available/ counterparts. These should be managed by using our
# helpers a2enmod/a2dismod, a2ensite/a2dissite and a2enconf/a2disconf. See
# their respective man pages for detailed information.
#
# * The binary is called apache2. Due to the use of environment variables, in
# the default configuration, apache2 needs to be started/stopped with
# /etc/init.d/apache2 or apache2ctl. Calling /usr/bin/apache2 directly will not
# work with the default configuration.


# Global configuration
#

#
# ServerRoot: The top of the directory tree under which the server's
# configuration, error, and log files are kept.
#
# NOTE! If you intend to place this on an NFS (or otherwise network)
# mounted filesystem then please read the Mutex documentation (available
# at <URL:http://httpd.apache.org/docs/2.4/mod/core.html#mutex>);
# you will save yourself a lot of trouble.
#
# Do NOT add a slash at the end of the directory path.
#
#ServerRoot "/etc/apache2"

# Set timezone for apache
SetEnv TZ America/Los_Angeles

#
# The accept serialization lock file MUST BE STORED ON A LOCAL DISK.
#
Mutex file:${APACHE_LOCK_DIR} default

#
# The directory where shm and other runtime files will be stored.
#

DefaultRuntimeDir ${APACHE_RUN_DIR}

#
# PidFile: The file in which the server should record its process
# identification number when it starts.
# This needs to be set in /etc/apache2/envvars
#
PidFile ${APACHE_PID_FILE}

#
# Timeout: The number of seconds before receives and sends time out.
#
Timeout 300

#
# KeepAlive: Whether or not to allow persistent connections (more than
# one request per connection). Set to "Off" to deactivate.
#
KeepAlive On

#
# MaxKeepAliveRequests: The maximum number of requests to allow
# during a persistent connection. Set to 0 to allow an unlimited amount.
# We recommend you leave this number high, for maximum performance.
#
MaxKeepAliveRequests 500

#
# KeepAliveTimeout: Number of seconds to wait for the next request from the
# same client on the same connection.
#
KeepAliveTimeout 5


# These need to be set in /etc/apache2/envvars
User ${APACHE_RUN_USER}
Group ${APACHE_RUN_GROUP}

#
# HostnameLookups: Log the names of clients or just their IP addresses
# e.g., www.apache.org (on) or 204.62.129.132 (off).
# The default is off because it'd be overall better for the net if people
# had to knowingly turn this feature on, since enabling it means that
# each client request will result in AT LEAST one lookup request to the
# nameserver.
#
HostnameLookups Off

# ErrorLog: The location of the error log file.
# If you do not specify an ErrorLog directive within a <VirtualHost>
# container, error messages relating to that virtual host will be
# logged here. If you *do* define an error logfile for a <VirtualHost>
# container, that host's errors will be logged there and not here.
#
ErrorLog ${APACHE_LOG_DIR}/error.log

#
# LogLevel: Control the severity of messages logged to the error_log.
# Available values: trace8, ..., trace1, debug, info, notice, warn,
# error, crit, alert, emerg.
# It is also possible to configure the log level for particular modules, e.g.
# "LogLevel info ssl:warn"
#
LogLevel warn

# Include module configuration:
IncludeOptional mods-enabled/*.load
IncludeOptional mods-enabled/*.conf

# Include list of ports to listen on
Include ports.conf


# Sets the default security model of the Apache2 HTTPD server. It does
# not allow access to the root filesystem outside of /usr/share and /var/www.
# The former is used by web applications packaged in Debian,
# the latter may be used for local directories served by the web server. If
# your system is serving content from a sub-directory in /srv you must allow
# access here, or in any related virtual host.
<Directory />
Options FollowSymLinks
AllowOverride None
Require all denied
</Directory>

<Directory /usr/share>
AllowOverride None
Require all granted
</Directory>

<Directory /var/www/>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>

#<Directory /srv/>
# Options Indexes FollowSymLinks
# AllowOverride None
# Require all granted
#</Directory>
# AccessFileName: The name of the file to look for in each directory
# for additional configuration directives. See also the AllowOverride
# directive.
#
AccessFileName .htaccess
#
# The following lines prevent .htaccess and .htpasswd files from being
# viewed by Web clients.
#
<FilesMatch "^.ht">
Require all denied
</FilesMatch>
#
# The following directives define some format nicknames for use with
# a CustomLog directive.
#
# These deviate from the Common Log Format definitions in that they use %O
# (the actual bytes sent including headers) instead of %b (the size of the
# requested file), because the latter makes it impossible to detect partial
# requests.
#
# Note that the use of %{X-Forwarded-For}i instead of %h is not recommended.
# Use mod_remoteip instead.
#
LogFormat "%v:%p %h %l %u %t "%r" %>s %O "%{Referer}i" "%{User-Agent}i"" vhost_combined
LogFormat "%h %l %u %t "%r" %>s %O "%{Referer}i" "%{User-Agent}i"" combined
LogFormat "%h %l %u %t "%r" %>s %O" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
# Include of directories ignores editors' and dpkg's backup files,
# see README.Debian for details.
# Include generic snippets of statements
IncludeOptional conf-enabled/*.conf
# Include the virtual host configurations:
IncludeOptional sites-enabled/*.conf
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet


And this is the conf for my virtual host...



<VirtualHost *:80>
ServerName EXAMPLE.com
ServerAlias www.EXAMPLE.com
UseCanonicalName Off
ServerAlias EXAMPLE1.com
ServerAlias www.EXAMPLE1.com
ServerAlias EXAMPLE2.com
ServerAlias www.EXAMPLE2.com
ServerAlias EXAMPLE.co.uk
ServerAlias www.EXAMPLE.co.uk
ServerAlias EXAMPLE.net
ServerAlias www.EXAMPLE.net
ServerAlias EXAMPLE3.com
ServerAlias www.EXAMPLE3.com
ServerAdmin EXAMPLEd@gmail.com
DocumentRoot /var/www/EXAMPLE.com/httpdocs
<Directory /var/www/EXAMPLE.com/httpdocs>
Options -Indexes +FollowSymLinks
AllowOverride All
</Directory>
ScriptAlias "/cgi-bin/" "/var/www/EXAMPLE.com/cgi-bin/"
#<Directory "/var/www/EXAMPLE.com/cgi-bin/">
# Options +ExecCGI
# AddHandler cgi-script .cgi
# AllowOverride All
#</Directory>
#<Directory "/var/www/EXAMPLE.com/httpdocs/members/cgi-bin">
# Options +ExecCGI
# AddHandler cgi-script .cgi
# AllowOverride All
#</Directory>
#<Directory "/var/www/EXAMPLE.com/httpdocs/pod">
# Options +ExecCGI
# AddHandler cgi-script .cgi
# AllowOverride All
#</Directory>

Alias "/passwd/" "/var/www/EXAMPLE.com/passwd/"

<IfModule mod_ssl.c>
SSLEngine off
</IfModule>

<Directory /var/www/EXAMPLE.com>
Options +ExecCGI +FollowSymLinks +Includes
AddHandler cgi-script .cgi
AllowOverride All
</Directory>

<Directory /var/www/EXAMPLE.com>
<IfModule sapi_apache2.c>
php_admin_flag engine on
php_admin_flag safe_mode on
php_admin_value open_basedir "/var/www/EXAMPLE.com/httpdocs:/tmp"
</IfModule>
<IfModule mod_php5.c>
php_admin_flag engine on
php_admin_flag safe_mode on
php_admin_value open_basedir "/var/www/EXAMPLE.com/httpdocs:/tmp"
</IfModule>
</Directory>

<Directory /var/www/EXAMPLE.com>
RewriteEngine on

# the following section prevents outside sites from hot-linking photos
# leave this next line in allow empty referrers, remove to disallow empty referrers
RewriteCond %{HTTP_REFERER} !^$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?([a-z0-9-]+.)*XX.XXX.XXX.XXX(:[0-9]+)?(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?([a-z0-9-]+.)*EXAMPLE.com(:[0-9]+)?(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?([a-z0-9-]+.)*EXAMPLE.org(:[0-9]+)?(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?([a-z0-9-]+.)*EXAMPLE.net(:[0-9]+)?(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?([a-z0-9-]+.)*EXAMPLE.co.uk(:[0-9]+)?(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?([a-z0-9-]+.)*EXAMPLE.de(:[0-9]+)?(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?1.2.3.4(:[0-9]+)?(/.*)?$
RewriteRule .*.(gif|jpeg|jpg)$ - [NC,F,L]
</Directory>

ErrorLog ${APACHE_LOG_DIR}/EXAMPLE.com-error.log
CustomLog ${APACHE_LOG_DIR}/EXAMPLE.com-access.log combined
# sends 404-not-found errors to error page
ErrorDocument 404 /404-error-page.html

# makes server side includes work on all html pages
AddType text/html .shtml .html .htm
AddHandler server-parsed .shtml .html .htm

RewriteEngine On

# If the hostname is NOT www.domain.com
# RewriteCond %{HTTP_HOST} !^www.EXAMPLE.com$
# 301 redirect to the same resource on www.EXAMPLE.com
# RewriteRule (.*) http://www.EXAMPLE.com$1 [L,R=301]

# sets the web surfer's browser to cache images, style sheets, and JavaScript for a week
<IfModule mod_headers.c>
# WEEK
<FilesMatch ".(jpg|jpeg|png|gif|swf|js|css)$">
Header set Cache-Control "max-age=604800, public"
</FilesMatch>
</IfModule>

</VirtualHost>


Any help anyone can give me will be greatly appreciated! It's amazing what you all do to help other fledgling programmers like myself. Thank you, thank you, thank you.










share|improve this question






















  • To be honest, it is going to be difficult to try and replicate the problem, I would simply start by getting the timezones the same as the previous server and work from there.
    – Gerhard Barnard
    Nov 21 at 8:11










  • An alternative approach instead of keeping a log is to map the time (as an integer, returned by time, to the images, and use that as an offset into the images: my @images = glob 'images/*.jpg'; my $ofs = time / (3600*24); $ofs = $ofs % scalar @images; my $image = $images[$ofs]. See metacpan.org/pod/Time::Slideshow for a module incorporating this.
    – Corion
    Nov 21 at 8:41










  • Does it work if rather than overwriting the log file, you write out the new version to a temporary file and then rename it into place?
    – Chris Turner
    Nov 21 at 10:22






  • 2




    Here's an alternative: Maybe you could rip part of the script out, put it into a new program and run it as a cronjob. Have it pick a picture every time it is called with the same behaviour, but only run it once a night as a cron. Make it create a symlink to the selected picture, and use that in your website. This will resolve the time issues as it will run when the server thinks it's midnight (you can reset the timezone), and it will decrease resource use as it will only be run once.
    – simbabque
    Nov 21 at 10:37












  • Thank you to all of you that replied, for your creative and useful ideas. Ikegami's solution did the trick and I'm back up and running again. I have a great appreciation for all of you who help the less gifted, like myself. Your generosity is inspiring.
    – Brad
    Nov 22 at 8:51
















1














I have a perl cgi script that has been working perfectly for me on a FreeBSD 5.4 Apache 1.3 webserver for many years without trouble. It's a picture of the day script that randomly selects a picture from a given directory for inclusion on an shtml page with the server side include



<!--#exec cgi="/cgi-bin/pod/pod.cgi"-->


I recently migrated to a new server on Google Cloud Platform - Debian 9 (Stretch), Apache 2.4. And the script broke. After setting the server configurations to execute cgi perl scripts correctly, and re-uploading the script in ASCII, the script began working again, but now with an anomalous behavior. Instead of displaying one image (the same image) all day long and then changing the image at midnight (the desired behavior) it is now changing the image every time the page is reloaded in a web browser.



The script uses a flat-file log that keeps track of which images have been used from the source directory, and doesn't repeat displaying of any images until all images from the target directory have been used (logged in pod.log). When working correctly, it will display a new image every day (changing at midnight), which will remain the same for all users, whether the page is reloaded or not, until the following midnight.



Permissions have all been set on the necessary files as specified in the comments of the script. The script has been uploaded to the server in ASCII format (will not work at all if uploaded in binary). The script is displaying an image from the correct directory. BUT..... every time the page is refreshed, a new images is loaded and logged to the pod.log file.



One thing that I thought might be affecting the script was where it was getting the time for the date/time function of the script. When I entered the "date" command from the debian command prompt the server returned the correct time that I had configured the server to - America/Los_Angeles. But I noticed that when files on my webserver were touched or changed, it was time-stamping them with UTC time, which is 8 hours later. Thinking that Apache might be causing the different time-stamp, I tried changing the time-zone in php.ini for apache2. This didn't seem to change anything (after apache2ctl restart), so I thought, maybe I'll change the server timezone to UTC. If you can't beat 'em, join 'em. Right? Well that made it so the "date" command from the debian command line returned the time in UTC. Also noted: files on the webserver were still time-stamping with UTC time zone. All was looking good! But then I checked the time that was being used by perl/cgi with this little gem, which returns the date and time in a human-readable format...



#!/usr/bin/perl
print "Content-type: text/htmlnn";
@months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
@weekDays = qw(Sun Mon Tue Wed Thu Fri Sat Sun);
($second, $minute, $hour, $dayOfMonth, $month, $yearOffset, $dayOfWeek, $dayOfYear, $daylightSavings) = localtime();
$year = 1900 + $yearOffset;
$theTime = "$hour:$minute:$second, $weekDays[$dayOfWeek] $months[$month] $dayOfMonth, $year";
print $theTime;


...And this script was returning the time in the time zone America/Los_Angeles, rather than UTC. Now I don't know if this discrepancy could be the thing causing the bug in my pic of the day script. But my guess, with my very limited experience is telling me that it's at least possible. But I've taken this debugging/troubleshooting of the script about as far as my technical abilities will take me.



I need to know:




  1. what is causing the script to return a new picture and update the log file on every reload, rather than remaining static for 1 day?

  2. is it caused by an unintentional (fat finger) error in the script?

  3. is it caused by some different way my new server and/or its configuration are handling the script?

  4. is it caused by the time-stamp/time-zone issues I mentioned in the previous paragraph?

  5. or is this a result of something I'm completely missing?


Next I'll provide the source code for the script and my apache configuration files. EXAMPLE.COM should be replaced by your domain name wherever it appears and paths to files should be adjusted to your locations.



#!/usr/bin/perl

##############################################################
# POD (Picture of the Day) Version 1.30
##############################################################

package VAR;
use strict;

##############################################################
# Installation
##############################################################

# 1. Edit path to Perl at top of script (pod.cgi) if it
# differs on your server. Usual and default path it
# [/usr/bin/perl]. However, on some servers it may be
# /usr/local/bin/perl. If in doubt, then refer to a script on
# your server that does work, or ask your web host. Edit
# variables below. Ensure you edit (and save) the script using
# an ASCII editor like Notepad.
#
# 2. Via FTP, create directory on server in CGI-BIN called
# pod. No need to CHMOD - you can leave set to server
# default directory permissions.
#
# 3. Via FTP, create subdirectory in 'pod' directory
# called data and CHMOD 777 (drwxrwxrwx).
#
# 4. FTP upload the pod.cgi script to the 'pod'
# directory in ASCII (text) and CHMOD 755 (rwxr-xr-x). You may
# need to rename the scripts with the .pl extension if your
# server uses the .pl extension for CGI-Perl scripts.
#
# images/ 755 (drwxr-xr-x)
# cgi-bin/pod/
# pod.cgi 755 (rwxr-xr-x)
# data/ 777 (drwxrwxrwx)
#

##############################################################
# Operation
##############################################################
#
# METHOD 1: SSI Method
# ====================
# Call the script via SSI (Server-Side Includes). The image
# is embedded in the page. Insert the following SSI tag in
# the desired page:
#
# <!--#exec cgi="/cgi-bin/pod/pod.cgi"-->
#
# In either case, ensure to replace the cgi-bin/pod/ portion
# of the SSI tag with your path to the script.
#
# If you get the [an error occurred while processing this
# directive] error message or no image / message displays,
# make sure (a) the path to Perl is correct, (b) the script
# was uploaded in ASCII, (c) the script is chmod 755
# (rwxr-xr-x) and (d) the path to the script in the SSI tag
# is correct - if in doubt, then ask your web host. If still
# problematic then try the following:
#
# 1. On most servers, the page with a SSI tag must be named
# with the SHTML extension in order for the server to parse
# and execute the SSI tag. Check the page source. If you
# still see the SSI tag, then it was not parsed. Try
# renaming the page with the SHTML extension. If the SSI tag
# is still not parsed (and still visible), then SSI may not
# be enabled on your server - ask your web host.
#
# 2. Try calling the script directly from the browser. If
# you get a server 500 error, then check your server error
# logs.
#
# 3. You can also try the following SSI tag:
#
# <!--#include virtual="/cgi-bin/pod/pod.cgi"-->
#
# METHOD 1: Non-SSI Method
# ====================
# You can also call the script directly from the browser:
#
# http://www.yourdomain.com/cgi-bin/pod/pod.cgi
#
# The image is NOT embedded, but is instead displayed in a
# script generated HTML page.

##############################################################
# Configuration
##############################################################

# Full (absolute) server directory path of directory holding
# image files for the POD script to draw from. Create this
# directory in advance and upload images (in Binary) to this
# directory. No need to chmod. NO trailing slash at end of
# path.
$VAR::image_dir = "/var/www/EXAMPLE.COM/httpdocs/pod";

# URL of directory holding image files for the POD script to
# draw from. NO trailing slash at end of URL.
$VAR::image_url = "http://www.EXAMPLE.COM/pod";

# Full (absolute) server directory path for script data files
# (pod.log, pod.err). Create this directory in advance and
# chmod (777 or drwxrwxrwx). NO trailing slash at end of path.
$VAR::data_dir = "/var/www/EXAMPLE.COM/httpdocs/pod/data";

# Output template - how POD image (or error message) is
# displayed. Feel free to change the HTML but (1) the MS link
# back MUST be retained and (2) the <%image%> tag MUST be
# retained as the tag is replaced with the image (or error
# message) HTML code.
$VAR::template = qq~
<center>
<table border="1">
<th>
<%image%>
</th>
</table>
</center>
~;

##########################################################################
# Do NOT change or alter the code below!
##########################################################################

eval {
($0 =~ m,(.*)/[^/]+,) && unshift (@INC, "$1");
require 5.004;
};
if ($@) {
print "Content-type: text/htmlnn";
print "Server Error Message: $@n";
exit;
}

eval { &main; };
if ($@) { &error ("[Error 01]: $@"); }
exit;

###############################################
# Main
###############################################
sub main {

my ($time, $date) = &get_time_stamp();
my $num;

if (-e "$VAR::data_dir/pod.log") {
open (LOG, "$VAR::data_dir/pod.log") ||
&error ("Error [02]: Cannot open pod.log file - $!");
my @entries = <LOG>;
close (LOG);
chomp (@entries);

my @match = grep (/^$date/, @entries);
if (@match) {
foreach (@match) {
split (/|/);
if ($_[0] eq $date) {
$num = $_[1];
last;
}
}
}
}

opendir (DIR, "$VAR::image_dir") || &error ("Error [03]: Cannot open $VAR::image - $!");
my @files = sort (grep { m/.*.gif|.jpg/ } readdir (DIR));
closedir (DIR);

if ($num eq "") { $num = int (rand @files); }
my $image = @files[$num];
if (! -e "$VAR::image_dir/$image") { &error ("Error [04]: Cannot find image file [$image]"); }

my $tag = "<img src="$VAR::image_url/$image">";
$VAR::template =~ s/<%image%>/$tag/gis;
print $VAR::template;

my ($found, $newfile);
if (-e "$VAR::data_dir/pod.log") {
open (LOG, "$VAR::data_dir/pod.log") ||
&error ("Error [05]: Cannot open pod.log file - $!");
my @entries = <LOG>;
close (LOG);
chomp (@entries);

foreach (@entries) {
split (/|/);
if ($_[0] eq $date) {
$_[2]++;
$newfile .= "$date|$_[1]|$_[2]|$_[3]n";
$found++;
}
else { $newfile .= "$_n"; }
}
if (! $found) { $newfile .= "$date|$num|1|$imagen"; }

open (LOG, ">$VAR::data_dir/pod.log") ||
&error ("Error [06]: Cannot open pod.log file - $!");
flock (LOG, 2) || &error ("Error [07]: Cannot lock pod.log file - $!");
print LOG $newfile;
close (LOG);
}
else {
open (LOG, ">$VAR::data_dir/pod.log") ||
&error ("Error [08]: Cannot open pod.log file - $!");
print LOG "$date|$num|1|$imagen";
close (LOG);
chmod (0666, "$VAR::data_dir/pod.log") ||
&error ("Error [09]: Cannot chmod pod.log file - $!");
}
}

###############################################
# Get Time Stamp
###############################################
sub get_time_stamp {

my (@tb) = localtime (time);
my ($ap) = "am";

$tb[4]++;
for (0..4) { $tb[$_] = sprintf ("%02d", $tb[$_]); }
$tb[5] += 1900;
$ap = "pm" if ($tb[2] >= 12);
$tb[2] -= 12 if ($tb[2] > 12);

my $date = "$tb[4]/$tb[3]/$tb[5]";
return ("$tb[2]:$tb[1]:$tb[0]$ap $date", $date);
}

###############################################
# Error Handler
###############################################
sub error {

my $error = shift;
my ($time, $date) = &get_time_stamp();

my $tag = "Cannot display image";
$VAR::template =~ s/<%image%>/$tag/gis;

print $VAR::template;

open (ERR, ">>$VAR::data_dir/pod.err");
print ERR "$time | $ENV{'REMOTE_ADDR'} | $errorn";
close (ERR);
chmod (0666, "$VAR::data_dir/pod.err");
exit;
}
########################################
#end of Picture of the Day script
########################################


This is my apache2.conf (again, I've changed my domain name to EXAMPLE.COM wherever my domain name appears...



# configuration directives that give the server its instructions.
# See http://httpd.apache.org/docs/2.4/ for detailed information about
# the directives and /usr/share/doc/apache2/README.Debian about Debian specific
# hints.
#
#
# Summary of how the Apache 2 configuration works in Debian:
# The Apache 2 web server configuration in Debian is quite different to
# upstream's suggested way to configure the web server. This is because Debian's
# default Apache2 installation attempts to make adding and removing modules,
# virtual hosts, and extra configuration directives as flexible as possible, in
# order to make automating the changes and administering the server as easy as
# possible.

# It is split into several files forming the configuration hierarchy outlined
# below, all located in the /etc/apache2/ directory:
#
# /etc/apache2/
# |-- apache2.conf
# | `-- ports.conf
# |-- mods-enabled
# | |-- *.load
# | `-- *.conf
# |-- conf-enabled
# | `-- *.conf
# `-- sites-enabled
# `-- *.conf
#
#
# * apache2.conf is the main configuration file (this file). It puts the pieces
# together by including all remaining configuration files when starting up the
# web server.
#
# * ports.conf is always included from the main configuration file. It is
# supposed to determine listening ports for incoming connections which can be
# customized anytime.
#
# * Configuration files in the mods-enabled/, conf-enabled/ and sites-enabled/
# directories contain particular configuration snippets which manage modules,
# global configuration fragments, or virtual host configurations,
# respectively.
#
# They are activated by symlinking available configuration files from their
# respective *-available/ counterparts. These should be managed by using our
# helpers a2enmod/a2dismod, a2ensite/a2dissite and a2enconf/a2disconf. See
# their respective man pages for detailed information.
#
# * The binary is called apache2. Due to the use of environment variables, in
# the default configuration, apache2 needs to be started/stopped with
# /etc/init.d/apache2 or apache2ctl. Calling /usr/bin/apache2 directly will not
# work with the default configuration.


# Global configuration
#

#
# ServerRoot: The top of the directory tree under which the server's
# configuration, error, and log files are kept.
#
# NOTE! If you intend to place this on an NFS (or otherwise network)
# mounted filesystem then please read the Mutex documentation (available
# at <URL:http://httpd.apache.org/docs/2.4/mod/core.html#mutex>);
# you will save yourself a lot of trouble.
#
# Do NOT add a slash at the end of the directory path.
#
#ServerRoot "/etc/apache2"

# Set timezone for apache
SetEnv TZ America/Los_Angeles

#
# The accept serialization lock file MUST BE STORED ON A LOCAL DISK.
#
Mutex file:${APACHE_LOCK_DIR} default

#
# The directory where shm and other runtime files will be stored.
#

DefaultRuntimeDir ${APACHE_RUN_DIR}

#
# PidFile: The file in which the server should record its process
# identification number when it starts.
# This needs to be set in /etc/apache2/envvars
#
PidFile ${APACHE_PID_FILE}

#
# Timeout: The number of seconds before receives and sends time out.
#
Timeout 300

#
# KeepAlive: Whether or not to allow persistent connections (more than
# one request per connection). Set to "Off" to deactivate.
#
KeepAlive On

#
# MaxKeepAliveRequests: The maximum number of requests to allow
# during a persistent connection. Set to 0 to allow an unlimited amount.
# We recommend you leave this number high, for maximum performance.
#
MaxKeepAliveRequests 500

#
# KeepAliveTimeout: Number of seconds to wait for the next request from the
# same client on the same connection.
#
KeepAliveTimeout 5


# These need to be set in /etc/apache2/envvars
User ${APACHE_RUN_USER}
Group ${APACHE_RUN_GROUP}

#
# HostnameLookups: Log the names of clients or just their IP addresses
# e.g., www.apache.org (on) or 204.62.129.132 (off).
# The default is off because it'd be overall better for the net if people
# had to knowingly turn this feature on, since enabling it means that
# each client request will result in AT LEAST one lookup request to the
# nameserver.
#
HostnameLookups Off

# ErrorLog: The location of the error log file.
# If you do not specify an ErrorLog directive within a <VirtualHost>
# container, error messages relating to that virtual host will be
# logged here. If you *do* define an error logfile for a <VirtualHost>
# container, that host's errors will be logged there and not here.
#
ErrorLog ${APACHE_LOG_DIR}/error.log

#
# LogLevel: Control the severity of messages logged to the error_log.
# Available values: trace8, ..., trace1, debug, info, notice, warn,
# error, crit, alert, emerg.
# It is also possible to configure the log level for particular modules, e.g.
# "LogLevel info ssl:warn"
#
LogLevel warn

# Include module configuration:
IncludeOptional mods-enabled/*.load
IncludeOptional mods-enabled/*.conf

# Include list of ports to listen on
Include ports.conf


# Sets the default security model of the Apache2 HTTPD server. It does
# not allow access to the root filesystem outside of /usr/share and /var/www.
# The former is used by web applications packaged in Debian,
# the latter may be used for local directories served by the web server. If
# your system is serving content from a sub-directory in /srv you must allow
# access here, or in any related virtual host.
<Directory />
Options FollowSymLinks
AllowOverride None
Require all denied
</Directory>

<Directory /usr/share>
AllowOverride None
Require all granted
</Directory>

<Directory /var/www/>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>

#<Directory /srv/>
# Options Indexes FollowSymLinks
# AllowOverride None
# Require all granted
#</Directory>
# AccessFileName: The name of the file to look for in each directory
# for additional configuration directives. See also the AllowOverride
# directive.
#
AccessFileName .htaccess
#
# The following lines prevent .htaccess and .htpasswd files from being
# viewed by Web clients.
#
<FilesMatch "^.ht">
Require all denied
</FilesMatch>
#
# The following directives define some format nicknames for use with
# a CustomLog directive.
#
# These deviate from the Common Log Format definitions in that they use %O
# (the actual bytes sent including headers) instead of %b (the size of the
# requested file), because the latter makes it impossible to detect partial
# requests.
#
# Note that the use of %{X-Forwarded-For}i instead of %h is not recommended.
# Use mod_remoteip instead.
#
LogFormat "%v:%p %h %l %u %t "%r" %>s %O "%{Referer}i" "%{User-Agent}i"" vhost_combined
LogFormat "%h %l %u %t "%r" %>s %O "%{Referer}i" "%{User-Agent}i"" combined
LogFormat "%h %l %u %t "%r" %>s %O" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
# Include of directories ignores editors' and dpkg's backup files,
# see README.Debian for details.
# Include generic snippets of statements
IncludeOptional conf-enabled/*.conf
# Include the virtual host configurations:
IncludeOptional sites-enabled/*.conf
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet


And this is the conf for my virtual host...



<VirtualHost *:80>
ServerName EXAMPLE.com
ServerAlias www.EXAMPLE.com
UseCanonicalName Off
ServerAlias EXAMPLE1.com
ServerAlias www.EXAMPLE1.com
ServerAlias EXAMPLE2.com
ServerAlias www.EXAMPLE2.com
ServerAlias EXAMPLE.co.uk
ServerAlias www.EXAMPLE.co.uk
ServerAlias EXAMPLE.net
ServerAlias www.EXAMPLE.net
ServerAlias EXAMPLE3.com
ServerAlias www.EXAMPLE3.com
ServerAdmin EXAMPLEd@gmail.com
DocumentRoot /var/www/EXAMPLE.com/httpdocs
<Directory /var/www/EXAMPLE.com/httpdocs>
Options -Indexes +FollowSymLinks
AllowOverride All
</Directory>
ScriptAlias "/cgi-bin/" "/var/www/EXAMPLE.com/cgi-bin/"
#<Directory "/var/www/EXAMPLE.com/cgi-bin/">
# Options +ExecCGI
# AddHandler cgi-script .cgi
# AllowOverride All
#</Directory>
#<Directory "/var/www/EXAMPLE.com/httpdocs/members/cgi-bin">
# Options +ExecCGI
# AddHandler cgi-script .cgi
# AllowOverride All
#</Directory>
#<Directory "/var/www/EXAMPLE.com/httpdocs/pod">
# Options +ExecCGI
# AddHandler cgi-script .cgi
# AllowOverride All
#</Directory>

Alias "/passwd/" "/var/www/EXAMPLE.com/passwd/"

<IfModule mod_ssl.c>
SSLEngine off
</IfModule>

<Directory /var/www/EXAMPLE.com>
Options +ExecCGI +FollowSymLinks +Includes
AddHandler cgi-script .cgi
AllowOverride All
</Directory>

<Directory /var/www/EXAMPLE.com>
<IfModule sapi_apache2.c>
php_admin_flag engine on
php_admin_flag safe_mode on
php_admin_value open_basedir "/var/www/EXAMPLE.com/httpdocs:/tmp"
</IfModule>
<IfModule mod_php5.c>
php_admin_flag engine on
php_admin_flag safe_mode on
php_admin_value open_basedir "/var/www/EXAMPLE.com/httpdocs:/tmp"
</IfModule>
</Directory>

<Directory /var/www/EXAMPLE.com>
RewriteEngine on

# the following section prevents outside sites from hot-linking photos
# leave this next line in allow empty referrers, remove to disallow empty referrers
RewriteCond %{HTTP_REFERER} !^$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?([a-z0-9-]+.)*XX.XXX.XXX.XXX(:[0-9]+)?(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?([a-z0-9-]+.)*EXAMPLE.com(:[0-9]+)?(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?([a-z0-9-]+.)*EXAMPLE.org(:[0-9]+)?(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?([a-z0-9-]+.)*EXAMPLE.net(:[0-9]+)?(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?([a-z0-9-]+.)*EXAMPLE.co.uk(:[0-9]+)?(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?([a-z0-9-]+.)*EXAMPLE.de(:[0-9]+)?(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?1.2.3.4(:[0-9]+)?(/.*)?$
RewriteRule .*.(gif|jpeg|jpg)$ - [NC,F,L]
</Directory>

ErrorLog ${APACHE_LOG_DIR}/EXAMPLE.com-error.log
CustomLog ${APACHE_LOG_DIR}/EXAMPLE.com-access.log combined
# sends 404-not-found errors to error page
ErrorDocument 404 /404-error-page.html

# makes server side includes work on all html pages
AddType text/html .shtml .html .htm
AddHandler server-parsed .shtml .html .htm

RewriteEngine On

# If the hostname is NOT www.domain.com
# RewriteCond %{HTTP_HOST} !^www.EXAMPLE.com$
# 301 redirect to the same resource on www.EXAMPLE.com
# RewriteRule (.*) http://www.EXAMPLE.com$1 [L,R=301]

# sets the web surfer's browser to cache images, style sheets, and JavaScript for a week
<IfModule mod_headers.c>
# WEEK
<FilesMatch ".(jpg|jpeg|png|gif|swf|js|css)$">
Header set Cache-Control "max-age=604800, public"
</FilesMatch>
</IfModule>

</VirtualHost>


Any help anyone can give me will be greatly appreciated! It's amazing what you all do to help other fledgling programmers like myself. Thank you, thank you, thank you.










share|improve this question






















  • To be honest, it is going to be difficult to try and replicate the problem, I would simply start by getting the timezones the same as the previous server and work from there.
    – Gerhard Barnard
    Nov 21 at 8:11










  • An alternative approach instead of keeping a log is to map the time (as an integer, returned by time, to the images, and use that as an offset into the images: my @images = glob 'images/*.jpg'; my $ofs = time / (3600*24); $ofs = $ofs % scalar @images; my $image = $images[$ofs]. See metacpan.org/pod/Time::Slideshow for a module incorporating this.
    – Corion
    Nov 21 at 8:41










  • Does it work if rather than overwriting the log file, you write out the new version to a temporary file and then rename it into place?
    – Chris Turner
    Nov 21 at 10:22






  • 2




    Here's an alternative: Maybe you could rip part of the script out, put it into a new program and run it as a cronjob. Have it pick a picture every time it is called with the same behaviour, but only run it once a night as a cron. Make it create a symlink to the selected picture, and use that in your website. This will resolve the time issues as it will run when the server thinks it's midnight (you can reset the timezone), and it will decrease resource use as it will only be run once.
    – simbabque
    Nov 21 at 10:37












  • Thank you to all of you that replied, for your creative and useful ideas. Ikegami's solution did the trick and I'm back up and running again. I have a great appreciation for all of you who help the less gifted, like myself. Your generosity is inspiring.
    – Brad
    Nov 22 at 8:51














1












1








1







I have a perl cgi script that has been working perfectly for me on a FreeBSD 5.4 Apache 1.3 webserver for many years without trouble. It's a picture of the day script that randomly selects a picture from a given directory for inclusion on an shtml page with the server side include



<!--#exec cgi="/cgi-bin/pod/pod.cgi"-->


I recently migrated to a new server on Google Cloud Platform - Debian 9 (Stretch), Apache 2.4. And the script broke. After setting the server configurations to execute cgi perl scripts correctly, and re-uploading the script in ASCII, the script began working again, but now with an anomalous behavior. Instead of displaying one image (the same image) all day long and then changing the image at midnight (the desired behavior) it is now changing the image every time the page is reloaded in a web browser.



The script uses a flat-file log that keeps track of which images have been used from the source directory, and doesn't repeat displaying of any images until all images from the target directory have been used (logged in pod.log). When working correctly, it will display a new image every day (changing at midnight), which will remain the same for all users, whether the page is reloaded or not, until the following midnight.



Permissions have all been set on the necessary files as specified in the comments of the script. The script has been uploaded to the server in ASCII format (will not work at all if uploaded in binary). The script is displaying an image from the correct directory. BUT..... every time the page is refreshed, a new images is loaded and logged to the pod.log file.



One thing that I thought might be affecting the script was where it was getting the time for the date/time function of the script. When I entered the "date" command from the debian command prompt the server returned the correct time that I had configured the server to - America/Los_Angeles. But I noticed that when files on my webserver were touched or changed, it was time-stamping them with UTC time, which is 8 hours later. Thinking that Apache might be causing the different time-stamp, I tried changing the time-zone in php.ini for apache2. This didn't seem to change anything (after apache2ctl restart), so I thought, maybe I'll change the server timezone to UTC. If you can't beat 'em, join 'em. Right? Well that made it so the "date" command from the debian command line returned the time in UTC. Also noted: files on the webserver were still time-stamping with UTC time zone. All was looking good! But then I checked the time that was being used by perl/cgi with this little gem, which returns the date and time in a human-readable format...



#!/usr/bin/perl
print "Content-type: text/htmlnn";
@months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
@weekDays = qw(Sun Mon Tue Wed Thu Fri Sat Sun);
($second, $minute, $hour, $dayOfMonth, $month, $yearOffset, $dayOfWeek, $dayOfYear, $daylightSavings) = localtime();
$year = 1900 + $yearOffset;
$theTime = "$hour:$minute:$second, $weekDays[$dayOfWeek] $months[$month] $dayOfMonth, $year";
print $theTime;


...And this script was returning the time in the time zone America/Los_Angeles, rather than UTC. Now I don't know if this discrepancy could be the thing causing the bug in my pic of the day script. But my guess, with my very limited experience is telling me that it's at least possible. But I've taken this debugging/troubleshooting of the script about as far as my technical abilities will take me.



I need to know:




  1. what is causing the script to return a new picture and update the log file on every reload, rather than remaining static for 1 day?

  2. is it caused by an unintentional (fat finger) error in the script?

  3. is it caused by some different way my new server and/or its configuration are handling the script?

  4. is it caused by the time-stamp/time-zone issues I mentioned in the previous paragraph?

  5. or is this a result of something I'm completely missing?


Next I'll provide the source code for the script and my apache configuration files. EXAMPLE.COM should be replaced by your domain name wherever it appears and paths to files should be adjusted to your locations.



#!/usr/bin/perl

##############################################################
# POD (Picture of the Day) Version 1.30
##############################################################

package VAR;
use strict;

##############################################################
# Installation
##############################################################

# 1. Edit path to Perl at top of script (pod.cgi) if it
# differs on your server. Usual and default path it
# [/usr/bin/perl]. However, on some servers it may be
# /usr/local/bin/perl. If in doubt, then refer to a script on
# your server that does work, or ask your web host. Edit
# variables below. Ensure you edit (and save) the script using
# an ASCII editor like Notepad.
#
# 2. Via FTP, create directory on server in CGI-BIN called
# pod. No need to CHMOD - you can leave set to server
# default directory permissions.
#
# 3. Via FTP, create subdirectory in 'pod' directory
# called data and CHMOD 777 (drwxrwxrwx).
#
# 4. FTP upload the pod.cgi script to the 'pod'
# directory in ASCII (text) and CHMOD 755 (rwxr-xr-x). You may
# need to rename the scripts with the .pl extension if your
# server uses the .pl extension for CGI-Perl scripts.
#
# images/ 755 (drwxr-xr-x)
# cgi-bin/pod/
# pod.cgi 755 (rwxr-xr-x)
# data/ 777 (drwxrwxrwx)
#

##############################################################
# Operation
##############################################################
#
# METHOD 1: SSI Method
# ====================
# Call the script via SSI (Server-Side Includes). The image
# is embedded in the page. Insert the following SSI tag in
# the desired page:
#
# <!--#exec cgi="/cgi-bin/pod/pod.cgi"-->
#
# In either case, ensure to replace the cgi-bin/pod/ portion
# of the SSI tag with your path to the script.
#
# If you get the [an error occurred while processing this
# directive] error message or no image / message displays,
# make sure (a) the path to Perl is correct, (b) the script
# was uploaded in ASCII, (c) the script is chmod 755
# (rwxr-xr-x) and (d) the path to the script in the SSI tag
# is correct - if in doubt, then ask your web host. If still
# problematic then try the following:
#
# 1. On most servers, the page with a SSI tag must be named
# with the SHTML extension in order for the server to parse
# and execute the SSI tag. Check the page source. If you
# still see the SSI tag, then it was not parsed. Try
# renaming the page with the SHTML extension. If the SSI tag
# is still not parsed (and still visible), then SSI may not
# be enabled on your server - ask your web host.
#
# 2. Try calling the script directly from the browser. If
# you get a server 500 error, then check your server error
# logs.
#
# 3. You can also try the following SSI tag:
#
# <!--#include virtual="/cgi-bin/pod/pod.cgi"-->
#
# METHOD 1: Non-SSI Method
# ====================
# You can also call the script directly from the browser:
#
# http://www.yourdomain.com/cgi-bin/pod/pod.cgi
#
# The image is NOT embedded, but is instead displayed in a
# script generated HTML page.

##############################################################
# Configuration
##############################################################

# Full (absolute) server directory path of directory holding
# image files for the POD script to draw from. Create this
# directory in advance and upload images (in Binary) to this
# directory. No need to chmod. NO trailing slash at end of
# path.
$VAR::image_dir = "/var/www/EXAMPLE.COM/httpdocs/pod";

# URL of directory holding image files for the POD script to
# draw from. NO trailing slash at end of URL.
$VAR::image_url = "http://www.EXAMPLE.COM/pod";

# Full (absolute) server directory path for script data files
# (pod.log, pod.err). Create this directory in advance and
# chmod (777 or drwxrwxrwx). NO trailing slash at end of path.
$VAR::data_dir = "/var/www/EXAMPLE.COM/httpdocs/pod/data";

# Output template - how POD image (or error message) is
# displayed. Feel free to change the HTML but (1) the MS link
# back MUST be retained and (2) the <%image%> tag MUST be
# retained as the tag is replaced with the image (or error
# message) HTML code.
$VAR::template = qq~
<center>
<table border="1">
<th>
<%image%>
</th>
</table>
</center>
~;

##########################################################################
# Do NOT change or alter the code below!
##########################################################################

eval {
($0 =~ m,(.*)/[^/]+,) && unshift (@INC, "$1");
require 5.004;
};
if ($@) {
print "Content-type: text/htmlnn";
print "Server Error Message: $@n";
exit;
}

eval { &main; };
if ($@) { &error ("[Error 01]: $@"); }
exit;

###############################################
# Main
###############################################
sub main {

my ($time, $date) = &get_time_stamp();
my $num;

if (-e "$VAR::data_dir/pod.log") {
open (LOG, "$VAR::data_dir/pod.log") ||
&error ("Error [02]: Cannot open pod.log file - $!");
my @entries = <LOG>;
close (LOG);
chomp (@entries);

my @match = grep (/^$date/, @entries);
if (@match) {
foreach (@match) {
split (/|/);
if ($_[0] eq $date) {
$num = $_[1];
last;
}
}
}
}

opendir (DIR, "$VAR::image_dir") || &error ("Error [03]: Cannot open $VAR::image - $!");
my @files = sort (grep { m/.*.gif|.jpg/ } readdir (DIR));
closedir (DIR);

if ($num eq "") { $num = int (rand @files); }
my $image = @files[$num];
if (! -e "$VAR::image_dir/$image") { &error ("Error [04]: Cannot find image file [$image]"); }

my $tag = "<img src="$VAR::image_url/$image">";
$VAR::template =~ s/<%image%>/$tag/gis;
print $VAR::template;

my ($found, $newfile);
if (-e "$VAR::data_dir/pod.log") {
open (LOG, "$VAR::data_dir/pod.log") ||
&error ("Error [05]: Cannot open pod.log file - $!");
my @entries = <LOG>;
close (LOG);
chomp (@entries);

foreach (@entries) {
split (/|/);
if ($_[0] eq $date) {
$_[2]++;
$newfile .= "$date|$_[1]|$_[2]|$_[3]n";
$found++;
}
else { $newfile .= "$_n"; }
}
if (! $found) { $newfile .= "$date|$num|1|$imagen"; }

open (LOG, ">$VAR::data_dir/pod.log") ||
&error ("Error [06]: Cannot open pod.log file - $!");
flock (LOG, 2) || &error ("Error [07]: Cannot lock pod.log file - $!");
print LOG $newfile;
close (LOG);
}
else {
open (LOG, ">$VAR::data_dir/pod.log") ||
&error ("Error [08]: Cannot open pod.log file - $!");
print LOG "$date|$num|1|$imagen";
close (LOG);
chmod (0666, "$VAR::data_dir/pod.log") ||
&error ("Error [09]: Cannot chmod pod.log file - $!");
}
}

###############################################
# Get Time Stamp
###############################################
sub get_time_stamp {

my (@tb) = localtime (time);
my ($ap) = "am";

$tb[4]++;
for (0..4) { $tb[$_] = sprintf ("%02d", $tb[$_]); }
$tb[5] += 1900;
$ap = "pm" if ($tb[2] >= 12);
$tb[2] -= 12 if ($tb[2] > 12);

my $date = "$tb[4]/$tb[3]/$tb[5]";
return ("$tb[2]:$tb[1]:$tb[0]$ap $date", $date);
}

###############################################
# Error Handler
###############################################
sub error {

my $error = shift;
my ($time, $date) = &get_time_stamp();

my $tag = "Cannot display image";
$VAR::template =~ s/<%image%>/$tag/gis;

print $VAR::template;

open (ERR, ">>$VAR::data_dir/pod.err");
print ERR "$time | $ENV{'REMOTE_ADDR'} | $errorn";
close (ERR);
chmod (0666, "$VAR::data_dir/pod.err");
exit;
}
########################################
#end of Picture of the Day script
########################################


This is my apache2.conf (again, I've changed my domain name to EXAMPLE.COM wherever my domain name appears...



# configuration directives that give the server its instructions.
# See http://httpd.apache.org/docs/2.4/ for detailed information about
# the directives and /usr/share/doc/apache2/README.Debian about Debian specific
# hints.
#
#
# Summary of how the Apache 2 configuration works in Debian:
# The Apache 2 web server configuration in Debian is quite different to
# upstream's suggested way to configure the web server. This is because Debian's
# default Apache2 installation attempts to make adding and removing modules,
# virtual hosts, and extra configuration directives as flexible as possible, in
# order to make automating the changes and administering the server as easy as
# possible.

# It is split into several files forming the configuration hierarchy outlined
# below, all located in the /etc/apache2/ directory:
#
# /etc/apache2/
# |-- apache2.conf
# | `-- ports.conf
# |-- mods-enabled
# | |-- *.load
# | `-- *.conf
# |-- conf-enabled
# | `-- *.conf
# `-- sites-enabled
# `-- *.conf
#
#
# * apache2.conf is the main configuration file (this file). It puts the pieces
# together by including all remaining configuration files when starting up the
# web server.
#
# * ports.conf is always included from the main configuration file. It is
# supposed to determine listening ports for incoming connections which can be
# customized anytime.
#
# * Configuration files in the mods-enabled/, conf-enabled/ and sites-enabled/
# directories contain particular configuration snippets which manage modules,
# global configuration fragments, or virtual host configurations,
# respectively.
#
# They are activated by symlinking available configuration files from their
# respective *-available/ counterparts. These should be managed by using our
# helpers a2enmod/a2dismod, a2ensite/a2dissite and a2enconf/a2disconf. See
# their respective man pages for detailed information.
#
# * The binary is called apache2. Due to the use of environment variables, in
# the default configuration, apache2 needs to be started/stopped with
# /etc/init.d/apache2 or apache2ctl. Calling /usr/bin/apache2 directly will not
# work with the default configuration.


# Global configuration
#

#
# ServerRoot: The top of the directory tree under which the server's
# configuration, error, and log files are kept.
#
# NOTE! If you intend to place this on an NFS (or otherwise network)
# mounted filesystem then please read the Mutex documentation (available
# at <URL:http://httpd.apache.org/docs/2.4/mod/core.html#mutex>);
# you will save yourself a lot of trouble.
#
# Do NOT add a slash at the end of the directory path.
#
#ServerRoot "/etc/apache2"

# Set timezone for apache
SetEnv TZ America/Los_Angeles

#
# The accept serialization lock file MUST BE STORED ON A LOCAL DISK.
#
Mutex file:${APACHE_LOCK_DIR} default

#
# The directory where shm and other runtime files will be stored.
#

DefaultRuntimeDir ${APACHE_RUN_DIR}

#
# PidFile: The file in which the server should record its process
# identification number when it starts.
# This needs to be set in /etc/apache2/envvars
#
PidFile ${APACHE_PID_FILE}

#
# Timeout: The number of seconds before receives and sends time out.
#
Timeout 300

#
# KeepAlive: Whether or not to allow persistent connections (more than
# one request per connection). Set to "Off" to deactivate.
#
KeepAlive On

#
# MaxKeepAliveRequests: The maximum number of requests to allow
# during a persistent connection. Set to 0 to allow an unlimited amount.
# We recommend you leave this number high, for maximum performance.
#
MaxKeepAliveRequests 500

#
# KeepAliveTimeout: Number of seconds to wait for the next request from the
# same client on the same connection.
#
KeepAliveTimeout 5


# These need to be set in /etc/apache2/envvars
User ${APACHE_RUN_USER}
Group ${APACHE_RUN_GROUP}

#
# HostnameLookups: Log the names of clients or just their IP addresses
# e.g., www.apache.org (on) or 204.62.129.132 (off).
# The default is off because it'd be overall better for the net if people
# had to knowingly turn this feature on, since enabling it means that
# each client request will result in AT LEAST one lookup request to the
# nameserver.
#
HostnameLookups Off

# ErrorLog: The location of the error log file.
# If you do not specify an ErrorLog directive within a <VirtualHost>
# container, error messages relating to that virtual host will be
# logged here. If you *do* define an error logfile for a <VirtualHost>
# container, that host's errors will be logged there and not here.
#
ErrorLog ${APACHE_LOG_DIR}/error.log

#
# LogLevel: Control the severity of messages logged to the error_log.
# Available values: trace8, ..., trace1, debug, info, notice, warn,
# error, crit, alert, emerg.
# It is also possible to configure the log level for particular modules, e.g.
# "LogLevel info ssl:warn"
#
LogLevel warn

# Include module configuration:
IncludeOptional mods-enabled/*.load
IncludeOptional mods-enabled/*.conf

# Include list of ports to listen on
Include ports.conf


# Sets the default security model of the Apache2 HTTPD server. It does
# not allow access to the root filesystem outside of /usr/share and /var/www.
# The former is used by web applications packaged in Debian,
# the latter may be used for local directories served by the web server. If
# your system is serving content from a sub-directory in /srv you must allow
# access here, or in any related virtual host.
<Directory />
Options FollowSymLinks
AllowOverride None
Require all denied
</Directory>

<Directory /usr/share>
AllowOverride None
Require all granted
</Directory>

<Directory /var/www/>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>

#<Directory /srv/>
# Options Indexes FollowSymLinks
# AllowOverride None
# Require all granted
#</Directory>
# AccessFileName: The name of the file to look for in each directory
# for additional configuration directives. See also the AllowOverride
# directive.
#
AccessFileName .htaccess
#
# The following lines prevent .htaccess and .htpasswd files from being
# viewed by Web clients.
#
<FilesMatch "^.ht">
Require all denied
</FilesMatch>
#
# The following directives define some format nicknames for use with
# a CustomLog directive.
#
# These deviate from the Common Log Format definitions in that they use %O
# (the actual bytes sent including headers) instead of %b (the size of the
# requested file), because the latter makes it impossible to detect partial
# requests.
#
# Note that the use of %{X-Forwarded-For}i instead of %h is not recommended.
# Use mod_remoteip instead.
#
LogFormat "%v:%p %h %l %u %t "%r" %>s %O "%{Referer}i" "%{User-Agent}i"" vhost_combined
LogFormat "%h %l %u %t "%r" %>s %O "%{Referer}i" "%{User-Agent}i"" combined
LogFormat "%h %l %u %t "%r" %>s %O" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
# Include of directories ignores editors' and dpkg's backup files,
# see README.Debian for details.
# Include generic snippets of statements
IncludeOptional conf-enabled/*.conf
# Include the virtual host configurations:
IncludeOptional sites-enabled/*.conf
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet


And this is the conf for my virtual host...



<VirtualHost *:80>
ServerName EXAMPLE.com
ServerAlias www.EXAMPLE.com
UseCanonicalName Off
ServerAlias EXAMPLE1.com
ServerAlias www.EXAMPLE1.com
ServerAlias EXAMPLE2.com
ServerAlias www.EXAMPLE2.com
ServerAlias EXAMPLE.co.uk
ServerAlias www.EXAMPLE.co.uk
ServerAlias EXAMPLE.net
ServerAlias www.EXAMPLE.net
ServerAlias EXAMPLE3.com
ServerAlias www.EXAMPLE3.com
ServerAdmin EXAMPLEd@gmail.com
DocumentRoot /var/www/EXAMPLE.com/httpdocs
<Directory /var/www/EXAMPLE.com/httpdocs>
Options -Indexes +FollowSymLinks
AllowOverride All
</Directory>
ScriptAlias "/cgi-bin/" "/var/www/EXAMPLE.com/cgi-bin/"
#<Directory "/var/www/EXAMPLE.com/cgi-bin/">
# Options +ExecCGI
# AddHandler cgi-script .cgi
# AllowOverride All
#</Directory>
#<Directory "/var/www/EXAMPLE.com/httpdocs/members/cgi-bin">
# Options +ExecCGI
# AddHandler cgi-script .cgi
# AllowOverride All
#</Directory>
#<Directory "/var/www/EXAMPLE.com/httpdocs/pod">
# Options +ExecCGI
# AddHandler cgi-script .cgi
# AllowOverride All
#</Directory>

Alias "/passwd/" "/var/www/EXAMPLE.com/passwd/"

<IfModule mod_ssl.c>
SSLEngine off
</IfModule>

<Directory /var/www/EXAMPLE.com>
Options +ExecCGI +FollowSymLinks +Includes
AddHandler cgi-script .cgi
AllowOverride All
</Directory>

<Directory /var/www/EXAMPLE.com>
<IfModule sapi_apache2.c>
php_admin_flag engine on
php_admin_flag safe_mode on
php_admin_value open_basedir "/var/www/EXAMPLE.com/httpdocs:/tmp"
</IfModule>
<IfModule mod_php5.c>
php_admin_flag engine on
php_admin_flag safe_mode on
php_admin_value open_basedir "/var/www/EXAMPLE.com/httpdocs:/tmp"
</IfModule>
</Directory>

<Directory /var/www/EXAMPLE.com>
RewriteEngine on

# the following section prevents outside sites from hot-linking photos
# leave this next line in allow empty referrers, remove to disallow empty referrers
RewriteCond %{HTTP_REFERER} !^$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?([a-z0-9-]+.)*XX.XXX.XXX.XXX(:[0-9]+)?(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?([a-z0-9-]+.)*EXAMPLE.com(:[0-9]+)?(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?([a-z0-9-]+.)*EXAMPLE.org(:[0-9]+)?(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?([a-z0-9-]+.)*EXAMPLE.net(:[0-9]+)?(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?([a-z0-9-]+.)*EXAMPLE.co.uk(:[0-9]+)?(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?([a-z0-9-]+.)*EXAMPLE.de(:[0-9]+)?(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?1.2.3.4(:[0-9]+)?(/.*)?$
RewriteRule .*.(gif|jpeg|jpg)$ - [NC,F,L]
</Directory>

ErrorLog ${APACHE_LOG_DIR}/EXAMPLE.com-error.log
CustomLog ${APACHE_LOG_DIR}/EXAMPLE.com-access.log combined
# sends 404-not-found errors to error page
ErrorDocument 404 /404-error-page.html

# makes server side includes work on all html pages
AddType text/html .shtml .html .htm
AddHandler server-parsed .shtml .html .htm

RewriteEngine On

# If the hostname is NOT www.domain.com
# RewriteCond %{HTTP_HOST} !^www.EXAMPLE.com$
# 301 redirect to the same resource on www.EXAMPLE.com
# RewriteRule (.*) http://www.EXAMPLE.com$1 [L,R=301]

# sets the web surfer's browser to cache images, style sheets, and JavaScript for a week
<IfModule mod_headers.c>
# WEEK
<FilesMatch ".(jpg|jpeg|png|gif|swf|js|css)$">
Header set Cache-Control "max-age=604800, public"
</FilesMatch>
</IfModule>

</VirtualHost>


Any help anyone can give me will be greatly appreciated! It's amazing what you all do to help other fledgling programmers like myself. Thank you, thank you, thank you.










share|improve this question













I have a perl cgi script that has been working perfectly for me on a FreeBSD 5.4 Apache 1.3 webserver for many years without trouble. It's a picture of the day script that randomly selects a picture from a given directory for inclusion on an shtml page with the server side include



<!--#exec cgi="/cgi-bin/pod/pod.cgi"-->


I recently migrated to a new server on Google Cloud Platform - Debian 9 (Stretch), Apache 2.4. And the script broke. After setting the server configurations to execute cgi perl scripts correctly, and re-uploading the script in ASCII, the script began working again, but now with an anomalous behavior. Instead of displaying one image (the same image) all day long and then changing the image at midnight (the desired behavior) it is now changing the image every time the page is reloaded in a web browser.



The script uses a flat-file log that keeps track of which images have been used from the source directory, and doesn't repeat displaying of any images until all images from the target directory have been used (logged in pod.log). When working correctly, it will display a new image every day (changing at midnight), which will remain the same for all users, whether the page is reloaded or not, until the following midnight.



Permissions have all been set on the necessary files as specified in the comments of the script. The script has been uploaded to the server in ASCII format (will not work at all if uploaded in binary). The script is displaying an image from the correct directory. BUT..... every time the page is refreshed, a new images is loaded and logged to the pod.log file.



One thing that I thought might be affecting the script was where it was getting the time for the date/time function of the script. When I entered the "date" command from the debian command prompt the server returned the correct time that I had configured the server to - America/Los_Angeles. But I noticed that when files on my webserver were touched or changed, it was time-stamping them with UTC time, which is 8 hours later. Thinking that Apache might be causing the different time-stamp, I tried changing the time-zone in php.ini for apache2. This didn't seem to change anything (after apache2ctl restart), so I thought, maybe I'll change the server timezone to UTC. If you can't beat 'em, join 'em. Right? Well that made it so the "date" command from the debian command line returned the time in UTC. Also noted: files on the webserver were still time-stamping with UTC time zone. All was looking good! But then I checked the time that was being used by perl/cgi with this little gem, which returns the date and time in a human-readable format...



#!/usr/bin/perl
print "Content-type: text/htmlnn";
@months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
@weekDays = qw(Sun Mon Tue Wed Thu Fri Sat Sun);
($second, $minute, $hour, $dayOfMonth, $month, $yearOffset, $dayOfWeek, $dayOfYear, $daylightSavings) = localtime();
$year = 1900 + $yearOffset;
$theTime = "$hour:$minute:$second, $weekDays[$dayOfWeek] $months[$month] $dayOfMonth, $year";
print $theTime;


...And this script was returning the time in the time zone America/Los_Angeles, rather than UTC. Now I don't know if this discrepancy could be the thing causing the bug in my pic of the day script. But my guess, with my very limited experience is telling me that it's at least possible. But I've taken this debugging/troubleshooting of the script about as far as my technical abilities will take me.



I need to know:




  1. what is causing the script to return a new picture and update the log file on every reload, rather than remaining static for 1 day?

  2. is it caused by an unintentional (fat finger) error in the script?

  3. is it caused by some different way my new server and/or its configuration are handling the script?

  4. is it caused by the time-stamp/time-zone issues I mentioned in the previous paragraph?

  5. or is this a result of something I'm completely missing?


Next I'll provide the source code for the script and my apache configuration files. EXAMPLE.COM should be replaced by your domain name wherever it appears and paths to files should be adjusted to your locations.



#!/usr/bin/perl

##############################################################
# POD (Picture of the Day) Version 1.30
##############################################################

package VAR;
use strict;

##############################################################
# Installation
##############################################################

# 1. Edit path to Perl at top of script (pod.cgi) if it
# differs on your server. Usual and default path it
# [/usr/bin/perl]. However, on some servers it may be
# /usr/local/bin/perl. If in doubt, then refer to a script on
# your server that does work, or ask your web host. Edit
# variables below. Ensure you edit (and save) the script using
# an ASCII editor like Notepad.
#
# 2. Via FTP, create directory on server in CGI-BIN called
# pod. No need to CHMOD - you can leave set to server
# default directory permissions.
#
# 3. Via FTP, create subdirectory in 'pod' directory
# called data and CHMOD 777 (drwxrwxrwx).
#
# 4. FTP upload the pod.cgi script to the 'pod'
# directory in ASCII (text) and CHMOD 755 (rwxr-xr-x). You may
# need to rename the scripts with the .pl extension if your
# server uses the .pl extension for CGI-Perl scripts.
#
# images/ 755 (drwxr-xr-x)
# cgi-bin/pod/
# pod.cgi 755 (rwxr-xr-x)
# data/ 777 (drwxrwxrwx)
#

##############################################################
# Operation
##############################################################
#
# METHOD 1: SSI Method
# ====================
# Call the script via SSI (Server-Side Includes). The image
# is embedded in the page. Insert the following SSI tag in
# the desired page:
#
# <!--#exec cgi="/cgi-bin/pod/pod.cgi"-->
#
# In either case, ensure to replace the cgi-bin/pod/ portion
# of the SSI tag with your path to the script.
#
# If you get the [an error occurred while processing this
# directive] error message or no image / message displays,
# make sure (a) the path to Perl is correct, (b) the script
# was uploaded in ASCII, (c) the script is chmod 755
# (rwxr-xr-x) and (d) the path to the script in the SSI tag
# is correct - if in doubt, then ask your web host. If still
# problematic then try the following:
#
# 1. On most servers, the page with a SSI tag must be named
# with the SHTML extension in order for the server to parse
# and execute the SSI tag. Check the page source. If you
# still see the SSI tag, then it was not parsed. Try
# renaming the page with the SHTML extension. If the SSI tag
# is still not parsed (and still visible), then SSI may not
# be enabled on your server - ask your web host.
#
# 2. Try calling the script directly from the browser. If
# you get a server 500 error, then check your server error
# logs.
#
# 3. You can also try the following SSI tag:
#
# <!--#include virtual="/cgi-bin/pod/pod.cgi"-->
#
# METHOD 1: Non-SSI Method
# ====================
# You can also call the script directly from the browser:
#
# http://www.yourdomain.com/cgi-bin/pod/pod.cgi
#
# The image is NOT embedded, but is instead displayed in a
# script generated HTML page.

##############################################################
# Configuration
##############################################################

# Full (absolute) server directory path of directory holding
# image files for the POD script to draw from. Create this
# directory in advance and upload images (in Binary) to this
# directory. No need to chmod. NO trailing slash at end of
# path.
$VAR::image_dir = "/var/www/EXAMPLE.COM/httpdocs/pod";

# URL of directory holding image files for the POD script to
# draw from. NO trailing slash at end of URL.
$VAR::image_url = "http://www.EXAMPLE.COM/pod";

# Full (absolute) server directory path for script data files
# (pod.log, pod.err). Create this directory in advance and
# chmod (777 or drwxrwxrwx). NO trailing slash at end of path.
$VAR::data_dir = "/var/www/EXAMPLE.COM/httpdocs/pod/data";

# Output template - how POD image (or error message) is
# displayed. Feel free to change the HTML but (1) the MS link
# back MUST be retained and (2) the <%image%> tag MUST be
# retained as the tag is replaced with the image (or error
# message) HTML code.
$VAR::template = qq~
<center>
<table border="1">
<th>
<%image%>
</th>
</table>
</center>
~;

##########################################################################
# Do NOT change or alter the code below!
##########################################################################

eval {
($0 =~ m,(.*)/[^/]+,) && unshift (@INC, "$1");
require 5.004;
};
if ($@) {
print "Content-type: text/htmlnn";
print "Server Error Message: $@n";
exit;
}

eval { &main; };
if ($@) { &error ("[Error 01]: $@"); }
exit;

###############################################
# Main
###############################################
sub main {

my ($time, $date) = &get_time_stamp();
my $num;

if (-e "$VAR::data_dir/pod.log") {
open (LOG, "$VAR::data_dir/pod.log") ||
&error ("Error [02]: Cannot open pod.log file - $!");
my @entries = <LOG>;
close (LOG);
chomp (@entries);

my @match = grep (/^$date/, @entries);
if (@match) {
foreach (@match) {
split (/|/);
if ($_[0] eq $date) {
$num = $_[1];
last;
}
}
}
}

opendir (DIR, "$VAR::image_dir") || &error ("Error [03]: Cannot open $VAR::image - $!");
my @files = sort (grep { m/.*.gif|.jpg/ } readdir (DIR));
closedir (DIR);

if ($num eq "") { $num = int (rand @files); }
my $image = @files[$num];
if (! -e "$VAR::image_dir/$image") { &error ("Error [04]: Cannot find image file [$image]"); }

my $tag = "<img src="$VAR::image_url/$image">";
$VAR::template =~ s/<%image%>/$tag/gis;
print $VAR::template;

my ($found, $newfile);
if (-e "$VAR::data_dir/pod.log") {
open (LOG, "$VAR::data_dir/pod.log") ||
&error ("Error [05]: Cannot open pod.log file - $!");
my @entries = <LOG>;
close (LOG);
chomp (@entries);

foreach (@entries) {
split (/|/);
if ($_[0] eq $date) {
$_[2]++;
$newfile .= "$date|$_[1]|$_[2]|$_[3]n";
$found++;
}
else { $newfile .= "$_n"; }
}
if (! $found) { $newfile .= "$date|$num|1|$imagen"; }

open (LOG, ">$VAR::data_dir/pod.log") ||
&error ("Error [06]: Cannot open pod.log file - $!");
flock (LOG, 2) || &error ("Error [07]: Cannot lock pod.log file - $!");
print LOG $newfile;
close (LOG);
}
else {
open (LOG, ">$VAR::data_dir/pod.log") ||
&error ("Error [08]: Cannot open pod.log file - $!");
print LOG "$date|$num|1|$imagen";
close (LOG);
chmod (0666, "$VAR::data_dir/pod.log") ||
&error ("Error [09]: Cannot chmod pod.log file - $!");
}
}

###############################################
# Get Time Stamp
###############################################
sub get_time_stamp {

my (@tb) = localtime (time);
my ($ap) = "am";

$tb[4]++;
for (0..4) { $tb[$_] = sprintf ("%02d", $tb[$_]); }
$tb[5] += 1900;
$ap = "pm" if ($tb[2] >= 12);
$tb[2] -= 12 if ($tb[2] > 12);

my $date = "$tb[4]/$tb[3]/$tb[5]";
return ("$tb[2]:$tb[1]:$tb[0]$ap $date", $date);
}

###############################################
# Error Handler
###############################################
sub error {

my $error = shift;
my ($time, $date) = &get_time_stamp();

my $tag = "Cannot display image";
$VAR::template =~ s/<%image%>/$tag/gis;

print $VAR::template;

open (ERR, ">>$VAR::data_dir/pod.err");
print ERR "$time | $ENV{'REMOTE_ADDR'} | $errorn";
close (ERR);
chmod (0666, "$VAR::data_dir/pod.err");
exit;
}
########################################
#end of Picture of the Day script
########################################


This is my apache2.conf (again, I've changed my domain name to EXAMPLE.COM wherever my domain name appears...



# configuration directives that give the server its instructions.
# See http://httpd.apache.org/docs/2.4/ for detailed information about
# the directives and /usr/share/doc/apache2/README.Debian about Debian specific
# hints.
#
#
# Summary of how the Apache 2 configuration works in Debian:
# The Apache 2 web server configuration in Debian is quite different to
# upstream's suggested way to configure the web server. This is because Debian's
# default Apache2 installation attempts to make adding and removing modules,
# virtual hosts, and extra configuration directives as flexible as possible, in
# order to make automating the changes and administering the server as easy as
# possible.

# It is split into several files forming the configuration hierarchy outlined
# below, all located in the /etc/apache2/ directory:
#
# /etc/apache2/
# |-- apache2.conf
# | `-- ports.conf
# |-- mods-enabled
# | |-- *.load
# | `-- *.conf
# |-- conf-enabled
# | `-- *.conf
# `-- sites-enabled
# `-- *.conf
#
#
# * apache2.conf is the main configuration file (this file). It puts the pieces
# together by including all remaining configuration files when starting up the
# web server.
#
# * ports.conf is always included from the main configuration file. It is
# supposed to determine listening ports for incoming connections which can be
# customized anytime.
#
# * Configuration files in the mods-enabled/, conf-enabled/ and sites-enabled/
# directories contain particular configuration snippets which manage modules,
# global configuration fragments, or virtual host configurations,
# respectively.
#
# They are activated by symlinking available configuration files from their
# respective *-available/ counterparts. These should be managed by using our
# helpers a2enmod/a2dismod, a2ensite/a2dissite and a2enconf/a2disconf. See
# their respective man pages for detailed information.
#
# * The binary is called apache2. Due to the use of environment variables, in
# the default configuration, apache2 needs to be started/stopped with
# /etc/init.d/apache2 or apache2ctl. Calling /usr/bin/apache2 directly will not
# work with the default configuration.


# Global configuration
#

#
# ServerRoot: The top of the directory tree under which the server's
# configuration, error, and log files are kept.
#
# NOTE! If you intend to place this on an NFS (or otherwise network)
# mounted filesystem then please read the Mutex documentation (available
# at <URL:http://httpd.apache.org/docs/2.4/mod/core.html#mutex>);
# you will save yourself a lot of trouble.
#
# Do NOT add a slash at the end of the directory path.
#
#ServerRoot "/etc/apache2"

# Set timezone for apache
SetEnv TZ America/Los_Angeles

#
# The accept serialization lock file MUST BE STORED ON A LOCAL DISK.
#
Mutex file:${APACHE_LOCK_DIR} default

#
# The directory where shm and other runtime files will be stored.
#

DefaultRuntimeDir ${APACHE_RUN_DIR}

#
# PidFile: The file in which the server should record its process
# identification number when it starts.
# This needs to be set in /etc/apache2/envvars
#
PidFile ${APACHE_PID_FILE}

#
# Timeout: The number of seconds before receives and sends time out.
#
Timeout 300

#
# KeepAlive: Whether or not to allow persistent connections (more than
# one request per connection). Set to "Off" to deactivate.
#
KeepAlive On

#
# MaxKeepAliveRequests: The maximum number of requests to allow
# during a persistent connection. Set to 0 to allow an unlimited amount.
# We recommend you leave this number high, for maximum performance.
#
MaxKeepAliveRequests 500

#
# KeepAliveTimeout: Number of seconds to wait for the next request from the
# same client on the same connection.
#
KeepAliveTimeout 5


# These need to be set in /etc/apache2/envvars
User ${APACHE_RUN_USER}
Group ${APACHE_RUN_GROUP}

#
# HostnameLookups: Log the names of clients or just their IP addresses
# e.g., www.apache.org (on) or 204.62.129.132 (off).
# The default is off because it'd be overall better for the net if people
# had to knowingly turn this feature on, since enabling it means that
# each client request will result in AT LEAST one lookup request to the
# nameserver.
#
HostnameLookups Off

# ErrorLog: The location of the error log file.
# If you do not specify an ErrorLog directive within a <VirtualHost>
# container, error messages relating to that virtual host will be
# logged here. If you *do* define an error logfile for a <VirtualHost>
# container, that host's errors will be logged there and not here.
#
ErrorLog ${APACHE_LOG_DIR}/error.log

#
# LogLevel: Control the severity of messages logged to the error_log.
# Available values: trace8, ..., trace1, debug, info, notice, warn,
# error, crit, alert, emerg.
# It is also possible to configure the log level for particular modules, e.g.
# "LogLevel info ssl:warn"
#
LogLevel warn

# Include module configuration:
IncludeOptional mods-enabled/*.load
IncludeOptional mods-enabled/*.conf

# Include list of ports to listen on
Include ports.conf


# Sets the default security model of the Apache2 HTTPD server. It does
# not allow access to the root filesystem outside of /usr/share and /var/www.
# The former is used by web applications packaged in Debian,
# the latter may be used for local directories served by the web server. If
# your system is serving content from a sub-directory in /srv you must allow
# access here, or in any related virtual host.
<Directory />
Options FollowSymLinks
AllowOverride None
Require all denied
</Directory>

<Directory /usr/share>
AllowOverride None
Require all granted
</Directory>

<Directory /var/www/>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>

#<Directory /srv/>
# Options Indexes FollowSymLinks
# AllowOverride None
# Require all granted
#</Directory>
# AccessFileName: The name of the file to look for in each directory
# for additional configuration directives. See also the AllowOverride
# directive.
#
AccessFileName .htaccess
#
# The following lines prevent .htaccess and .htpasswd files from being
# viewed by Web clients.
#
<FilesMatch "^.ht">
Require all denied
</FilesMatch>
#
# The following directives define some format nicknames for use with
# a CustomLog directive.
#
# These deviate from the Common Log Format definitions in that they use %O
# (the actual bytes sent including headers) instead of %b (the size of the
# requested file), because the latter makes it impossible to detect partial
# requests.
#
# Note that the use of %{X-Forwarded-For}i instead of %h is not recommended.
# Use mod_remoteip instead.
#
LogFormat "%v:%p %h %l %u %t "%r" %>s %O "%{Referer}i" "%{User-Agent}i"" vhost_combined
LogFormat "%h %l %u %t "%r" %>s %O "%{Referer}i" "%{User-Agent}i"" combined
LogFormat "%h %l %u %t "%r" %>s %O" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
# Include of directories ignores editors' and dpkg's backup files,
# see README.Debian for details.
# Include generic snippets of statements
IncludeOptional conf-enabled/*.conf
# Include the virtual host configurations:
IncludeOptional sites-enabled/*.conf
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet


And this is the conf for my virtual host...



<VirtualHost *:80>
ServerName EXAMPLE.com
ServerAlias www.EXAMPLE.com
UseCanonicalName Off
ServerAlias EXAMPLE1.com
ServerAlias www.EXAMPLE1.com
ServerAlias EXAMPLE2.com
ServerAlias www.EXAMPLE2.com
ServerAlias EXAMPLE.co.uk
ServerAlias www.EXAMPLE.co.uk
ServerAlias EXAMPLE.net
ServerAlias www.EXAMPLE.net
ServerAlias EXAMPLE3.com
ServerAlias www.EXAMPLE3.com
ServerAdmin EXAMPLEd@gmail.com
DocumentRoot /var/www/EXAMPLE.com/httpdocs
<Directory /var/www/EXAMPLE.com/httpdocs>
Options -Indexes +FollowSymLinks
AllowOverride All
</Directory>
ScriptAlias "/cgi-bin/" "/var/www/EXAMPLE.com/cgi-bin/"
#<Directory "/var/www/EXAMPLE.com/cgi-bin/">
# Options +ExecCGI
# AddHandler cgi-script .cgi
# AllowOverride All
#</Directory>
#<Directory "/var/www/EXAMPLE.com/httpdocs/members/cgi-bin">
# Options +ExecCGI
# AddHandler cgi-script .cgi
# AllowOverride All
#</Directory>
#<Directory "/var/www/EXAMPLE.com/httpdocs/pod">
# Options +ExecCGI
# AddHandler cgi-script .cgi
# AllowOverride All
#</Directory>

Alias "/passwd/" "/var/www/EXAMPLE.com/passwd/"

<IfModule mod_ssl.c>
SSLEngine off
</IfModule>

<Directory /var/www/EXAMPLE.com>
Options +ExecCGI +FollowSymLinks +Includes
AddHandler cgi-script .cgi
AllowOverride All
</Directory>

<Directory /var/www/EXAMPLE.com>
<IfModule sapi_apache2.c>
php_admin_flag engine on
php_admin_flag safe_mode on
php_admin_value open_basedir "/var/www/EXAMPLE.com/httpdocs:/tmp"
</IfModule>
<IfModule mod_php5.c>
php_admin_flag engine on
php_admin_flag safe_mode on
php_admin_value open_basedir "/var/www/EXAMPLE.com/httpdocs:/tmp"
</IfModule>
</Directory>

<Directory /var/www/EXAMPLE.com>
RewriteEngine on

# the following section prevents outside sites from hot-linking photos
# leave this next line in allow empty referrers, remove to disallow empty referrers
RewriteCond %{HTTP_REFERER} !^$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?([a-z0-9-]+.)*XX.XXX.XXX.XXX(:[0-9]+)?(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?([a-z0-9-]+.)*EXAMPLE.com(:[0-9]+)?(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?([a-z0-9-]+.)*EXAMPLE.org(:[0-9]+)?(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?([a-z0-9-]+.)*EXAMPLE.net(:[0-9]+)?(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?([a-z0-9-]+.)*EXAMPLE.co.uk(:[0-9]+)?(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?([a-z0-9-]+.)*EXAMPLE.de(:[0-9]+)?(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?1.2.3.4(:[0-9]+)?(/.*)?$
RewriteRule .*.(gif|jpeg|jpg)$ - [NC,F,L]
</Directory>

ErrorLog ${APACHE_LOG_DIR}/EXAMPLE.com-error.log
CustomLog ${APACHE_LOG_DIR}/EXAMPLE.com-access.log combined
# sends 404-not-found errors to error page
ErrorDocument 404 /404-error-page.html

# makes server side includes work on all html pages
AddType text/html .shtml .html .htm
AddHandler server-parsed .shtml .html .htm

RewriteEngine On

# If the hostname is NOT www.domain.com
# RewriteCond %{HTTP_HOST} !^www.EXAMPLE.com$
# 301 redirect to the same resource on www.EXAMPLE.com
# RewriteRule (.*) http://www.EXAMPLE.com$1 [L,R=301]

# sets the web surfer's browser to cache images, style sheets, and JavaScript for a week
<IfModule mod_headers.c>
# WEEK
<FilesMatch ".(jpg|jpeg|png|gif|swf|js|css)$">
Header set Cache-Control "max-age=604800, public"
</FilesMatch>
</IfModule>

</VirtualHost>


Any help anyone can give me will be greatly appreciated! It's amazing what you all do to help other fledgling programmers like myself. Thank you, thank you, thank you.







apache perl timestamp debian cgi






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 21 at 1:32









Brad

82




82












  • To be honest, it is going to be difficult to try and replicate the problem, I would simply start by getting the timezones the same as the previous server and work from there.
    – Gerhard Barnard
    Nov 21 at 8:11










  • An alternative approach instead of keeping a log is to map the time (as an integer, returned by time, to the images, and use that as an offset into the images: my @images = glob 'images/*.jpg'; my $ofs = time / (3600*24); $ofs = $ofs % scalar @images; my $image = $images[$ofs]. See metacpan.org/pod/Time::Slideshow for a module incorporating this.
    – Corion
    Nov 21 at 8:41










  • Does it work if rather than overwriting the log file, you write out the new version to a temporary file and then rename it into place?
    – Chris Turner
    Nov 21 at 10:22






  • 2




    Here's an alternative: Maybe you could rip part of the script out, put it into a new program and run it as a cronjob. Have it pick a picture every time it is called with the same behaviour, but only run it once a night as a cron. Make it create a symlink to the selected picture, and use that in your website. This will resolve the time issues as it will run when the server thinks it's midnight (you can reset the timezone), and it will decrease resource use as it will only be run once.
    – simbabque
    Nov 21 at 10:37












  • Thank you to all of you that replied, for your creative and useful ideas. Ikegami's solution did the trick and I'm back up and running again. I have a great appreciation for all of you who help the less gifted, like myself. Your generosity is inspiring.
    – Brad
    Nov 22 at 8:51


















  • To be honest, it is going to be difficult to try and replicate the problem, I would simply start by getting the timezones the same as the previous server and work from there.
    – Gerhard Barnard
    Nov 21 at 8:11










  • An alternative approach instead of keeping a log is to map the time (as an integer, returned by time, to the images, and use that as an offset into the images: my @images = glob 'images/*.jpg'; my $ofs = time / (3600*24); $ofs = $ofs % scalar @images; my $image = $images[$ofs]. See metacpan.org/pod/Time::Slideshow for a module incorporating this.
    – Corion
    Nov 21 at 8:41










  • Does it work if rather than overwriting the log file, you write out the new version to a temporary file and then rename it into place?
    – Chris Turner
    Nov 21 at 10:22






  • 2




    Here's an alternative: Maybe you could rip part of the script out, put it into a new program and run it as a cronjob. Have it pick a picture every time it is called with the same behaviour, but only run it once a night as a cron. Make it create a symlink to the selected picture, and use that in your website. This will resolve the time issues as it will run when the server thinks it's midnight (you can reset the timezone), and it will decrease resource use as it will only be run once.
    – simbabque
    Nov 21 at 10:37












  • Thank you to all of you that replied, for your creative and useful ideas. Ikegami's solution did the trick and I'm back up and running again. I have a great appreciation for all of you who help the less gifted, like myself. Your generosity is inspiring.
    – Brad
    Nov 22 at 8:51
















To be honest, it is going to be difficult to try and replicate the problem, I would simply start by getting the timezones the same as the previous server and work from there.
– Gerhard Barnard
Nov 21 at 8:11




To be honest, it is going to be difficult to try and replicate the problem, I would simply start by getting the timezones the same as the previous server and work from there.
– Gerhard Barnard
Nov 21 at 8:11












An alternative approach instead of keeping a log is to map the time (as an integer, returned by time, to the images, and use that as an offset into the images: my @images = glob 'images/*.jpg'; my $ofs = time / (3600*24); $ofs = $ofs % scalar @images; my $image = $images[$ofs]. See metacpan.org/pod/Time::Slideshow for a module incorporating this.
– Corion
Nov 21 at 8:41




An alternative approach instead of keeping a log is to map the time (as an integer, returned by time, to the images, and use that as an offset into the images: my @images = glob 'images/*.jpg'; my $ofs = time / (3600*24); $ofs = $ofs % scalar @images; my $image = $images[$ofs]. See metacpan.org/pod/Time::Slideshow for a module incorporating this.
– Corion
Nov 21 at 8:41












Does it work if rather than overwriting the log file, you write out the new version to a temporary file and then rename it into place?
– Chris Turner
Nov 21 at 10:22




Does it work if rather than overwriting the log file, you write out the new version to a temporary file and then rename it into place?
– Chris Turner
Nov 21 at 10:22




2




2




Here's an alternative: Maybe you could rip part of the script out, put it into a new program and run it as a cronjob. Have it pick a picture every time it is called with the same behaviour, but only run it once a night as a cron. Make it create a symlink to the selected picture, and use that in your website. This will resolve the time issues as it will run when the server thinks it's midnight (you can reset the timezone), and it will decrease resource use as it will only be run once.
– simbabque
Nov 21 at 10:37






Here's an alternative: Maybe you could rip part of the script out, put it into a new program and run it as a cronjob. Have it pick a picture every time it is called with the same behaviour, but only run it once a night as a cron. Make it create a symlink to the selected picture, and use that in your website. This will resolve the time issues as it will run when the server thinks it's midnight (you can reset the timezone), and it will decrease resource use as it will only be run once.
– simbabque
Nov 21 at 10:37














Thank you to all of you that replied, for your creative and useful ideas. Ikegami's solution did the trick and I'm back up and running again. I have a great appreciation for all of you who help the less gifted, like myself. Your generosity is inspiring.
– Brad
Nov 22 at 8:51




Thank you to all of you that replied, for your creative and useful ideas. Ikegami's solution did the trick and I'm back up and running again. I have a great appreciation for all of you who help the less gifted, like myself. Your generosity is inspiring.
– Brad
Nov 22 at 8:51












2 Answers
2






active

oldest

votes


















5














Before Perl 5.12, split stored its result in @_ when called in void context. That's a horrible practice, so that "functionality" was removed in 5.12, and a warning was added (Useless use of split in void context).



I suspect you are using a newer version of Perl than you previously used, one in which split doesn't behave specially in void context. If that's the case, you should have received a warning. Always use use strict; use warnings qw( all );!



To fix the problem, replace



split (/|/);


with



@_ = split (/|/);


(You should use a different array than @_, but the above is the minimal change.)





You seem to have spent a lot of time on this, but without actually spending any time trying to debug the problem! The first thing you have done is added the missing use warnings qw( all );, which would have identified the problem immediately. Even without that, minimal work should have narrowed down the problem to the split.




  1. You should have found that $num eq "" is always true.

  2. This would have led you to find that $_[0] eq $date is always false.

  3. This would have led you to find that $_[0] is never set.






share|improve this answer























  • ikegami - thank you so much for your detailed explanation. I can't begin to thank you enough. I'm very grateful to all of you who provide help to those of us who benefit from your work. This was not only the solution, but you led me to a better understanding of how to debug perl code in the future. The script is back to performing 100% as expected, thanks to you. Bravo! <standing and clapping> To paraphrase Sir Isaac Newton, "If my coding has improved, it is because I stand on the shoulders of giants."
    – Brad
    Nov 22 at 8:48



















1














To add some data to ikegami's excellent answer.




  • FreeBSD 5.4 seems to have shipped with two versions of Perl during its lifetime - 5.6.2 and 5.8.6.

  • Debian 9 ships with Perl 5.24.1.


The release notes for Perl 5.14 say this:




split() no longer modifies @_ when called in scalar or void context. In void context it now produces a "Useless use of split" warning. This was also a perl 5.12.0 change that missed the perldelta.




I'm sure you've learned a valuable lesson here :-) When moving code from one version of Perl to another, you should always at least scan the release notes for the intervening versions so you know what problems you might encounter.



I'll also reiterate the simbabque's comment. This approach seems rather weird. For every request to your web page, you are checking to see if you have already allocated a picture of the day (which happens on the first request of the day) and then serving the chosen picture. It would be far more efficient to use a cronjob to create a symlink to an image once a day and just include the URL of that image in your web page.






share|improve this answer





















  • Thank you for your added insight, Dave Cross. As I think I indicated in my post, this is just a script that I "borrowed" and modified for my purposes, that has always worked for me (until recently of course). My coding skills are abysmal. But thanks to generous contributors of knowledge such as yourself, I'm slowly learning. I found the prospect of posting here in the first place, to be daunting. And, in fact, I have waited until I absolutely could find no other solution, before I posted my request, because I wouldn't want to waste any of you or the others' time.
    – Brad
    Nov 22 at 9:00











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53404090%2fperl-cgi-picture-of-the-day-script-not-behaving-as-expected-after-migration-to-n%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes









5














Before Perl 5.12, split stored its result in @_ when called in void context. That's a horrible practice, so that "functionality" was removed in 5.12, and a warning was added (Useless use of split in void context).



I suspect you are using a newer version of Perl than you previously used, one in which split doesn't behave specially in void context. If that's the case, you should have received a warning. Always use use strict; use warnings qw( all );!



To fix the problem, replace



split (/|/);


with



@_ = split (/|/);


(You should use a different array than @_, but the above is the minimal change.)





You seem to have spent a lot of time on this, but without actually spending any time trying to debug the problem! The first thing you have done is added the missing use warnings qw( all );, which would have identified the problem immediately. Even without that, minimal work should have narrowed down the problem to the split.




  1. You should have found that $num eq "" is always true.

  2. This would have led you to find that $_[0] eq $date is always false.

  3. This would have led you to find that $_[0] is never set.






share|improve this answer























  • ikegami - thank you so much for your detailed explanation. I can't begin to thank you enough. I'm very grateful to all of you who provide help to those of us who benefit from your work. This was not only the solution, but you led me to a better understanding of how to debug perl code in the future. The script is back to performing 100% as expected, thanks to you. Bravo! <standing and clapping> To paraphrase Sir Isaac Newton, "If my coding has improved, it is because I stand on the shoulders of giants."
    – Brad
    Nov 22 at 8:48
















5














Before Perl 5.12, split stored its result in @_ when called in void context. That's a horrible practice, so that "functionality" was removed in 5.12, and a warning was added (Useless use of split in void context).



I suspect you are using a newer version of Perl than you previously used, one in which split doesn't behave specially in void context. If that's the case, you should have received a warning. Always use use strict; use warnings qw( all );!



To fix the problem, replace



split (/|/);


with



@_ = split (/|/);


(You should use a different array than @_, but the above is the minimal change.)





You seem to have spent a lot of time on this, but without actually spending any time trying to debug the problem! The first thing you have done is added the missing use warnings qw( all );, which would have identified the problem immediately. Even without that, minimal work should have narrowed down the problem to the split.




  1. You should have found that $num eq "" is always true.

  2. This would have led you to find that $_[0] eq $date is always false.

  3. This would have led you to find that $_[0] is never set.






share|improve this answer























  • ikegami - thank you so much for your detailed explanation. I can't begin to thank you enough. I'm very grateful to all of you who provide help to those of us who benefit from your work. This was not only the solution, but you led me to a better understanding of how to debug perl code in the future. The script is back to performing 100% as expected, thanks to you. Bravo! <standing and clapping> To paraphrase Sir Isaac Newton, "If my coding has improved, it is because I stand on the shoulders of giants."
    – Brad
    Nov 22 at 8:48














5












5








5






Before Perl 5.12, split stored its result in @_ when called in void context. That's a horrible practice, so that "functionality" was removed in 5.12, and a warning was added (Useless use of split in void context).



I suspect you are using a newer version of Perl than you previously used, one in which split doesn't behave specially in void context. If that's the case, you should have received a warning. Always use use strict; use warnings qw( all );!



To fix the problem, replace



split (/|/);


with



@_ = split (/|/);


(You should use a different array than @_, but the above is the minimal change.)





You seem to have spent a lot of time on this, but without actually spending any time trying to debug the problem! The first thing you have done is added the missing use warnings qw( all );, which would have identified the problem immediately. Even without that, minimal work should have narrowed down the problem to the split.




  1. You should have found that $num eq "" is always true.

  2. This would have led you to find that $_[0] eq $date is always false.

  3. This would have led you to find that $_[0] is never set.






share|improve this answer














Before Perl 5.12, split stored its result in @_ when called in void context. That's a horrible practice, so that "functionality" was removed in 5.12, and a warning was added (Useless use of split in void context).



I suspect you are using a newer version of Perl than you previously used, one in which split doesn't behave specially in void context. If that's the case, you should have received a warning. Always use use strict; use warnings qw( all );!



To fix the problem, replace



split (/|/);


with



@_ = split (/|/);


(You should use a different array than @_, but the above is the minimal change.)





You seem to have spent a lot of time on this, but without actually spending any time trying to debug the problem! The first thing you have done is added the missing use warnings qw( all );, which would have identified the problem immediately. Even without that, minimal work should have narrowed down the problem to the split.




  1. You should have found that $num eq "" is always true.

  2. This would have led you to find that $_[0] eq $date is always false.

  3. This would have led you to find that $_[0] is never set.







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 21 at 23:34

























answered Nov 21 at 11:18









ikegami

261k11176396




261k11176396












  • ikegami - thank you so much for your detailed explanation. I can't begin to thank you enough. I'm very grateful to all of you who provide help to those of us who benefit from your work. This was not only the solution, but you led me to a better understanding of how to debug perl code in the future. The script is back to performing 100% as expected, thanks to you. Bravo! <standing and clapping> To paraphrase Sir Isaac Newton, "If my coding has improved, it is because I stand on the shoulders of giants."
    – Brad
    Nov 22 at 8:48


















  • ikegami - thank you so much for your detailed explanation. I can't begin to thank you enough. I'm very grateful to all of you who provide help to those of us who benefit from your work. This was not only the solution, but you led me to a better understanding of how to debug perl code in the future. The script is back to performing 100% as expected, thanks to you. Bravo! <standing and clapping> To paraphrase Sir Isaac Newton, "If my coding has improved, it is because I stand on the shoulders of giants."
    – Brad
    Nov 22 at 8:48
















ikegami - thank you so much for your detailed explanation. I can't begin to thank you enough. I'm very grateful to all of you who provide help to those of us who benefit from your work. This was not only the solution, but you led me to a better understanding of how to debug perl code in the future. The script is back to performing 100% as expected, thanks to you. Bravo! <standing and clapping> To paraphrase Sir Isaac Newton, "If my coding has improved, it is because I stand on the shoulders of giants."
– Brad
Nov 22 at 8:48




ikegami - thank you so much for your detailed explanation. I can't begin to thank you enough. I'm very grateful to all of you who provide help to those of us who benefit from your work. This was not only the solution, but you led me to a better understanding of how to debug perl code in the future. The script is back to performing 100% as expected, thanks to you. Bravo! <standing and clapping> To paraphrase Sir Isaac Newton, "If my coding has improved, it is because I stand on the shoulders of giants."
– Brad
Nov 22 at 8:48













1














To add some data to ikegami's excellent answer.




  • FreeBSD 5.4 seems to have shipped with two versions of Perl during its lifetime - 5.6.2 and 5.8.6.

  • Debian 9 ships with Perl 5.24.1.


The release notes for Perl 5.14 say this:




split() no longer modifies @_ when called in scalar or void context. In void context it now produces a "Useless use of split" warning. This was also a perl 5.12.0 change that missed the perldelta.




I'm sure you've learned a valuable lesson here :-) When moving code from one version of Perl to another, you should always at least scan the release notes for the intervening versions so you know what problems you might encounter.



I'll also reiterate the simbabque's comment. This approach seems rather weird. For every request to your web page, you are checking to see if you have already allocated a picture of the day (which happens on the first request of the day) and then serving the chosen picture. It would be far more efficient to use a cronjob to create a symlink to an image once a day and just include the URL of that image in your web page.






share|improve this answer





















  • Thank you for your added insight, Dave Cross. As I think I indicated in my post, this is just a script that I "borrowed" and modified for my purposes, that has always worked for me (until recently of course). My coding skills are abysmal. But thanks to generous contributors of knowledge such as yourself, I'm slowly learning. I found the prospect of posting here in the first place, to be daunting. And, in fact, I have waited until I absolutely could find no other solution, before I posted my request, because I wouldn't want to waste any of you or the others' time.
    – Brad
    Nov 22 at 9:00
















1














To add some data to ikegami's excellent answer.




  • FreeBSD 5.4 seems to have shipped with two versions of Perl during its lifetime - 5.6.2 and 5.8.6.

  • Debian 9 ships with Perl 5.24.1.


The release notes for Perl 5.14 say this:




split() no longer modifies @_ when called in scalar or void context. In void context it now produces a "Useless use of split" warning. This was also a perl 5.12.0 change that missed the perldelta.




I'm sure you've learned a valuable lesson here :-) When moving code from one version of Perl to another, you should always at least scan the release notes for the intervening versions so you know what problems you might encounter.



I'll also reiterate the simbabque's comment. This approach seems rather weird. For every request to your web page, you are checking to see if you have already allocated a picture of the day (which happens on the first request of the day) and then serving the chosen picture. It would be far more efficient to use a cronjob to create a symlink to an image once a day and just include the URL of that image in your web page.






share|improve this answer





















  • Thank you for your added insight, Dave Cross. As I think I indicated in my post, this is just a script that I "borrowed" and modified for my purposes, that has always worked for me (until recently of course). My coding skills are abysmal. But thanks to generous contributors of knowledge such as yourself, I'm slowly learning. I found the prospect of posting here in the first place, to be daunting. And, in fact, I have waited until I absolutely could find no other solution, before I posted my request, because I wouldn't want to waste any of you or the others' time.
    – Brad
    Nov 22 at 9:00














1












1








1






To add some data to ikegami's excellent answer.




  • FreeBSD 5.4 seems to have shipped with two versions of Perl during its lifetime - 5.6.2 and 5.8.6.

  • Debian 9 ships with Perl 5.24.1.


The release notes for Perl 5.14 say this:




split() no longer modifies @_ when called in scalar or void context. In void context it now produces a "Useless use of split" warning. This was also a perl 5.12.0 change that missed the perldelta.




I'm sure you've learned a valuable lesson here :-) When moving code from one version of Perl to another, you should always at least scan the release notes for the intervening versions so you know what problems you might encounter.



I'll also reiterate the simbabque's comment. This approach seems rather weird. For every request to your web page, you are checking to see if you have already allocated a picture of the day (which happens on the first request of the day) and then serving the chosen picture. It would be far more efficient to use a cronjob to create a symlink to an image once a day and just include the URL of that image in your web page.






share|improve this answer












To add some data to ikegami's excellent answer.




  • FreeBSD 5.4 seems to have shipped with two versions of Perl during its lifetime - 5.6.2 and 5.8.6.

  • Debian 9 ships with Perl 5.24.1.


The release notes for Perl 5.14 say this:




split() no longer modifies @_ when called in scalar or void context. In void context it now produces a "Useless use of split" warning. This was also a perl 5.12.0 change that missed the perldelta.




I'm sure you've learned a valuable lesson here :-) When moving code from one version of Perl to another, you should always at least scan the release notes for the intervening versions so you know what problems you might encounter.



I'll also reiterate the simbabque's comment. This approach seems rather weird. For every request to your web page, you are checking to see if you have already allocated a picture of the day (which happens on the first request of the day) and then serving the chosen picture. It would be far more efficient to use a cronjob to create a symlink to an image once a day and just include the URL of that image in your web page.







share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 21 at 12:10









Dave Cross

46.2k33877




46.2k33877












  • Thank you for your added insight, Dave Cross. As I think I indicated in my post, this is just a script that I "borrowed" and modified for my purposes, that has always worked for me (until recently of course). My coding skills are abysmal. But thanks to generous contributors of knowledge such as yourself, I'm slowly learning. I found the prospect of posting here in the first place, to be daunting. And, in fact, I have waited until I absolutely could find no other solution, before I posted my request, because I wouldn't want to waste any of you or the others' time.
    – Brad
    Nov 22 at 9:00


















  • Thank you for your added insight, Dave Cross. As I think I indicated in my post, this is just a script that I "borrowed" and modified for my purposes, that has always worked for me (until recently of course). My coding skills are abysmal. But thanks to generous contributors of knowledge such as yourself, I'm slowly learning. I found the prospect of posting here in the first place, to be daunting. And, in fact, I have waited until I absolutely could find no other solution, before I posted my request, because I wouldn't want to waste any of you or the others' time.
    – Brad
    Nov 22 at 9:00
















Thank you for your added insight, Dave Cross. As I think I indicated in my post, this is just a script that I "borrowed" and modified for my purposes, that has always worked for me (until recently of course). My coding skills are abysmal. But thanks to generous contributors of knowledge such as yourself, I'm slowly learning. I found the prospect of posting here in the first place, to be daunting. And, in fact, I have waited until I absolutely could find no other solution, before I posted my request, because I wouldn't want to waste any of you or the others' time.
– Brad
Nov 22 at 9:00




Thank you for your added insight, Dave Cross. As I think I indicated in my post, this is just a script that I "borrowed" and modified for my purposes, that has always worked for me (until recently of course). My coding skills are abysmal. But thanks to generous contributors of knowledge such as yourself, I'm slowly learning. I found the prospect of posting here in the first place, to be daunting. And, in fact, I have waited until I absolutely could find no other solution, before I posted my request, because I wouldn't want to waste any of you or the others' time.
– Brad
Nov 22 at 9:00


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53404090%2fperl-cgi-picture-of-the-day-script-not-behaving-as-expected-after-migration-to-n%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

404 Error Contact Form 7 ajax form submitting

How to know if a Active Directory user can login interactively

TypeError: fit_transform() missing 1 required positional argument: 'X'