PDA

View Full Version : Uploading Multiple Image Files At Once


netroact
06-20-2005, 07:25 AM
Please excuse my laziness, but I know someone on here will find this question very simple to answer.

I have adapted an upload script I found somewhere to use with a drop-down menu. Now, I want to know how to submit up to 10 images together for upload without too much stress on the server. I will have 10 browse buttons.
I know I would probably need to process them one at a time, but could I submit them all at the same time. Below is the script I am currently using. Could someone show me how to adapt it for my purpose.



#!/usr/bin/perl
use CGI ':standard';
use CGI::Carp qw(fatalsToBrowser);
$upload_dir = "/home/lake/public_html/photo";
$query = new CGI;
$filename = $query->param("photo");
$filename =~ s/.*[\/\\](.*)/$1/;
$upload_filehandle = $query->upload("photo");
open UPLOADFILE, ">$upload_dir/$filename";
while ( <$upload_filehandle> )
{
print UPLOADFILE;
}
close UPLOADFILE;
print $query->header ( );
print <<END_HTML;
<HTML>
<HEAD>
<TITLE>Thanks!</TITLE>
</HEAD>
<BODY>
<P>Thanks for uploading your photo!</P>
<P>Your photo:</P>
<img src="http://somestupiddomain.com/photo/$filename" border="0">
</BODY>
</HTML>
END_HTML



I would appreciate any help.

mlseim
06-20-2005, 04:41 PM
A simple upload script. You can have as many as you want, set by the $max_files variable in the script. Uploaded to the directory of your choice with a relative path $upload_dir.

The HTML form:
<html>
<body>
<form method='post' action='/cgi-bin/simple_upload.pl' ENCTYPE='multipart/form-data'>
File 1: <input type='file' name='file1' size='20'><br>
File 2: <input type='file' name='file2' size='20'><br>
File 3: <input type='file' name='file3' size='20'><br>
<input type='submit' value='Upload Files' name='submit'>
</form>
</body>
</html>

The Perl script:
#!/usr/bin/perl
use CGI qw(:standard);
use strict;

my $cgi = new CGI;
my $upload_dir = '../uploads'; #directory where files will be uploaded.
my $max_files = 3; #maximum number of files allowed.

print $cgi->header(-type=>'text/html');

for (my $count=1; $count<=$max_files; $count++){
my $filen = "file".$count;
my $file = $cgi->param($filen);
my $filename = $file;
$filename =~ s/^.*(\\|\/)//g;

if($file){
open(OUT, ">$upload_dir/$filename") || die print "Fail to upload: $!";
while(<$file>) {
print OUT;
}
close(OUT);
}
}

print "File(s) Uploaded\n";

netroact
06-20-2005, 06:09 PM
Thank you very much. I really appreciate your help.

netroact
06-21-2005, 03:40 AM
Well, I can't get it to work. It will put the filenames in the upload directory, but they are 0 bytes. I copied your script and used it. My form looks the same as yours, except there are more fields. If I may ask, is your script tested?

netroact
06-21-2005, 07:46 AM
I used your form and it worked, so it must be something in my form. Thanks again.

netroact
06-21-2005, 08:01 AM
I found it! I left out the ENCTYPE='multipart/form-data' on the form. I didn't know I had any forms left without that part.

bazz
06-21-2005, 12:15 PM
On the basis that netroact seems to have got sorted out, I have a question on this subject.

Where I have a dir containing about 10 sub-dirs and each of these has, say, 5 images (jpg), is it possible for the above script to be modified, so that it can upload all the photos to their correct dirs, in one go? I'm not asking for it to be done for me, just can such a thing be done and any tips on how would be most welcome.

Bazz

mlseim
06-21-2005, 12:55 PM
Bazz ...

Sure.

You would know which variables go to which directory ...

In the form, the file variables are called:
file1
file2
file3
etc.

Watch the $count variable and change the $upload_dir variable where you need to alter the path using some "if" statements. The $count variable changes the last character of "file" ... file1, file2, file3, etc.

bazz
06-21-2005, 01:03 PM
That's great mlseim,

Thanks. :thumbsup:

That's the next job in the list. :)

Bazz

netroact
06-21-2005, 04:10 PM
How would I pass the variable values to the rest of my script?

bazz
06-21-2005, 04:16 PM
Do I understand what you mean?

Remember if you define a variable at the top of the script, then that variable will be 'replaced' throughout the running script as it is parsed for html output.

If you mean how you send variable values from one cgi script to another, then you can use 'hidden data'

