If you're like me, you are hosting a website on your IBM i system. I host a number of websites on a single partition and have virtually no issues with capability or function. While I don't have all the features that a small number of business may need (about 5%) I do have all the capabilities needed to provide everything I need. (This site for example, is written with RPG and the COZZI TOOLS.)
My websites are Java-free, PHP-free, ActiveX-free, .Net-free environment. When you introduce those components you require additional skills and software that I don't want to introduce in the mix. Although PHP is a sound investment today, those other languages and environments have certainly fallen out of favor after a brief 15-minutes-of-fame, so I tend to ignore those bleading-edge things when it comes to production use.
I do use Java for some solutions, but nothing on the webpage itself. Java certainly does some things easier than other solutions. For example, our Java Mail CL Command evokes a Java Class/Method to send email. I couldn't do it as well or as easily in RPG IV using native APIs. When it comes to using Java or other technologies with the web, I prefer using one of the great 3rd-party tooling products for this function, such as BCD or MRC
Recently a client who uses my popular COZTOOLS software to copy SPOOL files to PDF files and to copy PDF files on the IFS to remote Laser Printers around the world asked me to create a webpage. This page would allow their employees to upload a photo of themselves that would be used with online chat sessions. They also wanted to be able to support any image format, as well as PDF.
The task of building a web page that accepts a text input field and allows a file to be uploaded was finished very quickly. In fact it took longer to write this article than it did to write and test the implementation.
I used my COZTOOLS CGI library to help expedite the process. Its been around for over 10 years and has been thoroughly put through the ringer. Every type of business use it from Manufacturing to Casinos ("gaming") to Government agencies, to Universities. Just about all "RPG for the Web" tasks that you need in an IBM i shop are supported. So it was the logical choice.
COZTOOLS CGI Library supports files uploads, we think it does so better than similar solutions. You can simply grab the file from the webpage using RPG IV, and save it out to the IFS directly, or do more; it's up to you.
To allow web users to upload a file, you allow them to go to a webpage that has this capability. Once a user has gone through the normal security measures (the web-world refers to security as "Authorization") you present them with a web page that enables uploading. Here is an example section of a web page that enables uploading a file:
Here is the corresponding HTML for that upload screen.
To enable file uploads, the standard HTML <INPUT> tag is used within a <FORM> tag. Type type of INPUT tag is FILE and is specified as follows:
<INPUT name="img" type="file" size="64" maxlength="640" />
The SIZE and MAXLENGTH parameters are optional, but for older versions of Web Browsers, the input field is displayed for the file name; today, it is not. Instead only a Browse... button is displayed. When the file is selected (a file on your PC) its name is display to the right of the Browse... button.
The <FORM> tag contains several parameters. To upload a file you need to use the POST method (method="post") along with the ACTION keyword. The POST method means the data from the HTML form is pass along with the HTTP request and is not visible to the Browser user, in addition it has no size limits. Essentially any size file may be uploaded, and restricting it is the responsibility to the HTTP server configuration or the CGI program itself. You cannot upload files using the GET method.
The ACTION keyword identifies the CGI RPG program that you are using to process the POST request. This CGI program can access the data specified on the HTML form. In our example, the file being uploaded along with the EMPNAME (employee name) text is available to the program.
One other parameter or "attribute" of the FORM tag is the enctype (encoding type). The COZTOOLS processes data sent using the multipart/form-data encoding scheme. This allows multiple files and other FORM data to be specified on the FORM.
I find it incredibly easy to accept a file using COZTOOLS CGI service program. Writing RPG for the Web applications is a matter of using the CGI subprocedure calls. For example, to retrieve the data into the RPG program named UPLOADER you'd use the following:
H DFTACTGRP(*NO) ACTGRP('RPGWEB') OPTION(*SRCSTMT) (a) H BNDDIR('COZTOOLS/COZTOOLS') (b) /INCLUDE cozTools/QCPYSRC,CGILIB D saveDir S 640A Varying D fileName S 640A D imgType S 32A D szMsg S 255A Varying C Move *ON *INLR /free (1) cgiInit(); (2) saveDir = '/home/emp'; (3) cgiGetFileName( 'img' : fileName : %size(fileName) ); (4) imgType = cgiGetFileType('img'); (5) cgiSaveFileEx( 'img' : 1 : saveDir ); (6) szMsg = 'Content-Type: text/plain' + X'2525' + 'SAVED your ' + %trimR(imgType) + ' file named ' + %trim(fileName) + ' Thank you!' + X'25'; endif; (7) cgiStdOut( szMsg ); /end-free
The COZTOOLS CGI Service Program allows you to easily write RPG for the Web code. Let's review this simply CGI/RPG program that allows users to upload data and text information from the web page to the RPG program itself.
Line a: This is the Binding Directory that contains the Exports for COZTOOLS. Every program that calls a COZTOOLS function, should use this BNDDIR keyrword.
Line b: This is the CGI include member or "copybook" if your hair is a bit grayer. The way RPG IV works best is using Subprocedures. RPG IV requires the use of Prototypes in order for your program to be able to call any of those subprocedures. Since COZTOOLS exports over 200 subprocedures, we include the prototypes for you. If you only want the CGI library subprocedures in your code, the /COPY (or /INCLUDE) the CGILIB source member from our QCPYSRC ("copy source") source file. There are lot more functions that just CGI but CGI is certainly the most popular feature of our COZTOOLS.
Line 1: To initialize the CGI environment and tell this program that it is a CGI/RPG program, you call the cgiInit() (initialize CGI environment) subprocedure. This must be performed before any other CGI-related subprocedures. COZTOOLS, however, is smart enough to understand that if you forget to include the call to cgiInit() it will automatically evoke it for you. I prefer to explicitly code it, as I've done here because there are optional parameters for this subprocedure that can be overlooked if you not in the habit of using it.
Line 2: Before saving the uploaded file, we move the target directory into the SAVEDIR variable. This is used on line 5 to save the uploaded file.
Line 3: The cgiGetFileName() subprocedure returns the name of the file being uploaded. This is the file name the end-user specified on the Web Browser's HTML Form. For example, if a file named SELFIE.jpg is specified, "SELFIE.jpg" is returned by the cgiGetFileName() subprocedure. The cgiGetFileName() subprocedure will return only the file name, not the user-specified path. Ffor example "c:\user\cozzi\pictures\selfie.jpg" is returned as "selfie.jpg".
Line 4: The cgiGetFileType() subprocedure returns the type of file being uploaded. Typically it will contain the file suffix but it does not use the suffix to determine the file type. For example, "selfie.jpg" would return a file type of "JPEG".
Line 5: The cgiSaveFileEx() subprocedure saves the file being uploaded. The first parameter is the HTML Form Variable name that contains the file name and content. The 2nd parameter is the occurrence of the HTML Form Variable in the HTML Form. HTML allows you to have duplicate Form Field names. Each Form Field is referenced in the CGI/RPG program using its occurrence index. Think of this as a implied "subfile" for the web. All the cgiXXXXXX subprocedures support an occurrence index that defaults to 1. You can use the cgiGetVarCount() subprocedure to determine the number of occurrences for each Form Field. But typically if you specify only one, you can ignore the occurrence index.
The cgiSaveFileEx() subprocedure specifies the Form Field name as parameter 1, the occurrence as parameter 2, the IFS directory (save location) as parameter 3, and optionally, the file name as parameter 4. If no parameter 4 is specified, it uses the actual name of the file being uploaded. In our example, the file is saved as: /home/emp/selfie.jpg
Lines 6 and 7 build and then send the HTTP reply to the browser.
The ability to upload a file is increasingly important today. The proliferation of images, PDF files, and even Excel worksheets means content is being sent all over the place, Using the COZTOOLS you can easily allow someone to upload a file with HTML and RPG for the Web to your IBM i system.
With today's ever increasing Image File sizes, someone asked about uploading a file larger than 16MB. Normally RPG, Java and other methods limit file uploads to the 16 megabyte boundary. But when we wrote COZTOOLS CGILIB we wanted to allow any size file to be uploaded. In fact, our initial testing used 50MB files. How did we do it? The cgiInit() subprocedure has an optional parameter that allows you to provide an alternate "CGI Buffer". Internally we use a *USRSPC for the CGI buffer, but if you need larger than the 16MB limit of a user space, you can allocate and pass in a Teraspace pointer to the cgiInit() subprocedure, as follows:
(1) H ALLOC(*TERASPACE) (2) D bufLen S 10I 0 (3) D pBuffer S * /free (4) bufLen = cgiGetContentLen(); (5) pBuffer = %alloc( bufLen+1 ); (6) cgiInit( pCGIBuffer : bufLen+1 ); // Do your normal processing here. (7) deAlloc pBuffer;
To enable large file upload support in RPG IV, specify the ALLOC(*TERASPACE) keyword on the Header specification (Line 1). This causes the %ALLOC built-in function to use Teraspace pointers. The pointer that is returned by %ALLOC on line 5 will be a teraspace pointer.
Before calling cgiInit() subprocedure, you may call the cgiGetContentLen() subprocedure to determine the size of all the uploaded data. This includes the file(s), and the other HTML Form fields. It gives you an accurate size needed for your CGI buffer. Use the %ALLOC built-in function to allocate the memory for this CGI transaction (see line 5).
Then call cgiInit( ptr : size ) this causes the COZTOOLS CGI Library to use your user-provided CGI buffer. Since this buffer is large enough to handle the uploaded data, you won't have the 16MB limitation found in many other products.
Once you're finished with the CGI application (you've saved the data where it needs to be saved, and performed any required tasks) you need to DeAllocate the storage you previously Allocated. To do that, use the RPG IV DEALLOC opcode (see line 7). If you do NOT do this, you will have a learning experience, eventually. A Golden Rule of thumb: If you allocate storage, you must also deallocate that storage before your program ends.
That's all there is to it.
The COZTOOLS (Cozzi Tools) software product is available at www.cozTools.com Be sure to check out the list of included CL commands and the growing list of examples we provide.
Bob Cozzi is a technical advisor to IBM i clients around the world. His specialty is solving difficult programmming issues for his clients, training their programming staffs, and performing system migration/upgrades for small shops. His consulting rates are available online. To contact Bob, send an email to: bob at rpgworld.com
You can subscribe to RPG Report (we call it "follow") by visiting the RPG Report page on midrangeNews.com and then click the FOLLOW link in the table of contents for that page. To unsubscribe, simply click that same link. You must be signed up and signed in to midrangeNews.com to start following RPG Report.