Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

need to pass on a file from a form to cgi script to perl program

Status
Not open for further replies.

kavi98

Programmer
Dec 14, 2000
48
0
0
US
the html form is to take the file name upload it to the cgi script and then the file is to be passed on to a perl program to be used in execution there.

the form
<!Form to upload a text file to generate a script .>
<HTML>
<HEAD>
<TITLE>Uploading File</TITLE>
</HEAD>
<BODY>
<FONT size=6 type=&quot;ariel&quot; color = #0000FF align =&quot;center&quot;>Please click browse to Upload the File</FONT>
<TABLE width=&quot;510&quot; border=&quot;0&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; bgcolor=&quot;#FFFFFF&quot;>
<tr><td align=&quot;left&quot; valign=&quot;top&quot; height=&quot;20&quot;>
<FORM METHOD = POST ACTION =&quot; ENCTYPE=&quot;multipart/form-data&quot;>


Local File: <INPUT TYPE =&quot;file&quot; value= &quot;UPLOAD&quot; ACCEPT=&quot;text/plain,image/gif&quot;>
</td></tr><br>

<tr><td align=&quot;left&quot; valign=&quot;top&quot; height=&quot;20&quot;><br>
&amp;#032;&amp;#032;<INPUT TYPE = &quot;submit&quot; value =&quot;Transfer File&quot;>
<INPUT TYPE = &quot;reset&quot; value= &quot;Reset &quot;>
</td></tr>
</FORM>
</TABLE>
</BODY></HTML>

the cgi script which i am still trying to understand and write.So it still has a lot of loose ends.

#!/usr/local/bin/perl

print &quot;Content-type:text/html\n\n&quot;;

read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
@pairs = split(/&amp;/, $buffer);
foreach $pair (@pairs) {
($name, $value) = split(/=/, $pair);
$value =~ tr/+/ /;
$FORM{$name} = $value;
}
print &quot;$value \n&quot;;
print &quot;<html><head><title>Form Output</title></head><body>&quot;;
print &quot;<h2>Results from FORM post</h2>\n&quot;;

foreach $key (keys(%FORM)) {
print &quot;$key = $FORM{$key}<br>&quot;;
}

print &quot;</body></html>&quot;;

~
from this script i want to pass the file to the perl program and use the data in the text file passed

thanks for the help
 
Well, CGI_Lite is working if it is parsing it from the command line, so that's not the problem. It might be your form on your webpage. Make sure you have enctype=&quot;multipart/form-data&quot; in your form tag, and make sure it is a POST. Also, be sure you have a closing form tag. Why don't you post your form here?
Sincerely,

Tom Anderson
CEO, Order amid Chaos, Inc.
 
my html form
<!Form to upload a text file to generate a script .>
<HTML>
<HEAD>
<TITLE>Uploading File</TITLE>
</HEAD>
<BODY>
<FONT size=6 type=&quot;ariel&quot; color = #0000FF align =&quot;center&quot;>Please click browse to Upload the File</FONT>
<TABLE width=&quot;510&quot; border=&quot;0&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; bgcolor=&quot;#FFFFFF&quot;>
<tr><td align=&quot;left&quot; valign=&quot;top&quot; height=&quot;20&quot;>
<FORM ENCTYPE=&quot;multipart/form-data&quot; ACTION =&quot; METHOD = &quot;POST&quot; >


Local File: <INPUT TYPE =&quot;FILE&quot; value= &quot;UPLOAD&quot; >
</td></tr><br>

<tr><td align=&quot;left&quot; valign=&quot;top&quot; height=&quot;20&quot;><br>
&amp;#032;&amp;#032;<INPUT TYPE = &quot;submit&quot; value =&quot;Transfer File&quot;>
<INPUT TYPE = &quot;reset&quot; value= &quot;Reset &quot;>
</td></tr>
</FORM>
</TABLE>
</BODY></HTML>
 
There's your problem... your file input needs to named &quot;UPLOAD&quot;, not valued &quot;UPLOAD&quot;.

<input type=&quot;file&quot; name=&quot;UPLOAD&quot;>
Sincerely,

Tom Anderson
CEO, Order amid Chaos, Inc.
 
I have changed the name to UPLOAD but I transfer the name of the file and not the contents

the code that works is
#!/opt/ZDperl/bin/perl -w
# CGI routines
use CGI_Lite;
use Fcntl qw:)flock);
my $cgi = new CGI_Lite;
my %in = $cgi->parse_form_data();

# get the file from the input stream
my $upload = $in{&quot;UPLOAD&quot;};
my $filename = &quot;/zd/home/karora/textDir/filename.txt&quot;;