I suspect though that I misunderstand you so I shall ask you to, please, clarify before I add more.

Bazz

netroact
06-21-2005, 06:16 PM
I'm probably the one that doesn't understand. In the example I was given above, I am not through with the files once they are uploaded. I need to reuse them for some PerlMagick stuff at the bottom. The upload directory is full of files, so I can't just read the directory.

As I understand it I can't define the variables at the top of the script, because they are defined and parsed in the middle of the script.

I always have a problem with this upload thang. Any help would be appreciated. Otherwise, it will take me a week to figure it out

bazz
06-21-2005, 06:36 PM
Any help would be appreciated. Otherwise, it will take me a week to figure it out

Don't despair...I'm still working at a project 6 months after a proficient person around here could have finished it. Were it not for their help, I'd have cracked up ages ago ( instead of now :D ).

I would suggest you have a rethink of the line...

The upload directory is full of files, so I can't just read the directory. ...
just in case there is a workaround.
for example, if the image files you want can be distinguished from the others, by name or file extension, then you can use 'readdir' to output the files you choose, simply by making sure it only reads a certain extension. There are other ways to segregate files for reading chosen ones.

If it seems that variables can't be defined at the top of the script, then maybe they still can ;) Just think of there being another way to achieve the same result.

Now, I don't know how much control you have over your script but, couldn't you consider putting this at the top:

use CGI;
my $query = new CGI;
my $variableName = $query->param('subject');

This would mean that if you pass hidden data into this script, like this

<input type="hidden" name="subject" value="yourChosenValue">

that the query line reads the name (subject), and appends the value (yourChosenValue), to the variable $variableName

Then anywhere in your code, you can use that variable, $variableName.

I am not sure what you mean by " I need to reuse them for some PerlMagick stuff at the bottom." Do you mean, further down the script?


Post back again, to see what help we might be able to give.

Bazz

netroact
06-21-2005, 08:05 PM
Well mlseim showed me how to upload multiple files. I need to be able to use those files further down in the script. I have done it before with one file, but never with multiple files. I don't know exactly how to snatch the files out of the for loop he used. Thanks for the reply.

mlseim
06-22-2005, 02:35 AM
Netroact ...

That's a tough one ...

My solution would be to upload them as normal, but also copy it into a temporary directory that later, you will access with ImageMagick. You can then delete the files when finished.

See my example using a module (File::Copy) for copying files.

#!/usr/bin/perl
use CGI qw(:standard);
use File::Copy;
use strict;

my $cgi = new CGI;
my $upload_dir = '../uploads'; #directory where files will be uploaded.
my $temp_dir = '..'; #another directory where files are copied.
my $max_files = 3; #maximum number of files allowed.

print $cgi->header(-type=>'text/html');

for (my $count=1; $count<=$max_files; $count++){
my $filen = "file".$count;
my $file = $cgi->param($filen);
my $filename = $file;
$filename =~ s/^.*(\\|\/)//g;

if($file){
open(OUT, ">$upload_dir/$filename") || die print "Fail to upload: $!";
while(<$file>) {
print OUT;
}
close(OUT);
copy("$upload_dir/$filename","$temp_dir/$filename");

}
}

print "File(s) Uploaded\n";

netroact
06-22-2005, 02:48 AM
Would there be a way to read them into an array at the same time they are printed to the directory? That's really what I need.

I could use the other directory option by creating a directory based on the name given the final image from the form, but I really don't want to do it that way.

You have been very helpful. You have given me something to work with anyway, and I appreciate it.

mlseim
06-22-2005, 02:58 AM
Netroact ...

I hope Jeff Mott is monitoring this thread.

Perhaps he knows how to deal with filehandles.

I just don't think it can be put into an array.

The CGI, or gateway transfer, works something like this...
When the form is transmitted (or submitted), the data packet goes across with the filename, and how many bits to transfer. It really isn't the whole file per-say. The Perl script opens a temporary spot designated by a file handle (in the script example it's "OUT"). After the appropriate amount of bits are delivered, that gets put into a directory and assigned the filename.

Private Message Jeff and see if he can think of something to help you out with this. I'm like you, a little "newbie" about file handling.

--max--

mlseim
06-22-2005, 03:05 AM
Please excuse my laziness, but I know someone on here will find this question very simple to answer.


:D ... funny to look back on how this thread started. simple?

netroact
06-22-2005, 03:19 AM
This uploading stuff has always been difficult for me to understand.

