LibCGI is a Common Gateway Interface programming library for Euphoria. It cuts down on the grunt work CGI programming requires, so you can concentrate on writing your program. Normally when writing CGIs, you have to write code to parse and decode form data, and process uploaded files, etc. This takes alot of time if you're writing it from scratch. With LibCGI, all you have to do is call a few routines, and all the work is done! LibCGI was written on Windows95 using the Xitami Win32 webserver. The multipart form handling code was based off of RFC 1867 & 1872. It should work with most browsers that support form-based file upload. I haven't tested it on Linux, but it should work fine. Before you can try LibCGI out locally, you need to be running a webserver. If you're on Linux, you probably have (or can install) Apache. Windows machines are a bit trickier; I highly recommend Xitami - it's 100x more stable than IIS or PWS will ever be, and it's free ;-) I have tried to write LibCGI so it wraps up as much of the interface between server and script as possible. You don't need to access environment variables or standard input directly anymore (though you still can). And once you have your form data, LibCGI can parse it and pass it back as a sequence of name/value pairs. In a nutshell, you can use LibCGI to:
The next couple of sections show you how you can use LibCGI to accomplish these things. Accessing Server Environment Variables The conventional way of accessing environment variables is using getenv(). LibCGI provides the server_var() function (which does the same thing). For usage details, see the routine list. There is also a global constant called SERVER_VARS that has most of the commonly used webserver variables. Using these, you can find out things like the client's IP address, browser version, webserver name & version, and the current hostname and port. Example 1 on the examples page demonstrates how to use environment variables. The two ways the Common Gateway Interface uses of passing data from the client to the server script is through the GET and POST methods. These methods are part of the original form's tag - <form method='GET' action='foo.cgi'> The GET method puts the form data into the server variable QUERY_STRING, which is actually the part of the URL that comes after the '?'. Example: http://www.webcrawler.com/cgi-bin/WebQuery?text=euphoria+programming ^^^^^^^^^^^^^^^^^^^ this is the QUERY_STRING ______________| To grab the form's data using GET, call form_data() with the method as an argument. sequence foo foo = form_data("GET") That's the easy part. Now that you have the data, what do you do with it? If you try and print it, it comes out looking like: text=euphoria+programming. If it's more complex, it may have multiple fields, and even hex sequences: text=euphoria+programming&lookup=%3Dand%72or&chunk=25 This is where LibCGI really gets to work. The function process_form() can take that ugly string and turn it into a sequence of name/value pairs: sequence x x = form_data("GET") x = process_form(x) -- x = {"text","euphoria programming","lookup","=andror","chunk","25"} An added side-effect of using process_form() is that a global sequence named FORM_FIELDS gets the same value that is returned. Now you can use the field() routine to access the value for a particular name. Example: sequence x x = process_form(form_data("GET")) out(field("text")) -- prints "euphoria programming" to STDOUT Noticed that I used out() instead of puts()? I included it along with in() so that you can read/write to standard I/O a little easier :-) The POST method differs from GET in that it uses standard input to hold the data, instead of an environment variable. This is useful if you're sending a large amount of text, and the variable can't hold it all (yes, GET does have a limit to the amount of text you can send). To retrieve the form data from a POSTed form, all you need to use is form_data(). That's right folks! It uses a totally different delivery method, but you don't need to worry about it, because it returns the data in exactly the same format as the GET method - one long string. Since it's in the same format, you can also use process_form() to parse and decode the data. It's just that easy :-) But what if you don't know what method the form is using? To find out, use the method() function. It returns either "GET" or "POST" (or -1 if it failed, which it shouldn't). method() works by grabbing the value out of the REQUEST_METHOD server variable. Multipart forms are a little different from normal forms. They always use the POST method, and are encoded using MIME encoding (similar to e-mail messages). Typically they are used for transmitting large quantities of data, like files or text messages. File uploads via CGI scripts are only available using multipart forms. To use a multipart form in your webpage, use this FORM tag: <form enctype="multipart/form-data" method="POST"> Processing multipart forms takes a little more work, and that's why LibCGI has a whole module - multipart.e - dedicated to this. Here is a list of special multipart functions you can use:
Multipart data returned from process_form_multipart() is not in the same format as normal form data. Each form input element (text, file, etc) will have its own sub-sequence. For example, if you had an upload form for two files and two textboxes for descriptions, the sequence would look similar to this: { { disposition, form-data, name, file1, filename, f:\bar\foo.txt, {file data} }, { disposition, form-data, name, desc1, {text} }, { disposition, form-data, name, file2, filename, f:\foo\bar.txt, {file data} } { disposition, form-data, name, desc2, {text} }, } The actual data is always going to be the last element, no matter what type of input element you're using. If there are files in the sequence, usually there will also be a content type field. As you can see, handling multipart forms is more difficult than normal ones. You'll probably have to experiment a little to get familiar with them; that's what I did ;-) In fact, the code for the multipart module was written more from hacking than from the RFCs! Reading/Writing Files & Standard I/O To make it easier to access files, I've included some general-purpose routines that read and write binary & plain text files. I'm not going to go over them all here; that's what the routine list is for. Let me just say that there are some nice options in the binary ones ;-) LibCGI also has 2 standard I/O routines (mentioned earlier): in() and out(). out() prints whatever you give it to STDOUT, and in() reads on line (ending with a newline) from STDIN. I put these in here for no other reason than to eliminate excessive arguments to gets() and puts(), since the filehandle is always the same. Two functions that are very important for output are type_html() and type_text(). These output the content type information the browser needs in order to correctly interpret the output as text or HTML. You have to use one of these (or another content type if you prefer) before you print anything to STDOUT. There are 4 file routines, which are in fileio.e. They are listed in the routine list; syntax is also explained there. Just for fun, I added some routines that generate HTML markup. They (hopefully) will make it a little easier to generate new pages and comboforms. I haven't quite worked out exactly how they'll work yet, so they may be a little quirky ;-) All of the HTML routines are prefixed by html_, like html_body() and html_p(). They are all functions that return HTML code for the text you pass to them. They're simple, really. Which is why I'm not going into detail on them. See the routine list for a complete listing of them. General Routinesfunction server_var( sequence name ) Returns the value of the environment variable name. -1 if it doesn't exist. function in() Returns one line (ending with a newline) from STDIN. -1 if no input. procedure out( sequence text ) Prints text to STDOUT. procedure type_html() Prints "Content-type: text/html\n\n" to STDOUT. Usually used before any other output. procedure type_text() Prints "Content-type: text/text\n\n" to STDOUT. Usually used before any other output. procedure cgi_die( sequence error, sequence message) Generates an error webpage for the user from error and message. Unlike Perl's die() function, cgi_die() does not abort the program. function method() Returns the REQUEST_METHOD (GET or POST) for the form input. -1 if something seriously goes wrong ;) function form_data( sequence method ) This returns the form data using method as the REQUST_METHOD. Returns -1 if there was no data. function get_data() This function is used by form_data() to retrieve the QUERY_STRING. You can use this if you know you are using GET ahead of time. Returns a string if successful, -1 otherwise. function post_data() Also used by form_data() to retrieve standard input. Use this if you know ahead of time you're using POST. Returns a string (same format as get_data()) if successful, -1 otherwise. function field( sequence name ) Returns the value of name from FORM_FIELDS. -1 if name doesn't exist. (you need to have run process_form() before using this, otherwise you'll get a failed return) function process_form( sequence data ) Parses and decodes data, copies it into FORM_FIELDS and returns it. -1 if it failed (this shouldn't happen unless you give it invalid data). File I/Ofunction read_binary( sequence file, atom chunksize, atom offset ) Read file from disk. read_binary() treats the input as binary; it treats newlines like any other character. If you only want a certain number of bytes, set chunksize (otherwise set it to 0). If offset is 0, it starts at the beginning of the file. Returns -1 if something went wrong. function write_binary( sequence file, sequence data ) Write binary data to file to disk. All characters are preserved, and none are added. Returns -1 if something went wrong, otherwise 1. function read_text( sequence file, atom lines ) Read ASCII text from file. If lines is not zero, reads that number of lines from the file. Returns -1 if it failed, otherwise one long sequence. Newlines are not stripped. function write_text( sequence file, sequence data ) Writes ASCII text data to file. Expects one long sequence. Returns 1 if everything went fine, otherwise -1. Multipart Form Routinesfunction form_data_multipart() The cousin of form_data(), this returns the data from standard input (raw, with no stripped newlines). function parse_multipart_content( sequence content ) Parses the "Content-whatever" lines in content and returns a sequence of name/value pairs (or -1). content is expected to be one line (ie: no newlines). function process_form_multipart( sequence data ) This processes multipart form data; works similarly to process_form(). It parses and decodes data and returns a sequence (or -1). This function does not copy its results into FORM_FIELDS; you'll have to write a field handler yourself :) HTML Markup RoutinesThese HTML tag functions are far from complete; there's some missing that should be here, and maybe some of these shouldn't. I added them because I hated trying to cram HTML code into a puts() string ;-) function htmls_html( sequence text ) function htmls_head( sequence text ) function htmls_title( sequence text ) function htmls_body( sequence text, object bgcolor, object textcolor, object linkcolor, object background ) These are HTML structure (hence the htmls_ prefix) tags. They simply enclose text with whatever the tag is (html, head, title, etc.). If the argument type is object, then passing it 0 will make it ignore the attribute (it won't be added to the tag). function html_head( sequence text, atom level ) function html_p( sequence text ) function html_pre( sequence text ) function html_center( sequence text ) function html_b( sequence text ) function html_i( sequence text ) function html_u( sequence text ) These are basic formatting tags. html_head is like <H1>, not <HEAD> btw :) function html_font( sequence text, object face, atom size, object color ) function html_anchor( sequence text, object name, object href ) These are <FONT> and <a>. As before, setting an argument to 0 will make the attribute ignored. function html_form( sequence text, object name, object enctype, object action, object method ) function html_input( object name, object input_type, object value, object size ) function html_textarea( sequence text, object name, object rows, object cols ) These are form tags. There aren't many, but html_input() covers alot of elements (most of them except checkboxes and option boxes). |