# print your html header
print &quot;Content-type: text/html\n\n&quot;;

# check if it's there, and write it to disk
if ($upload)
{
open (TEXT,&quot;>$filename&quot;) || CgiDie(&quot;Cannot open $filename for writing: $!&quot;);
unless (flock (TEXT, LOCK_EX)) {CgiDie(&quot;Cannot lock $filename: $!&quot;);}
print TEXT $upload;
close(TEXT);
}
else {CgiDie(&quot;Error: file did not upload.&quot;);}

# print the page
print &quot;<html><head><title>Form Output</title></head>&quot;;
print &quot;<body>&quot;;
print &quot;<h2>Results from FORM post:</h2><br>&quot;;
print &quot;$upload&quot;;
print &quot;</body></html>&quot;;

sub CgiDie
{
my ($message) = @_;
print $message;
die (&quot;$message&quot;);
}
 
That doesn't make any sense. But what else is new? Try testing it from a different machine. That sounds like a browser error... the type=&quot;file&quot; is supposed to send the contents of the selected file, not its name. The name should never be sent to the CGI (unless maybe the file did not exist?). The problem is on the client-side not the server-side. You're using the HTML exactly as you wrote it above? Make sure you upload a file that exists on your local drive.

Also, I'd remove the line that says &quot;<!Form to upload a text file to generate a script .>&quot;. I don't think that is a valid comment, nor closed correctly.
Sincerely,

Tom Anderson
CEO, Order amid Chaos, Inc.
 
I did try it on another machine maybe the parse_form data is not working as when i type on the command line i give the contents of the file it does not have to get it from the file.

it still transfers the filename,can i work some thing around it.
Please help.

Thanks
 
I'm am not up to speed on using CGI_Lite, so I may be barking up a non-existent tree.....but,..

If I do this same trick with CGI.pm (not advocating switching at this point, just drawing a comparison), the file name that CGI.pm gets from the upload variable is also a FILE HANDLE which is then read from.

<snippet>

[red]$fileID[/red] = $query->param('fileID'); # get file name
@pathName = split(/\\/,[red]$fileID[/red]); # throw away path
$newFile = '/some/path/to/put/the/new_file/'; # build local path for new file
$newFile .= pop(@pathName); # new path/name for new file
open(OPF,&quot;>$newFile&quot;) || &amp;showError(&quot;Failed to open OPF, $!&quot;);
# $fileID is a filename and in the following context is a file HANDLE.
# read incoming stream and print to OPF, new file on local system
while ($bytesread=[red]read[/red]([red]$fileID[/red],$buffer,1024)) { print OPF &quot;$buffer&quot;; }
close OPF;

</snippet>

Where in kavi98's post from today, is the 'read' happening? Like I said, I'm not familiar with CGI_Lite, so maybe there is more going on in the code than I see. If CGI_Lite works similarly to CGI.pm, and it appears it does, then printing $upload would simply print the name of the file being uploaded, and not it's contents. If there is a behind the scenes 'read' going on, how do you descern between the filename and the file contents?





keep the rudder amid ship and beware the odd typo
 
Ok, I've never had to do this (since you don't have to do this in cgi-lib.pl and CGI_Lite is basically compatible with the same code), but I found this in the documentation, and it appears to answer your question. Right before you parse_form_data() do this:

$cgi->set_file_type ('handle');

Then use $in{'UPLOAD'} as a file handle.

Sincerely,

Tom Anderson
CEO, Order amid Chaos, Inc.
 
#!/opt/ZDperl/bin/perl -w
# CGI routines
use CGI_Lite;
use Fcntl qw:)flock);
my $cgi = new CGI_Lite;
$cgi->set_file_type ('UPLOAD');
my %in = $cgi->parse_form_data();

# get the file from the input stream
my $upload = $in{&quot;UPLOAD&quot;};
my $filename = &quot;/zd/home/karora/textDir/filename.txt&quot;;


this what i am doing?
I hope it is right,but it still uploads the name to the destination file.
 
go boating ,
I have a question for you the snippet you have pasted above,
I am using it in the script and it keeps giving me an error of unintialised variable.
how do you set a variable to null or 0 before you use it.

Thanks
 
good morning kavi98,

You can simply do it. like this ..... $variable = ''; to set it to null.
But, if you are getting that error, it means something. You don't want to set anything to '0' before this. If you are saying that you are using the small chunk between the <snippet> tags, then all variables in that snippet should be set going into that section of code.