I have uploaded single images, and used them in other PerlMagick scripts, but this is an animator. I already have it set up to where I can use files generated online in that same directory. I might just change my stategy, and make a file manager interface to which I can upload files. And, just choose the files from there.

I don't know how to use the private messaging. Hopefully Jeff or another expert will wander in, and help me out.

netroact
06-22-2005, 03:23 AM
<--------- Hey look! Now I'm a regular.

mlseim
06-22-2005, 03:37 AM
Go to a post that Jeff made and click on the "PM User" link just
above the message ... it appears on every post, on the line with the date and time.

rwedge
06-22-2005, 06:01 AM
For what's it's worth , here's another upload script for 10 files:#!/usr/bin/perl -w
use CGI;
use CGI::Carp(fatalsToBrowser);
$CGI::POST_MAX=1024 * 300; # max 300K posts
$CGI::DISABLE_UPLOADS = 0; # 1 = no uploads
use strict;
my ($q, $action, $path, $url, $i, $upload_file, @full, $filename, $buff);

$q = new CGI;
$action = $q->param('action') || '';
$path = '/home/user/public_html/temp';
$url = 'http://www.yourdomain.com/temp';

print "Content-type: text/html\n\n";
print qq~
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Upload Files</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<style type="text/css">
/*<![CDATA[*/
body { background: #fff;
color: #222;}
a { text-decoration: none; }
a:link { color: #f00; }
a:visited { color: #00c; }
a:active { color: #0c0; }
/*]]>*/
</style>
</head>
<body>
~;
if ($action eq 'upload') {
&upload;
}
print qq~
<h1>Upload Files</h1>
<form name="myform" method="post" action="aehupload.pl" enctype="multipart/form-data">
<input type="hidden" name="action" value="upload" />
~;
for ($i=0;$i<10;$i++) {
print '<input type="file" name="file'.$i.'" value="" size="90" maxlength="300" /> <input type="checkbox" value="on" name="mode'.$i.'" /> binary<br />';
}
print qq~
<input type="submit" name=".but" value="Submit" /> <input type="reset" name="clear" value="Reset" />
</form><br />

</body>
</html>

~;

sub upload {
for($i=0;$i<10;$i++) {
$upload_file = $q->param('file'.$i);
if ($upload_file) {
@full = split(/(\\)|(\/)/,$upload_file);
$filename = pop(@full);
$filename =~ s/\n//;
$filename =~ s/\r//;
if ( -e "$path/$filename" ) { $filename = $filename.'copy'; }
open(UPFILE,">$path/$filename") or die "Could not open file: $!";
if($q->param('mode'.$i) eq 'on') {
binmode UPFILE;
}
while (read($upload_file,$buff,2096)) {
print UPFILE $buff;
}
close UPFILE;
print "<a href=\"$url/$filename\" target=\"_blank\">$filename</a> has been SAVED.<br />";
}
}
}

The $filename can be pushed into an array instead of printing it out as a link as I have above. No error handling is done. I have used ImageMagick in a couple of scripts. I return the local copy of the file to the user for further processing.

netroact
06-22-2005, 06:21 AM
That's awesome! I can adapt that several different ways. Thanks!

I have a question - binmode is only required on windows servers, right?

FishMonger
06-22-2005, 06:24 AM
Would there be a way to read them into an arrayIf you haven't already done so, you should read the cpan doc for the cgi module. Here's a portion of it.
However, there are problems with the dual nature of the upload fields. If you use strict, then Perl will complain when you try to use a string as a filehandle. You can get around this by placing the file reading code in a block containing the no strict pragma. More seriously, it is possible for the remote user to type garbage into the upload field, in which case what you get from param() is not a filehandle at all, but a string.

To be safe, use the upload() function (new in version 2.47). When called with the name of an upload field, upload() returns a filehandle, or undef if the parameter is not a valid filehandle.

$fh = upload('uploaded_file');
while (<$fh>) {
print;
}

In an list context, upload() will return an array of filehandles. This makes it possible to create forms that use the same name for multiple upload fields.

This is the recommended idiom.
http://search.cpan.org/~lds/CGI.pm-3.10/CGI.pm#CREATING_A_FILE_UPLOAD_FIELD

mlseim
06-22-2005, 12:56 PM
rwedge ...

So the WHOLE graphic image itself is stored into an array and
not just the filename? How do you reference the actual image,
so later on, you could open it again, save it, use it with ImageMagick,
etc. ? .... like, the buffer part (I'm guessing that's the actual binary
bits -- the image itself?)

sorry, so many questions ... like netroact, I'm learning here too.

Netroact ...
I think you mean that you don't just want the "filename" saved in an array, but the actual "binary bits" that make up the image? I mean the actual image itself in the array.

.

netroact
06-22-2005, 06:23 PM
yea, somewhere in this thread I indicated I want to be able to reuse the files after upload for PerlMagick. I actually store the filenames in an array, and read the list of files with PerlMagick. I'm at my real job now, but later I will post the snippet from the first part of the script, where I read the array into an animated .gif file from the directory online.

I have just begun to explore ImageMagick. I really like what you can do with the various functions. I've been having fun with gradients lately.

netroact
06-22-2005, 11:40 PM
This is the first part of the animator script I am working on. I use it to make animated banners from banners I made previously with a bannermaker script. Now I can adapt the script from rwedge for the 2nd part. I will have to study Fish Monger's post. By the way, what is a fish monger?




#!/usr/bin/perl
use Image::Magick;
use CGI qw(:standard);

use CGI::Carp qw(fatalsToBrowser);

#################################################################################################

my $query = new CGI; # create new CGI object

my $delay = $query->param("delay");
my $banner1 = $query->param("banner1");
my $banner2 = $query->param("banner2");
my $banner3 = $query->param("banner3");
my $banner4 = $query->param("banner4");
my $banner5 = $query->param("banner5");
my $banner6 = $query->param("banner6");
my $banner7 = $query->param("banner7");
my $banner8 = $query->param("banner8");
my $banner9 = $query->param("banner9");
my $banner10 = $query->param("banner10");
my $new_banner = $query->param("new_banner");


if ($banner1)
{

my $directory = "/home/user/public_html/banners";

my @bannermator = ("/$directory/$banner1.gif","/$directory/$banner2.gif");


if ($banner3) { push (@bannermator, "/$directory/$banner3.gif"); }
if ($banner4) { push (@bannermator, "/$directory/$banner4.gif"); }
if ($banner5) { push (@bannermator, "/$directory/$banner5.gif"); }
if ($banner6) { push (@bannermator, "/$directory/$banner6.gif"); }
if ($banner7) { push (@bannermator, "/$directory/$banner7.gif"); }
if ($banner8) { push (@bannermator, "/$directory/$banner8.gif"); }
if ($banner9) { push (@bannermator, "/$directory/$banner9.gif"); }
if ($banner10) { push (@bannermator, "/$directory/$banner10.gif"); }

my($image, $x);
$image = Image::Magick->new;
$x = $image->Read(@bannermator);
warn "$x" if "$x";
$x = $image->Set(delay=>"$delay");
warn "$x" if "$x";
$x = $image->Set(loop=>infinite);
warn "$x" if "$x";
$x = $image->Write('x.gif');
warn "$x" if "$x";



rename("x.gif", "/home/user/public_html/banners/$new_banner.gif") || die "The file could not be renamed! $!";


print "Content-type: image/gif\r\n\r\n";
print "<html><head></head>\n";
print "<body>\n";
print "<table width='770'><tr>\n";
print "<td align='center' valign='middle'>\n";
print "<br><br><img src='http://somesite.com/banners/$new_banner.gif'><br><br>\n";
print "</td></tr></table></body></html>";


#################################################################################################

}



In case anyone is curious what this is for.

rwedge
06-23-2005, 12:45 AM
So the WHOLE graphic image itself is stored into an array andJust the filename(s).

I use a single directory to hold the uploaded files and attach random numbers and a fixed prefix to their names. The random number / file name is changed each time a user edits the image to avoid cached image problems. The back button is used to undo.

I return the results to the user by displaying the image with HTML giving them a chance to save or continue editing and have a cron job set to delete images over 3 hours old.

I was thinking with 10 image files an animation was planned.

FishMonger
06-23-2005, 01:38 AM
what is a fish monger?
http://dictionary.reference.com/search?q=fishmonger

fishmonger
n : someone who sells fish

I starting using "fishmonger" years ago when I worked for my brother in the wholesale/retail seafood business. I'm no longer in that business but he is.
www.rosysatthebeach.com

netroact
06-23-2005, 02:15 AM
I used to live in the Pismo Beach area. Nothing like eating fresh seafood.

netroact
06-23-2005, 02:32 AM
mlseim,
I figured out how to read the filenames into an array after I uploaded them, and it works with the PerlMagick animator code. I guess I didn't explain it well yesterday. I needed to read the directory and filenames into an array after it was uploaded. From there ImageMagick manipulated the files (.gif's) to make an animated file (.gif) . I figured it out looking at rwedge's script. Here is your script again with the array part in red:


#!/usr/bin/perl
use CGI qw(:standard);
use strict;

my $cgi = new CGI;
my $upload_dir = '../uploads'; #directory where files will be uploaded.
my $max_files = 3; #maximum number of files allowed.

print $cgi->header(-type=>'text/html');

for (my $count=1; $count<=$max_files; $count++){
my $filen = "file".$count;
my $file = $cgi->param($filen);
my $filename = $file;
$filename =~ s/^.*(\\|\/)//g;

if($file){
open(OUT, ">$upload_dir/$filename") || die print "Fail to upload: $!";
while(<$file>) {
print OUT;
}
close(OUT);
push (@bannermator, "$upload_dir/$filename");
}
}

print "File(s) Uploaded\n";



This uploader stuff is still difficult for me to follow though. Thanks for all the help.

bravetanveer
10-23-2005, 02:17 PM
Hello friends,

I have read all the posts on this topic.
As i am a novice to cgi programming, so my question is also very basic.

In the first post on this topic, it is like

1.
$upload_directory , variable is present , in which we can specify directory where we want to upload the pic or photo.

2.
In my case: my DocumentRoot is /var/www/html

3.
I want to use windows client and my server is apache on linux system.

4.
When i run the same cgi script as given in Ist post on this topic on backend i.e. on server then it works and a file is also created in upload directory.

5. but when i do the same thing using windows client, then i see that it is not able to create a new file in /var/www/html.

i have upload_directory as /var/www/html

6. When i did

open ( HANDLE, ">>$upload_dir/$filename") or die ("unable to create file");

then it didn't work out. It was not able to create a file in upload directory.
When i saw in log error messages, it gave that "unable to create file".

I know that there is a problem with httpd.conf file..... but i am not able to figure out what is the problem.

cgi-bin is also set with AliasesScript , so i think there is no problem with script execution because, if i open the file supplied as input and read, then it is properly read.

Just i am not able to create a new file on web server and give a meaning to upload


**** Sorry friends to ask such a simple question.

But still, badly needing help, as i am not left with any other option.


Thanks in advance.

cgibie
12-28-2005, 04:33 PM
mlsleim,

I tried that code out but whenever I tried to upload the images, it gave me the error: One or more files failed to upload. The reasons returned are:
No files were selected for uploading

What would be my problem? Does it accept any specific types/extension of files? I uploaded jpg and gif.

mlseim
12-28-2005, 04:42 PM
cgibie ...

Give us a link to your form ... I'm wondering if your form variables
don't match the ones in the script. Also, several scripts appeared
on this thread ... which one did you end up using?

cgibie
12-28-2005, 04:47 PM
cgibie ...

Give us a link to your form ... I'm wondering if your form variables
don't match the ones in the script. Also, several scripts appeared
on this thread ... which one did you end up using?

#!/usr/bin/perl

use CGI qw(:standard);
use CGI::Carp qw(warningsToBrowser fatalsToBrowser);
#use CGI Fcntl qw(:seek :flock);

require "path.cgi";

# declare file folder/directory to store the photo after uploading
$dir = $photopath;

my $cgi = new CGI;
my $max_files = 3; #maximum number of files allowed.

print $cgi->header(-type=>'text/html');

for (my $count=1; $count<=$max_files; $count++){
my $filen = "file".$count;
my $file = $cgi->param($filen);
my $filename = $file;
#$filename =~ s/.*[\/\\](.*)/$1/;
$filename =~ s/^.*(\\|\/)//g;

if($file){
open(OUT, ">$dir/$filename") || die print "Fail to upload: $!";
while(<$file>) {
print OUT;
}

close(OUT);
}
}

print "File(s) Uploaded\n";

cgibie
12-28-2005, 05:02 PM
Oh wait... mah bad.... I forgot about form action :) I linked to another script, hehe... sorry and thanks for the code, guys... I sure will come back later

cgibie
12-28-2005, 05:31 PM
See? I am back :) Okay here it is, I put this code after the perl code in that upload.cgi, syntax did compile.

<P>The photo you uploaded:</P>
<img src="$photourl/$filename" border="0">

But the image doesn't show up on the webpage/after i submitted the form, it does exist in the photo folder.

mlseim
12-28-2005, 07:38 PM
You need to set the proper permissions for the folder so
that the script can write to it.

Try: 766 or as a last resort (777).