CGIHELPER is an IBM i *SRVPGM with functions (aka procedures) that simplify CGI programming in the RPG IV language. Prototypes for RPG IV are included for all functions published in the service program. It is compatible with IBM i V7R3 and later, although it can be modified to work with V7R2 if necessary. The RPG IV code in which it is written, is 100% RPG IV and uses the free format syntax only.
Here is a short sample program that writes a title and then Hello
World out to the web browser using CGIHELPER.
The output from this program is shown below. To cause it to run you need to have a <ScriptAlias> or <ScriptAliasMatch> section in your HTTPD.CONF file on the IFS.
For example, if your web server instance name is SILVERLAKE, you would find the httd.conf file in the /www/silverlake/conf folder.
The config file should contain something like the following:
ScriptAliasMatch ^/CGILIB/(.*) /QSYS.LIB/WEBPGMLIB.LIB/$1
This allows programs in the IBM i library named WEBPGMLIB to be used as CGI programs. If you compile the above HELLODEMO program into WEBPGMLIB you can then run it from your web server as follows:
https://mydomain.com/cgilib/hellodemo.pgm
Of course the https//myDomain.COM part needs to be replaced with your own web server domain or host name. But that part is up to you to figure out.
Here is an example of the output from running this program.
There are several copy/include members included in CGIHELPER. However I've created on simple copy member to use to make sure you have all the prototypes for your CGI program. That general copy member is:
To include this in your CGI RPG programs, just use the /copy or the preferred /include directive as follows:
/include cgiHelper/cgiHelper,cgiHelper
In addition to this /include member, you also need to make sure CGIHELPER *SRVPGM is bound to your CGI RPG program. There are 2 ways to do that.
All three options accomplish the same results.So pick the one that you're used to using.
Note that the BNDDIR keyword, obviously goes on the H spec or the CTL-OPT keyword, where as the /include of member CGIHELPER should be placed after any RPG File Declaration specifications and before any main-line calc specs or DCL-PROC statements.
As you probably noticed, I am using the MAIN(MAIN) style RPG program. No RPG CYCLE is embedded in programs that use the MAIN keyword on the CTL-OPT spec. This means you do NOT "set on LR" to end the program. When the routine returns, the program ends.
Let's review the body of the main procedure, line by line.
DCL-PROC MAIN;
This declares a procedure named MAIN (it could be any name). The name for which is identified on the MAIN(main) keyword on the H spec or the CTL-OPT keyword. It identifies the name of the start-procedure that is run when the program is called. If you want a different name like PICKELS, then you would refactor the code as follows:
CTL-OPT MAIN(pickles) BNDDIR('CGIHELPER/CGIHELPER'); ... dcl-proc PICKLES;
While you can use any procedure name, other languages, such as C, C++ and some others use (actually they require) the main procedure to be named "main". This is because there is no equivalent of the RPG IV CTL-OPT MAIN keyword in those languages, so they have to depend on a reserved name in order to properly run. So I tend to use MAIN as the main procedure name.
CGI_Init();
The CGI_INIT() function clears any existing query strings and related information from the CGIHELPER service program's memory. Technically, if your CGI RPG IV program is running in ACTGRP(*NEW) this call isn't strictly needed. But it is a very short, fast routine with just a handful variables being cleared. So add this to the top of the CGI RPG IV main procedure.
myMSG = cgi_getVar('MSG');
The CGI_GETVAR function returns the value entered by the user into an HTML FORM field. For example, if you have this kind of form in your HTML, it would pass the MSG value to the CGI program as a QUERY_STRING entry and the CGI_GETVAR function retrieves that value for you. Here is a typical form with one field named MSG.
<form name="RCDFMT" action="/cgilib/dsphello.pgm" method="get"> <label for="MSG">Type your <input name="MSG" id=""MSG" type="text" maxlength="64" placeholder="Type your user message here"></label> </form>
This form is sent to the IBM i HTTP Server as follows:
rpgworld.com/cgilib/dsphello.pgm?MSG=Pickles
WHere rpgworld.com is replaced with your domain name.
The MSG field is added to the program name following a ? separator. If more input fields were specified on the FORM, then each subsequent input field is added to the string by separating each parameter with an & symbol. For example if there was also a QTY (quantity) inpu field and 12 was entered into it:
rpgworld.com/cgilib/dsphello.pgm?MSG=Pickles&QTY=12
The cgi_getVar function can specify any form field name. Note that HTML FORM input field names are case-sensitive. However, CGIHELPER's cgi_getVar function searches for them in a case-insensitive mannor. That is, upper/lower case in FORM field names is ignored.
Next we will look at the first 3 cgi_stdOut functions
cgi_stdOut( html_getStart() ); cgi_stdOut( html_tag('h1' : 'CGI Helper Demo Page')); cgi_stdOut( '<p>' + msgTEXT + '<p>\n');
The first cgi_stdOut writes the results (returned value) of the call to html_getStart(). This function generates standardized html file starter code. This includes the !DOCTYPE, HTML, HEAD, STYLE, and BODY tags. It has parameters to allow you to customize what is being generated, but I just want the default starter code.
The second cgi_sdtOut also uses an embedded procedure call to html_tag. This function composes the designated HTML tag (≶h1> in this case) and wrap the specified text in that HTML tag. This function is intended to allow you to avoid complex concat operations. But if you prefer to compose your own HTML tags, feel free to do so, using just the cgi_stdOut function itself; as I do in the next two cgi_stdOut statements.
The third cgi_stdOut writes out the data directly (no nested procedure calls). This statement writes out a parameter containing the data stored in the MSGTEXT variable. Which is "Hello Wolrd" in this example.
The fourth cgi_stdOut is conditioned based on whether or not the CGI FORM field was passed into the program and has any data inn it. If it does, then we write out a custom paragraph with that extra data in it.
The final cgi_stdOut writes out the results from the call to the html_getEnd function. This function returns a closing <body>\n<html> string to help close out the HTML page.