For Programmers: Free Programming Magazines  


Home > Archive > PERL Beginners > February 2007 > File uploading using CGI









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author File uploading using CGI
Kevin Zembower

2007-02-22, 6:59 pm

I'm having problems uploading a file with perl and CGI.pm. I have a form
that uses a script with CGI and MIME::Lite to email the contents of the
form and the file uploaded to an individual. I've written this section
so far:

#If there's a file to be attached, attach it here.
# This only works if <input type=3D'file' name=3D'Material_File' ...>
if ($query->param('Material_File')) {
my $temp_dir =3D -d '/tmp' ? '/tmp' : $ENV{TMP} || $ENV{TEMP};
my $tmp_file_name =3D sprintf("%s/%d-%d", $temp_dir, $$, time());

open(TMP_FILE, ">$tmp_file_name") or die "Can't open temp upload file
$tmp_file_name\n";
my $fh =3D $query->upload('Material_File');
while (<$fh> ) {
print TMP_FILE;
} # while there's more file to upload and store
close(TMP_FILE);

$msg->attach(Type =3D>'BINARY',
Data =3D>$tmp_file_name,
Filename =3D>'AttachedFile',
Disposition =3D>'attachment');

#Don't erase; for debugging.
#unlink($tmp_file_name);
} # If there's a file uploaded

This correctly creates a file in /tmp/ but it's always empty. When the
email is received, it has an attachment of around 90 bytes size, but it
seems to be nested and the innermost file just contains the complete
path and filename the user used to upload the file.

I think I have the form elements set up correctly. The <form> tag
includes 'method=3D"post" enctype=3D"multipart/form-data"' and the =
<input
type=3D"file"> tag includes 'accept=3D"application/octet-stream"'. Am I
missing something here?

This matches the documentation for CGI.pm. I'm stuck at this point. Can
anyone suggest what I might do differently or have other diagnostics I
could try?

On a related note, I really don't need to store the file on disk. I
really just want to send the file out as an email attachment. Can I do
this without saving the file to disk?

Thanks a lot for your help and suggestions.

-Kevin

Kevin Zembower
Internet Services Group manager
Center for Communication Programs
Bloomberg School of Public Health
Johns Hopkins University
111 Market Place, Suite 310
Baltimore, Maryland 21202
410-659-6139=20
usenet@DavidFilmer.com

2007-02-22, 6:59 pm

On Feb 22, 10:58 am, kzemb...@jhuccp.org (Kevin Zembower) wrote:
> I'm having problems uploading a file with perl and CGI.pm.


Before looking at your code, let me ask the obvious question: Are you
using start_multipart_form() instead of start_form()?


--
The best way to get a good answer is to ask a good question.
David Filmer (http://DavidFilmer.com)

Mumia W.

2007-02-22, 6:59 pm

On 02/22/2007 12:58 PM, Zembower, Kevin wrote:
> I'm having problems uploading a file with perl and CGI.pm. I have a form
> that uses a script with CGI and MIME::Lite to email the contents of the
> form and the file uploaded to an individual. I've written this section
> so far:
> [...]
>
> $msg->attach(Type =>'BINARY',
> Data =>$tmp_file_name,
> Filename =>'AttachedFile',
> Disposition =>'attachment');
> [...]


"Data => $tmp_file_name" submits the temporary file's name as the data.
You probably want to specify $tmp_file_name as the path to the file instead:

Path => $tmp_file_name,

Re-read the first few examples in "perldoc MIME::Lite" again.

HTH



Kevin Zembower

2007-02-22, 6:59 pm

Mumia, thanks for your suggestion. Unfortunately, it didn't work; the
file in /tmp/ on the server is still empty and the attachment received
was only 64 bytes and was completely empty, as opposed to my previous
solution, which at least contained the file path and name.

Thanks, again, for trying.

-Kevin

-----Original Message-----
From: Mumia W. [mailto:mumia.w.18.spam+nospam@earthlink.net]=20
Sent: Thursday, February 22, 2007 3:27 PM
To: Beginners List
Subject: Re: File uploading using CGI

On 02/22/2007 12:58 PM, Zembower, Kevin wrote:
> I'm having problems uploading a file with perl and CGI.pm. I have a

form
> that uses a script with CGI and MIME::Lite to email the contents of

the
> form and the file uploaded to an individual. I've written this section
> so far:
> [...]
>=20
> $msg->attach(Type =3D>'BINARY',
> Data =3D>$tmp_file_name,
> Filename =3D>'AttachedFile',
> Disposition =3D>'attachment');
> [...]


"Data =3D> $tmp_file_name" submits the temporary file's name as the =
data.=20
You probably want to specify $tmp_file_name as the path to the file
instead:

Path =3D> $tmp_file_name,

Re-read the first few examples in "perldoc MIME::Lite" again.

HTH




--=20
To unsubscribe, e-mail: beginners-unsubscribe@perl.org
For additional commands, e-mail: beginners-help@perl.org
http://learn.perl.org/
Mumia W.

2007-02-23, 3:59 am

On 02/22/2007 02:40 PM, Zembower, Kevin wrote:
> Mumia, thanks for your suggestion. Unfortunately, it didn't work; the
> file in /tmp/ on the server is still empty and the attachment received
> was only 64 bytes and was completely empty, as opposed to my previous
> solution, which at least contained the file path and name.
>
> Thanks, again, for trying.
>
> -Kevin
>


MIME::Lite works here. Again, re-read the docs on MIME::Lite (perldoc
MIME::Lite). I read the example, and that helped me create this example:

#!/usr/bin/perl
use strict;
use warnings;
use MIME::Lite;
use File::Slurp qw(write_file);

my $tmp_file_name = '/tmp/my-temp-file.txt';
my $from = "$ENV{USER}\@localhost";
my $to = $from;

write_file $tmp_file_name, q{
This is a sample text file.
It should be sent by mail using MIME::Lite.
};

my $mime = MIME::Lite->new (
Type => 'multipart/mixed',
From => $from,
To => $to,
Subject => 'Sample text file attached',
);

$mime->attach(
Type => 'text/plain',
Data => 'Another text message should follow (or be attached).',
);

$mime->attach(
Type => 'text/plain',
Path => $tmp_file_name,
Filename => 'lite.txt',
Disposition => 'attachment',
);

print $mime->as_string;
$mime->send;


__END__

The only way it could be easier is if you could use the MIND::Reader
module ;-)


