Notice: This material is excerpted from Special Edition Using CGI, ISBN: 0-7897-0740-3. The electronic version of this material has not been through the final proof reading stage that the book goes through before being published in printed form. Some errors may exist here that are corrected before the book is published. This material is provided "as is" without any warranty of any kind.
The Macintosh is one of the most popular server platforms on the Internet. One explanation for this is the ease that HTTP servers can be operated on the platform. With a simple button click, you can launch MacHTTP or its commercial sibling, WebSTAR. Both applications, along with many of the rapidly increasing number of MacHTTP server applications, support the use of CGI scripts for Web site customization.
As with other platforms, you have several options with which to program CGI scripts. One of the more popular languages in which CGI scripts are developed is the MacOS scripting language AppleScript. Freely bundled with recent versions of the MacOS, AppleScript offers a programming language with sophisticated natural language constructs. Users can use AppleScript to develop applications that manage applications and files within the operating system. However, AppleScript can be used to process information sent from Web browsers to Web servers.
This chapter discusses the following concepts:
Before I discuss CGI scripting with AppleScript, it's prudent to discuss the AppleScript environment. In this section, I'll cover the AppleScript language, environment, and information necessary to develop applications. This section isn't intended to be a comprehensive presentation of AppleScript but merely an introduction to the language to a level that will allow you to use and even create some CGI applications. For a more complete examination of the AppleScript environment, you should buy one of the several good books on the subject from your local computer bookstore.
Long-time Macintosh users have probably used the authoring application HyperCard at one point. Native to HyperCard is the scripting language HyperTalk. HyperTalk introduced Mac users to a sophisticated and natural programming language with which complicated HyperCard stacks could be created. In contrast to more established programming languages such as C, Pascal, and FORTRAN, HyperTalk allowed users to control various aspects of a HyperCard stack in familiar and almost conversational syntax.
AppleScript is the MacOS system-level scripting language and has some similarity to HyperCard's HyperTalk but is applied in a much broader context. AppleScript can bind the operating system with AppleScript-aware applications to automate and customize operations within the MacOS. For example, you can create an AppleScript that can open your e-mail application, open Netscape to a certain URL, copy cells from a table from a Microsoft Excel spreadsheet, and paste them into a Microsoft Word document all without you having to open the applications directly.
With System 7.5, AppleScript became more accessible to Mac users for two reasons. First, and perhaps most importantly, AppleScript and the associated Script Editor were now bundled freely with the operating system. Secondly, the Finder became scriptable and recordable under AppleScript. This facilitated the development of AppleScripts in a manner that will be discussed later in this chapter. Next, I'll discuss some of the tools at your disposal with which you can create AppleScript applications.
When System 7.0 of the Macintosh operating system was introduced in 1991, it suddenly became much easier for typical users to customize their systems. Users could alter the appearance of the desktop, add applications to the Apple Menu, and access other Macs by using a native AppleShare protocol.
Another new feature in this operating system release was the introduction of a message-handling system known as AppleEvents. Unseen to the user, AppleEvents flit back and forth between applications carrying various pieces of information. For example, Web browsers use AppleEvents to launch helper applications to view particular files; through AppleEvents, a browser starts the viewing application and transmits the newly downloaded file for interpretation.
At first, AppleEvents received very little attention among the Macintosh development community. The Finder supported only the most fundamental AppleEvents; even so, System 7.0 used these operations to open and close applications and print documents. With later versions of the MacOS, more AppleEvents became defined, allowing a wider variety of information to pass between applications.
AppleScript uses AppleEvents to create scripts that can command and control Finder operations as well as other applications. The framework for working with AppleEvents is known as the Open Scripting Architecture. The OSA provides an internal mechanism for scripting environments, such as AppleScript and HyperCard (versions later than 2.2), to use AppleEvents for interapplication communication.
Other scripting environments are available for the MacOS besides AppleScript. UserLand developed Frontier, which is a C-like, Power Mac-native, multithreaded scripting environment whose scripting language, UserTalk, provides much of AppleScript's functionality. What's more, CE Software's macro package, QuickKeys, offers a similar scripting environment.
If you're running at least System 7.5 on your Macintosh, you already have access to the software you need for this chapter. As of this writing, System 7.5 has been in wide use for more than a year, so it's a very stable implementation operating system. If you don't have it, I recommend that you upgrade to System 7.5 to run your CGI scripts. If you haven't installed or don't plan to install System 7.5, you must procure a copy of AppleScript 1.1 (or later) and Script Editor 1.1 (or later). You'll be at a disadvantage in running AppleScript with operating systems earlier than System 7.5, as the Finder isn't scriptable. To script the Finder in systems before 7.5, you need to install the Finder Scripting Extension that comes with the AppleScript package. To take full advantage of AppleScript, especially outside your CGI scripting ambitions, I strongly recommend that you upgrade to System 7.5.
Along with the AppleScript extension that resides in the Extensions folder, the AppleScript package comes with a utility known as the Script Editor. This utility allows you to develop AppleScript in a familiar text-editing environment. Although you could create script text using a conventional editor such as SimpleText or BBEdit, you'll need the Script Editor to check your syntax and actually create AppleScript applications.
Double-click the Script Editor application icon; you should see a window similar to that shown in figure 24.1. The top part of the window is the Description window, which is used to enter comments about the script, your name, your e-mail, or your excuses why it may not work. The lower part is the Scripting window, into which you enter your AppleScript commands.
Fig. 24.1
Within the main AppleScript Editor window, you can record, run, and check the syntax of your scripts.
Don't worry, it's not just you. By default, the main Screen Editor window is much too small to do any real work. You need to resize the window to write your scripts. When you open a script with the Script Editor, the window sizes to fit the script. You can set the default window size by opening the Script Editor File menu and choosing Set Default Window Size.
Notice the four buttons arranged horizontally between the Scripting and Description windows. The utility of these buttons can be summarized as follows:
You can execute the script by clicking the Run button. This action plays back the script you've just recorded. You'll see your actions mimicked by the script with application windows opening and closing. You probably won't encounter any errors if you run the script soon after creating it, but if you do, the Script Editor will return an appropriate message.
You also can compose a script from scratch with AppleScript syntax much as you would with any programming language. The Script Editor offers some rudimentary editing functions. and you can use the Check Syntax button to validate your script. What's more, the script formatting will change from a homogenous font to a display similar to that shown in figure 24.1, where various AppleScript commands appear in bold type and the looping constructs are indented accordingly.
To reuse the script over a long period of time, you'll eventually have to save the script to disk. You have several options with which you can save your files. They include straight text files, compiled scripts, and applications. Each brand of script is identified by a distinct icon, as shown in table 24.1. Table 24.1 AppleScript Saving Options
Icon | Type | Description |
[text.ic] | Script Text | Script is editable through any text editor. |
[script.ic] | Compiled Script | Script is executable through the Script Editor. |
[app.ic] | Application | Script can be run without the Script Editor. |
A text-only script is usually the first stage of script construction. In this step, you'll probably be building and modifying your script, so you should save it in an accessible format. You can't run the script at this point without checking the script syntax. Text-only scripts can be opened with other text editors.
Although text-only AppleScripts can be opened with MacOS text editors, some of the characters required in the AppleScript syntax are non-standard and don't adhere to the ISO-8859-1 character standard. When transferring text-only AppleScripts over the Internet (FTP, e-mail, and so on), it's best to encode the scripts using a binary-to-ASCII conversion scheme such as MIME (AppleSingle), BinHex, or MacBinary. Otherwise, key characters may not transfer with the script.
When you save a script, the Script Editor will want to compile it for you. For large uncomplicated script, you may not want to, or be able to, compile when you save it. Hold the Shift key down when you save the document to suppress compilation.
If your AppleScript syntax is correct, you can save your script as a compiled script. This allows you to edit and run the script within the Script Editor.
If you want to run your script without the inconvenience of opening the Script Editor, you can save it as an application. Your script then acts like any other Macintosh application. Simply double-clicking the application icon executes your AppleScript commands. You can also create aliases of AppleScript applications and install them in your Apple Menu Items folder. Many of the tasks performed in System 7.5's Speakable Items folder are compiled AppleScript applications. AppleScript applications require less space than normal applications as much of the work is performed by the system software.
You can save your application so that it will display the contents of the Description section in a dialog box. The user then can choose to quit or run the application based on the script description.
You may have reason to store your script in a format that prevents other users from editing your script. For this reason, you may want to save your script by using the File menu's Save As Run-Only option. A copy of your script will be saved as a run-only compiled script or application.
If you want to save your script as a run-only application, you need to have compiled it correctly. You'll be presented with two additional saving options (see fig. 24.2). Clicking the Stay Open check box causes the application to stay open until the user closes it (if a splash page was presented) or until an AppleEvent closes it. Clicking the Never Show Startup Screen check box prevents the splash page from appearing.
Fig. 24.2
When saving an AppleScript application as run-only, you can opt to allow it to stay open after it's executed, or to suppress the splash page.
When you save the file as a run-only application or compiled script, you'll no longer be able to edit the script, so be sure to save a backup copy.
It's advised that you save your CGI scripts by using the Save As Run-Only option. Also, you need to activate both the Stay Open and Never Show Startup Screen check boxes in the Save as Run-only dialog box. AppleScript CGI scripts need to stay open for a period of time after activation; allowing the splash screen to activate would interfere with communication between the Web server and the script.
Now that you've learned how the Script Editor works, it's time to start developing scripts. One easy way to produce a script is to tell the Script Editor to record your Finder actions. This is a useful and instructive procedure for learning how to program AppleScript, but it's not a procedure that you use to develop CGI scripts. For this reason, I will cover elementary AppleScript principles as though you were developing the script from scratch. The intent of this section is to teach you enough AppleScript to be able to understand the examples and to create some elementary CGI scripts.
You use AppleScript commands to tell the system to do things. Commands have optional parameters for use in performing some kind of action. For example, if you want to print a string, use the return command to display a string to the Result window, which displays output when the script is run in the Script Editor. For example, the simple script
return "hello world"
displays the string "hello world" in the Result window (see fig. 24.3). Any expression in a return statement is evaluated and converted to a variable called result. This variable is displayed in the Result window.
After you compile your script, notice that the Script Editor converts certain words to boldface. Later, you'll see that comments are transferred to italicized text. Operators, variables, and keywords all can be tagged with different typefaces. You can customize these options by using the Edit menu's AppleScript Formatting option.
In AppleScript, string expressions are denoted with double quotation marks. This is an important to note, as many of the scripts you write for your Web server will be returning strings to be interpreted by Web browsers as HTML.
Fig. 24.3
The Result window displays AppleScript output within the Script Editor.
return works without parameters as well. A single return statement in an AppleScript code adds a carriage return to the result variable.
Variables are treated in AppleScript much as they're treated in other applications. You set the variables equal to certain values by using the set command. For example, the script
set sum to 7 + 4 return sum
returns a result of 11. AppleScript maintains the usual stable of mathematical operators: +, -, /, and *.
With AppleScript, you can issue one value of result for each script. To return a more complicated variable, you have to concatenate several values. For example, the script
set title to "Boss" return title & " Hog"
returns a result of
"Boss Hog"
In the preceding example, I set the variable title to "Boss". To create a result comprised of several strings, I needed to concatenate the two strings using the & character.
Very often, you'll want to develop a statement that can't fit within the margin of the Script Editor or a document. In that situation, you'll want to use the continuation symbol ([ct]) by pressing Option+L. You can break the line into smaller segments, provided that you've installed the character at the end of the line. If you need to continue a long string to the next line, you can concatenate the first part of the string with the continuation character, like this
"My aunt, uncle, and cousins " & [ct] "are coming for a visit next week."
This string is converted to the result, without any trace of a carriage return, as
"My aunt, uncle, and cousins are coming for a visit next week."
This symbol will prove important in your CGI scripting.
Like any other programming effort, you may want to leave comments for explanation or illustration purposes. AppleScript comments serve a different purpose than the text in the Description window, as you can place comments within the script text to explain various parts of the script. All text to the right of a comment descriptor or within a comment field is ignored by the AppleScript processor.
You can denote a comment through one of two means. You can use double hyphens, --, to tell the compiler to ignore all text to the right. For example, the compiler sees the following script
-- This is a short test set pet to "dog" -- Dogs are my favorite pets.
and interprets it as
set pet to "dog"
If-then statements are expressed in AppleScript in a way that's very similar to other programming languages. For example,
set today to day of (current date) -- today is set to the current day of the week if today = "Sunday" then return "Go to Church" -- this is returned on Sundays else return "Stay home" -- this is returned during the rest of the week end if
AppleScript uses the usual logical operators-AND, OR, NOT, =, >, <, >=, and <=. You'll find that AppleScript often offers you several ways to express the same concept; logical operators are one example of this. For example, rather than use the operator = in the preceding example, you can substitute any of the strings equal, equals, equal to, or is equal to. The same is true of the other operators.
One of the more complicated AppleScript constructs is the handler. The syntax is too broad to give an example here, but the handler is an integral part of the AppleScript CGI. At the risk of oversimplifying the description of handlers, they can be described as subroutines that are executed when a certain event takes place. The next section looks at handlers more closely.
Scripting additions are very special types of system extensions. They can be found in the Scripting Additions folder in your Extensions folder. These tools are, in effect, external software libraries that extend the AppleScript vocabulary. Such a library is often referred to as an OSAX (Open System Architecture Extensions, pronounced oh' sax) or, in the plural form, OSAXen.
AppleScript maintains a very limited vocabulary by design; the language itself maintains a simple structure with many of the sophisticated tasks performed by the scripting additions. OSAXen are often programmed in an external language such as C or Pascal rather than AppleScript itself. As a result, performance is enhanced by using one of the commands inherent in an OSAX. Some of the scripts examined later in this chapter will use OSAXen designed to aid in CGI processing. AppleScript itself can handle these tasks, but the use of OSAX commands greatly speeds up the processing. This is desirable for all applications, but especially CGI processing.
OSAXen-like objects exist in scripting environments other than AppleScript. HyperTalk, for example, uses external commands (XCMDs) and external functions (XFCNs), which work much the same as OSAXen. You can tell whether a file is an OSAX by peeking at its file type with a resource editor such as ResEdit or File Buddy. If it's an OSAX, its file type will be osax.
Up to this point, I've just touched on some AppleScript fundamentals; there's a lot more to AppleScript than I've covered here. As you learn more about AppleScript, you'll be able to develop more sophisticated CGI scripts and more sophisticated scripts for your everyday use. Later in this chapter, you'll create some rudimentary CGI scripts and examine some more complicated scripts used by the AppleScript community.
As discussed throughout this book, the CGI mechanism is relatively straightforward. The browser encodes the data sent from HTML forms into a URL and hands it off to the server. The server, not really concerned with the content of the form data, passes it off to the CGI script. The CGI script, regardless of the language in which it's developed, processes the data and (we hope) returns some object to the server. This object can be in the form of an HTML page, a graphic image, or any sort of data that can be interpreted by the Web browser. The Web server is oblivious to the content of the CGI output but dutifully feeds the data to the browser.
AppleScript works much like the other CGI languages discussed in this book. The AppleScript CGI and Mac Web browser transfer data back and forth to one another. The MacOS has no concept analogous to UNIX's standard input and output so that a different means of communication between the two applications is needed. For this reason, the two applications use AppleEvents, the MacOS interapplication data transfer mechanism, to transfer data between one another.
The major Mac Web browsers (which, as of this writing, include MacHTTP, WebSTAR, and InterServer Publisher) rely on an AppleEvent not only to start up the CGI application but also to pass the HTML form data. This AppleEvent is composed of two parts: the class WWW and the actual event sdoc. These parts must be separated with the Greek letter omega, [go].
A different AppleEvent, WWW[go]srch, is required when the CGI is performing searches. Discussion of this type of CGI is beyond the scope of this chapter. What's more, the search interface passes less information to the script, which limits its usefulness as a CGI mechanism.
The WWW[go]sdoc AppleEvent is sent by the HTTP server. Included in this event is the information obtained from the HTML form. Your AppleScript CGI needs to do the following:
You'll need the following applications available to write and test your CGI scripts:
These applications don't need to reside on the same machine. In fact, some AppleScript authors claim that you'll run into problems running the server, the CGI, and the browser on the same machine. Therefore, it's advisable to edit your scripts and HTML on a local Macintosh, run your Web server on a remote Mac, and use an FTP application such as Anarchie or Fetch to transfer your scripts to a CGI folder. If your two machines are on a local area network, you can transfer the files using AppleShare. In this way, you'll test your scripts as others use them.
I also recommend that you organize your Web server folder into separate folders for HTML and CGI scripts. In my MacHTTP folder I keep a folder named Test, which I use to install my test scripts. Similarly, I store CGI scripts in a folder called CGI.
It's possible to develop AppleScript CGI scripts without having to use AppleEvents to transfer data between the Web server and the CGI script. AppleEvents aren't used when the AppleScript CGI is stored as a text-only script. Between the time that the Web server loads a text-only AppleScript CGI into RAM and when it sends the script to AppleScript for processing, the server adds the variables defined by the HTML form page to the AppleScript. Therefore, the information passed along with the form is directly inserted into the script, and no accommodations need to be made for processing AppleEvents.
The advantage to running text-only AppleScript is that you can edit the script and pass it to other users for their use. Furthermore, the text-only CGI quits after execution. This can be advantageous in that CGI scripts take up your server's RAM just like other applications and therefore must compete for server resources. Having the CGI quit after executing minimizes the RAM requirements on your server. An application CGI script needs to self-terminate using a process I'll describe later in the chapter.
The drawback to processing text-only files is that they must be compiled each time they're run. Also, the server must preload all the form variables onto the script before processing ever begins. This is a wasteful use of resources for all but the most elementary scripts. Large scripts will execute much faster if they're stored as run-only applications.
Your server should be set up to work with text-only scripts and applications. However, you may want to verify that your server's suffix mapping is configured so that files with .script, .cgi, and .acgi suffixes are interpreted with the MIME type text/html. Consult your Web server documentation for clarification.
A simple example is needed to show how you can get a simple AppleScript to return a Web page to your browser. First, you need to develop a simple AppleScript. Open the Script Editor (or any text editor) and type the following:
return "This is my first script!"
Store this script as Test-1.script. If you're using the Script Editor, save the script as a text file, not a compiled script or application, and place it in the Web server's CGI folder. Now you need to create a simple HTML form to activate this simple script. There are many ways to do this, but for this example you'll use a simple Submit button. The relevant form statements are
<FORM ACTION="http://cgi-test/cgi/Test-1.script" METHOD=POST> This is a test <INPUT TYPE="submit" VALUE="Submit Form"> </FORM>
Note
You can activate this script without using HTML forms in several ways. In Netscape Navigator, for example, you can submit the CGI script URL in the locator box. You also can enter the URL in a simple HTML anchor, as in <a href=cgi_script_URL>...</a>.
See "The <FORM> Tag" p. xxx, for more information on using HTML forms.
The associated HTML page is also available as Test-1.html. As with all the HTML examples in this chapter, you have to replace the string cgi-test with a proper server URL in the <FORM> statement.
You should see an HTML page exactly as shown in figure 24.4. Clicking the Submit Form button sends a request back to the server to activate the text-only script. The server complies with this request, and very soon the response appears as in figure 24.5. As indicated in the browser window, you've executed your first CGI script!
Fig. 24.4
This test form activates a text-only AppleScript CGI.
Fig. 24.5
This page was created by the response of a text-only AppleScript.
Although you've run your first CGI script, try to refrain from bragging to anyone because, in reality, it's a very poor example. The script doesn't adhere to any HTTP standards whatsoever. You just asked the CGI to produce a string; the Web server didn't know from where it came nor did it know what it was really serving. The browser was forgiving and added a default MIME type of text/html and interpreted it as text.
In truth, your script should do two things. First, it should include a standard HTTP header telling the browser what type of data was being sent. Furthermore, you didn't phrase the output in HTML format. The browser applied the default MIME type, which corrected this, but you're really limiting your options if you don't structure your CGI to return text output in HTML form.
Look at the script in listing 24.1, which does the same thing as Test-1.script, but with proper HTML.
Listing 24.1 Test-2.script: Using the HTTP 1.0 Header -- define a variable equal to a carriage return and a line feed set CLRF to (ASCII character 13) & (ASCII character (10)) --define a standard HTTP 1.0 header set http_10_header to "HTTP/1.0 200 OK" & CLRF & [ct] "Server: MacHTTP: 1.0" & CLRF & [ct] "MIME-Version: 1.0" & CLRF & [ct] "Content-type: text/html" & CLRF & CLRF -- return the following results as HTML output return http_10_header & [ct] "<HTML>" & return & [ct] "<HEAD>" & return & [ct] "<TITLE>Test 2</TITLE>" & return & [ct] "</HEAD>" & return & [ct] "<BODY>" & return & [ct] "This is my first <B>real</B> script!" & return & [ct] "<HEAD>"
Let's look at this script section by section.
The first code line of listing 24.1 develops a new variable that's equivalent to a carriage return and line feed:
set CLRF to (ASCII character 13) & (ASCII character 10)
This variable is used to create new lines in your HTML output. Note that the phrases ASCII character 13 and ASCII character 10 represent the means that AppleScript uses to express a carriage return and line feed characters; the carriage return and line feed characters have the ASCII character codes of 13 and 10 respectively.
To tell the browser what type of data is being sent to it, you next need to develop a standard HTTP 1.0 header. In the following code fragment, the variable http_10_header is constructed by using a series of strings welded together by continuation symbols. The variable consists of one long string.
set http_10_header to "HTTP/1.0 200 OK" & CLRF & [ct] "Server: MacHTTP" & CLRF & [ct] "MIME-Version: 1.0" & CLRF & [ct] "Content-type: text/html" & CLRF & CLRF
This header contains information telling the browser several pieces of information:
The next section of the script uses the return statement to convert a large string to the AppleScript variable result. This string is returned to the Web server for processing by the browser.
return http_10_header & [ct] "<HTML>" & return & [ct] "<HEAD>" & return & [ct] "<TITLE>Test 2</TITLE>" & return & [ct] "</HEAD>" & return & [ct] "<BODY>" & return & [ct] "This is my first <B>real</B> script!" & return & [ct] "<HEAD>"
The string http_10_header is concatenated with a series of HTML commands.
In this script section, you see two implementations of return, which is one of AppleScript's little idiosyncrasies. return makes several appearances as a variable within the HTML portion of the string. This is equivalent to inserting a carriage return in the output for illustrative purposes. Remember, carriage returns aren't processed in HTML, except when used within preformatted text (the <PRE> and </PRE> tags) and are otherwise included only for debugging and illustrative purposes.
With this simple text-only script, you can run the preceding script within the Script Editor to validate your HTML. Figure 24.6 shows what happens when you click the Run button for Test-2.script. Note that the script is properly formatted as though you had constructed it from scratch.
Fig. 24.6
Test-2.script returns a properly formatted HTML document to the Script Editor's Result window.
Similar to the HTML example used for the first script example, you can run the script using a simple HTML form. This HTML document, script-2.html, is available on the book's CD.
The result of the CGI script is shown in figure 24.7. Note that the HTML formatting is evident with the bold typing. This means that browser could interpret the code correctly using the MIME header information created by the CGI script.
Fig. 24.7
This page was created by the response of a properly-formatted text-only AppleScript.
In contrast to the previous text-only CGI examples, you can develop CGIs that are saved as run-only AppleScript applications. As mentioned previously, these applications require much less RAM and CPU time to run than text-only scripts. What's more, you can communicate with applications by using AppleEvents that give you greater performance and flexibility in CGI processing.
You can create AppleScript applications by saving the scripts as applications or run-only applications. The difference between these two formats is that you can edit the script used to build a standard application; you can't edit the script associated with a run-only application. As a result, run-only applications tend to be contained in smaller files. You can save your script as an application by choosing Save As from the File menu and saving the file as an application.
Run-only applications are saved in a similar fashion once you get to the Save As Run-Only option. If you do create a run-only application, make sure that you have a text version of the script around as you will no longer be able to edit the original script using the Script Editor or any other text editor. This is an extremely important point.
I discussed earlier how the WWW[go]sdoc AppleEvent is used by the Macintosh WWW server to transmit information from the Web browser to the CGI script. This AppleEvent contains information that's useful for CGI script processing. Table 24.2 summarizes the CGI variables sent to the server.Table 24.2 CGI Variables
Variable Description path_args The data after the $ and before a ? in an URL http_search_args Search arguments, which follow the ? in an URL such as in an <ISINDEX> tag or image map request post_args The data typed into the form method The method used to convey the information to the server, typically GET or POST client_address The IP address used by the Web browser username The validated user of the Web browser password The validated user's password server_name The IP address of the Web server server_port The IP listening port used by the server (usually 80) script_name The full path name of the CGI script referer The URL of the page containing the script user_agent The type and version of Web browser initiating the request content_type The MIME content type of post_args full_request The full WWW client request as seen by the CGI script ***begin x-ref*** [lbr] See "Request-Specific Environment Variables," p. xxx, for more information on CGI data variables. (Ch 4) ***end x-ref***
These variables are sent from HTML form documents to the Web server. The CGI can extract them from the AppleEvent for use in processing information.
Generally, the only variable you care about will be post_args, because it contains the content of your HTML forms. For the moment, let's put off worrying about the HTML form's content and look at a rudimentary post-query CGI script.
Listing 24.2, also stored as Test-3.script on this book's CD, shows a simple AppleScript CGI designed to publish the content of various CGI variables. This script is quite simple; it merely strips the values of the various CGI variables from the WWW[go]sdoc AppleEvent, writes them to local variables, and prints those variables.
Listing 24.2 Test-3.script: Post-Query Example -- Set up global variables global crlf global http_10_header global datestamp global idletime -- define a variable equal to a carriage return and a line feed set crlf to (ASCII character 13) & (ASCII character 10) -- set up number of seconds that script will remain idle before -- terminating set idletime to 15 -- set the current date to a variable set datestamp to current date -- define a standard HTTP 1.0 header set http_10_header to "HTTP/1.0 200 OK" & crlf & [ct] "Server: MacHTTP" & crlf & [ct] "MIME-Version: 1.0" & crlf & [ct] "Content-type: text/html" & crlf & crlf -- This is the handler that processes Apple events sent from MacHTTP. -- WWW[go]sdoc is the event sent with GET or POST methods. -- process AppleEvent sent by the WWW server on [lch]event WWW[go]sdoc[rch] path_args [ct] given [lch]class kfor[rch]:http_search_args, [lch]class post[rch]:post_args, [lch]class meth[rch]:method, [lch]class addr[rch]:client_address, [lch]class user[rch]:username, [lch]class pass[rch]:password, [lch]class frmu[rch]:from_user, [lch]class svnm[rch]:server_name, [lch]class svpt[rch]:server_port, [lch]class scnm[rch]:script_name, [lch]class ctyp[rch]:content_type -- develop HTML Output set return_page to http_10_header & [ct] "<HTML><HEAD><TITLE>Test 3</TITLE></HEAD>" & [ct] "<BODY><H1>Test 3</H1>" & return & [ct] "<H2>Post-Query Test</H3>" & return & [ct] "<HR>" & return -- list form variables set return_page to return_page & [ct] "<TABLE>" & return & [ct] "<TR><TD>path_args: " & "<TD>" & path_args & [ct] "</TR>" & return & [ct] "<TR><TD>http_search_args: " & "<TD>" & "</TR>" & [ct] http_search_args & return & [ct] "<TR><TD>post_args: " & "<TD>" & post_args & "</TR>" & [ct] return & [ct] "<TR><TD>method: " & "<TD>" & method & "</TR>" &[ct] return & [ct] "<TR><TD>client_address: " & "<TD>" & client_address & [ct] "</TR>" & return & [ct] "<TR><TD>user_name: " & "<TD>" & username & "</TR>" & [ct] return & [ct] "<TR><TD>password: " & "<TD>" & password & "</TR>" & [ct] return & [ct] "<TR><TD>from_user: " & "<TD>" & from_user & "</TR>" & [ct] return & [ct] "<TR><TD>server_name: " & "<TD>" & server_name & [ct] "</TR>" & return & [ct] "<TR><TD>server_port: " & "<TD>" & server_port & [ct] "</TR>" & return & [ct] "<TR><TD>script_name: " & "<TD>" & script_name & [ct] "</TR>" & return & [ct] "<TR><TD>content_type: " & "<TD>" & content_type & [ct] "</TR>" & return & [ct] "</TABLE></BODY></HTML>" return return_page end [lch]event WWW[go]sdoc[rch] -- Following on idle if (current date) > (datestamp + idletime) then quit end if return 5 end idle on quit continue quit end quit
Look at the newer elements of this script one section at a time.
Think of the AppleEvent handler as a subroutine. As with other programming languages, you need to define these variables globally so that they can be accessed within the subroutines. The following statements define variables that are defined outside the handlers but are used inside the handlers.
-- Set up global variables global crlf global http_10_header global datestamp global idletime -- set up number of seconds that script will remain idle before -- terminating set idletime to 15 -- set the current date to a variable set datestamp to current date
Two new variables are defined here. The variable datestamp is set to the current date, and the variable idletime is set to 15. I'll discuss the significance of these variables later in the chapter.
The next lines describe the header for a handler that's designed to activate on receiving an AppleEvent sdoc of class WWW sent by the Macintosh WWW server.
on [lch]event WWW[go]sdoc[rch] path_args [ct] given [lch]class kfor[rch]:http_search_args, [lch]class post[rch]:post_args, [lch]class meth[rch]:method, [lch]class addr[rch]:client_address, [lch]class user[rch]:username, [lch]class pass[rch]:password, [lch]class frmu[rch]:from_user, [lch]class svnm[rch]:server_name, [lch]class svpt[rch]:server_port, [lch]class scnm[rch]:script_name, [lch]class ctyp[rch]:content_type
Note
The [lch] and [rch] symbols are used to denote the AppleEvent parameter constants. These characters are created by pressing Option+\ and Option+Shift+\ respectively.
Remember that the script is activated by the form submission, but there's some time before the server sends the AppleEvent with the form data. The different AppleEvent parameter constants are stripped out and set to AppleScript variables. These variables are displayed later in the script.
The following code creates a large string called return_page, which is eventually set to result. This string variable contains the various HTML commands necessary to display the CGI variables, along with their associated variable names in an HTML borderless table.
-- develop HTML Output set return_page to http_10_header & [ct] "<HTML><HEAD><TITLE>Test 3</TITLE></HEAD>" & [ct] "<BODY><H1>Test 3</H1>" & return & [ct] "<H2>Post-Query Test</H3>" & return & [ct] "<HR>" & return -- list form variables set return_page to return_page & [ct] "<TABLE>" & return & [ct] "<TR><TD>path_args: " & "<TD>" & path_args & [ct] "</TR>" & return & [ct] "<TR><TD>http_search_args: " & "<TD>" & "</TR>" & [ct] http_search_args & return & [ct] "<TR><TD>post_args: " & "<TD>" & post_args & "</TR>" &[ct] return & [ct] "<TR><TD>method: " & "<TD>" & method & "</TR>" &[ct] return & [ct] "<TR><TD>client_address: " & "<TD>" & client_address &[ct] "</TR>" & return & [ct] "<TR><TD>user_name: " & "<TD>" & username & "</TR>" & [ct] return & [ct] "<TR><TD>password: " & "<TD>" & password & "</TR>" & [ct] return & [ct] "<TR><TD>from_user: " & "<TD>" & from_user & "</TR>" & [ct] return & [ct] "<TR><TD>server_name: " & "<TD>" & server_name & [ct] "</TR>" & return & [ct] "<TR><TD>server_port: " & "<TD>" & server_port & [ct] "</TR>" & return & [ct] "<TR><TD>script_name: " & "<TD>" & script_name & [ct] "</TR>" & return & [ct] "<TR><TD>content_type: " & "<TD>" & content_type & [ct] "</TR>" & return & [ct] "</TABLE></BODY></HTML>" return return_page
This output is placed within the WWW[go]sdoc handler so that it's activated only when the AppleEvent is received. The event is closed using the following statement:
end
In the earlier section describing the Script Editor, you learned that CGI scripts need to stay open after they're activated by the Web server. However, unlike text-only scripts, AppleScript applications remain open indefinitely when activated. Again, there's a discrete amount of time between the application's launch and response to the AppleEvent. Therefore, you need to build into the script the capability to remain open after it's launched; otherwise, the script never can receive the AppleEvent.
There are advantages and disadvantages to this. One advantage is that the application remains available for other CGI accesses; time is saved by not having the application launch over and over. However, the disadvantage is that CGI scripts do take up your server's RAM (although AppleScript applications have modest memory requirements). If your server maintains a large number of scripts, they may take up valuable memory while remaining idle.
One tradeoff is to tell the script to self-terminate after a predetermined period of time. Note that they're placed outside the AppleEvent handler.
on idle if (current date) > (datestamp + idletime) then quit end if return 5 end idle
The variable datestamp is set at the beginning of the program's execution. The variable idletime is also set at that time; this variable is defined to be the amount of time (in seconds) that the program will stay active after launch. If the application is idle after idletime seconds since startup, the application calls the quit handler that follows. If the application isn't idle and is instead processing an AppleEvent, the idle handler returns a value of 5, meaning that the server quit handler will be queried in 5 seconds.
The following quit handler allows you to insert some extra AppleScript commands before shutting down the script. You can perform such tasks as logging the CGI script access or writing some other type of data to a file.
on quit continue quit end quit
You'll want to set idletime high enough to keep the application open for AppleEvent requests. Keep in mind that any CGI request received while the application is quitting is lost. When this happens, the user will have to resubmit the browser request with an annoying loss of a few seconds. You don't want the application to be opening and closing every few seconds if it's a popular script such as a search script. For this reason, you'll have to adjust your idle time accordingly.
Store the preceding script, as test-3.cgi in your CGI folder. The following HTML can be used to activate the script:
<FORM METHOD=POST ACTION="http://cgi-test/cgi/test-3.cgi"> Enter some text here <INPUT NAME="POST-Argument" SIZE=35> </TEXTAREA><P> Press here to submit form <INPUT TYPE="submit" VALUE="Submit Form"> </FORM>
This HTML code appears in a Web browser as shown in figure 24.8. Note that the code provides for an input field in which text can be inserted; the variable name for this field is POST-Argument. Figure 24.9 shows the response from the CGI script.
Fig. 24.8
Submitting this form activates the Test-3.cgi post-query example.
Fig. 24.9
The post-query script prints out the CGI environment variables to a Web browser window.
If this CGI application had been running an image map or search application, there would have been values for the path_args and http_search_args variables. In figure 24.9, notice that the post_args variable contains the POST-Argument variable, along with the value of the text input field. The Web server has replaced spaces with plus (+) symbols. To process the form, the data will need to be parsed and stored in variables; I'll cover ways to accomplish this shortly. Values of the other variables are printed where valid.
As mentioned earlier, the most important variable you'll want to process, with normal HTML form queries, is post_args. The post-query example (shown in listing 24.2) showed the results of this variable as seen by the CGI script. Not only was the form data interspersed with plus symbols, but it was difficult to see how you could convert the results of the post_args variable into AppleScript variables for processing. In this section, I'll discuss an example which does these very tasks.
You need a variety of scripting additions to enhance the performance of your CGI processing. Some of these tools are useful for general scripting purposes. The most useful OSAX available for AppleScript CGI usage is the Parse CGI OSAX from Clearway Technologies; this software is available on this book's CD. This library allows you to decode, parse, and access the HTML form information passed to the CGI application from the Web server. It replaces some of the older OSAXen. The ScriptWeb archive maintains many OSAXen for use in CGI scripting as well as general AppleScript use.
Keep in mind that you can avoid using OSAXen if you want. But they're usually constructed using compiled C or Pascal code and therefore offer subroutines that run many times faster than AppleScript equivalents.
InterCon's InterServer Publisher provides the functionality of the Parse CGI OSAX, so you won't need this extension if you're using this particular Web server.
Listing 24.3 shows how the Parse CGI OSAX can be used to read data from HTML forms. This data is processed and included in an HTML response. This script is stored as Test-4.script on this book's CD-ROM.
Listing 24.3 Test-4.script: Parse CGI Example -- Set up global variables global crlf global http_10_header global datestamp global idletime -- define a variable equal to a carriage return and a line feed set crlf to (ASCII character 13) & (ASCII character 10) -- set up number of seconds that script will remain idle before -- terminating set idletime to 15 -- set the current date to a variable set datestamp to current date -- define a standard HTTP 1.0 header set http_10_header to "HTTP/1.0 200 OK" & crlf & [ct] "Server: MacHTTP" & crlf & [ct] "MIME-Version: 1.0" & crlf & [ct] "Content-type: text/html" & crlf & crlf -- This is the handler that processes Apple events sent from MacHTTP. -- WWW[go]sdoc is the event sent with GET or POST methods. -- process AppleEvent sent by the WWW server on [lch]event WWW[go]sdoc[rch] path_args given [lch]class post[rch]:post_args set formdata to parse CGI arguments post_args set full_name to CGI field "full_name" from formdata set rock to CGI field "rock" from formdata set age to CGI field "age" from formdata set return_page to http_10_header & [ct] "<HTML><HEAD><TITLE>Test 4</TITLE></HEAD>" & [ct] "<BODY><H1>Test 4</H1>" & return & [ct] "<H2>Parse CGI Test</H2>" & return & [ct] "<HR>" & return -- list form variables set return_page to return_page & [ct] "Your name is " & return & full_name & "<P>" & [ct] return & [ct] "Your favorite music group is " & rock & "<P>" & return & [ct] "You consider yourself to be of the " & age & [ct] " age group" & "<P>" & return & [ct] [ct] "</BODY></HTML>" return return_page end [lch]event WWW[go]sdoc[rch] -- Following handlers quit applications if idle after "idletime" -- seconds on idle if (current date) > (datestamp + idletime) then quit end if return 5 end idle on quit continue quit end quit
Look at the OSAX commands in this line:
on [lch]event WWW[go]sdoc[rch] path_args given [lch]class post[rch]:post_args
Note that the AppleEvent handler preamble is much shorter in this example than in the post-query example (refer to listing 24.2). This is because we're interested only in the post_args portion of the sdoc AppleEvent.
The Parse CGI OSAX contains a command called parse CGI arguments. This command returns and decodes the post_args variable, which contains the encoded HTML form data.
set formdata to parse CGI arguments post_args
This command then assigns the form data to the appropriate form names and concatenates these pairs into an AppleScript list formData.
The CGI field command retrieves the specific fields and assigns them to AppleScript variables. As you can see, these two OSAX commands provide a very straightforward means of accessing HTML form data.
set full_name to CGI field "full_name" from formdata set rock to CGI field "rock" from formdata set age to CGI field "age" from formdata
Listing 24.4 shows an example HTML script, and figure 24.10 shows how this code appears in a browser window. There are three different form elements in this example HTML document. Filling the form fields and submitting the document yields a response from the CGI script as shown in figure 24.11.
Listing 24.4 test-4.html: Parse CGI Example HTML <FORM METHOD=POST ACTION="http://cgi-test/cgi/test-4.cgi"> Enter your full name here: <INPUT NAME="full_name" SIZE=35> </TEXTAREA><P> Enter Your Favorite Music Group <SELECT NAME="Rock" SIZE=5> <OPTION> The Beatles <OPTION> The Who <OPTION> REM <OPTION> Nirvana <OPTION> The Talking Heads </SELECT><P> <DL> <DT>How old are you? <DD><INPUT TYPE="radio" NAME="age" VALUE="young">Younger than 18 <DD><INPUT TYPE="radio" NAME="age" VALUE="middle">18-35 <DD><INPUT TYPE="radio" NAME="age" VALUE="old">Older than 35 </DL> Press here to submit form <INPUT TYPE="submit" VALUE="Submit Form"> </FORM>
Fig. 24.10
This multiform document is used to activate the CGI in Test-4.cgi.
This document was created by the Test-4.cgi example. Note the smooth integration of predetermined HTML text and variables from the original HTML form.
You can program a number of tasks with AppleScript. You're limited only by your ability to program in AppleScript. Some more established uses of the AppleScript CGI platform are discussed next.
A normal CGI script is executed synchronously; all server activities are suspended until the CGI application is completed. An asynchronous CGI script is executed asynchronously, meaning that the script shares server resources with other processes. The script is alternatively suspended and executed depending on the needs of other processes. Synchronous CGI scripts are denoted by the .cgi suffix; asynchronous CGI scripts are labeled with the .acgi suffix. Macintosh Web servers, as well as other servers, process CGI applications differently based on these suffixes.
To take full advantage of asynchronous script handling, the script needs to be developed by using a multithreaded or finite state machine architecture. For the Macintosh, this means the script is developed using the Thread Manager libraries. The Thread Manager is a system extension that comes with System 7.5. Multithreaded computing is the next step below pre-emptive multitasking on the computer processing food chain. With multitasking, processes are computed simultaneously, whereas with multithreaded processing, processes share the server's resources asynchronously. AppleScript isn't multithreaded and therefore can't take full advantage of asynchronous script handling.
A copy of the Thread Manager is also available on the FTP server ftp.info.apple.com in the directory /Apple.Support.Area/Apple.Software.Updates/US/Macintosh/System/Other_System/.
AppleScript applications are executed identically regardless of the synchronous or asynchronous designation. This is because the system process that executes the scripts does so in a serial manner. For scripts written in languages such as C and Frontier's UserTalk, applications can be executed asynchronously.
An advantage of using AppleScript is that you have access to interapplication communications. The AppleEvent handler in AppleScript works very cleanly with other Mac applications. Therefore, you can include information processed by these other applications within your CGI scripts. Examples of these are given in the following sections.
Regardless of the operating system, one chief application of Web servers on all platforms is the interaction with external databases via the Web. One of the prominent database applications on the make is Claris' FileMaker Pro. The FMPro.acgi was developed by Chuck Shotton, the author of MacHTTP, for the purpose of allowing you to edit, add, and delete records in a FileMaker Pro database.
AppleSearch, a document search application developed by Apple Computer, allows you to search for text in documents that exist on other computers on a local area network. By using various filters, you can search for text inside binary application files stored in such formats as Microsoft Word, WordPerfect, and MacWrite Pro. Furthermore, you can use AppleSearch to initiate WAIS searches over the Internet.
The AppleSearch.acgi is a means of allowing you to establish AppleScript CGI that can search for documents within archives, on remote computers (even Windows machines), and for text on the Internet. AppleSearch is bundled with the high-end Apple Internet Server Solution machines.
Again, the opportunities for interactions with your CGI scripts is limited by your imagination. In addition to general CGI processing, you can program your scripts to extract actual words out of Microsoft Word documents and enter them in Microsoft Excel spreadsheets. AppleScript's native handling of AppleEvents allows you to interact with MacOS applications nearly seamlessly.
In truth, AppleScript is an easy language to learn for general desktop management. It's simpler to develop a simple script in AppleScript than it is to develop a similar function in a higher-level programming language such as C or Pascal. Any language or scripting environment can be used to develop CGI, providing it can manage AppleEvents. Because AppleScript is bundled with System 7.5 also makes it an attractive platform for which to generate CGI scripts.
However, many Macintosh programmers who cut their teeth with AppleScript are now using other languages to develop CGI scripts. Although the MacOS is used to power a large fraction of servers on the Internet, there are still more non-Mac Web servers than there are Mac servers. Therefore, you'll be constrained to share your AppleScript CGI only with other Mac users. If you're forced to move your server structure to a larger and faster system running UNIX or Windows NT, you'll have to redo all your CGI scripts.
Furthermore, AppleScript is neither multithreaded nor Power Mac-native. Hence, AppleScript can't take advantage of the Thread Manager, nor can it take advantage of higher-speed Power Macs. AppleScript is an excellent choice for using some basic scripts with low resource requirements, but for more advanced scripting you'll likely need to move to another scripting platform.
HyperCard sports a user-interface language, HyperTalk, of which AppleScript is highly derivative. The two languages share much in the way of structure and even grammar. HyperCard is a multimedia authoring tool with roots deep in the Mac family tree. It's one of the oldest applications for the Macintosh, having been bundled with Macs since the introduction of the Mac II.
HyperTalk can handle AppleEvents and therefore can manage interprocess communication. However, HyperTalk has always been criticized for its slow performance. Although you can now compile stand-alone applications with HyperCard, these applications aren't optimized for performance and tend to run much slower than applications compiled with higher-level programming languages. However, HyperCard 2.2 is OSA-compliant, meaning that you can run AppleScript scripts using a HyperCard front end. With the abundance of XCMDs and internal database capabilities, and a familiar and easy user interface, HyperCard-based CGI applications may gain in popularity as a CGI scripting environment.
For this reason, HyperCard isn't a popular CGI scripting platform for the Macintosh.
Many CGI applications on UNIX platforms are written in C or C++. These languages exist for the Macintosh but require external compilers and libraries to handle AppleEvents. Even so, these environments required extensive libraries to process HTML form data. This difficulty is a tradeoff, because scripts built using these languages tend to run faster than scripts written in other languages. Your scripts also will be portable to UNIX or Windows servers, which allows you to share CGI scripts with users of other platforms.
InterXTML is a server-side extension of HTML for use with the InterServer Publisher Web server. InterXTML allows you to add simple commands to your HTML code to execute functions that must be programmed into CGI scripts on other server platforms. These functions include access counters, date and time stamping of your Web pages, and directory listings. These extensions are limited to the InterServer Publisher software and therefore aren't portable to other Web servers.
The Practical Extraction and Report Language (PERL or, most commonly, Perl) is a popular text-processing language with origins in the UNIX operating system. Perl offers much of the utility of C, but with easier syntax rules. As a result, Perl is wildly popular as a CGI platform in the UNIX environment. MacPerl is a Macintosh port of the Perl language, and MacPerl scripts are becoming increasingly popular as a Macintosh CGI platform. MacPerl is extremely interchangeable with UNIX Perl, which means that your CGI scripts will be portable to other platforms. Also, you can easily modify UNIX Perl scripts to work with your Mac Web server.
UserTalk's Frontier is a scripting environment for the Macintosh that predates AppleScript. Many programmers have migrated from AppleScript to Frontier with praise for Frontier's performance and sophistication. Frontier is Power Mac-native and can use the Thread Manager extension for multithreaded processing.
Frontier's syntax isn't as elementary as the natural language conscripts seen in AppleTalk. However, Frontier is experiencing a growth in popularity with the Macintosh CGI scripting community, meaning that large script libraries are at your disposal.
Some interesting links are given in the following table. These links pertain to topics mentioned earlier in this chapter. Furthermore, these links point to libraries and archives containing ample examples of AppleScript CGIs as well as scripts in other languages.
Link Address/Description ***Production: Three of the entries in the right column below may look unaligned on the hard copy, but they should line up correctly on pages.*** Starnine Technologies, developers of MacHTTP and WebSTAR InterCon Systems, Inc., developers of InterServer Publisher InterCon Systems, Inc., a compilation of Macintosh scripting utilities InterCon Systems, Inc. MacPerl Q&A MacPerl Q&A MacPerl Q&A MacPerl Q&A MacPerl Q&A
For technical support for our books and software contact support@mcp.com
Copyright ©1996, Que Corporation