Perl for Win32 Frequently Asked Questions (FAQ)

Main Page

7. Web Programming (CGI and PerlIS)

7.1. What is HTTP, and how do I get more information on it?

HTTP (HyperText Transfer Protocol) is the protocol that Web browsers use to talk to Web servers. The official specification for the HTTP standard is available on the W3 Consortium web server at:

http://www.w3.org/pub/WWW/Protocols/

Some more readable introductions can be found on the Yahoo HTTP page at:

http://www.yahoo.com/Computers_and_Internet/Internet/World_Wide_Web/HTTP/

7.2. What is CGI, and how do I get more information on it?

CGI (Common Gateway Interface) is a protocol used by Web servers to run server programs. Scripts that support the CGI protocol are sometimes called "CGI scripts"; this leads to the unfortunate misperception that CGI is a language of its own.

The classic information on CGI is available on the NCSA server at:

http://hoohoo.ncsa.uiuc.edu/cgi/

If you haven't read this, read it now. If it doesn't click for you, you can check the Yahoo CGI page at:

http://www.yahoo.com/Computers_and_Internet/Internet/World_Wide_Web/

    CGI___Common_Gateway_Interface/

(All one URL, leave out the line feed).

Try also the following URL for CGI programming in Perl:

http://www.perl.com/perl/faq/perl-cgi-faq.html

If you still don't get it, try one of the "get-rich-quick-by-writing-CGI-scripts" books at your local bookstores.

7.3. How do I return a graphics file from a CGI script?

One of the big differences between UNIX and Win32 platforms is that on Win32 there's a difference between text or ASCII files and binary file. To return a graphics file, you need to specify that the file is a binary file, and that the standard output stream should accept binary data. Try something like this:

    $MY_FILE_NAME = 'Penelope.jpg';
    $CHUNK_SIZE = 4096;

    open( MY_FILE, "<$MY_FILE_NAME" )
      or die( "Can't open $MY_FILE_NAME: $!\n" );

    print "Content-type: image/jpeg\r\n";
    print "\r\n";

    binmode( MY_FILE ); # These are crucial!
    binmode( STDOUT );

    while ( $cb = read( MY_FILE, $data, $CHUNK_SIZE ) )
    {
      print $data;
    }
    
    close( MY_FILE );

PerlIS scripts need to add some extra header information, as noted below.

7.4. My CGI scripts don't seem to run right under PerlIS. What's wrong?

Scripts running under PerlIS are a lot like "nph" scripts, as defined in the CGI/1.1 specification (see question 7.2). You have to specify the HTTP response status line as well as all headers for the response.

Here's a sample that works under PerlIS:

    print <<"END";
    HTTP/1.0 200 OK
    Content-Type: text/html

    <HTML>
    <HEAD>
      <TITLE>PerlIS Response</TITLE>
    </HEAD>
    <BODY>
      This is a PerlIS response.
    </BODY>
    </HTML>
    END

If you don't add the HTTP status line, as above, the browser will assume that it is talking to an HTTP/0.9 server (the HTTP spec says that the difference between a 1.0 and an 0.9 server is the presence of the status line, and that good browsers should accept 0.9 responses). It will then try and treat your response headers as part of the HTML you are returning, so your headers will show up in the browser window, which you probably don't want.

There's a misperception that if you don't add the HTTP status line, PerlIS will add one for you, plus a Content-Type header. This is false, and can be checked with a little sockets coding.

You should probably review the HTTP spec (see question 7.1) if you're going to do any complicated PerlIS programming.