Also, that snippet uses CGI.pm. As stated in that post, it is not compatible with CGI_Lite. However, while I am not up to speed on CGI_Lite, I can do this trick with CGI.pm, easily. Do you have CGI.pm installed? If so, I am confident that we could get you running fairly quickly. Even with the OO syntax.... it is really not that hard. I can't believe this thread has meandered around for 40+ posts. You must be tired of this.

Let me know how I can help.

on second thought, I will reiterate now. If you have CGI.pm, then the following code will work. It is in two sections. The first is an HTML front page that should look very familiar (you stuff slightly tweaked). The second is a piece of CGI that accepts the information from the HTML input page and does the upload.

Save the following code to your html directory.
## HTML Page ##
<HTML><HEAD><TITLE>UPLOAD THIS</TITLE></HEAD>
<BODY>
<FORM METHOD=&quot;POST&quot; ACTION=&quot; ENCTYPE=&quot;multipart/form-data&quot;>
Enter or Browse to the file you would like to upload.<BR>
<INPUT TYPE=&quot;file&quot; NAME=&quot;UPLOAD&quot; VALUE=&quot;&quot; SIZE=50 MAXLENGTH=80><BR>
<INPUT TYPE=&quot;submit&quot; NAME=&quot;doWhat&quot; VALUE=&quot;uploadMe&quot;></FORM>
</BODY>
</HTML>

## end HTML Page ##

Save the following code to your cgi-bin directory.
## CGI Code ##
#!/opt/ZDperl/bin/perl
use CGI;
$query = new CGI;
print $query->header;
print $query->start_html(-title=>&quot;UPLOAD PLEASE&quot;);
$fileID = $query->param('UPLOAD');
@pathName = split(/\\/,$fileID);

unless ($fileID) { &amp;showError('No file name specified.'); }
# if $fileID is not null, read file from remote machine and write locally.
if ($fileID)
{
# [red]you must change the following line to point to a
# dir on your machine that is writable by the web server
# process[/red]
$newFile ='/path/to/put/the/new/file/';

# add upload filename to the new path
$newFile .= pop(@pathName);

# open a handle to the new file you will write
open(OPF,&quot;>$newFile&quot;) || &amp;showError(&quot;Failed to open OPF, $!&quot;);

# while you read from the remote machine,
# write to the output file.
print &quot;<P>Uploading <BR>$fileID <BR>to<BR>$newFile<BR></P>\n&quot;;
while ($bytesread=read($fileID,$buffer,1024))
{ print OPF &quot;$buffer&quot;; }
close OPF;

# check to make sure the uploaded file is safe to keep
# first retrieve the file type from the CGI object
# then, check that it is something you want.
$type = $query->uploadInfo($fileID)->{'Content-Type'};

# if it is not 'text/html', delete it.
# [red]Depending on what type of file you want to upload
# you may need to change the allowable types.[/red]
unless ($type =~ /text\/html/i)
{
unlink $newFile;
&amp;showError(&quot;Dangerous file type.<BR>Deleted file.&quot;);
}
}
print $query->end_html;

sub showError
{
# a generic complaint generator
my @error = @_;
print &quot;<CENTER><font color=\&quot;\#ff4500\&quot;>ERROR - @error</font><BR>\n&quot;;
print &quot;Please use the BACK button to return to the previous page<BR>\n&quot;;
print &quot;and correct the error.<BR></CENTER>\n&quot;;
print $query->end_html;
exit;
}

## end CGI Code ##

You should be able to save the HTML portion as anything you want in your normal HTML dir. Then copy/paste the CGI code into a file named load1.cgi, modify the parts that are shown in red in this post, and save that to cgi-bin dir specified in the <FORM ACTION=''...> tag of the HTML page. If you are on a UNIX box, ... looks like you are, make sure the execute bits are set on load1.cgi.

I wrote this on a Sun Solaris box, it worked. Then, copied onto a WinNT 4.0, changed the red parts and the URL of the CGI code in the HTML page and it worked there also.

Admittedly, the HTML output is not pretty. But, if you get the upload stuff working, making the HTML pretty is trivial.

I hope this helps.... feel free to ask questions.....




keep the rudder amid ship and beware the odd typo
 
kavi98, I said to use &quot;cgi->set_file_type ('handle');&quot; not &quot;cgi->set_file_type ('UPLOAD');&quot;. Go to the link I posted for the full explanation.

goBoating, that's what I thought too. I've used this code on multiple servers for many applications. Strange that it gives errors now.

