ON-REV ENGINE NOTES [ LAST UPDATED 2009-06-02 BY Mark Waddingham ] The On-Rev server-side engine (irev engine) is a new variant of the existing technology that allows you to mix Revolution code with HTML content on the same page much in the same way as PHP. At this point in time, the new features that have been added to the (Revolution) engine to support server-side scripting have been modelled very strongly after PHP and thus should be quite familiar to anyone who has ever done some coding in that language. It should be noted that, right now, all the 'new' features described here-in are 'experimental' in nature in that the final syntax and semantics are likely to change as we develop this version of the engine. The first section is a simple introduction to writing server-side scripts - more examples can be found at . The remainder provides information on the new syntax/features specific to the server engine and differences from the desktop engine. -------------------------------------------------------------------------------- INTRODUCTION An irev script is a simple text file that mixes content with code. Code blocks are identified by being surrounded by the pair of tokens ''. Content blocks, are anything between a '?>' tag and the next '

------- END FILE date.irev This example file has three blocks: 1) A content block consisting of "...

" 2) A code block consisting of "" 3) A content block consisting of "

..." Notice here that the "put" command is used without a destination. In the irev engine, this means "output the value of the expression". Although the engine is generally unconcerned with what is in the content blocks, it is geared towards SGML/HTML/XML (markup) for two reasons: 1) The comment pairs. [ Note: The contents of the characters can appear directly ] Code blocks can contain a mixture of both statements and definitions. When the engine encounters a statement it is executed directly, and when it encounters a definition it adds it to the global environment, allowing it to be referenced by statements executed later. [ Note: Statements inside handler definitions are *not* executed directly as they are part of the definition of the handler ] For example, the following defines a simple mathematical function, which is then used later on: ------- BEGIN FILE area.irev A circle of radius" && r && "units has area" && areaOfCircle(r) & " units squared.

" end repeat ?> ------- END FILE area.irev [ Note: Although here we have defined the 'areaOfCircle' handler right at the beginning, this isn't necessary, it just has to appear anywhere before it is first used ] The previous two examples have very much separated the idea of 'content' from 'code' however this isn't necessary. In actual fact a content block *is* a statement. You should think of any content block as an implicit irev 'put' statement, following the same rules as any normal statement. For example, we can rewrite the math_func.irev example as this: ------- BEGIN FILE area_content.irev

A circle of radius units has area units squared.

------- END FILE area_content.irev Notice here how there are content blocks *inside* the 'repeat' statement - their contents will be re-output each time round the loop, in the order they appear. This equivalence of content blocks with put statements works also inside handler definitions. A content block that appears *inside* a handler definition is not output immediately, but instead will be output at the appropriate time in its containing handler's execution. For example, the following script abstracts the generation of a single line of a table into a separate handler: -------- BEGIN FILE list_vars.irev
-------- END FILE list_vars.irev Notice here that we've used the $_SERVER variable - this is a new engine-defined global variable which contains information about the web page request. See later for more information about this. At some point you may want to re-use handlers that you've written in more than one script, or perhaps use a set of handlers someone else has written. The new "include" command can be used to share such definitions amongst several scripts. The include command takes an expression evaluation to a filename as a parameter and when executed will 'execute' the given file in exactly the same way as the main script file is executed. For example, in the following a collection of mathematical functions have been split up into a separate include which is then shared amongst two other scripts. ------- BEGIN FILE maths.irev A circle of radius" && r && "units has area" && areaOfCircle(r) & " units squared.

" end repeat ?> ------- END FILE area_include.irev ------- BEGIN FILE perim_include.irev A circle of radius" && r && "units has perimeter" && perimeterOfCircle(r) & " units squared.

