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

Hi Monks

I am new to Perl programming, so I apologise in advance if this is a dumb question, which it most probably is. I have checked the tutorials and Q and A sections, but I can't find the answer to my question.

What I want to do is modify a Perl CGI script so that the output (a load of html) is written to a file called output.htm rather than to the web browser. The reason for this is that the perl script takes a long time to run (it is doing many queries to a database), and so I want to make it a scheduled cron job.

I have used the following code:

#!/usr/bin/perl -w use CGI qw/:standard *table *Tr *td/; require "/home/httpd/cgi-bin/per +l_scripts/syb_handlers.pl"; use Sybase::DBlib; use CGI::Carp qw(fatalsToBrowser); &dbmsghandle ("message_handler"); &dberrhandle ("error_handler"); open(OUTPUTFILE, ">/home/output.htm") or die $!; # print OUTPUTFILE header; # print OUTPUTFILE start_html( -title=>'Title', ); print OUTPUTFILE (loads of lines of html resulting from the database +queries) # print end_html;
I find that unless I comment out the lines that I have commented out (relating to the header, start_html and end_html), the output won't go to the file. If I do comment the lines out, then obviously the html isn't well formed because the header is missing.

Is there an obvious way around this, or do I need to explicitly write the header to the file using a print statement such as the following?

print OUTPUTFILE "<html><head><title> TITLE </title></head>"; print OUTPUTFILE "<body>"; print OUTPUTFILE # all my html here"; print OUTPUTFILE "</body></html>";

Replies are listed 'Best First'.
Re: html output to a file
by Corion (Patriarch) on Apr 27, 2007 at 16:07 UTC

    The completely easy way is to reopen STDOUT to your file:

    my $outfile = "/home/output.htm"; open STDOUT, ">", $outfile or die "Couldn't write to '$outfile': $!"; ... rest of the program

    Of course, if your CGI expects some of the CGI specific variables you might need to fake them. If your CGI outputs a status code, you might want to comment that out from your CGI or just munge the created file afterwards.

    This trick works because

    print "Hello World"

    is secretly

    print STDOUT "Hello World";
Re: html output to a file
by kyle (Abbot) on Apr 27, 2007 at 16:15 UTC

    ... the output won't go to the file.

    Does anything go to the file? I'm guessing you need to take out the header line (since that prints the Content-Type needed by the HTTP protocol) and include the start_html line (since that includes the <title> tag (and other things) needed by the HTML standard. Commenting them both out is going to give you some malformed HTML.

      Kyle's point re header is worth noting, as the OP seems to reflect the view that the content sent by header, needs to be part of a valid .html file.

      It does NOT. Ultimately, in a cgi/server/browser context, it tells the browser how to render the rest of what's sent; it is NOT part of a basic .html file which begins with the content sent by start_html. Since OP is merely outputting to a file, it's not necessary.

      (The notes from Corion and others may make this unimportant at the moment, but at some time, a misunderstanding could jump up and bite.)

Re: html output to a file
by TomDLux (Vicar) on Apr 27, 2007 at 17:28 UTC

    The first question to consider is whether the problem really needs to be slow. Is there some bottleneck in your processing which can be eliminated, or some repetition of operations which can be simplified? profile the code to determine where the bulk of processing is used up. Can an alternate algorithm provide better performance?

    If it really is more than just a few seconds, and the results don't need to be spectacularly up-to-date, run it automatically from cron, and store the results in a file or in a database. But do you really want to store a HTML page? Or might it be better to have the program store simple data, maybe stored as key: value pairs, or as a fast-loading YAML file. That way, usage is not limited to the web but is available to any program.

    --
    TTTATCGGTCGTTATATAGATGTTTGCA

      Hmm. You know - maybe I'm out in left field here, but why not use a heredoc print instead of doing print after print? If you're just doing dozens of prints one after the other - this is more convenient.
      #quick sample of what I have a heredoc doing: print FILEHANDLE << "END_DATA"; <TABLE> <TR> <TH COLSPAN="2"> <A HREF="stuff"><IMG SRC="an_image.gif" BORDER="0" ALT="Hi!">< +/A> </TH> </TR> <TR> <TH COLSPAN="2"> $variables{whatever} </FONT> </TH> </TR> <TR> <TD VALIGN="top"> </TD> <TH ROWSPAN="2"> $details<br> $moreDetails<br> </FONT> </TH> </TR> <TR> <TD> $variables{evenMoreDetails} </FONT> </TD> </TR> <TR> <TH COLSPAN="2"> <FORM ACTION="../cgi-bin/some.cgi?somequery" METHOD="POST"> <INPUT TYPE="HIDDEN" NAME="item" VALUE="$variables{aVariab +le}"> Some Text: <INPUT TYPE="TEXT" VALUE=1 NAME="someText" SIZE +="1"> <INPUT TYPE="submit" VALUE="Submit"> </A> </FORM> </FONT> </TH> </TR> </TABLE> END_DATA
      It's convenient for me - and millions of executions later, just as good the regular prints - but 10 times lazier.
Re: html output to a file
by ikkon (Monk) on Apr 27, 2007 at 16:12 UTC
    first as was told to me and I will pass it on, its always a good thing to get in the habit of useing strict.
    #!/usr/bin/perl -w use strict; use CGI qw/:standard *table *Tr *td/; require "/home/httpd/cgi-bin/per +l_scripts/syb_handlers.pl"; use Sybase::DBlib; use CGI::Carp qw(fatalsToBrowser); &dbmsghandle ("message_handler"); &dberrhandle ("error_handler"); open(OUTPUTFILE, ">/home/output.htm") or die $!; # print OUTPUTFILE header; print OUTPUTFILE "<html><head>\n"; print OUTPUTFILE "<title>My Title</title></head><body>\n"; print OUTPUTFILE (loads of lines of html resulting from the database +queries) print OUTPUTFILE "</body></html>\n"; close(OUTPUTFILE);

    hopeing that I understood the question right, I myself would do it simular to this, or create variables with header and footer code in it, thus the same effect.

    in the code you posted you did not close the document in which you opened this can lead to bad things (dark side of the force).

    hope this helps, any more questions I will do what I can to help.

    Ben
Re: html output to a file
by derby (Abbot) on Apr 27, 2007 at 16:53 UTC
Re: html output to a file
by glasswalk3r (Friar) on Apr 27, 2007 at 17:03 UTC
    What I want to do is modify a Perl CGI script so that the output (a load of html) is written to a file called output.htm rather than to the web browser. The reason for this is that the perl script takes a long time to run (it is doing many queries to a database), and so I want to make it a scheduled cron job.

    I beg your pardon, but looking at the code you made available and the description above, seems to be that you don't need anyway to use a CGI. If you're going to query your database and execute the script in a regular basis using CRON, don't use CGI.

    BUT considering that your CGI is receiving some parameters and using them in the query, then what you need is to detach the query from the CGI itself. My suggestion is, if you want to use cron anyway, just use write the information from the webuser somewhere in a way that the script, that you be executed later, read this information and generate the new HTML content.

    Alceu Rodrigues de Freitas Junior
    ---------------------------------
    "You have enemies? Good. That means you've stood up for something, sometime in your life." - Sir Winston Churchill