| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
$VERSION = "1.29"; |
|
2
|
|
|
|
|
|
|
package CGI::SHTML; |
|
3
|
|
|
|
|
|
|
our $VERSION = "1.29"; |
|
4
|
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
# -*- Perl -*- Wed May 19 13:09:58 CDT 2004 |
|
6
|
|
|
|
|
|
|
############################################################################# |
|
7
|
|
|
|
|
|
|
# Written by Tim Skirvin |
|
8
|
|
|
|
|
|
|
# Copyright 2001-2004, Tim Skirvin and UIUC Board of Trustees. |
|
9
|
|
|
|
|
|
|
# Redistribution terms are below. |
|
10
|
|
|
|
|
|
|
############################################################################# |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
=head1 NAME |
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
CGI::SHTML - a CGI module for parsing SSI |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
use CGI::SHTML; |
|
19
|
|
|
|
|
|
|
my $cgi = new CGI::SHTML; |
|
20
|
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
# Print a full page worth of info |
|
22
|
|
|
|
|
|
|
print $cgi->header(); |
|
23
|
|
|
|
|
|
|
print $cgi->start_html('internal', -title=>"SAMPLE PAGE"); |
|
24
|
|
|
|
|
|
|
# Insert content here |
|
25
|
|
|
|
|
|
|
print $cgi->end_html('internal', -author=>"Webmaster", |
|
26
|
|
|
|
|
|
|
-address=>'webserver@ks.uiuc.edu'); |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
# Just parse some SSI text |
|
29
|
|
|
|
|
|
|
my @text = ''; |
|
30
|
|
|
|
|
|
|
print CGI::SHTML->parse_shtml(@text); |
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
# Use a different configuration file |
|
33
|
|
|
|
|
|
|
BEGIN { $CGI::SHTML::CONFIG = "/home/tskirvin/shtml.pm"; } |
|
34
|
|
|
|
|
|
|
use CGI::SHTML; |
|
35
|
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
Further functionality is documented with the CGI module. |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
In order to parse SSI, you generally have to configure your scripts to be |
|
41
|
|
|
|
|
|
|
re-parsed through Apache itself. This module eliminates that need by |
|
42
|
|
|
|
|
|
|
parsing SSI headers itself, as best it can. |
|
43
|
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
Some information on SSI is available at |
|
45
|
|
|
|
|
|
|
B. |
|
46
|
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
=head2 VARIABLES |
|
48
|
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
=over 2 |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
=item $CGI::SHTML::CONFIG |
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
Defines a file that has further configuration for your web site. This is |
|
54
|
|
|
|
|
|
|
useful to allow the module to be installed system-wide without actually |
|
55
|
|
|
|
|
|
|
requiring changes to be internal to the file. Note that you'll need to |
|
56
|
|
|
|
|
|
|
reset this value *before* loading CGI::SHTML if you want it to actually |
|
57
|
|
|
|
|
|
|
make any difference; it's loaded when you load the module. |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
=back |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
=cut |
|
62
|
|
|
|
|
|
|
|
|
63
|
1
|
|
|
1
|
|
806
|
use strict; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
33
|
|
|
64
|
1
|
|
|
1
|
|
1039
|
use Time::Local; |
|
|
1
|
|
|
|
|
2028
|
|
|
|
1
|
|
|
|
|
68
|
|
|
65
|
1
|
|
|
1
|
|
11197
|
use CGI; |
|
|
1
|
|
|
|
|
22439
|
|
|
|
1
|
|
|
|
|
7
|
|
|
66
|
1
|
|
|
1
|
|
54
|
use warnings; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
35
|
|
|
67
|
1
|
|
|
1
|
|
6
|
use vars qw( @ISA $EMPTY $ROOTDIR %REPLACE %CONFIG %HEADER %FOOTER $CONFIG ); |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
94
|
|
|
68
|
1
|
|
|
1
|
|
4
|
use vars qw( $IF $NOPRINT ); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
6323
|
|
|
69
|
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
### User Defined Variables #################################################### |
|
71
|
|
|
|
|
|
|
$CONFIG ||= "/home/webserver/conf/shtml.pm"; |
|
72
|
|
|
|
|
|
|
$ROOTDIR = $ENV{'DOCUMENT_ROOT'} || "/Common/WebRoot"; |
|
73
|
|
|
|
|
|
|
$EMPTY = ""; # Edit this for debugging |
|
74
|
|
|
|
|
|
|
%REPLACE = ( ); |
|
75
|
|
|
|
|
|
|
%CONFIG = ( 'timefmt' => "%D",); |
|
76
|
|
|
|
|
|
|
%HEADER = ( |
|
77
|
|
|
|
|
|
|
'internal' => '/include/header-info.shtml', |
|
78
|
|
|
|
|
|
|
'generic' => '/include/header-generic.shtml', |
|
79
|
|
|
|
|
|
|
); |
|
80
|
|
|
|
|
|
|
%FOOTER = ( |
|
81
|
|
|
|
|
|
|
'internal' => '/include/footer-info.shtml', |
|
82
|
|
|
|
|
|
|
'generic' => '/include/footer-generic.shtml', |
|
83
|
|
|
|
|
|
|
); |
|
84
|
|
|
|
|
|
|
############################################################################### |
|
85
|
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
# Set some environment variables that are important for SSI |
|
87
|
|
|
|
|
|
|
$ENV{'DATE_GMT'} = gmtime(time); |
|
88
|
|
|
|
|
|
|
$ENV{'DATE_LOCAL'} = localtime(time); |
|
89
|
|
|
|
|
|
|
$ENV{'DOCUMENT_URI'} = join('', "http://", |
|
90
|
|
|
|
|
|
|
$ENV{'SERVER_NAME'} || "localhost", |
|
91
|
|
|
|
|
|
|
$ENV{'SCRIPT_NAME'} || $0 ) ; |
|
92
|
|
|
|
|
|
|
$ENV{'LAST_MODIFIED'} = CGI::SHTML->_flastmod( $ENV{'SCRIPT_FILENAME'} || $0 ); |
|
93
|
|
|
|
|
|
|
delete $ENV{'PATH'}; |
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
@ISA = "CGI"; |
|
96
|
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
if ( -r $CONFIG ) { do $CONFIG } |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
=head2 SUBROUTINES |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
=over 2 |
|
102
|
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
=item new () |
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
Invokes CGI's new() command, but blesses with the local class. Also |
|
106
|
|
|
|
|
|
|
performs the various local functions that are necessary. |
|
107
|
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
=cut |
|
109
|
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
sub new { |
|
111
|
0
|
|
|
0
|
1
|
0
|
my $item = CGI::new(@_); |
|
112
|
0
|
|
|
|
|
0
|
$$item{'NOPRINT'} = []; |
|
113
|
0
|
|
|
|
|
0
|
$$item{'IFDONE'} = []; |
|
114
|
0
|
|
|
|
|
0
|
$$item{'IF'} = 0; |
|
115
|
0
|
|
|
|
|
0
|
bless $item, shift; $item; |
|
|
0
|
|
|
|
|
0
|
|
|
116
|
|
|
|
|
|
|
} |
|
117
|
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
=item parse_shtml ( LINE [, LINE [, LINE ]] ) |
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
Parses C as if it were an SHTML file. Returns the parsed set of |
|
121
|
|
|
|
|
|
|
lines, either in an array context or as a single string suitable for |
|
122
|
|
|
|
|
|
|
printing. All of the work is actually done by C. |
|
123
|
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
=cut |
|
125
|
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
sub parse_shtml { |
|
127
|
0
|
|
|
0
|
1
|
0
|
my ($self, @lines) = @_; |
|
128
|
0
|
|
|
|
|
0
|
map { chomp } @lines; my $line = join("\n", @lines); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
129
|
0
|
|
|
|
|
0
|
my @parts = split m/()/s, $line; |
|
130
|
|
|
|
|
|
|
|
|
131
|
0
|
|
|
|
|
0
|
my @return; |
|
132
|
0
|
|
|
|
|
0
|
while (@parts) { |
|
133
|
0
|
|
|
|
|
0
|
my @ssi = (); |
|
134
|
0
|
|
0
|
|
|
0
|
my $text = shift @parts || ""; |
|
135
|
0
|
0
|
|
|
|
0
|
unless ($self->_noprint) { |
|
136
|
0
|
0
|
0
|
|
|
0
|
push @return, $text if defined $text && $text ne ''; |
|
137
|
|
|
|
|
|
|
} |
|
138
|
0
|
0
|
0
|
|
|
0
|
if (scalar @parts && $parts[0] =~ /^\s*$/m) { |
|
139
|
0
|
|
|
|
|
0
|
@ssi = ($1, $2); shift @parts; |
|
|
0
|
|
|
|
|
0
|
|
|
140
|
|
|
|
|
|
|
} |
|
141
|
0
|
0
|
|
|
|
0
|
my $ssival = $ssi[0] ? $self->ssi(@ssi) : undef; |
|
142
|
0
|
0
|
|
|
|
0
|
unless ($self->_noprint) { |
|
143
|
0
|
0
|
0
|
|
|
0
|
push @return, $ssival if defined $ssival && $ssival ne ''; |
|
144
|
|
|
|
|
|
|
} |
|
145
|
|
|
|
|
|
|
} |
|
146
|
|
|
|
|
|
|
|
|
147
|
0
|
|
|
|
|
0
|
my $final = join("\n", @return); |
|
148
|
0
|
|
|
|
|
0
|
$final; |
|
149
|
|
|
|
|
|
|
} |
|
150
|
|
|
|
|
|
|
|
|
151
|
0
|
|
|
0
|
|
0
|
sub _ifdone { shift->_arrayset('IFDONE', @_) } |
|
152
|
0
|
|
|
0
|
|
0
|
sub _noprint { shift->_arrayset('NOPRINT', @_) } |
|
153
|
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
sub _arrayset { |
|
155
|
0
|
|
|
0
|
|
0
|
my ($self, $key, $val) = @_; |
|
156
|
0
|
|
|
|
|
0
|
my $array = $$self{$key}; |
|
157
|
0
|
|
|
|
|
0
|
my $if = $$self{'IF'} - 1; |
|
158
|
0
|
0
|
|
|
|
0
|
if (defined $val) { $$array[$if] = $val } |
|
|
0
|
|
|
|
|
0
|
|
|
159
|
0
|
0
|
|
|
|
0
|
$$array[$if] || 0; |
|
160
|
|
|
|
|
|
|
} |
|
161
|
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
=item ssi ( COMMAND, ARGS ) |
|
163
|
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
Does the work of parsing an SSI statement. C is one of the |
|
165
|
|
|
|
|
|
|
standard SSI "tags" - 'echo', 'include', 'fsize', 'flastmod', 'exec', |
|
166
|
|
|
|
|
|
|
'set', 'config', 'odbc', 'email', 'if', 'goto', 'label', and 'break'. |
|
167
|
|
|
|
|
|
|
C is a string containing the rest of the SSI command - it is parsed |
|
168
|
|
|
|
|
|
|
by this function. |
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
Note: not all commands are implemented. In fact, all that is implemented |
|
171
|
|
|
|
|
|
|
is 'echo', 'include', 'fsize', 'flastmod', 'exec', 'if/elif/else/endif', |
|
172
|
|
|
|
|
|
|
and 'set'. These are all the ones that I've actually had to use to this |
|
173
|
|
|
|
|
|
|
point. |
|
174
|
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
=cut |
|
176
|
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
sub ssi { |
|
178
|
0
|
|
|
0
|
1
|
0
|
my ($self, $command, $args) = @_; |
|
179
|
0
|
|
|
|
|
0
|
my %hash = (); |
|
180
|
|
|
|
|
|
|
|
|
181
|
0
|
|
|
|
|
0
|
while ($args) { # Parse $args |
|
182
|
0
|
|
|
|
|
0
|
$args =~ s/^(\w+)=(\"[^\"]*\"|'.*'|\S+)\s*//; |
|
183
|
0
|
0
|
|
|
|
0
|
last unless defined($1); |
|
184
|
0
|
|
|
|
|
0
|
my $item = lc $1; my $val = $2; |
|
|
0
|
|
|
|
|
0
|
|
|
185
|
0
|
|
|
|
|
0
|
$val =~ s/^\"|\"$//g; |
|
186
|
0
|
0
|
|
|
|
0
|
$hash{$item} = $val if defined($val); |
|
187
|
|
|
|
|
|
|
} |
|
188
|
|
|
|
|
|
|
|
|
189
|
0
|
|
|
|
|
0
|
my $orig = $self->_noprint; |
|
190
|
0
|
|
|
|
|
0
|
my $if = $$self{'IF'}; |
|
191
|
0
|
0
|
0
|
|
|
0
|
if (lc $command eq 'if' or lc $command eq 'elif') { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
192
|
0
|
0
|
|
|
|
0
|
if (lc $command eq 'if') { $$self{'IF'}++; $if = $$self{'IF'}; } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
193
|
0
|
0
|
|
|
|
0
|
if ($self->_ifdone) { $self->_noprint(1); return "" } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
194
|
0
|
|
|
|
|
0
|
my $val = _ssieval(\%hash); |
|
195
|
0
|
0
|
|
|
|
0
|
if ($val) { $self->_noprint(0); $self->_ifdone(1); } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
196
|
0
|
|
|
|
|
0
|
else { $self->_noprint(1); } |
|
197
|
|
|
|
|
|
|
|
|
198
|
0
|
|
|
|
|
0
|
my $noprint = $self->_noprint; |
|
199
|
0
|
|
|
|
|
0
|
return ""; |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
} elsif (lc $command eq 'else') { |
|
202
|
0
|
0
|
|
|
|
0
|
if ($self->_ifdone) { $self->_noprint(1); } |
|
|
0
|
|
|
|
|
0
|
|
|
203
|
0
|
|
|
|
|
0
|
else { $self->_noprint(0); $self->_ifdone(1); } |
|
|
0
|
|
|
|
|
0
|
|
|
204
|
0
|
|
|
|
|
0
|
my $noprint = $self->_noprint; |
|
205
|
0
|
|
|
|
|
0
|
return ""; |
|
206
|
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
} elsif (lc $command eq 'endif') { |
|
208
|
0
|
|
|
|
|
0
|
my $noprint = $self->_noprint(0); |
|
209
|
0
|
|
|
|
|
0
|
my $ifdone = $self->_ifdone(0); |
|
210
|
0
|
|
|
|
|
0
|
$$self{'IF'}--; |
|
211
|
0
|
|
|
|
|
0
|
return ""; |
|
212
|
|
|
|
|
|
|
} |
|
213
|
|
|
|
|
|
|
|
|
214
|
0
|
0
|
|
|
|
0
|
if (lc $command eq 'include') { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
215
|
0
|
0
|
|
|
|
0
|
if ( defined $hash{'virtual'} ) { $self->_file(_vfile( $hash{'virtual'} )) } |
|
|
0
|
0
|
|
|
|
0
|
|
|
216
|
0
|
|
|
|
|
0
|
elsif ( defined $hash{'file'} ) { $self->_file( $hash{'file'} ) } |
|
217
|
0
|
|
|
|
|
0
|
else { return "No filename offered" }; |
|
218
|
|
|
|
|
|
|
} elsif (lc $command eq 'set') { |
|
219
|
0
|
|
0
|
|
|
0
|
my $var = $hash{'var'} || return "No variable to set"; |
|
220
|
0
|
|
0
|
|
|
0
|
my $value = $hash{'value'} || ""; |
|
221
|
0
|
|
|
|
|
0
|
$value =~ s/\{(.*)\}/$1/g; |
|
222
|
0
|
0
|
|
|
|
0
|
$value =~ s/^\$(\S+)/$ENV{$1} || $EMPTY/egx; |
|
|
0
|
|
|
|
|
0
|
|
|
223
|
0
|
|
|
|
|
0
|
$ENV{$var} = $value; |
|
224
|
|
|
|
|
|
|
# Should do something with "config" |
|
225
|
0
|
|
|
|
|
0
|
return ""; |
|
226
|
|
|
|
|
|
|
} elsif (lc $command eq 'echo') { |
|
227
|
0
|
|
|
|
|
0
|
$hash{'var'} =~ s/\{(.*)\}/$1/g; |
|
228
|
0
|
|
0
|
|
|
0
|
return $ENV{$hash{'var'}} || $EMPTY; |
|
229
|
|
|
|
|
|
|
} elsif (lc $command eq 'exec') { |
|
230
|
0
|
0
|
|
|
|
0
|
if ( defined $hash{'cmd'} ) { $self->_execute( $hash{'cmd'} ) || "" } |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
|
|
|
231
|
0
|
|
|
|
|
0
|
elsif ( defined $hash{'cgi'} ) { $self->_execute( _vfile($hash{'cgi'}) ) } |
|
232
|
0
|
|
|
|
|
0
|
else { return "No filename offered" }; |
|
233
|
|
|
|
|
|
|
} elsif (lc $command eq 'fsize') { |
|
234
|
0
|
0
|
|
|
|
0
|
if ( defined $hash{'virtual'}) { $self->_fsize(_vfile($hash{'virtual'}))} |
|
|
0
|
0
|
|
|
|
0
|
|
|
235
|
0
|
|
|
|
|
0
|
elsif ( defined $hash{'file'}) { $self->_fsize( $hash{'file'} ) } |
|
236
|
0
|
|
|
|
|
0
|
else { return "No filename offered" }; |
|
237
|
|
|
|
|
|
|
} elsif (lc $command eq 'flastmod') { |
|
238
|
0
|
0
|
|
|
|
0
|
if (defined $hash{'virtual'}) { $self->_flastmod(_vfile($hash{'virtual'}))} |
|
|
0
|
0
|
|
|
|
0
|
|
|
239
|
0
|
|
|
|
|
0
|
elsif ( defined $hash{'file'}) { $self->_flastmod( $hash{'file'} ) } |
|
240
|
0
|
|
|
|
|
0
|
else { return "No filename offered" }; |
|
241
|
0
|
|
|
|
|
0
|
} else { return "" } |
|
242
|
|
|
|
|
|
|
} |
|
243
|
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
=item start_html ( TYPE, OPTIONS ) |
|
245
|
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
Invokes C, and includes the appropriate header file. |
|
247
|
|
|
|
|
|
|
C is passed directly into C, after being parsed |
|
248
|
|
|
|
|
|
|
for the 'title' field (which is specially set). C is used to decide |
|
249
|
|
|
|
|
|
|
which header file is being used; the possibilities are in |
|
250
|
|
|
|
|
|
|
C<$CGI::SHTML::HEADER>. |
|
251
|
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
=cut |
|
253
|
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
sub start_html { |
|
255
|
0
|
|
|
0
|
1
|
0
|
my ($self, $type, %hash) = @_; |
|
256
|
0
|
|
0
|
|
|
0
|
$type = lc $type; $type ||= 'default'; |
|
|
0
|
|
|
|
|
0
|
|
|
257
|
|
|
|
|
|
|
|
|
258
|
0
|
|
|
|
|
0
|
foreach my $key (keys %hash) { |
|
259
|
0
|
0
|
|
|
|
0
|
if (lc $key eq '-title') { $ENV{'TITLE'} = $hash{$key} } |
|
|
0
|
|
|
|
|
0
|
|
|
260
|
|
|
|
|
|
|
} |
|
261
|
|
|
|
|
|
|
|
|
262
|
0
|
|
|
|
|
0
|
my $command = ""; |
|
263
|
|
|
|
|
|
|
|
|
264
|
0
|
|
|
|
|
0
|
return join("\n", CGI->start_html(\%hash), $self->parse_shtml($command) ); |
|
265
|
|
|
|
|
|
|
} |
|
266
|
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
=item end_html ( TYPE, OPTIONS ) |
|
268
|
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
Loads the appropriate footer file out of C<$CGI::SHTML::FOOTER>, and invokes |
|
270
|
|
|
|
|
|
|
C. |
|
271
|
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
=cut |
|
273
|
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
sub end_html { |
|
275
|
0
|
|
|
0
|
1
|
0
|
my ($self, $type, %hash) = @_; |
|
276
|
0
|
|
0
|
|
|
0
|
$type = lc $type; $type ||= 'default'; |
|
|
0
|
|
|
|
|
0
|
|
|
277
|
|
|
|
|
|
|
|
|
278
|
0
|
|
|
|
|
0
|
my $command = ""; |
|
279
|
|
|
|
|
|
|
|
|
280
|
0
|
|
|
|
|
0
|
join("\n", $self->parse_shtml($command), CGI->end_html(\%hash)); |
|
281
|
|
|
|
|
|
|
} |
|
282
|
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
=back |
|
284
|
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
=cut |
|
286
|
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
############################################################################### |
|
288
|
|
|
|
|
|
|
### Internal Functions ######################################################## |
|
289
|
|
|
|
|
|
|
############################################################################### |
|
290
|
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
### _vfile ( FILENAME ) |
|
292
|
|
|
|
|
|
|
# Gets the virtual filename out of FILENAME, based on ROOTDIR. Also |
|
293
|
|
|
|
|
|
|
# performs the substitutions in C. |
|
294
|
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
sub _vfile { |
|
296
|
0
|
|
0
|
0
|
|
0
|
my $filename = shift || return undef; |
|
297
|
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
# If it starts with a '$' sign, then get the value out first |
|
299
|
0
|
0
|
0
|
|
|
0
|
if ($filename =~ /^\$\{?(\S+)\}?$/) { $filename = $ENV{$1} || ""; } |
|
|
0
|
|
|
|
|
0
|
|
|
300
|
|
|
|
|
|
|
|
|
301
|
0
|
|
0
|
|
|
0
|
my $hostname = $ENV{'HTTP_HOST'} || $ENV{'HOSTNAME'}; |
|
302
|
0
|
|
|
|
|
0
|
foreach my $replace (keys %REPLACE) { |
|
303
|
0
|
0
|
|
|
|
0
|
next if ($hostname =~ /^www/); # Hack |
|
304
|
0
|
|
|
|
|
0
|
$filename =~ s%$replace%$REPLACE{$replace}%g; |
|
305
|
|
|
|
|
|
|
} |
|
306
|
0
|
|
|
|
|
0
|
my $newname; |
|
307
|
0
|
0
|
|
|
|
0
|
if ($filename =~ m%^~(\w+)/(.*)$%) { $newname = "/home/$1/public_html/$2"; } |
|
|
0
|
0
|
|
|
|
0
|
|
|
308
|
|
|
|
|
|
|
elsif ( $filename =~ m%^[^/]% ) { |
|
309
|
0
|
|
|
|
|
0
|
my ($directory, $program) = $0 =~ m%^(.*)/(.*)$%; |
|
310
|
0
|
|
|
|
|
0
|
$newname = "$directory/$filename" |
|
311
|
|
|
|
|
|
|
} |
|
312
|
0
|
|
|
|
|
0
|
else { $newname = "$ROOTDIR/$filename" } |
|
313
|
0
|
|
|
|
|
0
|
$newname =~ s%/+%/%g; # Remove doubled-up /'s |
|
314
|
0
|
|
|
|
|
0
|
$newname; |
|
315
|
|
|
|
|
|
|
} |
|
316
|
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
## _file( FILE ) |
|
318
|
|
|
|
|
|
|
# Open a file and parse it with parse_shtml(). |
|
319
|
|
|
|
|
|
|
sub _file { |
|
320
|
0
|
|
|
0
|
|
0
|
my ($self, $file) = @_; |
|
321
|
0
|
0
|
0
|
|
|
0
|
open( FILE, "<$file" ) or warn "Couldn't open $file: $!\n" && return ""; |
|
322
|
0
|
|
|
|
|
0
|
my @list = ; |
|
323
|
0
|
|
|
|
|
0
|
close (FILE); |
|
324
|
0
|
|
|
|
|
0
|
map { chomp } @list; |
|
|
0
|
|
|
|
|
0
|
|
|
325
|
0
|
|
|
|
|
0
|
return $self->parse_shtml(@list); |
|
326
|
|
|
|
|
|
|
} |
|
327
|
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
## _execute( CMD ) |
|
329
|
|
|
|
|
|
|
# Run a command and get the information about it out. This isn't as |
|
330
|
|
|
|
|
|
|
# secure as we'd like it to be... |
|
331
|
|
|
|
|
|
|
sub _execute { |
|
332
|
0
|
|
|
0
|
|
0
|
my ($self, $cmd) = @_; |
|
333
|
0
|
|
|
|
|
0
|
foreach (qw( IFS CDPATH ENV BASH_ENV PATH ) ) { $ENV{$_} = ""; } |
|
|
0
|
|
|
|
|
0
|
|
|
334
|
0
|
|
|
|
|
0
|
my ($command) = $cmd =~ /^(.*)$/; # Not particularly secure |
|
335
|
0
|
0
|
|
|
|
0
|
open ( COMMAND, "$command |" ) or warn "Couldn't open $command\n"; |
|
336
|
0
|
|
|
|
|
0
|
my @list = ; |
|
337
|
0
|
|
|
|
|
0
|
close (COMMAND); |
|
338
|
0
|
|
|
|
|
0
|
map { chomp } @list; |
|
|
0
|
|
|
|
|
0
|
|
|
339
|
0
|
0
|
|
|
|
0
|
return "" unless scalar(@list) > 0; # Didn't return anything |
|
340
|
|
|
|
|
|
|
# Take out the "Content-type:" part, if it's a CGI - note, THIS IS A HACK |
|
341
|
0
|
0
|
0
|
|
|
0
|
if ( scalar(@list) > 1 && $list[0] =~ /^Content-type: (.*)$/i) { |
|
342
|
0
|
|
|
|
|
0
|
shift @list; shift @list; |
|
|
0
|
|
|
|
|
0
|
|
|
343
|
|
|
|
|
|
|
} |
|
344
|
0
|
0
|
|
|
|
0
|
wantarray ? @list : join("\n", @list); |
|
345
|
|
|
|
|
|
|
} |
|
346
|
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
## _flastmod( FILE ) |
|
348
|
|
|
|
|
|
|
## _fsize( FILE ) |
|
349
|
|
|
|
|
|
|
# Last modification and file size of the given FILE, respectively. |
|
350
|
1
|
|
50
|
1
|
|
44
|
sub _flastmod { localtime( (stat($_[1]))[9] || 0 ); } |
|
351
|
|
|
|
|
|
|
sub _fsize { |
|
352
|
0
|
|
0
|
0
|
|
|
my $size = ((stat($_[1]))[7]) || 0; |
|
353
|
0
|
0
|
|
|
|
|
if ($size >= 1048576) { |
|
|
|
0
|
|
|
|
|
|
|
354
|
0
|
|
|
|
|
|
sprintf("%4.1fMB", $size / 1048576); |
|
355
|
|
|
|
|
|
|
} elsif ($size >= 1024) { |
|
356
|
0
|
|
|
|
|
|
sprintf("%4.1fKB", $size / 1024); |
|
357
|
|
|
|
|
|
|
} else { |
|
358
|
0
|
|
|
|
|
|
sprintf("%4d bytes", $size); |
|
359
|
|
|
|
|
|
|
} |
|
360
|
|
|
|
|
|
|
} |
|
361
|
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
## _ssieval( HASHREF ) |
|
363
|
|
|
|
|
|
|
# Evaluates the expression with 'var' or 'expr'. Meant for use with |
|
364
|
|
|
|
|
|
|
# if/elif clauses. This actually more-or-less works! It's also very |
|
365
|
|
|
|
|
|
|
# dangerous, though, since it uses 'eval'. Then again, given that we're |
|
366
|
|
|
|
|
|
|
# already giving the user the capacity to invoke random pieces of code, |
|
367
|
|
|
|
|
|
|
# it's not realy that much of a stretch... |
|
368
|
|
|
|
|
|
|
sub _ssieval { |
|
369
|
0
|
|
|
0
|
|
|
my $hash = shift; |
|
370
|
0
|
0
|
|
|
|
|
if (my $var = $$hash{'var'}) { return $var ? 1 : 0 } |
|
|
0
|
0
|
|
|
|
|
|
|
371
|
0
|
0
|
|
|
|
|
if (my $eval = $$hash{'expr'}) { |
|
372
|
0
|
|
|
|
|
|
$eval =~ s/\s*\$(?:\{(\S+?)\}|(\S+?))\s* |
|
373
|
0
|
|
0
|
|
|
|
/ join('', "'", $ENV{$1 || $2} || "", "'" ) /egx; |
|
374
|
0
|
|
|
|
|
|
my $val = eval($eval); |
|
375
|
0
|
0
|
|
|
|
|
return $val ? 1 : 0; # Need to do more here. |
|
376
|
|
|
|
|
|
|
} |
|
377
|
|
|
|
|
|
|
0 |
|
378
|
0
|
|
|
|
|
|
} |
|
379
|
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
1; |
|
381
|
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
############################################################################### |
|
383
|
|
|
|
|
|
|
### Further Documentation ##################################################### |
|
384
|
|
|
|
|
|
|
############################################################################### |
|
385
|
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
=head1 NOTES |
|
387
|
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
This module was generated for a single research group at UIUC. Its goal |
|
389
|
|
|
|
|
|
|
was simple: parse the SSI header and footers that were being used for the |
|
390
|
|
|
|
|
|
|
rest of the web site, so that they wouldn't have to be re-implemented |
|
391
|
|
|
|
|
|
|
later. Ideally, we would liked to just have Apache take care of this, but |
|
392
|
|
|
|
|
|
|
it wasn't an option at the time (and as far as I know it still isn't one.) |
|
393
|
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
I mention the above because it's worth understanding the problem before |
|
395
|
|
|
|
|
|
|
you think about its limitations. This script will not offer particularly |
|
396
|
|
|
|
|
|
|
high performance for reasonably-sized sites that use a lot of CGI; I doubt |
|
397
|
|
|
|
|
|
|
it would work at all well with mod_perl, for instance. But it has done |
|
398
|
|
|
|
|
|
|
the job just fine for our research group, however; and if you want to copy |
|
399
|
|
|
|
|
|
|
our general website layout, you're going to need something like this to |
|
400
|
|
|
|
|
|
|
help you out. |
|
401
|
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
Also of note is that this has been designed for use so that if headers and |
|
403
|
|
|
|
|
|
|
footers are not being included, you can generally fall back to the default |
|
404
|
|
|
|
|
|
|
CGI.pm fairly easily enough. |
|
405
|
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
Also of note are the security issues. There are lots of ways for the user |
|
407
|
|
|
|
|
|
|
to run arbitrary code with this module; however, there were already plenty |
|
408
|
|
|
|
|
|
|
of ways for them to do it if you're giving them unfettered SSI access. |
|
409
|
|
|
|
|
|
|
This isn't a change. So make sure that the user that your webserver runs |
|
410
|
|
|
|
|
|
|
as isn't a particularly priveleged user, and *never* run code through this |
|
411
|
|
|
|
|
|
|
that came from the outside! You would be a fool to do otherwise. |
|
412
|
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
414
|
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
C |
|
416
|
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
=head1 TODO |
|
418
|
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
There are still a few functions that should be better implemented (format |
|
420
|
|
|
|
|
|
|
strings for flastmod(), for instance). It might be nice to make this more |
|
421
|
|
|
|
|
|
|
object-oriented as well; as it stands this wouldn't stand a chance with |
|
422
|
|
|
|
|
|
|
mod_perl. |
|
423
|
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
=head1 AUTHOR |
|
425
|
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
Tim Skirvin |
|
427
|
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
=head1 HOMEPAGE |
|
429
|
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
B |
|
431
|
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
=head1 LICENSE |
|
433
|
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
This code is distributed under the University of Illinois Open Source |
|
435
|
|
|
|
|
|
|
License. See |
|
436
|
|
|
|
|
|
|
B for |
|
437
|
|
|
|
|
|
|
details. |
|
438
|
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
=head1 COPYRIGHT |
|
440
|
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
Copyright 2000-2004 by the University of Illinois Board of Trustees and |
|
442
|
|
|
|
|
|
|
Tim Skirvin . |
|
443
|
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
=cut |
|
445
|
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
############################################################################### |
|
447
|
|
|
|
|
|
|
### Version History ########################################################### |
|
448
|
|
|
|
|
|
|
############################################################################### |
|
449
|
|
|
|
|
|
|
# v1.0 Thu Apr 13 13:30:30 CDT 2000 |
|
450
|
|
|
|
|
|
|
### Documented it, and put this module into its proper home. |
|
451
|
|
|
|
|
|
|
# v1.1 Thu Apr 20 09:25:28 CDT 2000 |
|
452
|
|
|
|
|
|
|
### Updated for new page layout, included better counter capabilities, and |
|
453
|
|
|
|
|
|
|
### put in the possiblity of hooks for when we need to update this for all |
|
454
|
|
|
|
|
|
|
### of the web pages. |
|
455
|
|
|
|
|
|
|
# v1.11 Thu Apr 20 13:48:28 CDT 2000 |
|
456
|
|
|
|
|
|
|
### Further updates, added NOCOUNTER flag for error messages |
|
457
|
|
|
|
|
|
|
# v1.12 Tue Apr 25 13:28:15 CDT 2000 |
|
458
|
|
|
|
|
|
|
### More updates of the header/footer files |
|
459
|
|
|
|
|
|
|
# v1.2 Tue Jun 13 09:42:11 CDT 2000 |
|
460
|
|
|
|
|
|
|
### Now just parses the header/footer files from the main directory, and |
|
461
|
|
|
|
|
|
|
### includes a "parse_shtml" function set. Hopefully at some point I'll |
|
462
|
|
|
|
|
|
|
### finish off parse_shtml to do all SSI functions. |
|
463
|
|
|
|
|
|
|
# v1.21 Wed Jun 28 10:56:26 CDT 2000 |
|
464
|
|
|
|
|
|
|
### Fixed the CGI handlings to trim out the Content-type header. |
|
465
|
|
|
|
|
|
|
# v1.22 Wed Oct 31 09:46:16 CST 2001 |
|
466
|
|
|
|
|
|
|
### Fixed _vfile() to do local directory checks properly. |
|
467
|
|
|
|
|
|
|
### Changed execute() behaviour to not worry about tainting - probably a |
|
468
|
|
|
|
|
|
|
### bad idea, but necessary for now. |
|
469
|
|
|
|
|
|
|
# v1.23 Mon Dec 10 11:58:25 CST 2001 |
|
470
|
|
|
|
|
|
|
### Created $EMPTY. Updated 'set' to use variables in its code. |
|
471
|
|
|
|
|
|
|
# v1.24 Tue Apr 2 13:05:12 CST 2002 |
|
472
|
|
|
|
|
|
|
### Changed parse_shtml() to remove a warning |
|
473
|
|
|
|
|
|
|
# v1.25 Tue Mar 11 10:47:36 CST 2003 |
|
474
|
|
|
|
|
|
|
### Updated to be a more generic name - CGI::SHTML. This will make things |
|
475
|
|
|
|
|
|
|
### a lot easier to distribute. Have to make a real package now. Eliminated |
|
476
|
|
|
|
|
|
|
### the COUNTER stuff, because it's not in use and was silly anyway. Put |
|
477
|
|
|
|
|
|
|
### in 'default' values in the headers/footers |
|
478
|
|
|
|
|
|
|
# v1.26 Thu Apr 22 15:00:51 CDT 2004 |
|
479
|
|
|
|
|
|
|
### Making fsize(), flastmod(), etc into internal functions. |
|
480
|
|
|
|
|
|
|
# v1.26.01 Thu Apr 22 23:32:57 CDT 2004 |
|
481
|
|
|
|
|
|
|
### Forgot to turn off some debugging information. |
|
482
|
|
|
|
|
|
|
# v1.27 Thu May 06 10:52:32 CDT 2004 |
|
483
|
|
|
|
|
|
|
### Added if/elif/else/endif functionality. This was challenging. |
|
484
|
|
|
|
|
|
|
### Documentation chanes came with it. |
|
485
|
|
|
|
|
|
|
# v1.28 Mon May 17 15:15:22 CDT 2004 |
|
486
|
|
|
|
|
|
|
### Put back old environment variables after an execute. |
|
487
|
|
|
|
|
|
|
# v1.28 Wed May 19 11:37:06 CDT 2004 |
|
488
|
|
|
|
|
|
|
### Parsing information is accurate again with parse_shtml - doesn't lose |
|
489
|
|
|
|
|
|
|
### newlines. Setting blank versions of those environment variables. |