File Coverage

blib/lib/File/BLOB.pm
Criterion Covered Total %
statement 118 167 70.6
branch 39 90 43.3
condition 5 12 41.6
subroutine 23 25 92.0
pod 8 11 72.7
total 193 305 63.2


line stmt bran cond sub pod time code
1             package File::BLOB;
2              
3             =pod
4              
5             =head1 NAME
6              
7             File::BLOB - A file (with name, and other metadata) you can BLOBify
8              
9             =head1 SYNOPSIS
10              
11             # Create a File::BLOB object from data or a filehandle
12             $file = File::BLOB->new( 'data' ); # Copies
13             $file = File::BLOB->new( \$data ); # Doesn't copy
14             $file = File::BLOB->new( $filehandle );
15            
16             # Create from an existing file
17             $file = File::BLOB->from_file( 'filename.txt' );
18            
19             # Create from a file uploaded via CGI
20             $file = File::BLOB->from_cgi( $CGI, 'param' );
21            
22             # You can assign arbitrary headers/metadata when creating objects
23             $file = File::BLOB->new( 'filename.txt',
24             content_type => 'text/plain',
25             filename => 'myname.txt',
26             owner => 'ADAMK',
27             );
28             if ( $file->get_header('filename') eq 'filename.txt' ) {
29             $file->set_header( 'filename' => 'yourname.txt' );
30             }
31            
32             # Get or change the content
33             if ( $file->get_content =~ /FOO/ ) {
34             my $backup = $file->get_content;
35             $file->set_content( 'data' );
36             $file->set_content( \$data );
37             $file->set_content( $filehandle );
38             }
39            
40             # Freeze to and thaw from a BLOB
41             my $blob = $file->freeze;
42             $file = File::BLOB->thaw( $blob );
43              
44             =head1 DESCRIPTION
45              
46             One of the most common types of data found in systems ranging from email to
47             databases is a "file". And yet there is no simple way to create a store a
48             file is a chunk of data across all of these systems.
49              
50             Modules designed for email aren't easily reusable in databases, and while
51             databases often support "BLOB" data types, they don't keep file names and
52             encoding types attached so that these files are usable beyond treating
53             them as mere data.
54              
55             C is an object that represents a file, L as a BLOB
56             in a database or some other system, but retaining metadata such as file
57             name, type and any other custom headers people want to attach.
58              
59             The range of tasks it is intented to span include such things as pulling
60             a file from the database and sending it straight to the browser, saving
61             an object from CGI to a database, and so on.
62              
63             In general, for code that needs to span problem domains without losing
64             the name of the file or other data.
65              
66             =head2 Storage Format
67              
68             C stores its data in a way that is compatible with both
69             L and HTTP. The stored form looks a lot like a HTTP response,
70             with a series of newline-seperated header lines followed by two newlines
71             and then file data.
72              
73             =head1 METHODS
74              
75             =cut
76              
77 3     3   67426 use 5.006;
  3         11  
  3         116  
78 3     3   32 use strict;
  3         6  
  3         102  
79 3     3   1985 use bytes ();
  3         23  
  3         54  
80 3     3   18 use Carp ();
  3         8  
  3         62  
81 3     3   2762 use IO::File ();
  3         42597  
  3         83  
82 3     3   3446 use Storable 2.16 ();
  3         16135  
  3         108  
83 3     3   30 use File::Basename ();
  3         5  
  3         63  
84 3     3   3660 use Params::Util 0.10 ();
  3         16444  
  3         149  
85              
86             # Optional prefork support
87             SCOPE: {
88             local $@;
89 3     3   1519 eval "use prefork 'File::Type';";
  0         0  
  0         0  
90             }
91              
92 3     3   24 use vars qw{$VERSION};
  3         6  
  3         140  
