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

hello all, Once again I am here to ask for wisdom to be bestowed on me. I am obviously new to perl (switching from vb), and I am having some novice troubles that the book won't fix. I need some experienced eyes to glance over my script. I am attempting to write info from a form to a txt file on my NT server. When I comment out the "write file section", my script works, but when the "write file section" is not commented out, I get an error saying, "/path/cgi-bin/script.pl produced no output." Any help would be greatly appreciated.
use CGI qw/:standard/; my $name = param(Name); my $address1 = param(Address1); ################################################################ # write info to a file open(FILE, ">>/data.txt") || die "The database could not be opened"; flock(FILE, 2); print FILE "$name\n"; flock(FILE, 8); close(FILE); ################################################################ $expires = "Tuesday, 1-Dec-2099 16:00:00 GMT"; $path = ""; $server_domain = "http://www.mydomain.com"; print "Set-Cookie: "; print "Name", "=", $name, "; expires=", $expires, "; path=", $path, "; domain=", $server_domain, "\n"; print "Address", "=", $address1, "; expires=", $expires, "; path=", $path, "; domain=", $server_domain, "\n"; print header; print "<body>"; print "The following data has been sent:"; print "<font color=blue>Name:</font> $name <br>"; print "<font color=blue>Address:</font> $address1 <br>";

update (broquaint): title change (was Writing to files)

Replies are listed 'Best First'.
Re: Writing to files
by Aristotle (Chancellor) on Dec 17, 2002 at 19:20 UTC

    Two comments: use Fcntl qw(:flock); and write flock FILE, LOCK_EX; instead of using the cryptic magic values. Also, don't unlock a locked file, ever, unless you know what you're doing - just close it and the lock will go away.

    Did you check your error logs? Is the scripting dieing at the open? Btw, you should prefer the three argument form: open(FILE, ">>", "/data.txt").

    If not, does your platform support flock at all? There should be something about that in your error log as well if that's the case.

    Update: Also, why not use CGI.pm's perfectly fine cookie-generation functions?

    print header(-cookie => cookie( -name => $name, -expires => $expires, -path => $path, -domain => $server_domain, -value => "there is none in your example", ));

    Makeshifts last the longest.

      Also, don't unlock a locked file, ever, unless you know what you're doing - just close it and the lock will go away.

      I'm inexperienced with flock and am now wondering what's going on here. Do you have an URL handy that explains why you don't unlock a file prior to closing. Or... *brainflash* buffering? Unlocking a handle doesn't flush the buffer so it introduces a race condition unless the handle is either hot (and autoflushed) or has been pre-flushed?

        Ding ding ding!! Bingo. :-) See also Don't use unflock (flock 8). Ever. by merlyn.

        It isn't a 100% valid concern anymore since 5.8 (or probably 5.7) and newer Perls make sure to flush and sync when unlocking, but you may still run on an older Perl (I write code for 5.6.1 and many people haven't gotten past 5.5 yet).

        Makeshifts last the longest.

Re: WRITING TO FILES
by jdporter (Paladin) on Dec 17, 2002 at 19:17 UTC
    Well, since this is a CGI, it is critical that the script print the HTTP headers before any other possible output.
    So you should move the print header; line to somewhere near the top. And also do $|++; at the top too, so that buffering of stdout is disabled.

    Now, as for your specific bug, you'll probably find that it is indeed the open() which is failing, and thus calling die(). Why is the open() failing? Most likely because the script does not have permission to open the /data.txt file, when run by the server. You will probably need to make adjustments with server/script permissions. Also, you'd do well to add the $! variable to the die() message, since that will contain info on the specific cause of failure.

    jdporter
    ...porque es dificil estar guapo y blanco.

      And also do $|++; at the top too, so that buffering of stdout is disabled.

      Why?

        Because die() writes its output to STDERR, which is unbuffered. If the script die's with STDOUT buffered (actually, autoflushed) as per normal, then even if you've printed the header, the die message might precede it in the pipe to the server, and that will hose the http message. You must have the http header first, and the way to ensure that is to unbuffer STDOUT. I suppose you could also just write the header to STDERR, but would be, um, less conventional.

        jdporter
        ...porque es dificil estar guapo y blanco.

Re: Writing to files
by Mr. Muskrat (Canon) on Dec 17, 2002 at 19:20 UTC

    open(FILE, ">>/data.txt") || die "The database could not be opened";

    Off the top of my head, I'd say that the file data.txt does not exist in the root directory of the currently active hard drive. Try using the entire file path (i.e. "c:/my/data/goes/here/data.txt").