fixed basd test, prepped version info
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Request / Upload.pm
CommitLineData
146554c5 1package Catalyst::Request::Upload;
2
e5ecd5bc 3use Moose;
531f1ab6 4with 'MooseX::Emulate::Class::Accessor::Fast';
146554c5 5
a2f2cde9 6use Catalyst::Exception;
47ae6960 7use File::Copy ();
89cb63ec 8use IO::File ();
3e22baa5 9use File::Spec::Unix;
554c7587 10use namespace::clean -except => 'meta';
146554c5 11
5fb12dbb 12has filename => (is => 'rw');
13has headers => (is => 'rw');
14has size => (is => 'rw');
15has tempname => (is => 'rw');
16has type => (is => 'rw');
02570318 17has basename => (is => 'ro', lazy_build => 1);
6adc45cf 18has raw_basename => (is => 'ro', lazy_build => 1);
19has charset => (is=>'ro', predicate=>'has_charset');
059c085b 20
21has fh => (
22 is => 'rw',
23 required => 1,
24 lazy => 1,
25 default => sub {
26 my $self = shift;
27
28 my $fh = IO::File->new($self->tempname, IO::File::O_RDONLY);
29 unless ( defined $fh ) {
30 my $filename = $self->tempname;
31 Catalyst::Exception->throw(
32 message => qq/Can't open '$filename': '$!'/ );
33 }
059c085b 34 return $fh;
35 },
36);
37
02570318 38sub _build_basename {
6adc45cf 39 my $basename = shift->raw_basename;
40 $basename =~ s|[^\w\.-]+|_|g;
41 return $basename;
42}
43
44sub _build_raw_basename {
02570318 45 my $self = shift;
46 my $basename = $self->filename;
47 $basename =~ s|\\|/|g;
48 $basename = ( File::Spec::Unix->splitpath($basename) )[2];
02570318 49 return $basename;
50}
51
059c085b 52no Moose;
146554c5 53
965f3e35 54=for stopwords uploadtmp
55
146554c5 56=head1 NAME
57
bab3a22c 58Catalyst::Request::Upload - handles file upload requests
146554c5 59
60=head1 SYNOPSIS
61
33455c7e 62 my $upload = $c->req->upload('field');
63
3e22baa5 64 $upload->basename;
bab3a22c 65 $upload->copy_to;
66 $upload->fh;
6adc45cf 67 $upload->decoded_fh
146554c5 68 $upload->filename;
4be535b1 69 $upload->headers;
3ffaf022 70 $upload->link_to;
146554c5 71 $upload->size;
32d4bba8 72 $upload->slurp;
6adc45cf 73 $upload->decoded_slurp;
146554c5 74 $upload->tempname;
75 $upload->type;
6adc45cf 76 $upload->charset;
146554c5 77
7257e9db 78To specify where Catalyst should put the temporary files, set the 'uploadtmp'
79option in the Catalyst config. If unset, Catalyst will use the system temp dir.
80
81 __PACKAGE__->config( uploadtmp => '/path/to/tmpdir' );
82
146554c5 83See also L<Catalyst>.
84
85=head1 DESCRIPTION
86
bab3a22c 87This class provides accessors and methods to handle client upload requests.
146554c5 88
89=head1 METHODS
90
b5ecfcf0 91=head2 $upload->new
cd3bb248 92
bab3a22c 93Simple constructor.
cd3bb248 94
b5ecfcf0 95=head2 $upload->copy_to
47ae6960 96
bab3a22c 97Copies the temporary file using L<File::Copy>. Returns true for success,
98false for failure.
47ae6960 99
3ffaf022 100 $upload->copy_to('/path/to/target');
101
42d0a52a 102Please note the filename used for the copy target is the 'tempname' that
103is the actual filename on the filesystem, NOT the 'filename' that was
104part of the upload headers. This might seem counter intuitive but at this
105point this behavior is so established that its not something we can change.
106
107You can always create your own copy routine that munges the target path
108as you wish.
109
47ae6960 110=cut
111
3ffaf022 112sub copy_to {
c462faf0 113 my $self = shift;
114 return File::Copy::copy( $self->tempname, @_ );
47ae6960 115}
116
6adc45cf 117=head2 $upload->is_utf8_encoded
118
119Returns true of the upload defines a character set at that value is 'UTF-8'.
120This does not try to inspect your upload and make any guesses if the Content
121Type charset is undefined.
122
123=cut
124
125sub is_utf8_encoded {
126 my $self = shift;
127 if(my $charset = $self->charset) {
128 return $charset eq 'UTF-8' ? 1 : 0;
129 }
130 return 0;
131}
132
b5ecfcf0 133=head2 $upload->fh
146554c5 134
bab3a22c 135Opens a temporary file (see tempname below) and returns an L<IO::File> handle.
146554c5 136
6adc45cf 137This is a filehandle that is opened with no additional IO Layers.
138
139=head2 $upload->decoded_fh(?$encoding)
140
141Returns a filehandle that has binmode set to UTF-8 if a UTF-8 character set
142is found. This also accepts an override encoding value that you can use to
143force a particular L<PerlIO> layer. If neither are found the filehandle is
144set to :raw.
145
0d94e986 146This is useful if you are pulling the file into code and inspecting bits and
147maybe then sending those bits back as the response. (Please note this is not
6adc45cf 148a suitable filehandle to set in the body; use C<fh> if you are doing that).
149
150Please note that using this method sets the underlying filehandle IO layer
151so once you use this method if you go back and use the C<fh> method you
152still get the IO layer applied.
153
154=cut
155
156sub decoded_fh {
157 my ($self, $layer) = @_;
158 my $fh = $self->fh;
159
160 $layer = ":encoding(UTF-8)" if !$layer && $self->is_utf8_encoded;
161 $layer = ':raw' unless $layer;
162
163 binmode($fh, $layer);
164 return $fh;
165}
166
b5ecfcf0 167=head2 $upload->filename
146554c5 168
bab3a22c 169Returns the client-supplied filename.
146554c5 170
b5ecfcf0 171=head2 $upload->headers
4be535b1 172
bab3a22c 173Returns an L<HTTP::Headers> object for the request.
4be535b1 174
b5ecfcf0 175=head2 $upload->link_to
146554c5 176
b0ad47c1 177Creates a hard link to the temporary file. Returns true for success,
bab3a22c 178false for failure.
146554c5 179
3ffaf022 180 $upload->link_to('/path/to/target');
146554c5 181
182=cut
183
3ffaf022 184sub link_to {
47ae6960 185 my ( $self, $target ) = @_;
5c0ff128 186 return CORE::link( $self->tempname, $target );
146554c5 187}
188
b5ecfcf0 189=head2 $upload->size
146554c5 190
bab3a22c 191Returns the size of the uploaded file in bytes.
146554c5 192
6adc45cf 193=head2 $upload->slurp(?$encoding)
194
195Optionally accepts an argument to define an IO Layer (which is applied to
196the filehandle via binmode; if no layer is defined the default is set to
197":raw".
32d4bba8 198
bab3a22c 199Returns a scalar containing the contents of the temporary file.
32d4bba8 200
965f3e35 201Note that this will cause the filehandle pointed to by C<< $upload->fh >> to
202be reset to the start of the file using seek and the file handle to be put
6adc45cf 203into whatever encoding mode is applied.
0fd00e7b 204
32d4bba8 205=cut
206
207sub slurp {
208 my ( $self, $layer ) = @_;
209
4be535b1 210 unless ($layer) {
32d4bba8 211 $layer = ':raw';
212 }
213
214 my $content = undef;
215 my $handle = $self->fh;
216
217 binmode( $handle, $layer );
218
89cb63ec 219 $handle->seek(0, IO::File::SEEK_SET);
32d4bba8 220 while ( $handle->sysread( my $buffer, 8192 ) ) {
221 $content .= $buffer;
222 }
223
89cb63ec 224 $handle->seek(0, IO::File::SEEK_SET);
32d4bba8 225 return $content;
226}
227
6adc45cf 228=head2 $upload->decoded_slurp(?$encoding)
229
230Works just like C<slurp> except we use C<decoded_fh> instead of C<fh> to
231open a filehandle to slurp. This means if your upload charset is UTF8
232we binmode the filehandle to that encoding.
233
234=cut
235
236sub decoded_slurp {
237 my ( $self, $layer ) = @_;
238 my $handle = $self->decoded_fh($layer);
239
240 my $content = undef;
241 $handle->seek(0, IO::File::SEEK_SET);
242 while ( $handle->sysread( my $buffer, 8192 ) ) {
243 $content .= $buffer;
244 }
245
246 $handle->seek(0, IO::File::SEEK_SET);
247 return $content;
248}
249
3e22baa5 250=head2 $upload->basename
251
6adc45cf 252Returns basename for C<filename>. This filters the name through a regexp
253C<basename =~ s|[^\w\.-]+|_|g> to make it safe for filesystems that don't
254like advanced characters. This will of course filter UTF8 characters.
255If you need the exact basename unfiltered use C<raw_basename>.
256
257=head2 $upload->raw_basename
258
259Just like C<basename> but without filtering the filename for characters that
260don't always write to a filesystem.
3e22baa5 261
b5ecfcf0 262=head2 $upload->tempname
146554c5 263
bab3a22c 264Returns the path to the temporary file.
146554c5 265
b5ecfcf0 266=head2 $upload->type
146554c5 267
bab3a22c 268Returns the client-supplied Content-Type.
146554c5 269
6adc45cf 270=head2 $upload->charset
271
272The character set information part of the content type, if any. Useful if you
273need to figure out any encodings on the file upload.
274
059c085b 275=head2 meta
276
277Provided by Moose
278
bab3a22c 279=head1 AUTHORS
146554c5 280
2f381252 281Catalyst Contributors, see Catalyst.pm
146554c5 282
283=head1 COPYRIGHT
284
536bee89 285This library is free software. You can redistribute it and/or modify
146554c5 286it under the same terms as Perl itself.
287
288=cut
289
e5ecd5bc 290__PACKAGE__->meta->make_immutable;
291
146554c5 2921;