a short non-working Perl script

M

Mark Tarver

I'm writing my first significant Perl CGI script. Its supposed to read
in the input from two forms and print them on the screen. The preamble
seems to work fine - takes the input string and spilts it into the
component tokens. The print HTML bit does not work fine. What
appears on the browser
is:

Info

--------------------------------------------------------------------------------

Name:
Email:

with neither values of name or email displayed. Why is this?

A minor niggle - Perl does not seem to match END_OF_PART2 unless I
place the redundant print statement at the bottom. No idea why.

Mark

# Here is the Code

#!/usr/bin/perl
# Reads the input from a forms file and splits it into parts.

$buffer = read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
$token = "";
@tokens = ( );

while ($buffer ne "")
{$c = chop($buffer);
if ($c eq "&" || $c eq "=")
{$tokens = push(@tokens, $token); $token = "";}
else
{$token = $c . $token;}
};
push(@tokens, $token);
@tokens = reverse(@tokens);

# Grabs name and email.

shift(@tokens);
$name = shift(@tokens);
shift(@tokens);
$email = shift(@tokens);

#__________________________HTML begins here
print <<END_OF_PART1;
Content-type: text/html

<HTML>
<HEAD>
<TITLE> Info</TITLE>
</HEAD>
<BODY>
<H1> Info</H1>
<HR>
<PRE>
END_OF_PART1
print "Name: $name <br>";
print "Email: $email <br>" ;
print <<END_OF_PART2;

</PRE>
<HR>
</BODY>
</HTML>
END_OF_PART2
print "";
 
B

boyd

$buffer = read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
$token = "";
@tokens = ( );

Well, this is not what you want. From perldoc -f read:

Attempts to read LENGTH characters of data into variable SCALAR from
the specified FILEHANDLE. Returns the number of characters actually
read...

You are overwriting the $buffer contents with the number of characters.

Boyd
 
P

Paul Lalli

Mark said:
I'm writing my first significant Perl CGI script.

Then now is the perfect time to trash whatever book or website has
taught you such horrendous coding methods. Please read:
perldoc CGI
and learn the *right* way to write a CGI script in Perl.
Its supposed to read
in the input from two forms and print them on the screen. The preamble
seems to work fine - takes the input string and spilts it into the
component tokens. The print HTML bit does not work fine. What
appears on the browser
is:

Info

--------------------------------------------------------------------------------

Name:
Email:

with neither values of name or email displayed. Why is this?

A minor niggle - Perl does not seem to match END_OF_PART2 unless I
place the redundant print statement at the bottom. No idea why.

Probably because you're not using a HEREDOC correctly. It must be the
only thing on the line, and it must be terminated with a newline. My
guess is you added an extra line using print "", but a blank line would
have "fixed" it just as well.
# Here is the Code

#!/usr/bin/perl

You've neglected:
use strict;
use warnings;
use CGI qw/:standard/;
use CGI::Carp qw/fatalsToBrowser/;

Those four should be in EVERY Perl CGI script you write. The first two
should be in EVERY Perl script you write.
# Reads the input from a forms file and splits it into parts.

$buffer = read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
$token = "";
@tokens = ( );

while ($buffer ne "")
{$c = chop($buffer);
if ($c eq "&" || $c eq "=")
{$tokens = push(@tokens, $token); $token = "";}
else
{$token = $c . $token;}
};
push(@tokens, $token);
@tokens = reverse(@tokens);

# Grabs name and email.

shift(@tokens);
$name = shift(@tokens);
shift(@tokens);
$email = shift(@tokens);

Get rid of this entire mess. Everything from my last comment to this
one. Replace it ALL with these two lines:

my $name = param('name');
my $email = param('email');