Mug

2007-02-23, 7:59 am

Zembower, Kevin wrote:
> open(TMP_FILE, ">$tmp_file_name") or die "Can't open temp upload file
> $tmp_file_name\n";
>

Do you want binmode() here? I see you'll use BINARY below.
> my $fh = $query->upload('Material_File');
> while (<$fh> ) {
> print TMP_FILE;
> } # while there's more file to upload and store
>

And if they are binary uploads, do you want to save them in different
place ?

> close(TMP_FILE);
>
> $msg->attach(Type =>'BINARY',
> Data =>$tmp_file_name,
> Filename =>'AttachedFile',
> Disposition =>'attachment');
>
> #Don't erase; for debugging.
> #unlink($tmp_file_name);

or die $! # if unlink not success ?

> } # If there's a file uploaded
>
>

HTH,
Mug

Kevin Zembower

2007-02-23, 7:01 pm

Mug, thanks for writing. According to the documentation on binmode,
"Binmode has no effect under Unix." I'll try it anyway and let the list
know if it seems to have any effect. Thanks for the reminder about the
error condition with unlink.

-Kevin

-----Original Message-----
From: Mug [mailto:perl@reborn.org]=20
Sent: Friday, February 23, 2007 8:35 AM
To: Zembower, Kevin
Cc: beginners@perl.org
Subject: Re: File uploading using CGI

Zembower, Kevin wrote:
> open(TMP_FILE, ">$tmp_file_name") or die "Can't open temp upload

file
> $tmp_file_name\n";
> =20

Do you want binmode() here? I see you'll use BINARY below.
> my $fh =3D $query->upload('Material_File');
> while (<$fh> ) {
> print TMP_FILE;
> } # while there's more file to upload and store
> =20

And if they are binary uploads, do you want to save them in different
place ?

> close(TMP_FILE);
>
> $msg->attach(Type =3D>'BINARY',
> Data =3D>$tmp_file_name,
> Filename =3D>'AttachedFile',
> Disposition =3D>'attachment');
>
> #Don't erase; for debugging.
> #unlink($tmp_file_name);

or die $! # if unlink not success ?

> } # If there's a file uploaded
>
> =20

HTH,
Mug
Kevin Zembower

2007-02-23, 7:01 pm

Mumia, I don't think the problem is in sending the file out. When the
file is recorded on /tmp/, its size is zero. The files I'm uploading are
at least 1KB. Something's wrong with reading the file from the uploaded
filehandle, I believe. Your example takes for granted a properly written
file on disk, and doesn't include reading an uploaded file from a
filehandle. I have other scripts that send out files as attachments
using MIME::Lite, so I'm somewhat confident in this part of my script.

Thanks, though, for taking the time and effort to try to help me with my
problems.

-Kevin

