How to upload multiple files in perl? - perl

I need to upload multiple files using perl cgi.
i used form type as
enctype="multipart/form-data
and also set
multiple='multiple' in input type file.
just need to know what should we do write at server side ?
Can anybody tell me how to upload multiple files using perl?

The following piece of code is enough and upload files present in the params to /storage location:
use CGI;
my $cgi = new CGI;
my #files = $cgi->param('multi_files[]');
my #io_handles=$cgi->upload('multi_files[]');
foreach my $upload(#files){
print "Filename: $upload<br>";
my $file_temp_path = "/storage";
my $upload_file = shift #io_handles;
open (UPLOADFILE,">$file_temp_path/$upload") or print "File Open Error";
binmode UPLOADFILE;
while (<$upload_file>) {
print UPLOADFILE;
}
}
print "Files Upload done";

On the server side, you first retrive the file file handle like this:
use CGI;
my $q = CGI->new();
my $myfh = $q->upload('field_name');
Now you have a filehandle to the temporary storage whither the file was uploaded.
The uploaded file anme can be had using the param() method.
$filename = $q->param('field_name');
and the temporary file can be directly accessed via:
$filename = $query->param('uploaded_file');
$tmpfilename = $query->tmpFileName($filename);
I highly recommend giving the CGI.pm docs a good solid read, a couple of times. While not trivial, it's all rather straightforward.

Something like this should handle multiple files upload:
my #fhs = $Cgi->upload('files');
foreach my $fh (#fhs) {
if (defined $fh) {
my $type = $Cgi->uploadInfo($fh)->{'Content-Type'};
next unless ($type eq "image/jpeg");
my $io_handle = $fh->handle;
open (OUTFILE,'>>','/var/directory/'.$fh);
while (my $bytesread = $io_handle->read(my $buffer, 1024)) {
print OUTFILE $buffer;
}
close (OUTFILE);
}
}
Ofc 'files' is the name of the file upload form.

Related

Extract specific data from multiple text files in a directory

This is my first program in perl.
I have more than 1000 files and I want to extract specific data from a file. The structure of all the files are same.
Its really difficult to open every file and then copy a specific data,
How can I achieve this using perl.
The structure looks like this.
LensMode=Normal
MicronMarker=500
DataDisplayCombine=1
Voltage=0 Volt
PixelSize=1.586612
I want to extract MicronMarker and PixelSize from each file.
Any help in the right direction is appreciated.
the location is D:\Files\Folder1
Try this
Use glob to read the directory
while (my $files = glob(" D:\Files\Folder1\*"))
{
open my $handler,"<","$files";
my #extract = grep{ m/^(MicronMarker|PixelSize)/g} <$handler>;
print #extract;
}
Extract the word from a file using the while loop by opendir.
opendir(my $dir, " D:\Files\Folder1");
while (my $ech = readdir($dir))
{
open my $handler,"<","test/$ech";
while(my $l = <$handler>)
{
if($l =~m/^(?:MicronMarker|PixelSize)/g)
{
print "$l";
}
}
close ($handler);
}
This is easy way to extract a words from a file using grep
while (my $ech = readdir($dir))
{
open my $handler,"<","test/$ech";
my #extract = grep{ m/^(MicronMarker|PixelSize)/g} <$handler>;
print #extract;
close($handler);
}

Error in file upload using perl "read() on unopened filehandle"

I am facing read the file error while i am uploading a file using perl like this
fileparse_set_fstype('MSWin32');
my ($OriginalName,$OriginalPath) = fileparse( $CgiRef->{'filename'} );
my $LocalName = $_ . $OriginalName;
open(FILE, ">$config->{'BASE_PATH'}/files/$LocalName")
or die "Could not open file:$!";
my $Req = new CGI;
while (read($Req->param('filename'), my $Buffer, 1024))
{
print FILE $Buffer;
}
close(FILE)
And There is no problem in accesing $CgiRef->{'$filename'} or any refernce variables.
please let me know where is the actual problem while uploading.
now it shows the error
read() on unopened filehandle
You're trying to read from the wrong place. In CGI-land, use $cgi->upload('varname') to get a filehandle on the object you're trying to receive.
This modified version of your snippet should work:
fileparse_set_fstype('MSWin32');
my ($OriginalName,$OriginalPath) = fileparse( $CgiRef->{'filename'} );
my $LocalName = $_ . $OriginalName;
open(FILE, ">", "$config->{'BASE_PATH'}/files/$LocalName")
or die "Could not open file:$!";
my $Req = CGI->new();
# Get the filehandle for the upload content
my $Req_file = $Req->upload('filename');
# Save to FILE
while (<$Req_file>) {
print FILE;
}
close(FILE);
Please note, always use the 3 param version of open. It's cleaner, safer, and clearer. See Modern Perl for an explanation.
A full example of the whole process from HTML form to CGI processing can be found here.

