goosenoose has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks,

I've been assigned as the webmaster for my AFROTC detachment at New Mexico State U. I've been able to hold my own managing the existing HTML of the site however I have nil experience with scripting/coding and our perl script that handles our e-mail broadcast system recently has gone down.

I've been in communication with our the IT guys with the university and they've advised they've fixed issues with some modules that weren't installed and were blocking our script's functionality. I'm still getting errors when running the e-mail script though, unfortunately. (see here: http://web.nmsu.edu/~afrotc/cgi-bin/cadet_email.pl)

this is the error that I receive in case the vpn doesn't let you guys access it...
Sorry, cannot open /home/canto8/~afrotc/public_html/tmp2/: No such file or directory Cannot close /home/canto8/~afrotc/public_html/tmp2/: Bad file descriptor
I thought it might be a simple fix with regard to creating/setting permissions of a public_html/tmp2 directory. No dice. I've attached the perl script for our e-mail system here.. My request is more of a troubleshooting more than anything else, but if someone happens to append any improvements on what we have, we'd be most grateful.

Sincerely,

C/ Robin Deguzman
#!/usr/bin/perl -wT ################### #Create new object of type CGI #################### use CGI; use MIME::Lite; $query = new CGI; ##################### #grab text # ##################### print "Content-type: text/html\n\n"; $cc = $query->param("Ccemail"); $from = $query->param("From"); $subject = $query->param("Subject"); $comment = $query->param("Comment"); $file = $query->param("Attach"); @list = $query->param("list"); @name = split(/\\/, $file); #finds all /'s # $name = $name[$#name]; #finds last / and assumes name is afterward $name = $name[$#name]; #finds last / and assumes name is afterward # my $FILE = "/home/wsc13/pub_html/Academic_Progs/CAS/afrotc/public_ht +ml/tmp/"; my $FILE = "/home/canto8/~afrotc/public_html/tmp2/"; my $type = "application/octet-stream";chmod $list=join(",", @list); ################### #Mail form # ################### @extension = split(/\./, $name); $extension = $extension[$#extension]; # These file types should be okay:doc, docx, gif, jpg, pdf, ppt, txt, +xls # allowed file types to upload @goodfiles = ("doc","docx","gif","jpg","pdf","ppt","txt","xls","rtf"," +odt","zip"); &fileopen; sub fileopen { open(UPLOAD, "+>$FILE/$name") or print "Sorry, cannot open $FILE: + $!<br>"; my ($data, $chunk); while ($chunk = read($file, $data, 1024)) { print UPLOAD $data; } close(UPLOAD) or print "Cannot close $FILE: $!<br>"; #chmod(0777, "$FILE") or print "Cannot chmod $FILE: $!<br>"; # $msg = "You attached file $name"; my $mime_msg = MIME::Lite->new( From => $from, To => $list, Cc => $cc, Subject => $subject, Type => 'text/plain', Data => $comment ); # JMD: Need to have mimetype and encoding type my ($mime_type, $encoding) = ('application/octet-stream','base64') +; # Attach the file $mime_msg->attach( Type => $type, # JMD: Seems to only work this way, without Filename attritbut +e, don't know why. Path => "$FILE$name", Disposition => 'attachment' ) or dienice("Cannot upload attachment: $!"); #MIME::Lite->send('sendmail', "/usr/lib/sendmail -t -oi -oem"); $mime_msg->send(); print "$_<br>"; unlink($FILE); } sub Error { die "No File uploaded or incorrect filetype"; } ############################################# #Printing a message to the user ############################################# print "Content-type: text/html\r\n\r\n"; print "Emailing the following content: \n\n"; print "$comment \n\nAttachment:$name \n"; #print "$msg\n"; print "To: $list\n"; #print "This is the query file:\n $query\n"; ############################################# #Mailing construct ############################################

Replies are listed 'Best First'.
Re: Web broadcast e-mail perl script
by dasgar (Priest) on Aug 20, 2010 at 19:06 UTC

    Is there a web-based form that you're filling out that is calling this script or are you just trying to go to this script directly?

    The $query->param statements are retrieving data that this script is expecting to receive. If you're going to the script directly using the URL that you provided, then you're not passing any data to the script. That means the subroutine is probably trying to act on a directory instead of a file as it is expecting to do. Without the web-based form that calls this script or a better understanding of what you're trying to do with this script, I'm probably not going to be able help much more.

    Also, the open statement seemed a bit odd in its syntax (referring to the "+>$FILE/$name" portion). My first instinct is that it is incorrect, but I'm not 100% sure about that. Perhaps others more experienced than me would be able to clarify if that is correct syntax or not.

      The open syntax is correct, the '+' opens the file for reading AND writing, see 'perldoc -f open'
Re: Web broadcast e-mail perl script
by wfsp (Abbot) on Aug 21, 2010 at 16:14 UTC
    I think dasgar has identified the reason you are getting that output from your script.

    Not what you want perhaps but it does reveal that

    • the web server can find the script
    • it is executable (has the right permissions)
    • the shebang line (the first one) is correct
    • the line endings are correct
    • the code compiles
    • the appropriate modules are available
    • the code runs
    • you get understandable, if unwanted, output
    When you are debugging cgi scripts that is a result. You're halfway there. :-)

    The script has warnings enabled (the -w on the shebang line) and uses CGI.pm. Also a good thing.

    If you're starting out on working with cgi scripts I would suggest putting your script to one side and writing a cut down version and get that working. For instance, if you are able to create a dir under cgi-bin you could create a /cgi-bin/test/test.cgi like the following (i.e. leaving out the email side of things).

    test.cgi

    #!/usr/bin/perl -w use CGI; $query = new CGI; # let CGI.pm print the content header print $query->header; $cc = $query->param("Ccemail"); $from = $query->param("From"); $subject = $query->param("Subject"); $comment = $query->param("Comment"); $file = $query->param("Attach"); @name = split(/\\/, $file); $name = $name[$#name]; @list = $query->param("list"); $list = join(",", @list); # change the file name to include a path that # the web server can write to # e.g. the path you have in your script open(UPLOAD, ">uploaded_file.txt") or die "Sorry, cannot open $FILE: $!"; my ($data, $chunk); while ($chunk = read($file, $data, 1024)){ print UPLOAD $data; } close(UPLOAD) or die "Cannot close $FILE: $!"; # let CGI.pm help output well formed HTML print $query->start_html; print "subject: $subject<br>"; print "from: $from<br>"; print "cc: $cc<br>"; print "comment: $comment<br>"; print "Attachment: $name<br>"; print $query->end_html;
    I've tried to keep the script as close to yours as possible (differences have comments) so that it will be familiar but have taken out the email stuff. Get this bit working first. Set the permissions to executable (0755 ought to do it). A test.txt somewhere you can find it e.g.
    one two three
    And a test.html in, say, the document root
    <html> <head> <title>form test</title> </head> <body> <p>upload file</p> <form name = "test_form" action = "/cgi-bin/test/test.cgi" method = "post" enctype = "multipart/form-data" > from:<br> <input type="text" name="From" ><br> subject:<br><input type="text" name="Subject" ><br> comment:<br><input type="text" name="Comment" ><br> cc:<br> <input type="text" name="Ccemail" ><br> list:<br> <input type="checkbox" name="list" value="Car" > car + <input type="checkbox" name="list" value="Bike"> bik +e<br> attach:<br> <input type="file" name="Attach"><br> <input type="submit" name="Submit" value="Submit"> </form> </body> </html>
    The html has a lot of whitespace blown into it which I find useful while developing.

    Typing http://your_domain/test.html into your browser should bring up the form. Fill in some dummy data and, if the wind is in the right direction, you will see something like

    subject: web broadcast from: a@b.com cc: b@b.com comment: hello Attachment: test.txt
    and there should be a file upload_file.txt in cgi-bin/test or wherever you set the path to in the script.

    There are a number of good tutorials that will help and it is worth have a look at the docs for CGI.pm (at least, the methods that you are using - there is rather a lot of it).

    There are a number of improvements that could be made (secutity, error checking etc) and many other approaches to developing cgi scripts (e.g. setting up your own local web server rather that 'playing' on a production server) but I reckon it's best to build up gradually .

    Hope this helps, let us know how you get on and get back to us if you need any more help.

    By the way, your introduction to perl was identical to my own. :-)

    Good luck!