我有一个perl cgi脚本,多年来在我的FreeBSD 5.4 Apache 1.3 Web服务器上一直运行良好,没有任何麻烦。这是一天脚本的图片,它从给定目录中随机选择一张图片,以使其包含在服务器端包含
的shtml页面中<!--#exec cgi="/cgi-bin/pod/pod.cgi"-->
我最近迁移到了Google Cloud Platform上的新服务器-Debian 9(Stretch),Apache 2.4。剧本坏了。设置服务器配置以正确执行cgi perl脚本,并以ASCII重新上载脚本后,该脚本再次开始工作,但是现在出现异常行为。现在,每次在Web浏览器中重新加载页面时,不再是整天显示一张图像(同一张图像),而是在午夜更改图像(所需的行为),而是在更改图像。
该脚本使用平面文件日志,该日志跟踪源目录中已使用了哪些图像,并且在使用了目标目录中的所有图像之前(在pod.log中记录)不会重复显示任何图像。 )。正常工作后,它将每天显示一个新图像(在午夜更改),无论页面是否重新加载,所有用户都将保持不变,直到下一个午夜。
所有权限均已在脚本注释中指定的必要文件上设置。该脚本已以ASCII格式上载到服务器(如果以二进制形式上载则完全不起作用)。该脚本正在显示来自正确目录的图像。但是.....每次刷新页面时,都会加载新图像并将其记录到pod.log文件中。
我认为可能会影响脚本的一件事是它获取脚本日期/时间功能的时间。当我从debian命令提示符输入“ date”命令时,服务器将我配置服务器的正确时间返回到-America / Los_Angeles。但是我注意到,当触摸或更改我的Web服务器上的文件时,它是用UTC时间(这是8小时后)加时间戳的。考虑到Apache可能会导致不同的时间戳,我尝试为apache2更改php.ini中的时区。 (在apache2ctl重新启动之后),这似乎没有任何改变,所以我想,也许我会将服务器时区更改为UTC。如果您无法击败他们,请加入他们。对?很好,因此来自debian命令行的“ date”命令返回了UTC时间。还应注意:Web服务器上的文件仍带有UTC时区的时间戳。一切都很好看!但是后来我用这个小宝石检查了perl / cgi所用的时间,该时间以人类可读的格式返回了日期和时间...
#!/usr/bin/perl
print "Content-type: text/html\n\n";
@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;
...并且此脚本返回的时区为America / Los_Angeles时区,而不是UTC。现在我不知道这种差异是否是导致我的每日脚本中的错误的原因。但是根据我的经验,我的猜测是告诉我至少有可能。但是我已经对脚本进行了调试/故障排除,以了解我的技术能力。
我需要知道:
接下来,我将提供脚本的源代码和我的apache配置文件。不论出现在哪里,EXAMPLE.COM都应替换为您的域名,并且文件的路径应根据您的位置进行调整。
#!/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/html\n\n";
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|$image\n"; }
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|$image\n";
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'} | $error\n";
close (ERR);
chmod (0666, "$VAR::data_dir/pod.err");
exit;
}
########################################
#end of Picture of the Day script
########################################
这是我的apache2.conf(同样,无论我的域名出现在哪里,我都将其域名更改为EXAMPLE.COM ...
# 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
这是我的虚拟主机的配置文件...
<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>
任何人都能给我的帮助将不胜感激!你们所有人都为帮助像我这样的新兴雏形而做的事情真是太神奇了。谢谢,谢谢,谢谢。
答案 0 :(得分:5)
在Perl 5.12之前,在空白上下文中调用时,split
将其结果存储在@_
中。这是一种可怕的做法,因此在5.12中删除了“功能”,并添加了警告(Useless use of split in void context
)。
我怀疑您正在使用比以前使用的Perl更新的版本,其中split
在void上下文中的行为不是特别的。如果是这样,您应该已经收到警告。始终使用use strict; use warnings qw( all );
!
要解决此问题,请替换
split (/\|/);
使用
@_ = split (/\|/);
(您应该使用与@_
不同的数组,但以上是最小的更改。)
您似乎在此上花费了很多时间,但实际上并没有花费任何时间来尝试调试问题!您要做的第一件事是添加了丢失的use warnings qw( all );
,这会立即发现问题。即使没有这些,最少的工作也应该将问题缩小到split
。
$num eq ""
始终是正确的。$_[0] eq $date
始终为假。$_[0]
。答案 1 :(得分:1)
为池上的出色回答添加一些数据。
release notes for Perl 5.14这样说:
在标量或无效上下文中调用时,
split()
不再修改@_
。在无效上下文中,它现在会产生“拆分的无用使用”警告。这也是Perl 5.12.0的更改,错过了Perldelta。
我确定您在这里学到了宝贵的经验:-)将代码从一个版本的Perl迁移到另一个版本时,应始终至少扫描发行说明中的中间版本,以便您了解可能遇到的问题
我还要重申辛巴克的评论。这种方法似乎很奇怪。对于您对网页的每个请求,您都在检查是否已经分配了当天的图片(在当天的第一个请求中发生),然后投放选定的图片。每天使用一次cronjob创建到图像的符号链接,而只需在网页中包含该图像的URL,效率会更高。