You should understand how print
(or any other function works):
1) Here's an example:
use strict;
use warnings;
use 5.020;
use autodie;
use Data::Dumper;
use DBI;
sub do_stuff {
print "xxx\n";
}
print "goodbye\n", do_stuff, "\n";
What do you think perl will output first? The string "goodbye\n" or the string "xxx"? In other words, is that print statement equivalent to:
print "goodbye\n";
print dostuff;
print "\n";
???
2) Here's another example:
print "hello", die("Too tired too print anything else...");
What do you think the output will be? die()
causes your program to terminate immediately and output the specified message before quitting.
The rule
is: a function's arguments must be fully determined before the function itself will execute. Therefore, in your perl script when you wrote:
print $q->header,
...that was correct because you have to output the response header first. But then there's that trailing comma. You continued your print statement with:
print $q->header, $q->start_html(), print $q->div()
That statement is equivalent to:
print(
$q->header,
$q->start_html(),
print($q->div)
)
Okay, applying the rule: the outer print()
won't execute until each of the three arguments are determined. Therefore, perl executes $q->header
, which returns a string. And rule #2 is: all function calls in your code are replaced by the function's return value. That gives you:
print(
"some http response info,
$q->start_html()
print($q->div)
)
Next, perl executes $q->html
, which also returns a string, giving you:
print(
"some http response info",
"<html> blah blah",
print($q->div)
)
Finally, the third argument is evaluated, print($q->div)
. The third argument is equivalent to print("<div>...")
, giving you:
print(
"some html response stuff",
"<html> blah blah",
print("<div...")
)
As my first two examples at the beginning of my answer demonstrate, the inner print() will execute before the outer print is able to print the first two arguments. Therefore, you end up NOT outputting the header first, hence your error. print("<div...")
actually returns 1 after outputting the string, so you end up with:
print(
"some html response stuff",
"<html> blah blah",
1
)
And now the outer print can finally execute.
I'm using Apache for my server, and your perl script is located here:
apache2/cgi-bin/perl2.pl
A url to retrieve the output of the script:
http://localhost:8080/cgi-bin/perl2.pl
I put a css file here:
apache2/cgi-bin/htdocs/css/my.css
Normally, I can retrieve html pages in htdocs without specifying the htdocs directory, so:
http://localhost:8080/page.html
As a result, the path from the cgi-bin directory to a file in the htdocs directory is simpy:
../css/my.css (rather than ../htdocs/css/my.css)
Here's your code with all the changes needed to access the css file:
use strict;
use warnings;
use CGI qw(:all);
use CGI::Carp qw(fatalsToBrowser);
my $q = new CGI;
print(
$q->header,
$q->start_html(
-title => 'Input Request',
-style=>{-src=>"../css/my.css"} #<==THIS CREATES A LINK TAG
),
$q->div(
{-id=>"divtop"},
$q->p("Here's a paragraph")
),
$q->start_form(
-method=>'post'
),
$q->div("OperatingSystem"),
$q->div(
$q->radio_group(
-name=>'ostype',
-values=>['Windows','Linux']
)
),
$q->end_form,
$q->end_html
);
Here's the html that the perl script creates(spacing adjusted by me):
<!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" lang="en-US" xml:lang="en-US">
<head>
<title>Input Request</title>
<link rel="stylesheet" type="text/css" href="../css/my.css" />
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
</head>
<body>
<div id="divtop"><p>Here's a paragraph</p></div>
<form method="post" action="/cgi-bin/perl2.pl" enctype="multipart/form-data">
<div>OperatingSystem</div>
<div>
<label><input type="radio" name="ostype" value="Windows" checked="checked" />Windows</label>
<label><input type="radio" name="ostype" value="Linux" />Linux</label>
</div>
<div><input type="hidden" name=".cgifields" value="ostype" /></div>
</form>
</body>
</html>
Note that you get the head tag for free. I assume that's because the title and link tags are supposed to be inside a head tag in well formatted html.
And, here it is using Link()
:
print(
$q->header,
$q->start_html(
-title => 'Input Request',
-head => Link({
-rel => 'stylesheet',
-type => 'text/css',
-href => '../css/my.css'
})
),
$q->div(
{-id=>"divtop"},
$q->p("Here's a paragraph")
),
$q->start_form(
-method=>'post'
),
$q->div("OperatingSystem"),
$q->div(
$q->radio_group(
-name=>'ostype',
-values=>['Windows','Linux']
)
),
$q->end_form(),
$q->br(),
$q->end_html()
);
If I add media => 'print
to the Link()
hash, which adds the attribute media="print"
to the link tag, the css is disabled in my browser. On the other hand, when I do a Print Preview of the page in my browser, I do see the css styling. I think that's the expected behavior. Here's the html:
<!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" lang="en-US" xml:lang="en-US">
<head>
<title>Input Request</title>
<link type="text/css" rel="stylesheet" href="../css/my.css" />
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
</head>
<body>
<div id="divtop"><p>Here's a paragraph</p></div><form method="post" action="/cgi-bin/perl2.pl" enctype="multipart/form-data"><div>OperatingSystem</div><div><label><input type="radio" name="ostype" value="Windows" checked="checked" />Windows</label> <label><input type="radio" name="ostype" value="Linux" />Linux</label></div><div><input type="hidden" name=".cgifields" value="ostype" /></div></form><br />
</body>
</html>