Beginning Perl Q and A
August 21, 2000
|
Got
Questions?
|
The Experts Have Got Answers!
|
Thank you for
submitting your questions to the author of "Beginning Perl." Below, you'll find the answers to several select questions.
Brought
to you by:
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
View our chapter excerpt on
Beginning Perl.
Watch for more answers next week!
Question 1:
Is Perl the best way to make a passworded page? Been checking my webdesign books and links and really haven't found a easy solution to this.
Simon Cozens
responds:
I guess this is a question about CGI design, rather than Perl in
particular, because it's going to be the same in any language. One good
way to password a web site is to let the web server do it for you; Apache
supports something called "Basic authentication" which lets you very easily
add a password to the site. An introduction to basic authentication can be
found at http://www.rahul.net/howto/basicauth.html and there are plenty of
other tutorials available on the web. Apache will also let you add pluggable
modules to do different types of authentication, such as secure sockets.
(HTTPS).
If you want greater flexibilty and interaction with your CGI program, then
you're going to have to have a page which asks for a user name and password,
and then either give the user a cookie, or store an encrypted form of the
password as a hidden field to the CGI request.
For most uses, basic authentication is what you want, though; it's the easiest and the most secure way to add a password, and, best of all, it's already done for you by the server.
Question 2:
About 6 weeks ago I was taking a class. The instructor put me on the spot. He wrote a perl script that he could not get to work. Hence I was supposed to solve it. He was working on a Novell NDS OS and the script would not pull the file from the directory system. Whenever the data was input directly into the script it works. By the way I do not like the way the HTML is written in the script either. Bad form. The challenge in order for this thing to work what is the correct form (code).
The script is included after this line:
require ("cgilib.pl");
print &PrintHeader;
print '<HTML><BODY>';
print '<H1>Perl Test Script 10</H1>';
#open (INPUT, "\\\\fs1_1\\data\\web\\docs\\655-i10.txt");
#@balance=<INPUT>;
$balance[0] =
$balance[1]
$balance[2] =
$max = @balance;
print '<p>';
print '<table>';
print '<tr><th>Number<th>Negative<th<Positve';';
print '<tr><td>-----<td>-----<td>-----';
for ($x = 0; $x < $max; $x++)
{
if ($balance[$x] ==0)
{
print '<tr><td>';
print $x;
print '<td>';
print $balance[$x];
}
else
{
print '<tr><td>';
print $x;
print '<td> <td>';
print $balance[$x];
}
}
print '</table></body></html>';
Simon Cozens responds:
Well, this has quite a few problems. Let's think first about the file problem.
When you're asking the operating system to do something, such as open a file
or run a program, it's vitally important that you check to ensure that the
operation was successful. I'd guess that Perl had a problem here trying to
open the file, and so couldn't get at the data. So what I'd do is check that
the file could be opened, and if not, look at the variable $! which tells us
what the problem was. Instead of this:
open (INPUT, "\\\\fs1_1\\data\\web\\docs\\655-i10.txt");
We'll say this:
unless (open (INPUT, "\\\\fs1_1\\data\\web\\docs\\655-i10.txt")) {
die "Couldn't open that file: $!";
}
In fact, it's become common to write that like this:
open (INPUT, '\\fs1_1\data\web\docs\655-i10.txt')
or die "Couldn't open that file: $!";
Notice also how we use single quotes to cut down on all the backslashes. Now
if the open doesn't work, we'll find out why not. That should tell you what
was wrong with reading the data from the file.
How to avoid putting the HTML into the program? To be honest, I think that's
probably the best thing to do with very simple examples like this, because
if you store the HTML separately, you'll have to store it on the disk
somewhere. If you do that, every time someone looks at the page, you'll have
to open and read in a file, which isn't terribly efficient.
If you do want to store it separately, look into the Text::Template module on
CPAN which allows your program to fill in the gaps of a template. Another way
would be to use HTML::Mason, which is a module which works a little bit like
the PHP language - you write your Perl inside a HTML document, like this:
<html>
<body>
<H1> This is ordinary HTML </H1>
<%perl>
for (0..5) {
print "And this is Perl!<br>\n";
}
</%perl>
</body>
</html>
Question 3:
I am a begining perl scripter but have a question regarding its use.
I want to setup a form with a perl serach engine that will
query an LDAP server for attributes such as cn, phone number, location, etc.
- things that are generally considered to be public information. Can you
give me some pointers.
Simon Cozens responds:
The best pointer I can give you is to CPAN, the Comprehensive Perl Archive Network, which is at http://www.cpan.org/.
It's a repository of reusable Perl code, which are wrapped up into modules.
If you search for "LDAP" in the CPAN Search Engine (http://search.cpan.org/)
you should come across Net::LDAP, which is a big and complicated module which
pretty much takes care of all aspects of LDAP interaction. A much less scary
way of using it is to also get the module called Tie::LDAP, which lets you use
a Perl hash to navigate an LDAP database.
An example from the documentation to that module:
## connect
tie %LDAP, 'Tie::LDAP', { base => 'o=IMASY, c=JP' };
## lookup entry for [dn: cn=tai, o=IMASY, c=JP]
$info = $LDAP{q{cn=tai, o=IMASY, c=JP}};
## lookup each attribute
$user = $info->{username}->[0];
$mail = @{$info->{mailaddr}};
The funny business in the last two lines is about references: look at
http://language.perl.com/newdocs/pod/perlreftut.html for help on explaining
them.
Hope this helps!
Question 4:
Can we create COM using Perl?
Simon Cozens responds:
ActiveState produces the Perl DevKit which contains PerlCOM. PerlCOM is, according to the web site, "A COM object factory that works with Perl packages, objects and bare script. PerlCom, in conjunction with DCOM, allows you to use Perl to easily build distributed applications." There's also
something called PerlCtrl in the DevKit which allows you to create standalone
COM applications.
I'm not aware of any other COM solutions in Perl, and there's nothing on CPAN.
Question 5:
How can I use perl-DBI in Mysql for searching in the database. I would like to know about the use of CURSORS in Mysql.
Simon Cozens responds:
MySQL doesn't support cursors, but I think what you mean can be achieved using the prepare_cached method in DBI. This automatically caches SQL
statements inside a hash, so if prepare_cached is called again with the same
parameters, the prepared statement can be pulled directly from the hash. This
is equivalent to having a statement cursor.
Question 6:
Can a script be written in PERL, which does a scheduled telnet to a router and make the changes in the configurations?
Simon Cozens responds:
Yes; the easiest way to do this is to use the Expect module from CPAN. This allows you to spawn a telnet process and command it much like the
Tcl Expect utility. For example:
use Expect;
my $router = Expect->spawn("telnet", $router_address);
# Look for a password prompt.
$router->expect(30,"ssword: ") || die "Never got password prompt";
# Give the password.
print $router "$password\n";
You'll need to combine this with your scheduling software such as
cron. You might also want to look at Net::Telnet for another way to
send telnet commands to a server.
If you have a Cisco router, of course, this is all done for you. Look
at the Cisco::Conf module on CPAN.
Question 7:
I am looking for some scripts to analyze log files created by my firewall. Do you know where I can find some sample scripts?
Simon Cozens responds:
The "Logfile" module on CPAN will give you a framework for creating
log file analyzers. There are plenty of examples there, as well as a
full module for analyzing Radius logs.
Question 8:
I want to issue a command to a system prompt in NT (i.e. NET USE X:) and then take the end of one of the lines of output and print it. How do I do this?
Simon Cozens responds:
You can capture the output by using backticks (``), like this:
$output = `NET USE X:`;
You can have Perl automatically split the output into lines by using
an array:
@output = `NET USE X:`;
print $output[0]; # First line of output
print $output[-1]; # Last line of output
For more flexibility, you can read each line at a time from a pipe, as
if you were reading from a filehandle:
open (OUTPUT, "NET USE X: |") or die "Couldn't run command: $!";
while (
Question 9:
Are there problems with using pipes with perl on Windows 9x? The following code works fine on Windows NT, and Linux, but just hangs on Windows 9x.
open (Reader, "dir|");
while (){
print $_."\n";
}
In Linux I used ls instead of dir.
Simon Cozens responds:
The only pipe-blocking bug I've found in Win 9x was reported to ActiveState in
March, and Gurusamy Sarathy attempted to investigate the bug but could not
reproduce it himself. If you're using the latest release of ActivePerl, you
might want to check out http://bugs.activestate.com/.
Question 10:
I have a cgi/PERL script that outputs a list of items and counts. However, I want to
imbed this script's output on the homepage of our website. How could this be done?
There are four basic ways to do this:
i) Have the front page as a CGI program and output everything there.
ii) Have the front page as a CGI program and use something like
Text::Template to fill in the parts dynamically generated by Perl.
iii) Have the front page as a server-parsed HTML (shtml) file and use server side includes like this:
<!--#exec cgi="/cgi-bin/your.cgi" -->
iv) My preferred solution is to use HTML::Mason to generate the pages in a Cold-Fusion-like manner, like this:
Mason Demonstration
<%perl>
for (0..10) {
print "The square of $_ is ", $_*$_, " <BR>";
}
</%perl>
See http://www.masonhq.com/ for more information about Mason.
Question 11:
When inside a subroutine, is there any "special" variable that returns the name of that subroutine? For instance, the same way ${0} returns the program name? This would be very useful for logging, etc.
The function caller() will do what you want:
sub thingy {
print ((caller(0))[3]);
}
thingy()
prints "main::thingy"
Question 12:
What is Perl and how does it work?
Perl is a general purpose programming language which is often used for system
administration and web-related tasks. It borrows a lot of its syntax from Unix
utilities such as sh, awk, and sed, as well as mainstream languages like C.
It seems to work extremely well.
Question 13:
We have a new web application written in Mod Perl that is remotely hosted. Our best possible scenario is for the developers to be able to build and test our apps on the test bed, then move the final product en masse over to the production site without the need to make any changes.
The problem occurs in the hard-coding of the absolute URL on each page of our site. We obviously cannot have 2 www.dollarsdirect.coms sitting up in Exodus, both open to the Internet (test for development, production for customers), and both carrying identical apps. We have decided to point the test bed servers to test.dollarsdirect.com, and have instructed our developers to rewrite the code on the test enviroment.
How could we programmatically change the hard-coded absolute URL on each page of our site from test to production or back to facilitate quick migrations?
I think the best situation would be to completely avoid hard-coding the
URL, and have it settable by a variable. For instance, if you have a
configuration file which sets
$CONFIG{url} = "http://test.dollarsdirect.com";
You can read that in and interpolate $CONFIG{url} when you need it:
print <<EOF;
See our <A HREF="$CONFIG{url}/search.html">Search page</A>.
EOF
Question 14:
How do I create a Perl program to ask the user to type in two numbers, then add the two numbers together and display the result?
You can ask the user for a line of input using the construction "<STDIN>".
What you would probably do is store each number into a variable, and
then add them together like this:
print "Enter your first number: ";
$first = <STDIN>;
print "Enter your second number: ";
$second = <STDIN>;
print "The total is : ";
print $first+$second;
print "\n";
Question 14:
How do I create a Perl program to ask the user to type in two numbers, then add the two numbers together and display the result?
You can ask the user for a line of input using the construction "<STDIN>".
What you would probably do is store each number into a variable, and
then add them together like this:
print "Enter your first number: ";
$first = <STDIN>;
print "Enter your second number: ";
$second = <STDIN>;
print "The total is : ";
print $first+$second;
print "\n";
Question 15:
It appears as if there are no useable SNMP agents or MIBs for the system I describe below. I have no PERL experience. My question is: Is it possible (and is it difficult) to create some PERL scripts for the following system:
System: DEC Alpha OpenVMS with various flavors of Oracle 7. to 8.15. We need to look at least 8 or so Oracle activities.
Perl will certainly run fine on OpenVMS, but I don't know about SNMP.
If you can compile the UCD SNMP library, ucd-snmp-4.1.0 libsnmp, on OpenVMS,
then you can use the Perl SNMP module from CPAN. This will allow you to
walk SNMP trees and compile and monitor MIBS.
Question 16:
I use a Perl script (FormMail.cgi) on many web pages that I'm hosting. Every time I add a new web site, I have to edit the script and add the web address to the "referers" variable in the script. What I'd rather do is use an IP address with a wildcard, like this: 208.37.153.* Since all my sites are on the same IP block, this would work great. Instead I have to keep adding to an already long variable that looks like this:
@referers = ('www.bob.com','www.fred.com','www.etc.com' );
Is there a way to acheive this without adding every new web address? Thanks for your time!
I'm not sure which FormMail.cgi you have (there are an awful lot of formmail
programs out there, some better than others...) so I'm going to assume you're
unfortunate enough to be using the badly-written and dangerously insecure
FormMail.cgi from Matt's Script Archive. This has been the subject of many,
many security advisories, and I'd highly advise you not to use it. It's also
extremely non-Perlish style, it doesn't use taint checking to ensure
security, and it's more or less an example of what not to do when writing
CGI programs.
Anyway, lecture over: it appears to contain the following code:
foreach $referer (@referers) {
if ($ENV{'HTTP_REFERER'} =~ m|https?://([^/]*)$referer|i) {
$check_referer = 1;
last;
}
}
Now add "use Socket;" at the top of the file, and change the above code
to the following:
$ENV{'HTTP_REFERER'} =~ m|https?://([^/]+)|i;
my $whence = inet_ntoa($1); # Obtain the IP they're coming from.
foreach $allowed (@referers) {
if ($whence =~ /^$allowed/) {
$check_referer = 1;
last;
}
}
You should now be able to provide ordinary Perl regular expressions on
the IP address in @referers. I make no guarantees that this will not
damage anything else in Matt's code.
Question 17:
I want to create a Perl form that accepts user input and then e-mails the responses to someone to act on it. However my server is controlled by my ISP. What is an equivalent to the Unix sendmail and how do I persuade an ISP to let me program a script to use it?
The Mail::SMTP module from CPAN will attempt to send email directly, without
using sendmail. If you need to install that on the server, you will need to
say
perl Makefile.PL PREFIX=/my/perl_directory
when installing, and add
use lib '/my/perl_directory';
to the top of your program.
Question 18:
What do you have to do to get execute Perl scripts under Windows Scripting Host (WSH)?
Please see http://pages.infinit.net/che/perlwsh/perlwsh0.html.
|