93             BEGIN {
94 3     3   6179 $VERSION = '1.08';
95             }
96              
97              
98              
99              
100              
101             #####################################################################
102             # Constructor and Accessors
103              
104             =pod
105              
106             =head1 new
107              
108             $file = File::BLOB->new( $data );
109             $file = File::BLOB->new( \$data );
110             $file = File::BLOB->new( $iohandle );
111             $file = File::BLOB->new( $data,
112             header => 'value',
113             filename => 'file.txt',
114             );
115              
116             Creates a new C object from data.
117              
118             It takes as its first param the data, in the form of a normal scalar
119             string (which will be copied), a C reference (which will
120             B be copied), or as a filehandle (any subclass of L
121             can be used).
122              
123             While the C header will be set automatically, you
124             may wish to provide the C header yourself if know, to
125             avoid having to load L to determine the file type.
126              
127             Returns a C object, or dies on error.
128              
129             =cut
130              
131             sub new {
132 6 50   6 0 37 my $class = ref $_[0] ? ref shift : shift;
133              
134             # Create the basic object
135 6         19 my $self = bless {}, $class;
136              
137             # Set the content (don't copy it yet)
138 6         25 $self->set_content(shift);
139              
140             # Set the headers
141 6         22 while ( @_ ) {
142 12         29 $self->set_header(shift, shift);
143             }
144              
145             # Unless we know the MIME type, find it
146 6   66     21 $self->{content_type} ||= $self->_mime_type($self->{content});
147              
148 6         961 $self;
149             }
150              
151             =pod
152              
153             =head2 from_file
154              
155             $file = File::BLOB->from_file( "/home/me/some_picture.gif" );
156             $file = File::BLOB->from_file( "foo.txt",
157             'content_type' => 'text/plain',
158             'foo' => 'bar',
159             );
160              
161             The C method provides an alternative constructor that creates
162             an object directly from a file, using that filename and detecting the
163             MIME type automatically.
164              
165             The same rules as for the C constructor apply regarding additional
166             parameters.
167              
168             Returns a new C object, or dies on error.
169              
170             =cut
171              
172             sub from_file {
173 2 50   2 1 946 my $class = ref $_[0] ? ref shift : shift;
174 2         5 my $path = shift;
175 2         6 my %params = @_; # Just for use here
176              
177             # Basic checks on the filename
178 2 50 33     75 unless ( $path and -e $path ) {
179 0         0 Carp::croak("Invalid file name or file does not exist");
180             }
181 2 50       13 unless ( -r _ ) {
182 0         0 Carp::croak("Insufficient permissions to read file");
183             }
184              
185             # Find the file name
186 2         8 my @auto = ();
187 2 50       7 unless ( exists $params{filename} ) {
188 2 50       116 my $file = File::Basename::basename($path)
189             or Carp::croak("Failed to determine file name");
190 2         8 push @auto, 'filename' => $file;
191             }
192              
193             # Open the file
194 2         19 my $handle = IO::File->new($path, "r");
195 2 50       268 unless ( $handle ) {
196 0         0 Carp::croak("Failed to open file: $!");
197             }
198              
199 2         12 $class->new( $handle, @auto, @_ );
200             }
201              
202             =pod
203              
204             =head2 from_cgi
205              
206             my $file = File::BLOB->from_cgi( $CGI, 'param' );
207              
208             The C constructor allows you to create a C
209             object from a named file upload field in a CGI form.
210              
211             It takes a L object and a CGI param name. Only a single
212             file upload for the param is supported.
213              
214             When called in list context, the C method will return
215             a list of C objects, or the null list of there are
216             no uploaded files for the param.
217              
218             When called in scalar context, the C method return a
219             single C object (if more than one the first), or
220             false (C<''>) if there are no file uploads.
221              
222             An exception will be thrown if an error is encountered.
223              
224             =cut
225              
226             sub from_cgi {
227 9 50   9 1 217991 my $class = ref $_[0] ? ref shift : shift;
228 9 100       585 my $cgi = Params::Util::_INSTANCE(shift, 'CGI') or Carp::croak(
229             'First argument to from_cgi was not a CGI object'
230             );
231 5         10 my $param = shift;
232 5 100       495 Params::Util::_SCALAR(\$param) or Carp::croak(
233             'Second argument to from_cgi was not a CGI param'
234             );
235              
236             # Fetch the filehandles
237 2 50       41 my @handles = $cgi->upload($param) or return;
238 0 0       0 if ( ! wantarray ) {
239             # Remove all but the first filehandle
240 0         0 while ( @handles > 1 ) {
241 0         0 pop @handles;
242             }
243             }
244              
245             # Convert each of the filehandles to File::BLOB objects,
246             # with all headers intact.
247 0         0 my @objects = ();
248 0         0 foreach my $fh ( @handles ) {
249 0 0       0 my $headers = $cgi->uploadInfo($fh) or Carp::croak(
250             "Failed to get headers for upload '$param'"
251             );
252 0 0       0 my $file = File::BLOB->new( $fh, %$headers ) or Carp::croak(
253             "Failed to create File::BLOB for upload '$param'"
254             );
255 0         0 push @objects, $file;
256             }
257              
258             # Return in either list or scalar context
259 0 0       0 wantarray ? @objects : $objects[0];
260             }
261              
262              
263              
264              
265              
266             #####################################################################
267             # Work with the Content
268              
269             =pod
270              
271             =head2 get_content
272              
273             my $data = $file->get_content;
274             my $copy = $$data;
275              
276             The C returns the contents of the file as C reference.
277              
278             Please note that the reference returned points to the actual data in the
279             object, so it should not modified. If you want to modify the contents,
280             you need to copy it first.
281              
282             =cut
283              
284             sub get_content {
285 1     1 1 5 $_[0]->{content};
286             }
287              
288             =pod
289              
290             =head2 set_content
291              
292             $file->set_content( $data );
293             $file->set_content( \$data );
294             $file->set_content( $iohandle );
295              
296             The C method sets the contents of the file to a new value.
297              
298             It takes a single param which should be an ordinary scalar (which will
299             be copied), a C reference (which will not be copied), or a
300             filehandle (any object which is a subclass of L).
301              
302             Because you aren't really meant to use this to add in entirely new
303             content, any C header will not be changed, although the
304             C header will be updated.
305              
306             So while the modification of content without changing its type is fine,
307             don't go adding different types of data.
308              
309             Returns true, or dies on error.
310              
311             =cut
312              
313             sub set_content {
314 6     6 1 10 my $self = shift;
315 6         8 my $data = shift;
316              
317             # Ensure the passed data is a scalar reference
318 6         9 my $content;
319 6 100 33     57 if ( Params::Util::_SCALAR($data) ) {
    100          
    50          
320 3         5 $content = $data;
321             } elsif ( Params::Util::_INSTANCE($data, 'IO::Handle') ) {
322             # Read in as binary data
323 2         9 local $/ = undef;
324 2 50       21 $data->binmode if $data->can('binmode');
325 2         76 my $data = $data->getline;
326 2 50 33     133 unless ( defined $data and ! ref $data ) {
327 0         0 Carp::croak("Failed to get content from filehandle");
328             }
329 2         9 $content = \$data;
330             } elsif ( defined $data and ! ref $data ) {
331 1         3 $content = \$data;
332             } else {
333 0         0 Carp::croak("Invalid parameter to File::BLOB::new");
334             }
335              
336             # Set the content and content_length
337 6         24 $self->{content} = $content;
338 6         25 $self->{content_length} = bytes::length($$content);
339              
340 6         1044 1;
341             }
342              
343             =pod
344              
345             =head2 get_header
346              
347             my $name = $file->get_header('filename');
348              
349             The C method gets a named header for the file.
350              
351             Names are case-insensitive but must be a valid Perl identifier. For things
352             that have a dash in HTTP (Content-Type:) use an underscore instead.
353              
354             Returns the header as a string, C if a header by that name does not
355             exist, or dies on error.
356              
357             =cut
358              
359             sub get_header {
360 11     11 1 2064 my $self = shift;
361 11         22 my $name = $self->_name(shift);
362 11         48 return $self->{$name};
363             }
364              
365             =pod
366              
367             =head2 set_header
368              
369             # Set a header
370             $file->set_header('filename', 'foo.txt');
371            
372             # Delete a header
373             $file->set_header('filename', undef );
374              
375             The C method takes a header name and a value, and sets the
376             header to that value.
377              
378             Names are case-insensitive but must be a valid Perl identifier. For things
379             that have a dash in HTTP (Content-Type:) use an underscore instead.
380              
381             Values must be a normal string of non-null length. If the value passed is
382             C, the header will be deleted. Deleting a non-existant header will
383             not cause an error.
384              
385             Returns true if header set or dies on error.
386              
387             =cut
388              
389             sub set_header {
390 13     13 1 19 my $self = shift;
391 13         31 my $name = $self->_name(shift);
392 13 50       27 @_ or Carp::croak("Did not provide a value for header $name");
393 13         47 my $value = $self->_value(shift);
394              
395 13 50       23 if ( defined $value ) {
396             # Set the header
397 13         32 $self->{$name} = $value;
398             } else {
399             # Remove the header
400 0         0 delete $self->{$name};
401             }
402              
403 13         33 1;
404             }
405              
406              
407              
408              
409              
410             #####################################################################
411             # Storable Support
412              
413             =pod
414              
415             =head2 freeze
416              
417             my $string = $file->freeze;
418              
419             The C method generates string that will be stored in the database.
420              
421             Returns a normal string.
422              
423             =cut
424              
425             sub freeze {
426 3     3 1 160851 my $self = shift;
427              
428             # Generate the headers
429 3         8 my $frozen = '';
430 3         28 foreach my $name ( sort keys %$self ) {
431 13 100       32 next if $name eq 'content';
432 10         31 $frozen .= "$name: $self->{$name}\012";
433             }
434 3         9 $frozen .= "\012";
435              
436             # Add the main content and return
437 3         5 return ( $frozen . ${$self->{content}} );
  3         18  
438             }
439              
440             =pod
441              
442             =head2 thaw
443              
444             my $file = File::BLOB->thaw( $string );
445              
446             The C method takes a string previous created by the C
447             method, and creates the C object from it.
448              
449             Returns a C object, or dies on error.
450              
451             =cut
452              
453             sub thaw {
454 3     3 1 3562 my ($class, $serialized) = @_; # Copy to destroy
455              
456             # Parse in the data
457 3         9 my %headers = ();
458 3         37 while ( $serialized =~ s/^(.*?)\012//s ) {
459 13         31 my $header = $1;
460 13 100       34 if ( bytes::length($header) ) {
461 10 50       70 unless ( $header =~ /^(.+?): (.+)\z/s ) {
462 0         0 Carp::croak("Frozen File::BLOB object is corrupt");
463             }
464 10         33 $headers{lc $1} = $2;
465 10         49 next;
466             }
467              
468             # We hit the double-newline. The remainder of
469             # the file is the content.
470 3 50       21 unless ( defined $headers{content_length} ) {
471 0         0 Carp::croak("Frozen File::BLOB object is corrupt");
472             }
473 3 50       10 unless ( $headers{content_length} == bytes::length($serialized) ) {
474 0         0 Carp::croak("Frozen File::BLOB object is corrupt");
475             }
476              
477             # Hand off to the constructor
478 3         23 delete $headers{content_length};
479 3         19 return $class->new( \$serialized, %headers );
480             }
481              
482             # This would be bad. It shouldn't happen
483 0         0 Carp::croak("Frozen File::BLOB object is corrupt");
484             }
485              
486              
487              
488              
489              
490             #####################################################################
491             # File Serialization
492              
493 0     0 0 0 sub save {
494              
495             }
496              
497             sub read {
498 0     0 0 0 my $class = shift;
499              
500             # Check the file
501 0         0 my $file = shift;
502 0 0       0 Carp::croak('You did not specify a file name') unless $file;
503 0 0       0 Carp::croak("File '$file' does not exist") unless -e $file;
504 0 0       0 Carp::croak("'$file' is a directory, not a file") unless -f _;
505 0 0       0 Carp::croak("Insufficient permissions to read '$file'") unless -r _;
506              
507             # Open the file and read in the headers
508 0         0 my %headers = ();
509 0         0 my $handle = IO::File->new($file, 'r');
510 0 0       0 Carp::croak("Failed to open file $file") unless $handle;
511 0         0 while ( defined(my $line = $handle->getline) ) {
512 0         0 chomp($line);
513 0 0       0 last if ! length($line);
514 0 0       0 unless ( $line =~ /^(\w+):\s*(.+?)\s$/ ) {
515 0         0 Carp::croak("Illegal header line $line");
516             }
517 0         0 $headers{$1} = $2;
518             }
519              
520             # Check class
521 0 0       0 unless ( $headers{class} eq $class ) {
522 0         0 Carp::croak("Serialized class mismatch. Expected $class, got $headers{$class}");
523             }
524              
525 0         0 return $class->new( $handle, %headers );
526             }
527              
528              
529              
530              
531              
532             #####################################################################
533             # Support Methods
534              
535             # Check a name parameter
536             sub _name {
537 24     24   29 my $self = shift;
538              
539             # Check the name is a string
540 24         29 my $name = shift;
541 24 50       67 if ( ! defined $name ) {
542 0         0 Carp::croak("Header name was an undefined value");
543             }
544 24 50       45 if ( ref $name ) {
545 0         0 Carp::croak("Header name cannot be a reference");
546             }
547 24 50       46 if ( $name eq '' ) {
548 0         0 Carp::croak("Header name cannot be a null string");
549             }
550              
551             # The name should be an identifier
552 24         41 $name = lc $name;
553 24 50       692 unless ( Params::Util::_IDENTIFIER($name) ) {
554 0         0 Carp::croak("Header name is not in a valid format");
555             }
556 24 50       227 if ( $name eq 'content' ) {
557 0         0 Carp::croak("Header name 'content' is reserved");
558             }
559              
560 24         36 return $name;
561             }
562              
563             # Check the value is a string
564             sub _value {
565 13     13   19 my $self = shift;
566              
567             # Check the value is a string
568 13         17 my $value = shift;
569 13 50       93 if ( ! defined $value ) {
570             # In this case, it is legal
571 0         0 return $value;
572             }
573 13 50       21 if ( ref $value ) {
574 0         0 Carp::croak("Header value cannot be a reference");
575             }
576 13 50       27 if ( $value eq '' ) {
577 0         0 Carp::croak("Header value cannot be a null string");
578             }
579              
580             # Cannot contain newlines or colons
581 13 50       30 if ( $value =~ /\n/s ) {
582 0         0 Carp::croak("Header value cannot contain newlines");
583             }
584              
585 13         27 return $value;
586             }
587              
588             # Takes a SCALAR reference and returns the MIME type
589             sub _mime_type {
590 2     2   3 my $self = shift;
591 2 50       8 my $data = Params::Util::_SCALAR(shift) or Carp::croak(
592             "Did not provide a SCALAR reference to File::BLOB::_mime_type"
593             );
594 2         917 require File::Type;
595 2         9297 return File::Type->checktype_contents($$data);
596             }
597              
598             1;
599              
600             =pod
601              
602             =head1 SUPPORT
603              
604             Bugs should be reported via the CPAN bug tracker at
605              
606             L
607              
608             For other issues, contact the author.
609              
610             =head1 AUTHOR
611              
612             Adam Kennedy Eadamk@cpan.orgE
613              
614             =head1 COPYRIGHT
615              
616             Copyright 2005 - 2011 Adam Kennedy.
617              
618             This program is free software; you can redistribute
619             it and/or modify it under the same terms as Perl itself.
620              
621             The full text of the license can be found in the
622             LICENSE file included with this module.
623              
624             =cut