Philip Nelson has written a good exposition on the differences between PerlIS and CGI (http://www.dct.com/~nelsonp/IISHeader.html).

[Any other suggestions?]

7.5. How does my script know if it's running under Perl for Win32 or PerlIS?

PerlIS sets an environment variable, PERLXS, for scripts that are executed under PerlIS. The following script will run as a perl.exe CGI script or as a PerlIS script. It checks the environment variable to see if it needs to print out a status line.

    print "HTTP/1.0 200 OK\r\n" if $ENV{PERLXS} eq "PerlIS";
    print <<"END";
    Content-Type: text/html

    <HTML>
    <HEAD>
      <TITLE>Both</TITLE>
    </HEAD>
    <BODY>
      This script will work with perl.exe and PerlIS.
    </BODY>
    </HTML>
    END

7.6. What CGI modules run with Perl for Win32?

The CGI.pm module works with Perl for Win32. It's available at

http://www-genome.wi.mit.edu/ftp/pub/software/WWW/cgi_docs.html

Note that you need to change the $OS variable in CGI.pm before it will work correctly with Windows NT or Windows 95.

[Any other CGI modules work with Perl for Win32? -ESP]

7.7. How do I use redirection in my script?

You can use redirection to point the client browser to another file or script, usually in a way that's invisible to the user. It requires using the Location header as well as a special HTTP code, if you're using PerlIS. The following code redirects the browser to a simple text file.

    print "HTTP/1.0 303 See Other\r\n" if $ENV{PERLXS} eq "PerlIS";
    print <<"END";
    Content-Type: text/plain
    Location: /text/mytextfile.txt
    END

Note that, if CGI (perl.exe) is used, the _server_ will retrieve the location and send it to the browser, so the browser thinks that the content is from the URL of your script. If PerlIS is used, the _browser_ has to retrieve the content itself, and the URL of the resource you redirected to will be displayed to the user.

If you're using PerlIS, you should check out HTTP status codes 301 (Moved Permanently), 302 (Moved Temporarily), and 303 (See Other) to see which is most appropriate to your application. See question 7.1.

7.8. What are cookies and how do I use them?

Cookies are packets of data that a server can give to a client to identify the client in future interactions. They were first defined by NetScape, and the definition of cookies can be found at:

http://home.netscape.com/newsref/std/cookie_spec.html

You can set the cookie as one of the CGI (for PerlIS, HTTP response) headers in your file. You can get the cookie, if one is passed, throught the HTTP_COOKIE environment variable. Here's a simple script that counts how many times a user has accessed a page:

    $cookie = $ENV{HTTP_COOKIE};
    
    $count = ( $cookie ) ? (split( "=", $cookie ))[1] : 0;

    $count++; # counting this visit.

    if ( $count > 1 )
    {
      $welcome = "Welcome back for visit #$count to this page!";
    }
    else
    {
      $welcome = "Welcome to my page for the first time!";
    }

    $cookie = "COUNT=$count";

    print "HTTP/1.0 200 OK\r\n" if $ENV{PERLXS} eq "PerlIS";

    print <<"END";
    Content-Type: text/html
    Set-Cookie: $cookie

    <HTML>
    <HEAD>
      <TITLE>Cookie Sample</TITLE>
    </HEAD>
    <BODY>
      $welcome
    </BODY>
    </HTML>
    END

To set persistent cookies, define domains, specify expiration dates, etc., refer to the specification above.

7.9. How do I get the e-mail address of the user?

It's not, in general, possible to get the e-mail address of a user without asking them for it. If you need an e-mail address, provide the user with a form to fill in an address.

The HTTP specification (see question 6.2) defines an HTTP request header , "From", that can contain the e-mail address of the user making the connection. Your script can retrieve it using the environment variable HTTP_FROM. However, it's rarely provided and can't really be counted on.

There are all kinds of sneaky ways to determine where requests come from -- like checking the IP address that was used to connect -- but you can't figure out the e-mail address of the user this way.

Generally, it's considered a violation of the user's privacy to get their e-mail address without their knowledge. Perhaps that's why it's so difficult.

7.10. I need a CGI script to do X. Has anyone done it before?

There are several CGI script archives on the Web. You may not be able to find exactly the script you want, but you will probably find something that can be adapted to your needs.

Two of the most famous script pages are:

[Others? -ESP]

Note that most script archives have UNIX-targeted scripts, and you may have to make some adaptations to them to make them run (see question 5.7).

This is one of the most common questions on the Perl-Win32-Users list. Occasionally it's phrased more like "I have a program to write. Here are the specs. Please e-mail it to me by Friday." Hopefully the reader can understand why these messages are usually answered with flames or ignored.

7.11. How do I test my CGI programs that take arguments without running them through the Web server?

The hard way to test your CGI programs from the command line is to set up environment variables and a standard input stream just like a Web server would (see the CGI 1.1 specification for more details on this -- question 7.2).

The easy way is to use CGI.pm, the Perl module for CGI programming. It provides an easy mechanism to run CGI programs, with arguments, from the command line.

7.12. The "Content-Type" header I output from my CGI script shows up in the Web browser. What gives?

You are using PerlIS as your Perl interpreter on an IIS Web server (this is set up by default by the install.bat program), but you're not outputting an HTTP status line. See question 7.4 for details on how to fix your problem.

7.13. When I try to run a CGI script from my browser, it tries to download a file of type "application/x-perl" instead. What gives?

Your Web server has been misconfigured. It doesn't know that it should execute your Perl program, so it's just returning it to the browser. See section 6 of this document for details on how to configure your particular Web server to know that Perl scripts should be executed.