|
© Andy Wilson, 1998
Tips and Tricks: Server Communication in Director
In some of the first articles in this series I looked at how you can get JavaScript talking to Shockwave and Shockwave talking back. This month I want to talk about a different sort of communication in Director, which involves Director (including Director Shockwave) talking to a server on the internet and getting information back in return.
Of course it’s easy enough to recover static information from the net. Your cast members can be linked directly to files on the net or you can use the network capabilities of Director to recover files. For example, the following code will retrieve a text file from the internet and place it’s contents into the variable retrievedText;
set processID = getNetText ("http://www.myserver.com/myText.txt")
……
if netDone (processID) then
set retrievedText = getNetTextResult (processID)
end if
The first step involves telling getNetText to retrieve the required file. GetNetText returns an integer representing this particular internet process, which you will need in order to get the result of the download. At some point later in your projector you can use the netDone command to see whether the downloaded process has completed - you’ll probably put this test in a handler that you call regularly, perhaps in an on idle handler, until the process has completed - and once completed you use getNetTextResult to put the result of the operation (the contents of the file myText.txt) into your variable.
So far so good, but what many people don’t realise is that the target of your download doesn’t have to be a static file at all, but may be a dynamic application sitting on the internet. In fact, you can use getNetText to recover any kind of text from the web, whether it be in the form of a flat file, or the output of a script, a program or even a database. More than that, you can use getNetText to pass information in the opposite direction, so that data entered by the user can be sent back to a database or similar application
For our example, let’s assume that you have a program that asks the user for their name and email PRE, and you want to send that information back to your server to log it into a database. One way to do this is to write a CGI script for your server which stores the information passed to it into a text file. ‘CGI’ here stands for the Common Gateway Interface, a protocol that allows data to be handled dynamically in HTML. The normal way of using CGI is to build an HTML form which the user enters data into, this data is then passed to the CGI script which logs the data and responds appropriately. As far as we are concerned there are two important things about this process. In the first place, the CGI script is called in the same way, and using the same protocol, that other HTML or text file might be called up by a browser. Second, as a result, Director is able to use CGI scripts and programs just as easily as a web browser might.
To see what I mean, consider how a web browser passes information from a form to the CGI script. Let’s assume that the form captures two bits of information, the users name and email PRE, to send to the script. The way this is actually set up in HTML needn’t concern us. Enough to say that you create two form fields, calling them, let’s say, UNAME and UMAIL, and the browser then passes the users data to the script by calling a URL as follows (where I’m assuming that the CGI script is a Perl, file called ‘register.pl’, and is stored in the folder ‘cgi-bin’ in the root of the site);
http://www.mydomain.com/cgi-bin/register.pl?¬
UNAME=Andy&UMAIL=andyw@dircon.co.uk
There are several things to note about this format. The first part of the URL consists of the protocol that is being used to submit the data, in this case, specified as the HTTP protocol, expressed as ‘http://’. The next part of the URL consists of the full URL of the CGI script. Since the CGI script is in the cgi-bin folder, is called ‘register.pl’, and is assumed to be on the server www.mydomain.com, the script URL is, then, www.mydomain.com/cgi-bin/register.pl. The final part of the script, separated from the script URL by the ‘?’ character, consists of the data entered by the user into the form. This data is passed in the form ‘field1name=field1value&field2name=field2value&…’, with one entry for every piece of data being passed.
The point about this rather long description of how CGI works is that Director can pass exactly the same information to exactly the same script by using getNetText to call exactly the same URL. In other words, you could capture the same information within your Director (or Shockwave) application and the data would be logged and dealt with just as it would be if the script had been called by a web browser in the regular way. The code to achieve this would simply be;
set processID = getNetText ("http://www.mydomain.com/¬
cgi-bin/register.pl?¬
UNAME=Andy&UMAIL=andyw@dircon.co.uk")
There’s only one more thing you have to know about CGI to make all this work in your next Director project, namely that the data you pass to the script has first to be ‘URL encoded’. This encoding is not a security measure but simply a way of ensuring that any data entered by the user complies with HTTP protocols, and consists simply of converting some non-alphanumeric characters into their hexadecimal values before putting them into the full URL. You can use the following code to do the encoding;
on URLEncode myString
if not stringP (myString) then return EMPTY
set swapList = [13: "%0D", 32: "%20", 34: "%22", 35: "%23", ¬
37: "%25", 38: "%26", 39: "%27", 44: "%2C", 47: "%2F", ¬
58: "%3A", 59: "%3B", 60: "%3C", 61: "%3D", 62: "%3E", ¬
63: "%3F", 64: "%40", 91: "%5B", 92: "%5C", 93: "%5D", ¬
94: "%5E", 123: "%7B", 124: "%7C", 125: "%7D", 126: "%7E"]
set newString = EMPTY
set len = length (myString)
repeat with x = 1 to len
set char = char x of myString
set charNum = charToNum (char)
set res = getaProp (swapList, charNum)
if not (voidP (res)) then
put res after newString
else
put char after newString
end if
return newString
end
Using this code, you can build your URL as follows;
Set scriptURL = "http://www.mydomain.com/cgi-bin/register.pl"
Set userName = URLEncode (userNameInput)
Set userEMail = URLEncode (userEMailInput)
Set processID = getNetText (scriptURL & "?" & "UNAME=" & ¬
userName & "&" & "UMAIL=" & userEMail)
You would then recover the result of the process as before (perhaps you write the script so that it returns either "OK" or some sort of warning if the process of saving the data failed in some way). You now have a script that sends user data off to be saved on a database and checks that the process has completed successfully. Of course, you can have your script on the server do anything it is capable of with the data you send to it – mailing it on to you, maintaining a high score database, whatever.
Of course there’s a big bit of this process that I’ve left out so far – writing the CGI script. In fact, although I’ve repeatedly talked about scripts, your CGI may be implemented as a program. CGI is simply a protocol, and you can write CGI programs in many languages, including Perl, Visual Basic, C and C++. Perl is one of the oldest and most popular ways of implementing CGI, being both widely supported by both UNIX and NT based servers, relatively easy to write, and easily portable. To do the kind of work we are discussing you are either going to have to learn Perl or get someone to write your scripts for you. Before doing anything though, check with your web space provider that they support Perl and that you will be able to install and run your script on the server.
To get you started, here is some Perl code that could accept the data passed in the example above and store it in a comma delimited file (easy enough to import into any database). You may have to modify it to get it to work for you (for example, the first line tells UNIX systems where to find the Perl interpreter on the system to actually run the script, and will have to be modified appropriately), but any decent service provider will help you started with CGI programming, and there are plenty of Perl resources on the net to call on. If you run your own server, there are several Perl interpreters available freely on the web, and installing them is usually pretty straight forward.
Anyway, as I said, here is some typical code that would deal with the data produced by the code above. In a real world application this code would need a little extra work, perhaps performing some kind of input validation, perhaps. Nevertheless, just studying the code and getting it working on your server should teach you all you need to know to be able to perform most basic tasks in Perl;
#!/usr/local/bin/perl5
# a constant, used in locking your
# data file when writing it
$LOCK_EXCLUSIVE = 2;
# call the subroutine below to extract
# the data passed to the script
%queries = &parsecgi;
# now set some variables by plucking
# the necessary data
$uname = $queries{'UNAME'};
$uemail = $queries{'UMAIL'};
# start printing the response that will be
# returned to the calling program
print ("HTTP/1.0 200 OK\nContent-type: text/html\n\n");
# this code determines the format
# of the written data
# here I’m telling it to write the
# two values passed separated by a comma
format USER_DATA =
@<<<<<<<<<<<<,@<<<<<<<<<<<<
$uname, $uemail
.
# open (or create and open) the file user.dat
# in the same directory as the script
open (USER_DATA, ">>user.dat");
flock (USER_DATA, $LOCK_EXCLUSIVE); # lock the file
write USER_DATA; #write your data
close (USER_DATA); # close the file
# tell the user that the process completed successfully
print ("OK");
###########################################
# subroutines used to capture the
# data passed in the calling URL
###########################################
# captures the data passed to the script
#and stores each of the name=value pairs
# passed into a hash table
sub parsecgi {
my ($data) = ();
if ($ENV{'REQUEST_METHOD'} eq 'POST')
{
# read from STDIN
local ($len) = $ENV{'CONTENT_LENGTH'};
if (read (STDIN, $data, $len) != $len) {
die ("Error reading 'POST' data\n");
}
}
else
{
# fetch from environment variable
$data = $ENV{'QUERY_STRING'};
}
local (%args) = ();
# split the name/value pairs
foreach $qs (split ('&', $data))
{
# now split name and value
my ($name, $val) = split ('=', $qs);
# URL decode
$name = &url_decode ($name);
if (defined ($qs{$name}))
{
# multiple values - append using \0 separator
$qs{$name} .= "\0" . &url_decode ($val);
}
else
{
# store it
$qs{$name} = &url_decode ($val);
}
}
# return results
%qs;
}
# decodes any of the characters you encoded
# using the URLEncode handler above
sub url_decode {
local ($s) = @_;
$s =~ tr/+/ /;
$s =~ s/%([0-9A-F][0-9A-F])/pack("C",oct("0x$1"))/ge;
$s
}
That’s really about all there is to it. As I said before, you’re going to need to polish up your Perl skills, but I think you’ll agree it’s worth the effort in order to start being able to create some really dynamic and interesting net-aware Director applications. Remember that you can pass data in both directions so, for example, instead of passing user information to be logged to a file, you could send a search query and the script could return the result of a database search, where the database is stored on the server. That way your user could receive absolutely up to date information even if the Director application they are running is months or even years old. As I think you’ll have grasped by now, the combination of Director and server-side programming opens the door to making some very powerful applications that take advantage of both the media richness of Director’s authoring environment and the timeliness of data accessed from the web.
Don’t forget that this and all of the previous articles in this series are available on the web at http://www.andyw.com/. Comments on the series and suggestions for suture articles can be mailed to me at andyw@dircon.co.uk.
|