" end repeat ?> ------- END FILE perim_include.irev Notice here that the 'maths.irev' file has a '' tag - the end-of-file is left to terminate the code block. It is generally good practice to leave off the '?>' at the end of included files if they are just being used as handler libraries to ensure no content is accidentally output. [ Note: It isn't necessary for 'included' files to have the extension '.irev' - they do in this example because the on-rev client currently doesn't allow editing of non-.irev files! ] -------------------------------------------------------------------------------- NEW SYNTAX: $_SERVER The $_SERVER variable is an array containing the CGI-related variables passed to the engine from the web-server. It has the following keys: GATEWAY_INTERFACE The version of the CGI specification to which the server complies SERVER_ADDR The IP address of the server SERVER_PORT The port on which the request came through SERVER_NAME The DNS name of the server SERVER_SOFTWARE The webserver software version string SERVER_PROTOCOL The protocol through which this request came SERVER_ADMIN The email set for the adminstrator of the site the request is for SERVER_SIGNATURE The signature line of the webserver REQUEST_METHOD The form method used to request the page (e.g. GET or POST) REQUEST_URI The path portion of the request URL REMOTE_ADDR The IP address of the client that made the request REMOTE_PORT The local port on which the request is being served PATH_TRANSLATED The absolute local path of the requested page DOCUMENT_ROOT The absolute local path of the document root of the site this page relates to In addition, it will contain all HTTP_* variables passed through from the client's HTTP request as a result of the HTTP headers that the client sent. The following are ones that might be of the most interest: HTTP_HOST The site domain name that was requested HTTP_CONNECTION The type of connection requested by the client HTTP_ACCEPT_LANGUAGE The language the client would prefer HTTP_USER_AGENT The web-browser that made the request HTTP_ACCEPT A list of content-types the browser understands with preference weightings HTTP_ACCEPT_ENCODING A list of (data) encodings the browser can understand HTTP_COOKIE The cookie(s) previously attached to the domain/folder/page HTTP_REFERRER The URL of the page the current request was made from. Note that this list is not exhaustive nor mandatory - which of these variables are present depends on the HTTP request the client sends the webserver. Limitation: The $_SERVER variable should be treated as read-only, although the engine does not currently throw an error if you do attempt to modify it. -------------------------------------------------------------------------------- NEW SYNTAX: $_GET and $_POST When a FORM on a web page is submitted, or a URL with a query string is requested, the engine will attempt to parse this data into structured arrays. For a query string, or a form 'GET' method, this information will placed in the $_GET array. For a form 'POST' method, this information will be placed in the $_POST array. In both cases the conversion to an array is the same. The incoming data is a set of key/value pairs. The key determines which (nested) element of the array, the value gets put in. In the case of the query-string, the key/values are extracted according to the following pattern: =&=& ... &= In the case of form data, the key's will be the individual names/ids of the elements, and the value will be whatever the 'value' of the form element is defined to be. Each key is an initial identifier, following by one or more indices: ([]|[])* For example: 1. foo_1 2. foo_2[bar] 3. foo_2[baz][bar][foo] 4. foo_3[] 5. foo_3[][bar] The key determines where in the array the value should be placed. The initial identifier determines the top-level key, while the subsequent indices specify the nested keys. For any empty index, the first available unused numeric key above 0 is substituted. For example, if the above keys were all present in the query string, then you would access them with the following expressions: 1. $_GET["foo_1"] 2. $_GET["foo_2"]["bar"] 3. $_GET["foo_2"]["baz"]["bar"]["foo"] 4. $_GET["foo_3"][1] 5. $_GET["foo_3"][2]["bar"] Limitation: The $_GET and $_POST variables should be treated as read-only, although the engine does not currently throw an error if you do attempt to modify it. -------------------------------------------------------------------------------- NEW SYNTAX: PUT [ NEW ] HEADER By default, the irev engine will output the necessary HTTP headers just before the first byte of content is written by the script. To do this it is necessary for the engine to manage the list of HTTP headers that are returned. The put header command allows you to add an additional header to be output. It takes an expression evaluating to a string: put header Upon execution, assuming headers have not already been sent, it will add the given header string to the list. The string must be of the form:
: Any existing header with the same
field in the list will have its existing value overwritten with the new value. When headers get sent, if there is not a 'Content-Type' header in the list, the irev engine will automatically send: Content-Type: text/html For example, if you wish to return an image file to the client you might do something like: put url ("binfile:" & tPathToMyImage) into tImageData put header "Content-Type: image/gif" put header "Content-Length: " && the length of tImageData put tImageData By default, the 'put header' command will overwrite the most recent header of the same type. For example: put header "Foobar: baz" put header "Foobar: baz2" Will result in the header "Foobar: baz2" being sent to the server. If you wish to add an additional header of the same type then use the following syntax instead: put new header This is particularly useful for setting multiple cookies. e.g. put new header "Set-Cookie: foo=100" put new header "Set-Cookie: bar=200" -------------------------------------------------------------------------------- NEW SYNTAX: PUT CONTENT By default, the 'put' command outputs the string its given verbatim to the current page being constructed. However, in many cases, escaping is required for the correct HTML to be generated. The 'put content' command allows you to construct strings for output between HTML content without having to worry about escaping any characters. It takes an expression evaluating to a string: put content Upon execute, the expression will be evaluated, treated as text and any 'special' HTML characters encoded. At present the following mappings are made: " -> " < -> < > -> > & -> & When variable output text encoding is supported, this form will also automatically convert any characters that cannot be represented to their appropriate HTML entities. -------------------------------------------------------------------------------- NEW SYNTAX: INCLUDE The include command allows you to parse and execute script files other than the one launched by the CGI request. It takes an expression evaluating to a filename as a parameter: include Upon execution, the given file will be loaded and executed in the same manner as the main script - any definitions will be added to the global environment, any statements directly executed and any content blocks directly output. The engine presumes that file begins in a content block and as such if it just contains code - indeed, for 'library' style includes it is advised that you do not terminate the file with ?> to stop headers being output earlier than you expect. Includes can be nested up to a depth of 16 - attempting to include beyond this limit will throw an error. Stability: It is not expected that the action of the include command when used at top-level scope, or when the target file consists entirely of definitions/content blocks will change - i.e. when the 'include' is used to load library scripts. -------------------------------------------------------------------------------- NOTES: ENGINE EXECUTION Each request of an '.irev' page from a web-browser causes an independent instance of the irev engine to be launched. In particular, note that there is no 'persistent' engine environment in which irev scripts are executed - each one is entirely separate. -------------------------------------------------------------------------------- NOTES: FORM PROCESSING At present the irev engine has native support for the GET method and POST method when using an enc-type of "application/x-www-form-urlencoded". If a form sends data to the irev engine with an encoding type it doesn't understand then the $_SERVER["CONTENT_TYPE"] and $_SERVER["CONTENT_LENGTH"] variables will contain information about them and the sent data can be read from stdin. Note that if these variables are not present/are empty then it means the irev engine has already processed the sent data. Any natively processed data will be placed into the $_GET and/or $_POST global arrays. -------------------------------------------------------------------------------- NOTES: COOKIES As yet there is no inbuilt support for cookies. However, you can set and fetch cookies attached to a page directly. To set a cookie simply use the 'put new header' command: put new header "Set-Cookie: mycookie=myvalue" [ Note that we use the 'put new header' form here, since it is likely you might want to set more than one cookie, and the 'put header' form will only allow one header of a given type ] The cookie will be passed back to the server in a subsequent request in the $_SERVER["HTTP_COOKIE"] variable. For more information about cookies, the Wikipedia page is a good starting point. -------------------------------------------------------------------------------- NOTES: TEXT ENCODINGS There is currently a discrepancy between the text encoding natively handled by the irev engine - ISO8859-1 - and that which is used for filenames - UTF-8. We are currently working to resolve this, but for now recommend that you stick to ASCII filenames in order to prevent forward compatibility issues. -------------------------------------------------------------------------------- NOTES: STACKS The irev engine does not currently support stacks. Although the syntax related to them might appear to work in some cases this is not in any way integrated with the 'global environment' in which the main/any included scripts run. We are currently working on a way to integrate these two models in a clean fashion. -------------------------------------------------------------------------------- NOTES: EXTERNALS Currently, Revolution externals are tied to the loading of stacks and as such the irev engine does not yet support user-specified externals. However, the following externals are integrated into the environment and thus available for use without any explicit action: revxml, revzip, revdb. In the case of revdb, you can use SQLite, PostgreSQL and MySQL. -------------------------------------------------------------------------------- NOTES: VERSIONING The current version and buildnumber of the irev engine should be considered not to reflect anything in particular except that fact that the code is branched from (desktop) Revolution version 3.5.0-gm-1. We are still working out a sensible versioning system for the irev engine and will roll this out when we reach the first 'stable' development version. (Note there are no versioning conflicts with this at present as updates to the irev engine are done synchronously across all of our servers, and only one version will be present at once for the time being).