Note: In perl a list is an array, so I may use the two terms interchangeably. Also, I always use strict so each variable must begin with my as in, my $variable; when first initializing them.
On this page... (hide)
- 1. Subroutines or functions
- 2. Send email
- 3. Email script using a groups file for the To: addresses
- 3.1 Group file
- 3.2 Email script
- 4. Parsing XML
- 5. Perl Data Dumper
- 6. System calls
- 7. Messing with what headers are actually printed with certain functions like
header()andredirect() - 8. How to loop through an array
- 9. Sessions
- 10. Print header with CGI
- 11. Perl Trim Functions
- 12. How to add a directory to @INC array for modules located in a custom directory
- 13. Installing modules locally
- 14. Encoding html entities (Prevents cross site scripting - XSS)
- 15. Using the CGI module to print the html header and get query strings
- 16. Parsing query strings
- 17. Redirect pages
- 18. Query Strings
- 19. Testing values with if statements ... etc
- 20. Writing to files
- 21. Displaying all environment variables like PHP does with
phpinfo() - 22. Using backreferences
- 23.
heredoc - 24. Running system commands
- 25. Search and Replace
- 26. Perl Modules
- 27. Default array
@_ - 28.
use strict - 29. Finding information about Perl functions with
perldoc - 30. Stripping text off of the end of a string
- 31. Using the LWP module to download a URL.
- 32. Command line replacements
- 33. Troubleshooting Perl
- 34. Troubleshooting CGI Scripting
- 35. Page Comments (Click to edit)
1. Subroutines or functions
When writing subroutines, if you do the following,
sub myfunc()
{
my($a1,$a2,$a3) = @_;
return $a1 . $a2 . $a3;
}
print(myfunc("this","is","a test"));
it will give you an error - something like too many arguments.
What's happening is if you start your subroutine with myfunc(), meaning you have parentheses, you are saying this function takes no arguments, so the too many arguments error makes sense. You should actually write the above as,
sub myfunc
{
my($a1,$a2,$a3) = @_;
return $a1 . $a2 . $a3;
}
print(myfunc("this","is","a test"));
2. Send email
2.1 Using the Mail::Sendmail module to send email
use Mail::Sendmail;
my %mail = ( To => 'joe@example.com',
From => 'foo@example.com',
Message => 'This is a very cool message that I hope you get.'
);
sendmail(%mail) or die $Mail::Sendmail::error;
print "OK. Log says:\n", $Mail::Sendmail::log;
http://search.cpan.org/~mivkovic/Mail-Sendmail-0.79/Sendmail.pm »
Here's another example in it's entirety which also uses the Email::Valid module to validate email addresses.
#!/usr/local/bin/perl
use strict;
use warnings;
use XML::Simple;
use Data::Dumper;
use Mail::Sendmail;
use Email::Valid;
### Usage: send_email("to\@address","subject line","message body","from\@address");
### Returns: True and sends an email, or it dies.
### Note: Must escape @ if using "quotes".
sub send_email
{
my($to,$subject,$message,$from) = @_;
if(Email::Valid->address($to))
{
my %mail = ( To => $to, Subject => $subject, Message => $message, From => $from );
sendmail(%mail) or die('Email could not be sent');
}
else
{
die('Invalid email address');
}
}
send_email("foo@example.com","This is a subject","This is a message body","frombar@example.com");
2.2 Simple script using sendmail
# Simple Email Function
# ($to, $from, $subject, $message)
sub sendEmail
{
my ($to, $from, $subject, $message) = @_;
my $sendmail = '/usr/lib/sendmail';
open(MAIL, "|$sendmail -oi -t");
print MAIL "From: $from\n";
print MAIL "To: $to\n";
print MAIL "Subject: $subject\n\n";
print MAIL "$message\n";
close(MAIL);
}
http://perl.about.com/od/email/a/perlemailsub.htm »
Another useful site about emailing mentions the Email::Valid module which can validate email addresses for you and strip out strings that could be sent to sendmail.
http://www.perlfect.com/articles/sendmail.shtml »
3. Email script using a groups file for the To: addresses
3.1 Group file
groups_file.xml
<notif_grps>
<notifs>
<email>joe@example.com</email>
<email>sally@example.com</email>
<email>mark@example.com</email>
</notifs>
</notif_grps>
3.2 Email script
#!/usr/local/bin/perl
use strict;
use warnings;
use XML::Simple;
use Data::Dumper;
use Mail::Sendmail;
use Email::Valid;
my $xml = new XML::Simple (ForceArray=>1);
my $xml_data = $xml->XMLin("path/to/groups_file.xml");
sub trim($)
{
my $str = shift;
$str =~ s/^\s+//;
$str =~ s/\s+$//;
return $str;
}
### Usage: get_group_emails("notification_group","path/to/group/email/file");
### Returns: A comma delimited list of email addresses.
sub get_group_emails
{
my($notif_group,$notif_group_file) = @_;
my $xml = new XML::Simple (ForceArray=>1);
if(-e $notif_group_file)
{
my $xml_data = $xml->XMLin($notif_group_file);
my($email_string,$is_email);
for my $email (@{ $xml_data->{$notif_group}->[0]->{email} })
{
$email = trim($email);
if(Email::Valid->address($email))
{
$email_string .= "$email, ";
$is_email = "yes";
}
}
$email_string =~ s/, $//;
if($is_email eq "yes")
{
return $email_string;
}
else
{
die("Did not receive a valid email address from $notif_group_file.");
}
}
else
{
die("$notif_group_file does not exist.");
}
}
### Usage: send_email("notification_group","subject line","message body","from\@address");
### Returns: True and sends an email, or it dies.
### Note: Must escape @ if using "quotes".
sub send_email
{
my($to,$subject,$message,$from) = @_;
if(!Email::Valid->address($to))
{
$to = get_group_emails($to,"/hard/coded/path/to/notification_groups.xml")
}
my %mail = ( To => $to, Subject => $subject, Message => $message, From => $from );
sendmail(%mail) or die('Email could not be sent');
}
send_email("test_group","test subj","test body","hardcoded@example.com");
4. Parsing XML
Here is a sample script that parses the following xml,
<notif_grps>
<notifs>
<email>joe@example.com</email>
<email>sally@example.com</email>
<email>mark@example.com</email>
</notifs>
</notif_grps>
The following script will print out each email in the xml above in the order listed,
#!/usr/local/bin/perl
use strict;
use warnings;
use XML::Simple;
use Data::Dumper;
use CGI;
my $xml = new XML::Simple (ForceArray=>1);
my $xml_data = $xml->XMLin("path/to/notif_grps.xml");
my $cgi = new CGI;
print $cgi->header();
#print Dumper($xml_data);
for my $email (@{ $xml_data->{notifs}->[0]->{email} })
{
print $email . " ";
}
The {notifs}->[0] part means we are reading the first <notifs> tag. In our example there is only one <notifs> tag, but if there was a second, you would reference it with {notifs}->[0].
5. Perl Data Dumper
If you use the Data::Dumper module you can print out the structure of arrays/hashes ... etc by doing the following.
#!/usr/bin/perl use strict; use warnings; use Data::Dumper; $data = "This is actually an array or hash place holder - NOT a string."; print Dumper($data);
I think this is like using PHP's print_r() function.
6. System calls
If you need to make a system call, there's a couple easy ways to do it. One is to use the system() function like so,
system("whoami");
The above will print to STDOUT the username the account is running under, but it does print.
If you'd like to store this value in a variable, you can use the back tick character as in the following,
my $username = `whoami`;
7. Messing with what headers are actually printed with certain functions like header() and redirect()
7.1 redirect("http://www.example.com »")
print redirect("http://www.example.com");
outputs
Status: 302 Moved Location: http://www.example.com
Note, each line of the header ends with a line ending, except the Location: part which ends in two line endings.
7.2 header()
If you use use CGI; with my $cgi = CGI->new();, the output of
print $cgi->header();
will be,
Content-Type: text/html; charset=ISO-8859-1
which also contains two line endings at the end.
If you use use CGI::Session with my $session = CGI::Session->new();, the output of the following,
print $session->header();
will be,
Set-Cookie: CGISESSID=72151d3a108260797dab2c82ad32d021; path=/ Date: Wed, 16 Jul 2008 17:44:58 GMT Content-Type: text/html; charset=ISO-8859-1
This time a cookie is set to store your session parameters, a date was sent, and the Content-Type of text/html. The cookies name will be CGISESSID.
I actually send that cookie manually if I want to retrieve session parameters before the Content-Type: text/html is sent by setting the cookie with the following,
my $cgisession_cookie = new CGI::Cookie(-name=>'CGISESSID', -value=>$session->id); print "Set-Cookie: $cgisession_cookie\n";
Don't forget your line endings (\n) after each header line. And don't forget the last header that's printed out, like Content-Type: text/html should have two line endings.
8. How to loop through an array
If you have an array @myarray and you want to loop through it line by line, you can use the following,
foreach(@myarray)
{
$line = $_;
print $line . "\n";
}
9. Sessions
I used CGI::Session.
Here's an example,
#!/usr/bin/perl
use strict;
use CGI::Session;
my $session = CGI::Session->new();
my $sessid = CGI->id();
### Set params
$session->param('variable','value');
### Retrieve params
$variable = $session->param('variable');
### Print headers that set a cookie with the session id
print $session->header();
10. Print header with CGI
The header prints out Content-type: text/html\n\n . You can do the same thing with sessions above, which also sets a cookie.
#!/usr/bin/perl use strict; use CGI; $cgi = CGI->new(); print $cgi->header();
print $cgi->header(); actually sets a cookie, prints the date, and the Content-type: text/html\n\n portion of the headers.
You can set that cookie manually with,
$cookie = new CGI::Cookie(-name=>'CGISESSID', -value=>$session->id); print $cgi->header(-cookie=>$cookie);
11. Perl Trim Functions
# Perl trim function to remove whitespace from the start and end of the string
sub trim($)
{
my $string = shift;
$string =~ s/^\s+//;
$string =~ s/\s+$//;
return $string;
}
# Left trim function to remove leading whitespace
sub ltrim($)
{
my $string = shift;
$string =~ s/^\s+//;
return $string;
}
# Right trim function to remove trailing whitespace
sub rtrim($)
{
my $string = shift;
$string =~ s/\s+$//;
return $string;
}
12. How to add a directory to @INC array for modules located in a custom directory
use lib qw(/path/to/your/perl/modules);
13. Installing modules locally
Run perl -MCPAN -e shell from the command line and it will ask you some questions. Make sure you say don't fill in stuff for me. Just say no.
To rerun the configuration, enter the following command at the cpan shell o conf init.
When you get to a question that says something about PREFIX, you will want to enter something like /home/username/myperlmodules so that they will be installed there.
This will put a configuration file called MyConfig.pm in your home directory at /home/username/.cpan/CPAN.
To install modules, type cpan at the command line and it will bring up the cpan> prompt.
Now you can type install WWW::Curl for example to install the curl module.
Use force install WWW::Curl if you really want to install the module while ignoring errors ... etc. I've done this many times without problems, but I'm sure there could have been.
14. Encoding html entities (Prevents cross site scripting - XSS)
use HTML::Entities;
$text = "<script>alert('hi');</script>";
$encoded_text = HTML::Entities::encode($text)
15. Using the CGI module to print the html header and get query strings
#!/usr/bin/perl use strict; use CGI; my $cgi = CGI->new(); print $cgi->header();
If you pass a query string such as ?var1=val1&var2=val2&var3=val3 you can access them with the $cgi->param('variable') as so,
#!/usr/bin/perl
use strict;
use CGI;
my $cgi = CGI->new();
print $cgi->header();
print $cgi->param('val1');
16. Parsing query strings
$qq will contain an associative array of the query string parameters.
use strict;
use URI::Query;
my $qs = query_string();
my $qq = URI::Query->new($qs);
my %qq = $qq->hash;
print $qq{'action'};
17. Redirect pages
print "Location:http://www.example.com\n\n";
or
print redirect("http://www.example.com");
The redirect() function actually sends the 304 Moved header.
18. Query Strings
You can get them with the query_string() function.
19. Testing values with if statements ... etc
When testing numeric values, you can use == and != ... etc, but when testing strings, you should use eq for equal and ne for not equal to.
20. Writing to files
Basically, the FP below is the file pointer (or that's what I call it). You open a file using one right angle bracket to overwrite the file with the contents, and two right angle brackets to append the contents to the file.
The variable $content contains the content you want to add to the file.
You can have as many print commands as you want, as long as they are in between open and close.
open(FP,">filename.txt"); print FP $content; close(FP);
21. Displaying all environment variables like PHP does with phpinfo()
Just update the shebang #!/usr/local/bin/perl with the path to your perl binary and copy this code to something like perlinfo.cgi and execute in a browser.
#!/usr/local/bin/perl
print "Content-type: text/html\n\n";
print "<ul>\n";
foreach $key (sort keys(%ENV)) {
print "<li><strong>$key</strong> = $ENV{$key}</li>";
}
print "</ul>";
22. Using backreferences
First a PHP example.
$string = "Hello to the World";
$string = eregi_replace("^.*(to) (the) World.*$","\\1 and \\2");
print($string); #> outputs "to and the"
In Perl, you use the =~ operator to start a RegExp. Below I have used it to get back references which can be used outside of the expression via in this case $1 and $2.
my $string = "Hello to the World"; $string =~ /^.*(to) (the) World.*$/; print $string . " && the last two back references are |$1| and |$2|";
You can use the back references inside the string like below which is like the first PHP example.
my $string = "Hello to the World"; $string =~ s/^.*(to) (the).*$/$1 and $2/gi;
For more information, see in this document for Regular Expressions.
23. heredoc
In Perl, you can create a heredoc with the following syntax.
$a_variable = <<"eof"; This is a variable that contains a bunch of text on a bunch of lines. That's the benefit of using heredocs - you don't have to print line by line. eof
Note here that there is a semi-colon after the first line ... "eof"; but none after the last line eof. This is important. Also, the eof part, that's up to you. Put anything there you like. eof generally stands for end of file, or eol end of line. I'm not sure why I use eof, but I do.
Just for reference, in PHP, a heredoc looks like
$a_variable = <<<eof This is a variable that contains a bunch of text on a bunch of lines. That's the benefit of using heredocs - you don't have to print line by line. eof;
24. Running system commands
In Perl, all you have to do is use a similar syntax that UNIX shell scripting uses -- at least BASH. Here's an example that displays the date from the UNIX date command. Basically, just enclose your system commands in back ticks. (`)
#!/usr/bin/perl use strict; my $date = `date +%Y%m%d`; print $date;
The use strict; just forces you to use the my function which delares a variable local to the containing block.
25. Search and Replace
In Perl you can perform a search and replace just like the eregi and preg functions in PHP. Here is an example.
Basically, in this example, we have a $string and we want to grab the variable values from a query string. You can see that we use =~ to find the patterns. This is equivalent to ereg or preg functions in PHP. You can actually perform an ereg_replace or preg_replace like in PHP. It just stores the back references in the $ variable.
#!/usr/local/bin/perl
$string = "foo_name=DLP&bar_name=RT";
$string =~ m/foo_name=(.+)&bar_name=(.+)/gi;
print("foo_name=$1 and bar_name=$2 \n"); ### outputs: foo_name=DLP and bar_name=RT ###
If you wanted to manipulate a string directly and store the new value back into it's variable, you would do the following. Basically, let's make the $string above have only the value DLP.
#!/usr/local/bin/perl $string = "foo_name=DLP&bar_name=RT"; $string =~ s/foo_name=(.+)&bar_name=.+/$1/gi; print($string . "\n"); ### outputs: DLP ###
26. Perl Modules
27. Default array @_
Here below, $x and $y are passed to the function geomean(). By doing ($a,$b) = @_, the values from the first list ($x,$y) are passed respectively to ($a,$b) via the default array variable @_. @_ is similar to $_, but not the same.
$x = 10;
$y = 20;
print geomean($x,$y);
sub geomean() {
($a,$b) = @_;
return sqrt( $a*$b );
}
Another way to do this is with shift (below). Again the list ($x,$y) is passed to the function geomean(). $a = shift; means that, if no array is provided to the shift function, it operates on the default array, @_. So, the default array contains ($x,$y), so $a = shift; takes the first array value from the default array and stores it in $a. Then, the shift function removes the first array value and moves all other values one step forward which is why $b becomes $y.
$x = 10;
$y = 20;
print geomean($x,$y);
sub geomean() {
$a = shift;
$b = shift;
return sqrt( $a*$b);
}
A last way to do this is with $_.
$x = 10;
$y = 20;
print geomean($x,$y);
sub geomean() {
$a = $_[0];
$b = $_[1];
return sqrt( $a*$b);
}
http://www.gossland.com/course/functions/user.html »
Another way of thinking about the default array is to think about how functions operate (I'm thinking in PHP here). I may have a function that just adds 3 numbers together, such as
<?php
function add_us($a,$b,$c){
$sum = $a + $b + $c;
return $sum;
}
print(add_us(2,7,3)); #> output here is 12
?>
Basically, it just removes the ($a,$b,$c) from the function definition and moves it inside the function.
In Perl, you could think of ($a,$b,$c) as a list or an array, so we could write our function in Perl as,
sub add_us {
($a,$b,$c) = @_;
$sum = $a + $b + $c;
return $sum;
}
print(add_us(3,5,6)); #> output here is 14
The difference I'm trying to get across is that when you define the function, in Perl you don't have to put the list in the function definition like in PHP. i.e. function foo($val1,$val2,$val3). Just use the default array in Perl.
28. use strict
If you issue use strict; at the top of your Perl script, this forces you to use the my() function to declare all variables local. If not you will receive error messages like, Global symbol "foo" requires explicit package name at test.pl line 3..
http://www.cs.cf.ac.uk/Dave/PERL/node151.html »
29. Finding information about Perl functions with perldoc
Say you want to find out something about the function my, just issue the command
$ perldoc -f my
and it will output information about my.
30. Stripping text off of the end of a string
The script below will strip /search?q=perl master off the end of $srcUrl.
#!/usr/bin/perl my $srcUrl = 'http://www.google.com/search?q=perl master'; my $modUrl; $srcUrl =~ /\/search/; $modUrl = $`; print $modUrl;
31. Using the LWP module to download a URL.
This one line command downloads a URL and the finds certain lines and emails them to whomever.
$ perl -MLWP::Simple -e "getprint 'http://cpan.org/RECENT'" \
| grep "/by-module/Acme" | mail -s "New Acme modules! Joy!" $USER
32. Command line replacements
Say you have a file 'file.txt' and you want to replace all instances of 'dog' with 'cat' - do this,
perl -p -i.BACKUP -e "s?dog?cat?g" file.txt
The -i specifies a backup file. It can be any extension. In this case, file.txt will be changed, and the original will be saved to file.txt.BACKUP. The ? can be replaced by / if need be. Also the " can be '. The g specifies all instances of 'dog'. If g is not there, it will only replace the first instance of 'dog'.
33. Troubleshooting Perl
I was running a cgi script and a 1 kept being printed to the browser. It ended up that, unless you have a return something in your functions, it may just return a 1;
34. Troubleshooting CGI Scripting
I ran into something really touchy today. Look at the difference between these two scripts -- one of them works and the other doesn't.
#!/bin/perl
print("Content-type: text/html\n\n");
print("Hello, world!");
and
#!/bin/perl
print("Content-type: text/html\n\n");
print("Hello, world!");
Which one works? The second one because it has two line endings at the end of text/html. If you only put one line ending the script will fail.
If you don't put the shebang, #!/bin/perl, pointing to your perl executable, the script will fail.
Also, every CGI script should print the content type header before anything else is printed.
print("Content-type: text/html\n\n");
That let's everyone know the output is html (meaning your machines).
