Short answer: yes. I've found that the best thing to do is never to try to call the header line inside subs, leaving that header call in the main parts of the routine, just to avoid this situation.
-----------------------------------------------------
Dr. Michael K. Neylon - mneylon-pm@masemware.com
||
"You've left the lens cap of your mind on again, Pinky" - The Brain
"I can see my house from here!"
It's not what you know, but knowing how to find it if you don't know that's important
| [reply] |
If you print headers in several places (eg, depending on action to take), you might want to set up a couple of subs to keep your vars nice and local, eg:
#!/usr/bin/perl -w
use strict;
use CGI;
my $q = CGI->new();
# create cookie
my $cookie1 = $q->cookie(-name=>'sessionID',
-value=>'xyzzy',
-expires=>'+1h',
-path=>'/');
# set cookie
set_cookie($cookie1);
# create another cookie
my $cookie2 = $q->cookie(-name=>'another_one',
-value=>'abbaaba',
-expires=>'+1h',
-path=>'/');
# set other cookie
set_cookie($cookie2);
# or, set both cookies at the same time
set_cookie($cookie1,$cookie2);
print cookie_header(),
$q->start_html,
$q->p('hello'),
$q->end_html;
exit(0);
# this is the localized 'cookie jar' :)
{
my @cookies = ();
sub set_cookie {
push @cookies, @_;
}
sub cookie_header {
$q->header(-cookie=>[@cookies]);
}
}
And if there's no cookies to be set, no problem as far as the script is concerned - so just replace $q->header with cookie_header() throughout and you can stop worrying.
.02
cLive ;-)
--
seek(JOB,$$LA,0);
| [reply] [d/l] [select] |
No one's mentioned this yet, so I will. In CGI.pm there's a special $HEADERS_ONCE flag that, when set, will suppress duplicate prints of the HTTP header information. In short, it does exactly what you want. Just put:
#!/usr/bin/perl
use CGI qw(:standard);
$CGI::HEADERS_ONCE =1;
at the top of your program and you can call header() as many times as you like and only the first print will make it to the browser. Easy cheesy. (No, this is not in the CGI.pm documentation. :-D)
Gary Blackburn
Trained Killer | [reply] [d/l] |
Depending of your version of CGI, the header function will look a little different, but here is the basic jist of it
#### Method: header
# Return a Content-Type: style header
#
####
'header' => <<'END_OF_FUNC',
sub header {
my($self,@p) = self_or_default(@_);
my(@header);
return undef if $self->{'.header_printed'}++ and $HEADERS_ONCE;
my($type,$status,$cookie,$target,$expires,$nph,$charset,$attachmen
+t,@other) =
rearrange([['TYPE','CONTENT_TYPE','CONTENT-TYPE'],
'STATUS',['COOKIE','COOKIES'],'TARGET',
'EXPIRES','NPH','CHARSET',
'ATTACHMENT'],@p);
$nph ||= $NPH;
if (defined $charset) {
$self->charset($charset);
} else {
$charset = $self->charset;
}
# rearrange() was designed for the HTML portion, so we
# need to fix it up a little.
foreach (@other) {
next unless my($header,$value) = /([^\s=]+)=\"?(.+?)\"?$/;
($_ = $header) =~ s/^(\w)(.*)/$1 . lc ($2) . ': '.$self->unescapeH
+TML($value)/e;
}
$type ||= 'text/html' unless defined($type);
$type .= "; charset=$charset" if $type ne '' and $type =~ m!^text/
+! and $type !~ /\bcharset\b/;
# Maybe future compatibility. Maybe not.
my $protocol = $ENV{SERVER_PROTOCOL} || 'HTTP/1.0';
push(@header,$protocol . ' ' . ($status || '200 OK')) if $nph;
push(@header,"Server: " . &server_software()) if $nph;
push(@header,"Status: $status") if $status;
push(@header,"Window-Target: $target") if $target;
# push all the cookies -- there may be several
if ($cookie) {
my(@cookie) = ref($cookie) && ref($cookie) eq 'ARRAY' ? @{$cookie}
+ : $cookie;
foreach (@cookie) {
my $cs = UNIVERSAL::isa($_,'CGI::Cookie') ? $_->as_string
+: $_;
push(@header,"Set-Cookie: $cs") if $cs ne '';
}
}
# if the user indicates an expiration time, then we need
# both an Expires and a Date header (so that the browser is
# uses OUR clock)
push(@header,"Expires: " . expires($expires,'http'))
if $expires;
push(@header,"Date: " . expires(0,'http')) if $expires || $cookie
+|| $nph;
push(@header,"Pragma: no-cache") if $self->cache();
push(@header,"Content-Disposition: attachment; filename=\"$attachm
+ent\"") if $attachment;
push(@header,@other);
push(@header,"Content-Type: $type") if $type ne '';
my $header = join($CRLF,@header)."${CRLF}${CRLF}";
if ($MOD_PERL and not $nph) {
my $r = Apache->request;
$r->send_cgi_header($header);
return '';
}
return $header;
}
END_OF_FUNC
The header function behaves as it should. The reason you get the so called eyesore, is because the header has already been printed, and you're attempting to print it again, so at this point, it might be formatted like a header, but it's treated as content. The key value pairs that make up the http header are usually referred to as "http headers" but they're just fields of the http header. The http header is terminated by a "\n\n", which is what most people leave out when first printing a header on their own, and that is the purpose of the header function, to make sure a valid header is printed (one terminated with \n\n)....
I suggest you learn more about HTTP and CGI, as well as read CGI.pm (in this case at least the header funtion), and you'll see why the answer to your question is yes. | [reply] [d/l] |
I asked this exact same question. With all due respect to masem, the short answer is no you dont. | [reply] |
Err -- hold your horses, there. It isn't the exact same question. CGI::Application is a whole nother ball game than just plane ole CGI.pm. The problem you had, and both of the solutions which were given to you, are CGI::Application specific. Both solutions use the header_props method on CGI::Application, which does not exist in CGI.pm. Do not be so quick to assume that your question is identical to others'.
As a side note, it's generally curtious to use the [id://130409|some node] format when giving links to other places in the Monastery, so as to not inadvertantly log out other monks.
perl -pe '"I lo*`+$^X$\"$]!$/"=~m%(.*)%s;$_=$1;y^`+*^e v^#$&V"+@( NO CARRIER'
| [reply] [d/l] |
Ahhhhh whoops, that'll teach me to skim.
mea culpa
| [reply] |