The main reason I don't like CGI.pm is because it takes too much control of what you are doing. I like to get to the guts of things. Just one reason I don't like OO programming that much... the entire theory of it is to hide the true functionality from the user. As we've seen with Windows, that is a bad philosophy because you cannot fix the inherent bugs and it strips power away from you in controlling your own system. I like CGI_Lite because its functions simply dump the input into the %in array at which point I can work on it as I please. So, I would say that CGI.pm is to Windows, as CGI_Lite.pm is to Linux. Of course, that is not entirely true, since you could go into the module and change stuff around, but on the surface, that is what it is like. Maybe a better comparison would be that CGI.pm is to FrontPage, as CGI_Lite.pm is to Emacs. Yeah, that gets to the core of it.
Sincerely,

Tom Anderson
CEO, Order amid Chaos, Inc.
 
Tom,
On the whole, I agree that flexibility in the tool is important. But, I find that in the universe of things I want to do with CGI code, CGI.pm does some of them pretty well with minimal labor on my part. There are other things that it is pretty poor at, so I take other routes. This upload trick is pretty easy with CGI.pm, so I use it.

Later,




keep the rudder amid ship and beware the odd typo
 
goboating ,
I have tried to check for synatax mistakes i might have made ,but this error keeps comming.
used only once: possible typo at (eval 18) line 5.
Can't use an undefined value as a HASH reference at /zd/home/karora/cgi-bin/try2.cgi line 23.

@pathName = split(/\\/,$fileID);
it just keeps giving an error on this line and

$type = $query->uploadInfo($fileID)->{'Content-Type'};

thanks for all the help,but i am at a loss totally as to why it is doing it,but when i use CGI::Debug it transfers the file and prints out the error.

Thanks
Another question can i call another perl program within a CGI script.


 
OK,

There must be a disconnect between the HTML front page and your CGI. Fields are named inconsistently or something like that. I can't tell exactly with out more of the code.

I will help until it works, but, as I stated before, I don't know nada about CGI_Lite or cgi_lib. So, are you using CGI.pm exclusively and did you try to copy/paste the code I posted this morning? If yes, then email those text files to me at john.ulmer@noaa.gov. I'll take a look at them and get back with you. We can get this working and then post our solution once we get one.

If you want to try to use the other modules, I will have to leave this to Tom. He is much better with them than I.

What ever works...;^)



keep the rudder amid ship and beware the odd typo
 
Hey, the Perl motto is, there's more than one way to do it! There are other modules besides CGI_Lite.pm and CGI.pm that do this as well. Pick one and go with it. The fix to that one line I pointed out should get the code working. Or use the CGI.pm method. Personally, I'd go the lowest level possible, even to the point of parsing STDIN yourself. In fact, that would be the best way to know what these modules are actually trying to do with their object-oriented functions. Why learn a proprietary interface to your code, when you could just learn the code itself? ...and probably more easily!
Sincerely,

Tom Anderson
CEO, Order amid Chaos, Inc.
 
The code that works
I want to thank you all for helping me make it work.

#!/opt/ZDperl/bin/perl -w
use CGI;
$query = new CGI|| die(&quot;$!&quot;);
print $query->header;
print $query->start_html(-title=>&quot;UPLOAD THIS&quot;);
$fileID = $query->param('UPLOAD');
@pathName = split(/\\/,$fileID);

unless ($fileID) { &amp;showError('No file name specified.'); }
if ($fileID)
{
$newFile = '/zd/home/karora/textDir/';
$newFile .= pop(@pathName);
chmod (0755, &quot;$newFile&quot;);
open(OPF,&quot;>$newFile&quot;) || &amp;showError(&quot;Failed to open OPF, $!&quot;);
print &quot;<P>Uploading <BR>$fileID <BR>to<BR>$newFile<BR></P>\n&quot;;
while (read($fileID,$buffer,1024)) { print OPF &quot;$buffer&quot;; }
close OPF;
}
print &quot;<BR>Upload of $newFile Successful<BR>\n&quot;;
print $query->end_html;

sub showError
{
my @error = @_;
print &quot;<CENTER><font color=\&quot;\#ff4500\&quot;>Fatal ERROR - @error</font><BR>\n&quot;;
print &quot;Submission aborted - your data was not saved!!<BR>\n&quot;;
print &quot;Please use the BACK button to return to the previous page<BR>\n&quot;;
print &quot;and correct the error.<BR></CENTER>\n&quot;;
print $query->end_form;
print $query->end_html;
exit;
}
 
goBoating, I've renamed the FAQ I wrote in this forum to specify the libraries it uses. Please write a FAQ illustrating the use of CGI.pm for file uploads, well commented if possible. I think it will be very helpful to have that.
Sincerely,

Tom Anderson
CEO, Order amid Chaos, Inc.
 
' will do.

Thanks



keep the rudder amid ship and beware the odd typo
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top