After implementing the Hello World with plain CGI, the next step is to implement the Echo.

Echo without any module

The first solution I'll show is without using any module. You should probably never use this. The reason I am showing it is that I hope that this will give you some background information on how the web, HTTP, and CGI work.

When you access a web page, the web server, in our case Apache, will create a number of "environment variables". Put them values. Run the appropriate program on the server and whatever that program prints "on the screen" will be captured by the web server and sent back to the browser. That's why in the Hello World example we simply used print.

The user sitting in front of the web browser can even send parameters to the program by adding a question mark (?) after the URL followed by key-value pairs. Like this: http://127.0.0.1:8080/cgi-bin/echo.pl?name=Foo The web server will take all the content after the ? mark and put it in an environment variable called QUERY_STRING.

Exactly the same will happen if the HTML page has a form that you fill out. (Actually, it will only work this way if the form method is GET, but let's not jump ahead.)

As with any other environment variables we can access the content of QUERY_STRING via the %ENV hash.

Our first solution looks like this:

examples/plain-cgi-echo.pl

#!/usr/bin/perl
use strict;
use warnings;

print "Content-type: text/html\n\n";
my $name = '';
if ($ENV{QUERY_STRING}) {
    ($name) = $ENV{QUERY_STRING} =~ /^name=(.*)$/;
}

print "Hello $name\n";

If we access this page like this:

http://127.0.0.1:8080/cgi-bin/echo.pl

the QUERY_STRING will be empty. Therefore, after printing the Content-type in the HTTP header, we print "Hello". The variable $name will remain empty.

On the other hand if the user types in

http://127.0.0.1:8080/cgi-bin/echo.pl?name=Foo

Then the QUERY_STRING will contain name=Foo. We will enter the if condition where we'll extract the value (Foo) from the QUERY_STRING and assign it to the $name variable. The result will be "Hello Foo".

As you can see this works, but parsing QUERY_STRING is an ancient technique. There are plenty of libraries that would do it for you. Some of them being also ancient already.

Parsing QUERY_STRING, and other sources of input is the main service modules such as CGI, CGI::Simple, and Plack provide.

Echo using CGI

Switching from manual parsing of the QUERY_STRING to using the CGI module makes the code cleaner. We can use the header method of the CGI instance to create the header as we did in the Hello World example, but the interesting part is that $q which is the instance object created from the CGI class has a method called param. If we give it a string, it will return the corresponding value from the QUERY_STRING.

examples/cgi-echo.pl

#!/usr/bin/perl
use strict;
use warnings;

use CGI;
my $q = CGI->new;
print $q->header;

my $name = $q->param('name') || '';

print "Hello $name\n";

If there was no value it will return undef. Therefore, in order to avoid getting Use of uninitialized value warnings, we set the default value to the empty string.

Echo using CGI::Simple

Instead of the heavy-weight CGI module we can also use the much lighter CGI::Simple module as well:

examples/cgi-simple-echo.pl

#!/usr/bin/perl
use strict;
use warnings;

use CGI::Simple;
my $q = CGI::Simple->new;
print $q->header;

my $name = $q->param('name') || '';

print "Hello $name\n";

Echo with form using CGI

The earlier examples relied on the user typing in

http://127.0.0.1:8080/cgi-bin/echo.pl?name=Foo

as the URL.

That's not how we are used to web applications. Hence in the next two example we'll see how to create a real HTML form that when filled out will send the above request to the server.

examples/cgi-echo-form.pl

#!/usr/bin/perl
use strict;
use warnings;

use CGI;
my $q = CGI->new;
print $q->header;

my $text = $q->param('text');


my $html = <<'HTML';
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport"
     content="width=device-width, initial-scale=1, user-scalable=yes">
 
  <title>Echo</title>
</head>
<body>
<form>
<input type="text" name="text">
<input type="submit" value="Echo">
</form>
HTML

if (defined $text) {
    $html .= "You wrote <b>$text</b>";
}

$html .= <<'HTML';
</body>
</html>
HTML

print $html;

The heart of the solution is the form element in the HTML which has two input elements. The first one has type="text" which means it will be a text input box. The second one has type="submit" which means it will be a submit button with the text "Echo" on it. If the user types some text in the input box and clicks on the submit button, the browser will send a request to the server adding ?text=some text to the end of the URL.

Instead of returning a plain string like in the previous solutions, here we build a longer string which is a simple HTML 5 page.

If the variable $text has any defined value in it, then it will be included in the HTML with bold letter.

Echo with form using CGI::Simple

This is exactly the same solution using CGI::Simple instead of CGI.

examples/cgi-simple-echo-form.pl

#!/usr/bin/perl
use strict;
use warnings;

use CGI::Simple;
my $q = CGI::Simple->new;
print $q->header;

my $text = $q->param('text');


my $html = <<'HTML';
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport"
     content="width=device-width, initial-scale=1, user-scalable=yes">
 
  <title>Echo</title>
</head>
<body>
<form>
<input type="text" name="text">
<input type="submit" value="Echo">
</form>
HTML

if (defined $text) {
    $html .= "You wrote <b>$text</b>";
}

$html .= <<'HTML';
</body>
</html>
HTML

print $html;

Echo using PSGI

CGI and CGI::Simple can work for you, but you'd be probably better off using PSGI.