| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package CGI::UploadEasy; |
|
2
|
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
18900
|
use 5.006; |
|
|
1
|
|
|
|
|
4
|
|
|
|
1
|
|
|
|
|
43
|
|
|
4
|
1
|
|
|
1
|
|
6
|
use strict; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
35
|
|
|
5
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
|
1
|
|
|
|
|
5
|
|
|
|
1
|
|
|
|
|
47
|
|
|
6
|
1
|
|
|
1
|
|
2146
|
use CGI 2.76; |
|
|
1
|
|
|
|
|
32019
|
|
|
|
1
|
|
|
|
|
7
|
|
|
7
|
1
|
|
|
1
|
|
102
|
use File::Spec; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
25
|
|
|
8
|
1
|
|
|
1
|
|
6
|
use Carp; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
2105
|
|
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
$Carp::CarpLevel = 1; |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
our $VERSION = '1.00'; |
|
13
|
|
|
|
|
|
|
# $Id: UploadEasy.pm,v 1.8 2009/02/01 21:04:22 gunnarh Exp $ |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=head1 NAME |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
CGI::UploadEasy - Facilitate file uploads |
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
20
|
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
use CGI::UploadEasy; |
|
22
|
|
|
|
|
|
|
my $ue = CGI::UploadEasy->new(-uploaddir => '/path/to/upload/dir'); |
|
23
|
|
|
|
|
|
|
my $cgi = $ue->cgiobject; |
|
24
|
|
|
|
|
|
|
my $info = $ue->fileinfo; |
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
C is a wrapper around, and relies heavily on, L. Its |
|
29
|
|
|
|
|
|
|
purpose is to provide a simple interface to the upload functionality of C. |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
At creation of the C object, the module saves one or more files |
|
32
|
|
|
|
|
|
|
from a file upload request in the upload directory, and information about uploaded |
|
33
|
|
|
|
|
|
|
files is made available via the B method. C performs |
|
34
|
|
|
|
|
|
|
a number of tests, which limit the risk that you encounter difficulties when |
|
35
|
|
|
|
|
|
|
developing a file upload application. |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
=head2 Methods |
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
=cut |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
sub new { |
|
42
|
0
|
|
|
0
|
1
|
|
my $class = shift; |
|
43
|
0
|
|
|
|
|
|
my $self = { |
|
44
|
|
|
|
|
|
|
maxsize => 1000, |
|
45
|
|
|
|
|
|
|
&_argscheck, |
|
46
|
|
|
|
|
|
|
}; |
|
47
|
|
|
|
|
|
|
|
|
48
|
0
|
|
|
|
|
|
$CGI::POST_MAX = $self->{maxsize} * 1024; |
|
49
|
0
|
|
|
|
|
|
$CGI::DISABLE_UPLOADS = 0; |
|
50
|
0
|
0
|
|
|
|
|
$CGITempFile::TMPDIRECTORY = $self->{tempdir} if $self->{tempdir}; |
|
51
|
0
|
|
|
|
|
|
$self->{cgi} = CGI->new; |
|
52
|
0
|
0
|
|
|
|
|
if ( my $status = $self->{cgi}->cgi_error ) { |
|
53
|
0
|
|
|
|
|
|
_error($self, $status, "Post too large: Maxsize $self->{maxsize} KiB exceeded."); |
|
54
|
|
|
|
|
|
|
} |
|
55
|
|
|
|
|
|
|
|
|
56
|
0
|
0
|
0
|
|
|
|
if ( $ENV{REQUEST_METHOD} eq 'POST' and $ENV{CONTENT_TYPE} !~ /^multipart\/form-data\b/i ) { |
|
57
|
0
|
|
|
|
|
|
_error($self, '400 Bad Request', 'The content-type at file uploads shall be ' |
|
58
|
|
|
|
|
|
|
. "'multipart/form-data'. \nMake sure that the 'FORM' tag includes the " |
|
59
|
|
|
|
|
|
|
. 'attribute: enctype="multipart/form-data"'); |
|
60
|
|
|
|
|
|
|
} |
|
61
|
|
|
|
|
|
|
|
|
62
|
0
|
|
|
|
|
|
$self->{files} = _upload($self); |
|
63
|
|
|
|
|
|
|
|
|
64
|
0
|
|
|
|
|
|
bless $self, $class; |
|
65
|
|
|
|
|
|
|
} |
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
=over 4 |
|
68
|
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
=item Bnew( -uploaddir =E $dir [ , -maxsize =E $kibibytes, ... ] )> |
|
70
|
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
The B constructor takes hash style arguments. The following arguments are |
|
72
|
|
|
|
|
|
|
recognized: |
|
73
|
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
=over 4 |
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
=item B<-uploaddir> |
|
77
|
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
Specifying the upload directory is mandatory. |
|
79
|
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
=item B<-tempdir> |
|
81
|
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
To control which directory will be used for temporary files, set the -tempdir |
|
83
|
|
|
|
|
|
|
argument. |
|
84
|
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
=item B<-maxsize> |
|
86
|
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
Specifies the maximum size in KiB (kibibytes) of a POST request data set. |
|
88
|
|
|
|
|
|
|
Default limit is 1,000 KiB. To disable this ceiling for POST requests, set a |
|
89
|
|
|
|
|
|
|
negative -maxsize value. |
|
90
|
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
=back |
|
92
|
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
=back |
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
=cut |
|
96
|
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
sub cgiobject { |
|
98
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
99
|
0
|
|
|
|
|
|
$self->{cgi}; |
|
100
|
|
|
|
|
|
|
} |
|
101
|
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
=over 4 |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
=item B<$ue-Ecgiobject> |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
Returns a reference to the C object that C uses internally, |
|
107
|
|
|
|
|
|
|
which gives access to all the L methods. |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
If you prefer the function-oriented style, you can import a set of methods |
|
110
|
|
|
|
|
|
|
instead. Example: |
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
use CGI qw/:standard/; |
|
113
|
|
|
|
|
|
|
print header; |
|
114
|
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
=back |
|
116
|
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
=cut |
|
118
|
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
sub fileinfo { |
|
120
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
121
|
0
|
0
|
|
|
|
|
if ( @_ ) { croak "The 'fileinfo' method does not take arguments" } |
|
|
0
|
|
|
|
|
|
|
|
122
|
0
|
|
|
|
|
|
$self->{files}; |
|
123
|
|
|
|
|
|
|
} |
|
124
|
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
=over 4 |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
=item B<$ue-Efileinfo> |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
Returns a reference to a 'hash of hashes' with info about uploaded files. The info |
|
130
|
|
|
|
|
|
|
may be of use for a result page and/or an email notification, and it lets you use |
|
131
|
|
|
|
|
|
|
e.g. MIME type and file size as criteria for how to further process the files. |
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
=back |
|
134
|
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
=cut |
|
136
|
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
sub otherparam { |
|
138
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
139
|
0
|
0
|
|
|
|
|
if ( @_ ) { croak "The 'otherparam' method does not take arguments", |
|
|
0
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
"--use CGI.pm's 'param' method to access values" } |
|
141
|
0
|
|
|
|
|
|
my $cgi = $self->{cgi}; |
|
142
|
0
|
|
|
|
|
|
grep ! ref $cgi->param($_), $cgi->param; |
|
143
|
|
|
|
|
|
|
} |
|
144
|
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
=over 4 |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
=item B<$ue-Eotherparam> |
|
148
|
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
The B method returns a list of parameter names besides the names |
|
150
|
|
|
|
|
|
|
of the file select controls that were used for file uploads. To access the values, |
|
151
|
|
|
|
|
|
|
use L's B method. |
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
=back |
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
=cut |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
sub _argscheck { |
|
158
|
0
|
|
|
0
|
|
|
my %args; |
|
159
|
0
|
|
|
|
|
|
my %names = ( |
|
160
|
|
|
|
|
|
|
-uploaddir => 'uploaddir', |
|
161
|
|
|
|
|
|
|
-tempdir => 'tempdir', |
|
162
|
|
|
|
|
|
|
-maxsize => 'maxsize', |
|
163
|
|
|
|
|
|
|
); |
|
164
|
0
|
|
|
|
|
|
local $Carp::CarpLevel = 2; |
|
165
|
|
|
|
|
|
|
|
|
166
|
0
|
0
|
0
|
|
|
|
@_ % 2 == 0 and @_ > 0 or croak 'One or more name=>argument pairs are ', |
|
167
|
|
|
|
|
|
|
'expected at the creation of the CGI::UploadEasy object'; |
|
168
|
|
|
|
|
|
|
|
|
169
|
0
|
|
|
|
|
|
while ( my $arg = shift ) { |
|
170
|
0
|
|
|
|
|
|
my $name = lc $arg; |
|
171
|
0
|
0
|
|
|
|
|
$names{$name} or croak "Unknown argument: '$arg'"; |
|
172
|
0
|
|
|
|
|
|
$args{ $names{$name} } = shift; |
|
173
|
|
|
|
|
|
|
} |
|
174
|
0
|
0
|
|
|
|
|
$args{uploaddir} or croak "The compulsory argument '-uploaddir' is missing"; |
|
175
|
|
|
|
|
|
|
|
|
176
|
0
|
|
|
|
|
|
for my $dir ( @args{ grep exists $args{$_}, qw/uploaddir tempdir/ } ) { |
|
177
|
0
|
0
|
|
|
|
|
-d $dir or croak "Can't find any directory '$dir'"; |
|
178
|
0
|
0
|
0
|
|
|
|
-r $dir and -w _ and -x _ or croak 'The user this script runs as ', |
|
|
|
|
0
|
|
|
|
|
|
179
|
|
|
|
|
|
|
"does not have write access to '$dir'"; |
|
180
|
|
|
|
|
|
|
} |
|
181
|
0
|
0
|
0
|
|
|
|
$args{maxsize} and $args{maxsize} !~ /^-?\d+$/ |
|
182
|
|
|
|
|
|
|
and croak "The '-maxsize' argument shall be an integer"; |
|
183
|
|
|
|
|
|
|
|
|
184
|
0
|
|
|
|
|
|
%args; |
|
185
|
|
|
|
|
|
|
} |
|
186
|
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
sub _upload { |
|
188
|
0
|
|
|
0
|
|
|
my $self = shift; |
|
189
|
0
|
|
|
|
|
|
my $cgi = $self->{cgi}; |
|
190
|
0
|
|
|
|
|
|
my %files; |
|
191
|
|
|
|
|
|
|
|
|
192
|
0
|
|
|
|
|
|
for my $TEMP ( map $cgi->upload($_), $cgi->param ) { |
|
193
|
0
|
|
|
|
|
|
( my $name = $TEMP ) =~ s#.*[\]:\\/]##; |
|
194
|
0
|
0
|
|
|
|
|
$name =~ tr/ /_/ unless $^O eq 'MSWin32'; |
|
195
|
0
|
|
|
|
|
|
$name =~ tr/-+@a-zA-Z0-9. /_/cs; |
|
196
|
0
|
|
|
|
|
|
($name) = $name =~ /^([-+@\w. ]+)$/; |
|
197
|
0
|
|
|
|
|
|
my $path = File::Spec->catfile( $self->{uploaddir}, $name ); |
|
198
|
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
# don't overwrite file with same name |
|
200
|
0
|
|
|
|
|
|
my $i = 2; |
|
201
|
0
|
|
|
|
|
|
while (1) { |
|
202
|
0
|
0
|
|
|
|
|
last unless -e $path; |
|
203
|
0
|
|
|
|
|
|
$name =~ s/([^.]+?)(?:_\d+)?(\.|$)/$1_$i$2/; |
|
204
|
0
|
|
|
|
|
|
$path = File::Spec->catfile( $self->{uploaddir}, $name ); |
|
205
|
0
|
|
|
|
|
|
$i++; |
|
206
|
|
|
|
|
|
|
} |
|
207
|
|
|
|
|
|
|
|
|
208
|
0
|
|
|
|
|
|
my ($cntrname) = $cgi->uploadInfo($TEMP)->{'Content-Disposition'} =~ /\bname="([^"]+)"/; |
|
209
|
0
|
|
|
|
|
|
$files{$name} = { |
|
210
|
|
|
|
|
|
|
ctrlname => $cntrname, |
|
211
|
|
|
|
|
|
|
mimetype => $cgi->uploadInfo($TEMP)->{'Content-Type'}, |
|
212
|
|
|
|
|
|
|
}; |
|
213
|
|
|
|
|
|
|
|
|
214
|
0
|
0
|
|
|
|
|
open my $OUT, '>', $path or die "Couldn't open file: $!"; |
|
215
|
0
|
0
|
|
|
|
|
if ( $files{$name}{mimetype} =~ /^text\b/ ) { |
|
216
|
0
|
|
|
|
|
|
binmode $TEMP, ':crlf'; |
|
217
|
0
|
|
|
|
|
|
print $OUT $_ while <$TEMP>; |
|
218
|
|
|
|
|
|
|
} else { |
|
219
|
0
|
|
|
|
|
|
binmode $OUT, ':raw'; |
|
220
|
0
|
|
|
|
|
|
while ( read $TEMP, my $buffer, 1024 ) { |
|
221
|
0
|
|
|
|
|
|
print $OUT $buffer; |
|
222
|
|
|
|
|
|
|
} |
|
223
|
|
|
|
|
|
|
} |
|
224
|
0
|
0
|
|
|
|
|
close $TEMP or die $!; # so the temporary file gets deleted |
|
225
|
0
|
0
|
|
|
|
|
close $OUT or die $!; # so file size can be grabbed below |
|
226
|
|
|
|
|
|
|
|
|
227
|
0
|
|
|
|
|
|
$files{$name}{bytes} = -s $path; |
|
228
|
|
|
|
|
|
|
} |
|
229
|
|
|
|
|
|
|
|
|
230
|
0
|
|
|
|
|
|
\%files; |
|
231
|
|
|
|
|
|
|
} |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
sub _error { |
|
234
|
0
|
|
|
0
|
|
|
my ($self, $status, $msg) = @_; |
|
235
|
0
|
|
|
|
|
|
my $cgi = $self->{cgi}; |
|
236
|
0
|
|
|
|
|
|
print $cgi->header(-status => $status), |
|
237
|
|
|
|
|
|
|
$cgi->start_html(-title => "Error $status"), |
|
238
|
|
|
|
|
|
|
$cgi->h1('Error'), |
|
239
|
|
|
|
|
|
|
$cgi->tt($msg), |
|
240
|
|
|
|
|
|
|
$cgi->end_html; |
|
241
|
0
|
|
|
|
|
|
exit 1; |
|
242
|
|
|
|
|
|
|
} |
|
243
|
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
1; |
|
245
|
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
__END__ |