-----Original Message-----
From: Mumia W. [mailto:mumia.w.18.spam+nospam@earthlink.net]=20
Sent: Thursday, February 22, 2007 9:59 PM
To: Beginners List
Subject: Re: File uploading using CGI

On 02/22/2007 02:40 PM, Zembower, Kevin wrote:
section[color=darkred]
data.=20[color=darkred]
> Mumia, thanks for your suggestion. Unfortunately, it didn't work; the
> file in /tmp/ on the server is still empty and the attachment received
> was only 64 bytes and was completely empty, as opposed to my previous
> solution, which at least contained the file path and name.
>=20
> Thanks, again, for trying.
>=20
> -Kevin
>=20


MIME::Lite works here. Again, re-read the docs on MIME::Lite (perldoc=20
MIME::Lite). I read the example, and that helped me create this example:

#!/usr/bin/perl
use strict;
use warnings;
use MIME::Lite;
use File::Slurp qw(write_file);

my $tmp_file_name =3D '/tmp/my-temp-file.txt';
my $from =3D "$ENV{USER}\@localhost";
my $to =3D $from;

write_file $tmp_file_name, q{
This is a sample text file.
It should be sent by mail using MIME::Lite.
};

my $mime =3D MIME::Lite->new (
Type =3D> 'multipart/mixed',
From =3D> $from,
To =3D> $to,
Subject =3D> 'Sample text file attached',
);

$mime->attach(
Type =3D> 'text/plain',
Data =3D> 'Another text message should follow (or be attached).',
);

$mime->attach(
Type =3D> 'text/plain',
Path =3D> $tmp_file_name,
Filename =3D> 'lite.txt',
Disposition =3D> 'attachment',
);

print $mime->as_string;
$mime->send;


__END__

The only way it could be easier is if you could use the MIND::Reader=20
module ;-)



--=20
To unsubscribe, e-mail: beginners-unsubscribe@perl.org
For additional commands, e-mail: beginners-help@perl.org
http://learn.perl.org/
Randal L. Schwartz

2007-02-23, 7:01 pm

>>>>> ""Zembower," == "Zembower, Kevin" <kzembowe@jhuccp.org> writes:

"Zembower,> I'm having problems uploading a file with perl and CGI.pm.

beginners-cgi@perl.org was specifically set up for this type of problem.

Just FYI, because you were also already helped here.

--
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<merlyn@stonehenge.com> <URL:http://www.stonehenge.com/merlyn/>
Perl/Unix/security consulting, Technical writing, Comedy, etc. etc.
See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl training!
Mumia W.

2007-02-23, 7:01 pm

On 02/23/2007 09:06 AM, Zembower, Kevin wrote:
> Mumia, I don't think the problem is in sending the file out. When the
> file is recorded on /tmp/, its size is zero. The files I'm uploading are
> at least 1KB. Something's wrong with reading the file from the uploaded
> filehandle, I believe. Your example takes for granted a properly written
> file on disk, and doesn't include reading an uploaded file from a
> filehandle. I have other scripts that send out files as attachments
> using MIME::Lite, so I'm somewhat confident in this part of my script.
>
> Thanks, though, for taking the time and effort to try to help me with my
> problems.
>
> -Kevin
>


Yeah, I should've read your message more closely, sorry.

> open(TMP_FILE, ">$tmp_file_name") or die "Can't open temp upload file
> $tmp_file_name\n";
> my $fh = $query->upload('Material_File');
> while (<$fh> ) {
> print TMP_FILE;
> } # while there's more file to upload and store
> close(TMP_FILE);
>


You've already mentioned that you're on a UNIX system, so setting
binmode to raw shouldn't matter, but I suggest covering all the bases
anyway:

open (TMP_FILE, ">:raw", $tmp_file_name) or die "Can't open temp upload
file $tmp_file_name: $!";
print TMP_FILE <$fh>;
close(TMP_FILE);

However, I don't see a reason to save the data to a file at all. Why not
just slurp the data directly from the file handle? Here is an example
that doesn't send the mail:


use strict;
use warnings;
use CGI::Pretty qw(-no_xhtml :standard);


url_param('posted') ? process() : request() ;

sub request {
print header(
-type => 'text/html',
'-cache-control', 'no-cache',
);

print start_html('Upload File'),
h1('Upload File'),
p('Use this page to test uploading a file.') ;

print start_form('POST',
url(-relative => 1) . '?posted=1',
'multipart/form-data'),
p('Enter the path to your file to upload here:'),
p(filefield('test-upload','',10,4000)),
submit,

end_form;


print end_html;
}

