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.

Perl with Simple XML (XML::Simple)

Installation

XML::Simple works by parsing an XML file and returning the data within it as a Perl hash reference. Within this hash, elements from the original XML file play the role of keys, and the CDATA between them takes the role of values. Once XML::Simple has processed an XML file, the content within the XML file can then be retrieved using standard Perl array notation.

Written entirely in Perl, XML::Simple is implemented as an API layer over the XML::Parser module, and it's currently maintained by Grant McLean. It comes bundled with most recent Perl distributions, but if you don't have it, the easiest way to get it is from CPAN. Detailed installation instructions are provided in the download archive, but by far the simplest way to install it is to use the CPAN shell: shell> perl -MCPAN -e shell cpan> install XML::Simple

If you use the CPAN shell, dependencies will be automatically downloaded for you (unless you configured the shell not to download dependent modules). If you manually download and install the module, you may need to download and install the XML::Parser module before XML::Simple can be installed. This article uses version 2.12 of XML::Simple. Basic XML parsing

Once you've got the module installed, create the following XML file and call it "data.xml": <?xml version='1.0'?> <employee>

        <name>John Doe</name>
        <age>43</age>
        <sex>M</sex>
        <department>Operations</department>

</employee>

And then type out the following Perl script, which parses it using the XML::Simple module:

  1. !/usr/bin/perl
  2. use module

use XML::Simple; use Data::Dumper;

  1. create object

$xml = new XML::Simple;

  1. read XML file

$data = $xml->XMLin("data.xml");

  1. print output

print Dumper($data);

Using XML::Simple is, well, simplicity itself. Every object of the XML::Simple class exposes two methods, XMLin() and XMLout(). The XMLin() method reads an XML file or string and converts it to a Perl representation; the XMLout() method does the reverse, reading a Perl structure and returning it as an XML document instance. The script above uses the XMLin() method to read the "data.xml" file created previously and store the processed result in $data. The contents of $data are then displayed with Perl's Data::Dumper module.

When you run this script, here's what you'll see: $VAR1 = {

          'department' => 'Operations',
          'name' => 'John Doe',
          'sex' => 'M',
          'age' => '43'
        };

As you can see, each element and its associated content has been converted into a key-value pair of a Perl associative array. You can now access the XML data as in the following revision of the script above:

  1. !/usr/bin/perl
  2. use module

use XML::Simple;

  1. create object

$xml = new XML::Simple;

  1. read XML file

$data = $xml->XMLin("data.xml");

  1. access XML data

print "$data->{name} is $data->{age} years old and works in the $data->{department} section\n";

Here's the output: John Doe is 43 years old and works in the Operations section [/output]

Now let's look at how to use XML::Simple to handle more complicated XML documents. Handling multilevel document trees

The ease of use in XML::Simple's basic XML handling extends to XML documents with multiple levels as well. Consider the XML file in Listing A. If you read this in with XMLin(), you'll receive a structure like the one shown in Listing B.

XML::Simple represents repeated elements as items in an anonymous array. Thus, the various <employee> elements from the XML file have been converted into a Perl array, whose every element represents one employee. To access the value "John Doe", therefore, you need simply use the syntax $data->{employee}->[0]->{name}.

You can also do this automatically in a Perl script by dereferencing $data->{employees} and then iterating over the array using a foreach() loop. An example of this is the code in Listing C. And here's the output: John Doe Age/Sex: 43/M Department: Operations

Jane Doe Age/Sex: 31/F Department: Accounts

Be Goode Age/Sex: 32/M Department: Human Resources Handling attributes

XML::Simple handles attributes in much the same way as it handles elements—by placing them in a hash. Consider the XML file in Listing D.

If you were to parse this with XML::Simple, the output would look like that in Listing E. Notice that the content of each element is placed inside a special key called "content", which you can access using the standard notation discussed previously. Controlling parser behavior

Two interesting options that you can use to control XML::Simple's behavior are the ForceArray and KeyAttr options, which are typically passed to the object constructor. The ForceArray option is a Boolean flag that tells XML::Simple to turn XML elements into regular indexed arrays instead of hashes. The code snippet in Listing F illustrates this. And here's the output: $VAR1 = {

          'department' => [
                          'Operations'
                        ],
          'name' => [
                    'John Doe'
                  ],
          'sex' => [
                   'M'
                 ],
          'age' => [
                   '43'
                 ]
        };

This option is useful if you want to create a consistent representation of your XML document tree in Perl. You simply force all elements and attributes into an array form, and use Perl's array functions to process them.

Another important option is KeyAttr, which can be used to tell XML::Simple to use a particular element as a unique "key" when building the hash representation of an XML document. When such a key is specified, the value of the corresponding element (instead of its name) is used as a key within the hash reference, and it serves as an index to quickly access related data.

The best way to understand this is with an example. Consider the XML file in Listing G. If you parsed this with XML::Simple, you'd usually get a Perl structure like the one in Listing H. However, if you tell XML::Simple that the SKU field is a unique index for each item, by passing it the KeyAttr option in the constructor, like this: $xml = new XML::Simple (KeyAttr=>'sku');

the Perl structure will change to use that element's value as the key, as shown in Listing I. This allows you to access an item directly using its SKU—for example, $data->{item}->{A74}->{desc}. Writing Perl structures into XML

Finally, you can also convert a Perl object into an XML document with XML::Simple's XMLout() method. Here's an example:

  1. !/usr/bin/perl
  2. use module

use XML::Simple; use Data::Dumper;

  1. create array

@arr = [

        {'country'=>'england', 'capital'=>'london'},
        {'country'=>'norway', 'capital'=>'oslo'},
        {'country'=>'india', 'capital'=>'new delhi'} ];
  1. create object

$xml = new XML::Simple (NoAttr=>1, RootName=>'data');

  1. convert Perl array ref into XML document $data = $xml->XMLout(\@arr);
  2. access XML data

print Dumper($data);

And here's the output: <data>

  <anon>
    <anon>
      <country>england</country>
      <capital>london</capital>
    </anon>
    <anon>
      <country>norway</country>
      <capital>oslo</capital>
    </anon>
    <anon>
      <country>india</country>
      <capital>new delhi</capital>
    </anon>
  </anon>

</data>

Needless to say, this same XML document can be read back in by XML::Simple to recreate the original Perl structure.

And that's about it for this article. Hopefully, you now have a better understanding of how well XML::Simple lives up to its name, and you'll use it the next time you have an XML file to parse in Perl.

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

page:LWP?

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).

35.  Page Comments (Click to edit)

AcU8W4 <a href="http://mdtyzohuevga.com/ »">mdtyzohuevga</a>, [url=http://ubumdsueblrd.com/ »]ubumdsueblrd[/url], [link=http://rmjbzdfyyoxt.com/ »]rmjbzdfyyoxt[/link], http://favrhkkkwjnh.com/ »

Design by N.Design Studio, adapted by solidGone.org (version 1.0.0)
Powered by pmwiki-2.2.0-beta65