| App-ZofCMS-Plugin-FileUpload documentation | Contained in the App-ZofCMS-Plugin-FileUpload distribution. |
App::ZofCMS::Plugin::FileUpload - ZofCMS plugin to handle file uploads
In your ZofCMS template:
file_upload => {
query => 'uploaded_file',
},
plugins => [ qw/FileUpload/ ],
In your HTML::Template template:
<tmpl_if name="upload_error">
<p class="error">Upload failed: <tmpl_var name="upload_error">
</tmpl_if>
<tmpl_if name="upload_success">
<p>Upload succeeded: <tmpl_var name="upload_filename"></p>
</tmpl_if>
<form action="" method="POST" enctype="multipart/form-data">
<div>
<input type="file" name="uploaded_file">
<input type="submit" value="Upload">
</div>
</form>
The module is a ZofCMS plugin which provides means to easily handle file uploads.
This documentation assumes you've read App::ZofCMS, App::ZofCMS::Config and App::ZofCMS::Template
pluginsplugins => [ qw/FileUpload/ ],
First and obvious, you need to stick FileUpload in the list of your
plugins.
file_upload file_upload => {
query => 'upload',
path => 'zofcms_upload',
name => 'foos',
ext => '.html',
content_type => 'text/html',
on_success => sub {
my ( $uploaded_file_name, $template, $query, $conf ) = @_;
# do something useful
}
},
# or
file_upload => [
{ query => 'upload1', },
{ query => 'upload2', },
{}, # all the defaults
{
query => 'upload4',
name => 'foos',
ext => '.html',
content_type => 'text/html',
on_success => sub {
my ( $uploaded_file_name, $template, $query, $conf ) = @_;
# do something useful
}
},
],
Plugin takes input from file_upload first level ZofCMS template key which
takes an arrayref or a hashref as a value. Passing a hashref as a value
is the same as passing an arrayref with just that hashref as an element.
Each element of the given arrayref is a hashref which
represents one file upload. The possible keys/values of those hashrefs
are as follows:
query { query => 'zofcms_upload' },
Optional. Specifies the query parameter which is the file being uploaded,
in other words, this is the value of the name="" attribute of the
<input type="file".... Defaults to: zofcms_upload
path { path => 'zofcms_upload', }
Optional. Specifies directory (relative to index.pl) into which
the plugin will store uploaded files. Defaults to: zofcms_upload
name { name => 'foos', }
{ name => '[rand]', }
{ name => \1 } # any scalar ref
{
name => sub {
my ( $t, $q, $config ) = @_;
return 'file_name.png';
},
}
Optional. Specifies the name (without the extension)
of the local file into which save the uploaded file. Special value of
[rand] specifies that the name should be random, in which case it
will be created by calling rand() and time() and removing any dots
from the concatenation of those two. If a scalarref is specified
(irrelevant of its value), the plugin will use the filename that the
browser gave it (relying on File::Spec::Functions's
splitpath here; also, note that extension will be obtained
using ext argument (see below). The name parameter can also take
a subref, if that's the case, then the name parameter will obtain
its value from the return value of that subref. The subref's @_ will
contain the following (in that order): ZofCMS Template hashref, hashref
of query parameters and App::ZofCMS::Config object.
Defaults to: [rand]
ext { ext => '.html', }
Optional. Specifies the extension to use for the name of local file into which the upload will be stored. By default is not specified and therefore the extension will be obtained from the name of the remote file.
name_filter { name_filter => qr/Z(?!ofcms)/i, }
Optional. Takes a regex ref (qr//) as a value. Anything
in the path + name + ext final string (regardles of how each
of those is obtained) that matches this regex
will be stripped. By default is not specified.
content_type { content_type => 'text/html', }
{ content_type => [ 'text/html', 'image/jpeg' ], }
Optional. Takes either a scalar string or an arrayref of strings. Specifying a string is equivalent to specifying an arrayref with just that string as an element. Each element of the given arrayref indicates the allowed Content-Type of the uploaded files. If the Content-Type does not match allowed types the error will be shown (see HTML TEMPLATE VARS section below). By default all Content-Types are allowed.
on_success on_success => sub {
my ( $uploaded_file_name, $template, $query, $config ) = @_;
# do something useful
}
Optional. Takes a subref as a value. The specified sub will be
executed upon a successful upload. The @_ will contain the following
elements: $uploaded_file_name, $template, $query, $config where
$uploaded_file_name is the directory + name + extension of the local
file into which the upload was stored, $template is a hashref of
your ZofCMS template, $query is a hashref of query parameters and
$config is the App::ZofCMS::Config object. By default is not
specified.
Single upload:
<tmpl_if name="upload_error">
<p class="error">Upload failed: <tmpl_var name="upload_error">
</tmpl_if>
<tmpl_if name="upload_success">
<p>Upload succeeded: <tmpl_var name="upload_filename"></p>
</tmpl_if>
<form action="" method="POST" enctype="multipart/form-data">
<div>
<input type="file" name="upload">
<input type="submit" value="Upload">
</div>
</form>
Multi upload:
<tmpl_if name="upload_error0">
<p class="error">Upload 1 failed: <tmpl_var name="upload_error0">
</tmpl_if>
<tmpl_if name="upload_success0">
<p>Upload 1 succeeded: <tmpl_var name="upload_filename0"></p>
</tmpl_if>
<tmpl_if name="upload_error1">
<p class="error">Upload 2 failed: <tmpl_var name="upload_error1">
</tmpl_if>
<tmpl_if name="upload_success1">
<p>Upload 2 succeeded: <tmpl_var name="upload_filename1"></p>
</tmpl_if>
<form action="" method="POST" enctype="multipart/form-data">
<div>
<input type="file" name="upload">
<input type="file" name="upload2">
<input type="submit" value="Upload">
</div>
</form>
NOTE: upload of multiple files from a single <input type="file"...
is currently not supported. Let me know if you need such functionality.
The folowing <tmpl_var name="">s will be set in your
HTML::Template template.
If you are handling only one upload, i.e. you have only one hashref in
file_upload ZofCMS template key and you have only one
<input type="file"... then the HTML::Template variables described
below will NOT have any trailing numbers, otherwise each of them
will have a trailing number indicating the number of the upload. This number
will starts from zero and it will correspond to the index of hashref of
file_upload arrayref.
upload_error # single
<tmpl_if name="upload_error">
<p class="error">Upload failed: <tmpl_var name="upload_error">
</tmpl_if>
# multi
<tmpl_if name="upload_error0">
<p class="error">Upload 1 failed: <tmpl_var name="upload_error0">
</tmpl_if>
The upload_error will be set if some kind of an error occurred during
the upload of the file. This also includes if the user tried to upload
a file of type which is not listed in content_type arrayref.
upload_success # single
<tmpl_if name="upload_success">
<p>Upload succeeded: <tmpl_var name="upload_filename"></p>
</tmpl_if>
# multi
<tmpl_if name="upload_success0">
<p>Upload 1 succeeded: <tmpl_var name="upload_filename0"></p>
</tmpl_if>
The upload_success will be set to a true value upon successful upload.
upload_filename # single
<tmpl_if name="upload_success">
<p>Upload succeeded: <tmpl_var name="upload_filename"></p>
</tmpl_if>
# multi
<tmpl_if name="upload_success0">
<p>Upload 1 succeeded: <tmpl_var name="upload_filename0"></p>
</tmpl_if>
The upload_filename will be set to directory + name + extension of the
local file into which the upload was saved.
Zoffix Znet, <zoffix at cpan.org>
(http://zoffix.com, http://haslayout.net, http://zofdesign.com/)
Please report any bugs or feature requests to bug-app-zofcms-plugin-fileupload at rt.cpan.org, or through
the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=App-ZofCMS-Plugin-FileUpload. I will be notified, and then you'll
automatically be notified of progress on your bug as I make changes.
You can find documentation for this module with the perldoc command.
perldoc App::ZofCMS::Plugin::FileUpload
You can also look for information at:
http://rt.cpan.org/NoAuth/Bugs.html?Dist=App-ZofCMS-Plugin-FileUpload
Copyright 2008 Zoffix Znet, all rights reserved.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
| App-ZofCMS-Plugin-FileUpload documentation | Contained in the App-ZofCMS-Plugin-FileUpload distribution. |
package App::ZofCMS::Plugin::FileUpload; use warnings; use strict; our $VERSION = '0.0114'; use File::Spec::Functions qw/catfile splitpath/; sub new { bless {}, shift } sub process { my ( $self, $template, $query, $config ) = @_; return unless $template->{file_upload}; my $uploads = delete $template->{file_upload}; $uploads = [ $uploads ] unless ref $uploads eq 'ARRAY'; my $upload_counter = @$uploads == 1 ? '' : 0; for my $upload ( @$uploads ) { $self->_process_upload( $template, $query, $config, $upload_counter++, $upload, ); } return 1; } sub _process_upload { my ( $self, $template, $query, $config, $upload_counter, $upload ) = @_; my $error_key = "upload_error$upload_counter"; my $filename_key = "upload_filename$upload_counter"; my $success_key = "upload_success$upload_counter"; $upload = { query => 'zofcms_upload', path => 'zofcms_upload', name => '[rand]', %$upload, }; my $cgi = $config->cgi; my $remote_filename = $cgi->param( $upload->{query} ); return unless defined $remote_filename; ( $upload->{ext} ) = $remote_filename =~ /[^.]+([.].+)$/ unless defined $upload->{ext}; $upload->{ext} = '' unless defined $upload->{ext}; if ( ref $upload->{name} eq 'CODE' ) { $upload->{name} = $upload->{name}->( $template, $query, $config ); } if ( $upload->{name} eq '[rand]' ) { UNIQUE_NAME: { $upload->{name} = catfile( $upload->{path}, do { my $x = rand() . time(); $x =~ tr/.//d; $x } . $upload->{ext} ); redo UNIQUE_NAME if -e $upload->{name}; } } elsif ( ref $upload->{name} eq 'SCALAR' ) { $upload->{name} = ( splitpath $remote_filename )[-1]; $upload->{name} =~ s/(?<=[^.])[.].+$//; $upload->{name} = catfile( $upload->{path}, $upload->{name} . $upload->{ext} ); } else { $upload->{name} = catfile( $upload->{path}, $upload->{name} . $upload->{ext} ); } if ( $upload->{name_filter} ) { $upload->{name} =~ s/$upload->{name_filter}//g; } my $upload_info = $cgi->uploadInfo( $remote_filename ); if ( defined $upload->{content_type} ) { $upload->{content_type} = [ $upload->{content_type} ] unless ref $upload->{content_type} eq 'ARRAY'; unless ( grep { $upload_info->{'Content-Type'} eq $_ } @{ $upload->{content_type} } ) { $template->{t}{ $error_key } = 'Invalid file type'; return; } } my $fh = $cgi->upload( $upload->{query} ); if ( not $fh and $cgi->cgi_error ) { $template->{t}{ $error_key } = $cgi->cgi_error; return; } return unless $fh; my $fh_out; unless ( open $fh_out, '>', $upload->{name} ) { $template->{t}{ $error_key } = "Failed to open local file [$!]"; return; } seek $fh, 0, 0; binmode $fh; binmode $fh_out; { local $/ = \1024; while ( <$fh> ) { print $fh_out $_; } } close $fh; close $fh_out; if ( ref $upload->{on_success} ) { $upload->{on_success}->( $upload->{name}, $template, $query, $config, ); } $template->{t}{ $success_key } = 1; $template->{t}{ $filename_key } = $upload->{name}; return 1; } 1; __END__