sub process {
require MIME::Lite;

print header(
-type => 'text/plain',
'-cache-control', 'no-cache',
);

my $fh = param('test-upload');
return unless $fh;

my $mime = MIME::Lite->new(
From => 'roger@localhost',
To => 'julie@localhost',
Subject => 'Test of File Upload',
Type => 'text/plain',
Data => do { local $/; <$fh> },
);

print "\n";
print $mime->as_string;

}


__HTH__



Kevin Zembower

2007-02-23, 7:01 pm

I owe this list, and Mumia in particular, an apology. Apparently, my
script was working yesterday when I was asking for help. I'm guessing
that at some point, I made a change to the HTML input form and forgot to
refresh the copy in my browser. For the rest of yesterday, it continued
to appear to malfunction. However, today, after starting my system
fresh, it just began to work. I apologize for wasting folk's time and
energy.

Mumia, thank you especially for your patience and effort on my behalf.
In addition, you've shown me a way to pipe the file into the email
directly without writing to a file, which is very helpful.

-Kevin

-----Original Message-----
From: Mumia W. [mailto:mumia.w.18.spam+nospam@earthlink.net]=20
Sent: Friday, February 23, 2007 12:53 PM
To: Beginners List
Subject: Re: File uploading using CGI

On 02/23/2007 09:06 AM, Zembower, Kevin wrote:
> Mumia, I don't think the problem is in sending the file out. When the=20
> file is recorded on /tmp/, its size is zero. The files I'm uploading

are=20
> at least 1KB. Something's wrong with reading the file from the

uploaded=20
> filehandle, I believe. Your example takes for granted a properly

written=20
> file on disk, and doesn't include reading an uploaded file from a=20
> filehandle. I have other scripts that send out files as attachments=20
> using MIME::Lite, so I'm somewhat confident in this part of my script.
>=20
> Thanks, though, for taking the time and effort to try to help me with

my=20
> problems.
>=20
> -Kevin
>=20


Yeah, I should've read your message more closely, sorry.

> open(TMP_FILE, ">$tmp_file_name") or die "Can't open temp upload

file
> $tmp_file_name\n";
> my $fh =3D $query->upload('Material_File');
> while (<$fh> ) {
> print TMP_FILE;
> } # while there's more file to upload and store
> close(TMP_FILE);
>=20


You've already mentioned that you're on a UNIX system, so setting=20
binmode to raw shouldn't matter, but I suggest covering all the bases=20
anyway:

open (TMP_FILE, ">:raw", $tmp_file_name) or die "Can't open temp upload
file $tmp_file_name: $!";
print TMP_FILE <$fh>;
close(TMP_FILE);

However, I don't see a reason to save the data to a file at all. Why not

just slurp the data directly from the file handle? Here is an example=20
that doesn't send the mail:


use strict;
use warnings;
use CGI::Pretty qw(-no_xhtml :standard);


url_param('posted') ? process() : request() ;

sub request {
print header(
-type =3D> 'text/html',
'-cache-control', 'no-cache',
);

print start_html('Upload File'),
h1('Upload File'),
p('Use this page to test uploading a file.') ;

print start_form('POST',
url(-relative =3D> 1) . '?posted=3D1',
'multipart/form-data'),
p('Enter the path to your file to upload here:'),
p(filefield('test-upload','',10,4000)),
submit,

end_form;


print end_html;
}

sub process {
require MIME::Lite;

print header(
-type =3D> 'text/plain',
'-cache-control', 'no-cache',
);

my $fh =3D param('test-upload');
return unless $fh;

my $mime =3D MIME::Lite->new(
From =3D> 'roger@localhost',
To =3D> 'julie@localhost',
Subject =3D> 'Test of File Upload',
Type =3D> 'text/plain',
Data =3D> do { local $/; <$fh> },
);

print "\n";
print $mime->as_string;

}


__HTH__




--=20
To unsubscribe, e-mail: beginners-unsubscribe@perl.org
For additional commands, e-mail: beginners-help@perl.org
http://learn.perl.org/
Mumia W.

2007-02-24, 3:59 am

On 02/23/2007 12:36 PM, Zembower, Kevin wrote:
> I owe this list, and Mumia in particular, an apology. Apparently, my
> script was working yesterday when I was asking for help. I'm guessing
> that at some point, I made a change to the HTML input form and forgot to
> refresh the copy in my browser. For the rest of yesterday, it continued
> to appear to malfunction. However, today, after starting my system
> fresh, it just began to work. I apologize for wasting folk's time and
> energy.


Now you see the value of '-cache-control' => 'no-cache', no?

>
> Mumia, thank you especially for your patience and effort on my behalf.
> In addition, you've shown me a way to pipe the file into the email
> directly without writing to a file, which is very helpful.
>
> -Kevin
>


You're quite welcome.


Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com