PERL CGI multiple content types. How To Download File AND view contents.

A page that prints out a file (on the server) contents and provides a direct download link.
Download File HERE
Start contents of file:
line 1
line 2
line 3
...
I am not sure of the best way and the right header that will allow a download link and HTML text. This prints out blank
print $mycgi->header(
-cookie => $mycookie,
-Type => "application/x-download"
-'Content-Disposition'=>'attachment; filename="FileName"'
);
You can include a link to a script and pass the filename as a parameter. The link might look something like this:
http://url/to/script?action=download&file=foo
Below that, simply print the contents of the file:
#!/usr/bin/perl -T
use strict;
use warnings;
use CGI qw/escapeHTML/;
my $q = CGI->new;
print $q->header,
$q->start_html('foo'),
$q->a({ -href => 'http://url/to/script?action=download&file=foo' }, 'Click to download'),
"<pre>";
open my $fh, "<", "/path/to/file" or die $!;
print escapeHTML($_) while <$fh>;
close $fh;
print "</pre>", $q->end_html;
Note that you should use escapeHTML() to prevent the browser from rendering anything in the file as HTML (which the <pre> tag alone does not take care of).
When the script is called with the action parameter set to download, use the application/x-download content type as you did above:
my $q = CGI->new;
# Untaint parameters
my ($action) = ($q->param('action') =~ /^(\w+)$/g);
my ($file) = ($q->param('file') =~ /^([-.\w]+)$/g);
# Map file parameter to the actual file name on your filesystem.
# The user should never know the actual file name. There are many
# ways you could implement this.
???
if ($action eq "download") {
print $q->header(
-type => "application/x-download",
-'Content-Disposition' => 'attachment; filename="FileName"'
);
open my $fh, "<", $file or die "Failed to open `$file' for reading: $!";
print while <$fh>;
close $fh;
}
Note that you also need to print the contents of the file in the body of the response.

Creating a file on the fly and return on the fly (Perl)

I have to create a file based on user inputs on the server. Return that file.
Now, I don't want the files once the file is returned to the user (otherwise they will fill up my disk space).
Is there a good way of doing this?
I have to do it in Perl.
Thank You.
If you're building a zip file and immediately sending it back to the client then you have lots of options.
You could use writeToFileHandle combined with IO::Scalar to write the zip file data straight to a string and send that back. This approach avoids the whole file issue completely.
You could also use writeToFileHandle combined with File::Temp to write to a temporary file and then stream that file back. The UNLINK option for File::Temp will help you automatically clean up the temp file as well.
This is what I created and works for me. When user opening some URL on my page I am creating ZIP archive on the fly and sending it to user.
If change "-" to "file.zip" it will save archive into your hosting/server (and don't need print "content type").
Tried with big size files (400-500Mb each file) - all ok.
use IO::Compress::Zip qw(:all);
my #files = ('example.gif', 'example1.png', 'example2.jpg', 'example3.avi', 'example4.mov');
my $path = "/home/********/**********";
print "Content-Type:application/zip\n";
print "Content-Disposition: attachment; filename=\"filename.zip\"\n\n";
my $z;
foreach my $file (#files) {
if ($z) {
$z->newStream(Name => $file, Method => ZIP_CM_STORE);
} else {
$z = new IO::Compress::Zip "-", Name => $file, Method => ZIP_CM_STORE;
}
open(FILE, "<", "$path/$file");
binmode FILE;
my ($buf, $data, $n);
while (($n = read FILE,$data, 1024) != 0) {
$z->print($data);
}
close(FILE);
}
$z->close;
exit;

How do I process the response as a file without using the :content_file option?

Example code:
my $ua = LWP::UserAgent->new;
my $response = $ua->get('http://example.com/file.zip');
if ($response->is_success) {
# get the filehandle for $response->content
# and process the data
}
else { die $response->status_line }
I need to open the content as a file without prior saving it to the disk. How would you do this?
You can open a fake filehandle that points to a scalar. If the file argument is a scalar reference, Perl will treat the contents of the scalar as file data rather than a filename.
open my $fh, '<', $response->content_ref;
while( <$fh> ) {
# pretend it's a file
}
Not quite a file, but here is a relevant SO question: What is the easiest way in pure Perl to stream from another HTTP resource?