File Coverage

blib/lib/BW/Include.pm
Criterion Covered Total %
statement 18 125 14.4
branch 0 60 0.0
condition 0 33 0.0
subroutine 6 21 28.5
pod 5 14 35.7
total 29 253 11.4


line stmt bran cond sub pod time code
1             # BW::Include.pm
2             # Template support for BW::* (esp BW::CGI)
3             #
4             # by Bill Weinman - http://bw.org/
5             # Copyright (c) 1995-2010 The BearHeart Group, LLC
6             #
7             # See POD for History
8              
9             # Important note:
10             # This is a bona-fide kludge. I've been using it, or some version of it,
11             # for so many years that it works well for me. YMMV.
12              
13             package BW::Include;
14 1     1   3176 use strict;
  1         3  
  1         46  
15 1     1   7 use warnings;
  1         2  
  1         43  
16              
17 1     1   7 use IO::File;
  1         2  
  1         304  
18 1     1   1019 use IO::Pipe;
  1         1430  
  1         30  
19 1     1   6 use BW::Constants;
  1         2  
  1         90  
20 1     1   5 use base qw( BW::Base );
  1         2  
  1         3861  
21              
22             our $VERSION = "1.0.2";
23              
24             sub _init
25             {
26 0     0     my $self = shift;
27 0           $self->SUPER::_init(@_);
28              
29 0 0 0       $self->self( $ENV{SCRIPT_NAME} || EMPTY ) unless $self->{self};
30 0 0         $self->{dir} = $self->{DIR} if $self->{DIR};
31 0 0         $self->{filename} = $self->{FILENAME} if $self->{FILENAME};
32              
33 0           return SUCCESS;
34             }
35              
36             # _setter_getter entry points
37 0     0 0   sub self { BW::Base::_setter_getter(@_); } # self-reference URI
38 0     0 0   sub dir { BW::Base::_setter_getter(@_); } # base dir -- must be absolute
39 0     0 0   sub DIR { BW::Base::_setter_getter(@_); } # for backward compatibility
40 0     0 0   sub filename { BW::Base::_setter_getter(@_); } # filename for preloading
41 0     0 1   sub FILENAME { BW::Base::_setter_getter(@_); } # for backward compatibility
42 0     0 0   sub QUIET { BW::Base::_setter_getter(@_); } # for quiet mode
43              
44             sub version
45             {
46 0     0 0   return $VERSION;
47             }
48              
49             # set or get quiet mode
50             sub quiet
51             {
52 0     0 0   my $self = shift;
53 0 0         $self->{QUIET} = shift if @_;
54 0           return $self->{QUIET};
55             }
56              
57             # set and get vars
58             sub var
59             {
60 0     0 1   my $self = shift;
61 0 0         my $name = shift or return '';
62 0           my $value = shift;
63              
64 0 0         if ( defined($value) ) {
65 0           $self->{VARS}{$name} = $value;
66             }
67              
68 0           return $self->{VARS}{$name};
69             }
70              
71             # wrapper for print self->spf
72             sub pf
73             {
74 0     0 1   my $self = shift;
75 0   0       my $filename = shift || $self->{filename};
76 0 0         return $self->_error( "pf: No filename" ) unless $filename;
77 0           STDOUT->autoflush(1);
78 0           print $self->spf($filename);
79             }
80              
81             # expand from a string to a string
82             sub sps
83             {
84 0     0 1   my ( $self, $string ) = @_;
85 0 0         return $string unless $string;
86              
87 0           $string =~ s|\$([a-z0-9_:]+)\$|$self->var($1)|gei;
  0            
88 0           $string =~ s||$self->var($1)|ge;
  0            
89 0           return $string;
90             }
91              
92             # main routine -- recursively builds a string from file with includes
93             sub spf
94             {
95 0     0 1   my $self = shift;
96              
97 0   0       my $filename = shift || $self->{filename};
98 0 0         return $self->_error( "No filename" ) unless $filename;
99              
100             # create the filename
101 0 0 0       if ( substr( $filename, 1, 1 ) eq '/' and $ENV{DOCUMENT_ROOT} ) {
    0          
102 0           $filename = $ENV{DOCUMENT_ROOT} . $filename;
103             } elsif ( $self->{dir} ) {
104 0           $filename = "$self->{dir}/$filename";
105             }
106              
107 0           my $s = '';
108              
109             # this alows arbitrary perl code in the included file
110             sub expand
111             {
112 0     0 0   my $self = shift;
113 0           my $v = shift;
114 0           my $x;
115 0 0 0       if ( $x = $self->var($v) or defined $x ) { $x }
  0 0 0        
    0 0        
    0 0        
116 0           elsif ( $x = eval("\$main::$v") or defined $x ) { $x }
117 0           elsif ( $x = eval("\$$v") or defined $x ) { $x }
118 0           elsif ( $x = eval("\$ENV{$v}") or defined $x ) { $x }
119 0 0         else { $self->{QUIET} ? '' : "Undefined Variable ($v)" }
120             }
121              
122             # include virtual for running CGI ...
123             sub runprog
124             {
125 0     0 0   my $self = shift;
126 0           my $_qs = '';
127 0           my $x = '';
128 0   0       my $pn = shift || '';
129              
130             # $pn =~ m|^/| or $pn = '/' . $pn; # imply the leading / if missing
131 0           my $progpath = '';
132 0 0         if ( $pn =~ m|^/| ) {
133 0           $progpath = "$ENV{DOCUMENT_ROOT}$pn";
134             } else {
135 0 0         if ( $ENV{SCRIPT_FILENAME} ) { # derive the current directory if possible
136 0           $ENV{SCRIPT_FILENAME} =~ m|(.*[\\/])|;
137 0   0       $progpath = $1 || '';
138             } else {
139 0           $progpath = "./"; # a unixish guess
140             }
141 0           $progpath .= $pn;
142             }
143              
144 0           ( $progpath, $_qs ) = split( /\?/, $progpath, 2 );
145 0 0         if ( -f $progpath ) {
146 0 0         if ( -x $progpath ) { # run it as CGI
147             # save the environment
148 0           my $sn = $ENV{SCRIPT_NAME};
149 0           my $qs = $ENV{QUERY_STRING};
150 0 0         my $cl = $ENV{CONTENT_LENGTH} if $ENV{CONTENT_LENGTH};
151 0 0         my $ct = $ENV{CONTENT_TYPE} if $ENV{CONTENT_TYPE};
152 0   0       my $rm = $ENV{REQUEST_METHOD} || 'GET';
153              
154             # set up the CGI environment
155 0 0         $pn =~ /(.*)\?/ and $pn = $1; # SCRIPT_NAME has no query
156 0           $ENV{SCRIPT_NAME} = $pn;
157 0   0       $ENV{QUERY_STRING} = $_qs || '';
158              
159             # post method is always invalid for included CGI . . .
160 0 0         delete $ENV{CONTENT_LENGTH} if $ENV{CONTENT_LENGTH};
161 0 0         delete $ENV{CONTENT_TYPE} if $ENV{CONTENT_TYPE};
162 0           $ENV{REQUEST_METHOD} = 'GET';
163              
164             # make the path safe for the -T switch
165 0   0       my $env_path = $ENV{PATH} || '';
166 0           $ENV{PATH} = '';
167              
168             # makesure the progpath string is safe
169 0 0         if ( $progpath =~ /^([-\/\\\@\w.]+)$/ ) {
170 0           $progpath = $1;
171              
172             # run it
173 0           my $p = new IO::Pipe;
174 0           $p->reader($progpath);
175 0           while (<$p>) { $x .= $_ }
  0            
176 0           $p->close;
177              
178             # can't use the mime header
179 0 0         $x =~ s/^content-type:.*//i if $x;
180             }
181              
182             else {
183 0           $x = 'unsafe characters in exec';
184             }
185              
186             # restore the environment
187 0           $ENV{PATH} = $env_path;
188 0           $ENV{SCRIPT_NAME} = $sn;
189 0           $ENV{QUERY_STRING} = $qs;
190 0 0         $ENV{CONTENT_LENGTH} = $cl if $cl;
191 0 0         $ENV{CONTENT_TYPE} = $ct if $ct;
192 0           $ENV{REQUEST_METHOD} = $rm;
193 0           return $x;
194             } else { # display it
195 0           return $self->spf($progpath);
196             }
197             } else {
198 0           return "$progpath: $!";
199             }
200             }
201              
202 0 0         my $fh = IO::File->new("<$filename") or return $self->_error( "spf: cannot open $filename ($!)" );
203              
204 0           while (<$fh>) {
205 0           $_ =~ s|\$([a-z0-9_:]+)\$|expand($self, $1)|gei;
  0            
206 0           $_ =~ s||expand($self, $1)|ge;
  0            
207 0           $_ =~ s||runprog($self, $1)|ge;
  0            
208 0           $s .= $_;
209             }
210 0           close $fh;
211              
212 0           return $s;
213             }
214              
215             return 1;
216              
217              
218             __END__