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__ |