(presuming, of course, that you did in fact name your inputs 'name' and
'email', respectively.
#__________________________HTML begins here
print <<END_OF_PART1;
Content-type: text/html

<HTML>
<HEAD>
<TITLE> Info</TITLE>
</HEAD>
<BODY>

Get rid of this entire mess and replace with:
print header();
print start_html('Info');

<H1> Info</H1>
<HR>
<PRE>
END_OF_PART1
print "Name: $name <br>";
print "Email: $email <br>" ;
print <<END_OF_PART2;

</PRE>
<HR>

print h1('Info');
print hr();
print pre("Name: $name<br>\nEmail: $email<br>\n");


</BODY>
</HTML>

print end_html();
END_OF_PART2
print "";

Learning to code the correct way now will save you endless frustrations
as you write more complex scripts in the future.

Paul Lalli
 
J

John Bokma

Sherm Pendley said:
Adding any statement after the second END_OF_PART2, or even just
ending that line with an EOL sequence, would work just as well. Most
programmer's editors have an option to add an EOL to the last line
automatically when a file is saved.

And trimming trailing spaces (and tabs), which is another way to make here
docs fail (having whitespace other then EOL after the marker)
 
M

Mark Tarver

Ah ,much clearer, thanks.

Mark

P.S. what is the significance of 'my' in the code?
 
K

krakle

print header();
print start_html('Info');


print hr();

His way of outputting HTML to the browser is better than your
suggestion of using CGI.pm to display HTML. Since when does programming
on top of an additional layer of abstraction better than dealing with
the markup language directly?

Nobody who makes a serious Perl script for the web uses CGI.pm to write
HTML. It's just far too limiting and makes it virtually impossible to
easily update..
 
T

Tony Curtis

His way of outputting HTML to the browser is better than your
suggestion of using CGI.pm to display HTML. Since when does programming
on top of an additional layer of abstraction better than dealing with
the markup language directly?

Because HTML is a structured language. Just printing out the HTML
directly as text confuses (IMHO) the actual structure of the document,
with serialization for transmission to the client.

print html( head(...) . body(...) );

Using the abstraction layer afforded by a module allows you to write to
your purpose, not to the underlying implementation (HTML).

hth
t
 
J

Jürgen Exner

Thus spoke (e-mail address removed) (on 2006-11-24 20:30):
Hmmm. I am surprised that you are frequenting a Perl NG.
After all when taking this argument serious I would expect you to program in
binary code (aka machine code) using dip switches.
Don't use assembler, that's already a layer of abstraction!

jue
 
J

John Bokma

His way of outputting HTML to the browser is better than your
suggestion of using CGI.pm to display HTML.

Depends. But it's extremely important to note that CGI.pm spits out XHTML
(horror, surprise) unless that has been changed. Hence I never use it for
HTML generation :-D.
Since when does programming
on top of an additional layer of abstraction better than dealing with
the markup language directly?

I can come up with several examples, and I am sure you as well.
Nobody who makes a serious Perl script for the web uses CGI.pm to write
HTML. It's just far too limiting and makes it virtually impossible to
easily update..

Have you concluded this from serious research, or it's just how you would
like to see things? When is a Perl script serious?
 
M

Mark Tarver

Well, this is not what you want. From perldoc -f read:
From tests I found that if I set the buffer to a fixed string then the
program worked perfectly. Ergo I expect that this was the line that
was fouling it up. What is the code for reading the forms output to
the $buffer - do you know?

Mark
 
P

Paul Lalli

Mark said:
program worked perfectly. Ergo I expect that this was the line that
was fouling it up. What is the code for reading the forms output to
the $buffer - do you know?

Are you *reading* any of these replies? You were given the correct way
to do this by several different people. If you want to continue to
ignore the right way, you were even quoted a part of the documentation
of the read() function that tells you what you did wrong. $buffer is
passed as the second argument to the function, and the function fills
that buffer. It then returns HOW MANY BYTES WERE READ, not the actual
text. Therefore, you're reading, for example, "Hello World", which
Perl is storing into $buffer automatically. But then you immediately
replace that string with the number 11, because you assigned the
$buffer variable to the return value of read(). Stop doing that.

Paul Lalli
 
U

Uri Guttman

PL> Are you *reading* any of these replies? You were given the correct way
PL> to do this by several different people. If you want to continue to
PL> ignore the right way, you were even quoted a part of the documentation
PL> of the read() function that tells you what you did wrong. $buffer is
PL> passed as the second argument to the function, and the function fills
PL> that buffer. It then returns HOW MANY BYTES WERE READ, not the actual
PL> text. Therefore, you're reading, for example, "Hello World", which
PL> Perl is storing into $buffer automatically. But then you immediately
PL> replace that string with the number 11, because you assigned the
PL> $buffer variable to the return value of read(). Stop doing that.

and to back this up, the OP's cgi parser is even worse than the classic
matt wright parser which did minimally work even if it was crappy code
with major holes in it.

so to the OP, use cgi.pm or don't code basic cgi scripts in perl. until
you get good enough to graduate to beyond cgi.pm (and use some other
higher level framework) don't stray away from it.

but if you continue to ignore the postings here (as paul stated) you
will lose most of us as we can't help those that won't help themselves.

uri
 
M

Mark Tarver

PL> Are you *reading* any of these replies? You were given the correct way
PL> to do this by several different people.

Of course. I now have a working version using cgi.pm.

#!/usr/bin/perl
use strict;
use warnings;
use CGI qw/:standard/;
use CGI::Carp qw/fatalsToBrowser/;

my $name = param('name');
my $email = param('email');

print header();
print start_html('Info');

print h1('Info');
print hr();
print pre("Name: $name<br>\nEmail: $email<br>\n");

print end_html();
_______________________________________________________________
But for my own education I would still like to know the answer to my
question as to how $buffer can read the output of series of forms.
cgi.pm is actually not part of Perl itself, but a package on top of
Perl.

The original program works apart from this one line. Here is an
example where $buffer is set to a string.
_________________________________________________________________
#!/usr/bin/perl
# Reads the input from a forms file and splits it into parts.

$buffer = "name=Mark&email=over the rainbow";
$token = "";
@tokens = ( );

while ($buffer ne "")
{$c = chop($buffer);
if ($c eq "&" || $c eq "=")
{$tokens = push(@tokens, $token); $token = "";}
else
{$token = $c . $token;}
};
push(@tokens, $token);
@tokens = reverse(@tokens);

# Grabs name and email.

shift(@tokens);
$name = shift(@tokens);
shift(@tokens);
$email = shift(@tokens);

#__________________________HTML begins here
print <<END_OF_HTML;
Content-type: text/html

<HTML>
<HEAD>
<TITLE> Info</TITLE>
</HEAD>
<BODY>
<H1> Info</H1>
<HR>
<PRE>
Name: $name <br>
Email: $email <br>
</PRE>
<HR>
</BODY>
</HTML>
END_OF_HTML
print "";

____________________________
produces the correct

<HTML>
<HEAD>
<TITLE> Info</TITLE>
</HEAD>
<BODY>
<H1> Info</H1>
<HR>
<PRE>
Name: Mark <br>
Email: over the rainbow <br>
</PRE>
<HR>
</BODY>
</HTML>

You don't have to answer the question, but the correct answer in Perl
should not be too long.

Mark
 
G

Gunnar Hjalmarsson

Mark said:
Of course.
...
But for my own education I would still like to know the answer to my
question as to how $buffer can read the output of series of forms.

Boyd already answered that question. So again, _are_ you reading the
replies you got?
The original program works apart from this one line. Here is an
example where $buffer is set to a string.
_________________________________________________________________
#!/usr/bin/perl
# Reads the input from a forms file and splits it into parts.

$buffer = "name=Mark&email=over the rainbow";

If submitted from a from, that would come in STDIN ( or in
$ENV{QUERY_STRING} ) as "name=Mark&email=over+the+rainbow", so your code
would not complete the task.

I have emphasized the limitations of CGI.pm many times, and I don't
always use it for my own CGI scripts. I'd still recommend that you
follow the advice given to you: Use CGI.pm and drop that code. You have
quite a few things to learn before you should consider anything else.
 
B

boyd

_______________________________________________________________
But for my own education I would still like to know the answer to my
question as to how $buffer can read the output of series of forms.
cgi.pm is actually not part of Perl itself, but a package on top of
Perl.

The original program works apart from this one line. Here is an
example where $buffer is set to a string.
_________________________________________________________________
#!/usr/bin/perl
# Reads the input from a forms file and splits it into parts.

$buffer = "name=Mark&email=over the rainbow";
$token = "";
@tokens = ( ); ....
You don't have to answer the question, but the correct answer in Perl
should not be too long.

Mark

Your script looks fine. We repeat: when you write
$buffer = read( $a, $buffer, $c), the $buffer variable gets the
correct string (I assume), but then the read function returns a number,
which then overwrites $buffer, and replaces the string with a number.

Your script would work, probably, if you did something like:

my $buffer_length = read( $a, $buffer, $c)

Boyd
 
P

Paul Lalli

Mark said:
But for my own education I would still like to know the answer to my
question as to how $buffer can read the output of series of forms.

Un-f***ing-believable. Your question was answered at least 4 times, at
least one of those times by me. You're using read() wrong. I
explained to you exactly how you were using it wrong. When you assign
$buffer to the return value of read(), you overwrite the correct
contents of $buffer with an integer. That's why your script was wrong.
How many more times would you like me to tell you that?
cgi.pm is actually not part of Perl itself, but a package on top of
Perl.

This is pure nonsense. CGI.pm (there is no cgi.pm, despite what a
certain regular here would apparently like you to believe by his
refusal to use the shift key) is part of the core distrobution. It is
as much Perl as anything else.
The original program works apart from this one line. Here is an
example where $buffer is set to a string.

Yes, and your example DIDN'T DO THAT. Because you were NOT USING
read() CORRECTLY. That's three time's I've explained it. Would you
like one more?
You don't have to answer the question, but the correct answer in Perl
should not be too long.

Screw you. We did answer it. Repeatedly. Your inability to read is
now your own problem.

*plonk*

Paul Lalli
 
G

Gunnar Hjalmarsson

Paul said:
Un-f***ing-believable. Your question was answered at least 4 times,

Then I have a problem with the maths. Which 4 posts explain that the
STDIN contents in $buffer is replaced by the return value from read()?
at least one of those times by me.
Where?

Screw you. We did answer it. Repeatedly. Your inability to read is
now your own problem.

What about ability to count? ;-)

That's your own business.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top