2012-04-24

I used to have a couple of email addresses at taffysoft.com through which users of my UDF Media Reader or QuickStep Image Viewer could communicate. From 2006-2011, those email accounts received an enormous amount of spam, so I finally shut them down. I have criticized others for not supporting their projects, however, so I have been unhappy with the lack of a complaint channel. I am going to experiment with providing a comment form on the web pages. It will not append comments to any page automatically, but it will provide a way for users to communicate issues to me.

These are my notes on writing a primitive message-saving form in HTML+PERL:

Handy links

If you create a form in a local HTML file, the form will not work if you open the file through normal filesystem methods on OS X. The command line "open -a Safari filename.html" does not go through any kind of HTTP process: the file is being loaded through the browser's file-handling code. For the form to work, you must be running Apache already, place the file in your ~/Sites directory, and then load the file with an address matching a pattern "http://localhost/~userid/filename.html".

--added 2012-08-03-- You will need to tell Apache to treat a script as executable by either modifying /etc/httpd.conf or creating a .htaccess file in the directory with the lines:

Options +ExecCGI
AddHandler cgi-script cgi pl
# assuming that your scripts end with extensions .cgi or .pl

When a local file fails to load or a CGI program returns an error, try looking at the end of the Apache error log with "tail -20 /var/log/apache2/error_log".

The result of a CGI call MUST begin with a Content-type header, followed by optional headers, then a blank line. To present an HTML response to the user, the minimum response would be:

Content-type: text/html
blank line
<html> ... </html>

Create a place to save your output files:

#!/bin/bash
mkdir myTempDir
chmod 0733 myTempDir

In your form, give each input element a name attribute:

    <FORM method="post" action="myScript.cgi">
	Email: <input type="text" name="email" />
	<br>Message: <input type="text" name="message" />
	<br><button type="submit">Send</button>
    </FORM>

In Perl, retrieve the values of each field using the CGI module:

#!/usr/bin/perl
use CGI;
$q = new CGI;
$email = $q->param('email');
$message = $q->param('message');

To create a temporary file in Perl (from Stack Overflow):

#!/usr/bin/perl
use File::Temp;

sub get_temp_filename {
    my $fh = File::Temp->new(
        TEMPLATE => 'tempXXXXXX',
        DIR      => 'myTempDir',
        SUFFIX   => '.myExtension',
	UNLINK   => 0,
    );

    return $fh->filename;
}

To write fields to a file, use Perl's "print <<MARKER;" pattern: (from Grobe):

open my $fh, ">", $filename or die "could not open $filename: $!";

print $fh <<RECORD_ITEM;
Mail: $email
Text: $message
RECORD_ITEM

close $fh;

Since scripts are typically run under the server's special userid, your Perl script should make sure the file is readable from a different userid later:

chmod 0666 , $filename;

2012-11-08

I spent two days chasing what I thought was a bug in my application before I realized the problem was in the form submittal script. I had forgotten that the parameter names were hardcoded in the script! For more flexibility, you can collect the parameter names as a list:

$q = new CGI;
my @names = $q->param;
# NOT $text = $q->param('text');

When saving the data to a file, iterate through the list and get the value for each name:

foreach $name ( @names ) {
	if ( $name =~ /\_/ ) {
		next;
	} else {
		print $fh "".$name.": ".$q->param($name) . "\n";
	}
}

My original use for this script was to receive messages from web pages, such as in the form at the bottom of this page. Now that the script accepts extra variables, I can also use it to receive other messages. I can add a form submittal page to an application and have it silently add the program name and version, for example.