PHP from an RPG Perspective, Part 2: Browser PHPunctions

Article ID: 64526
An overview of PHP browser handling, control structures, and more on arrays

Editors' Note
Please check out the companion forum thread called Homework: PHP from an RPG Perspective" in our e-Development forum on SystemiNetwork.com.

Welcome to Part 2 of the introductory PHP series, "PHP from an RPG Perspective." This time I'll take a look at the basics of handling browser input in PHP, and in particular how a few simple tweaks to the naming of our HTML form variables can simplify the process. As you will see, just about everything in PHP, and specifically processing browser input, involves the use of arrays to one degree or another. While this month's example will introduce you to some aspects of PHP arrays, there are a number of other features that I'd like to introduce you to that don't fit easily into the example, so I'll be covering them in the sidebar "Fun and Games with Arrays" below. In addition to discussing the basics of browser input, I'll also take a closer look at control structures and compare and contrast those of PHP with RPG's.

Separating Logic from Display Formatting

Because it's a common question and relates to this month's topic, I want to briefly discuss the separation of PHP logic from display formatting (i.e., HTML) code. During my PHP classes, RPGers often ask why, in most of my PHP examples, the HTML is embedded in the script; as indeed it is to some degree in my main example, Figure 4. The reason—I believe—is quite simple. Unlike RPG, PHP doesn't have a single equivalent to externally described display files. When I write an RPG example, I can be certain that if I use an EXFMT in the code, my audience will understand what I am doing. PHP can, and in most modern applications does, externalize its screen formats just as RPG does, but there are many ways of doing this. As result, examples cannot depend on the reader being familiar with any one method.

You will have the chance to study more of these approaches later in this series. For now I'll use the embedded-HTML approach, but with a "twist" in this particular example. The main technique I use in this case is to incorporate the HTML form in the main script, but to code it as pure HTML rather than using echo or print to add it to the web page. This technique lets me use a conventional HTML editor to design the form. Indeed, the PHP editor in Zend Studio, which is where I do most of my PHP work, understands and checks HTML syntax, but it doesn't have a WYSIWYG view. Most of today's WYSIWYG HTML editors (such as Dreamweaver and KompoZer) understand PHP code islands to the extent that they can highlight them as such in their WYSIWYG views. These editors do not, however, understand PHP syntax, so I tend to stay with Zend Studio.

Employing static HTML within a PHP script requires you to first understand how PHP can be used to condition the output of such HTML. And before you can understand that, you need to know how basic conditional logic is coded in PHP. All this for just a simple input form! But having struggled for some hours with how to explain this series of related simple techniques in a meaningful way, I have concluded that only by taking it a step at a time can I hope to adequately explain it. It really isn't hard—honestly—but there are a number of simple principles involved.

A Useful Illustration

Figure 1 illustrates the basic technique. The script begins by assigning the value 5 to the variable $x. It then tests (at A in Figure 1) to see whether $x contains the value 5 (Yes, I know that will always be true at this point, but have patience!). If it does, then the script uses echo to output a message to that effect. If the test fails, the else condition comes into play and a failure message is output. Simple, right? But perhaps an explanation of PHP's if control structure is in order. I cover more details of control structures in the sidebar "PHP's Conditional Control Structures" below, but for now it will suffice to say that there are three primary differences between the use of if statements in PHP and in RPG. In RPG the basic syntax for if/else is:

          If expression;
            code to execute if true;
          else;
            code to execute if false;
          endif; 

In PHP the same thing would be coded as:

          if (expression) {
            code to execute if true;
          } else {
            code to execute if false;
          }

The actual alignment of the { } characters is a style choice, but the basic construct remains the same. As you can see, there are three primary differences:

  1. The expression being evaluated must be in parentheses ( ) for PHP; whereas in RPG it's merely considered good practice and isn't compulsory.
  2. In PHP, the code to be executed is surrounded by { } characters (known as a "statement group"), and there is no ";" (semicolon) following either the if or the else.
  3. No endif is required in PHP—the closing } effectively replaces it. However, there is a variant of PHP syntax that uses it. Read "PHP's Conditional Control Structures" below for details.

If you look at B in Figure 1, you'll see that I have an identical if statement to the one at A—but—immediately following the { that begins the true statement group, I end the PHP code island with a ?>. Seems a little strange, doesn't it? But the effect it has is that the HTML text at C in Figure 1 will only be output to the browser when the expression at B is true. At D in Figure 1 I've opened another code island, in which I immediately close the true group, code an else, and then open the statement group before immediately ending the PHP code island, leaving the HTML at E to be considered part of the statement group. Naturally, the content at E will only be output when the result of the if test is false. Last, but not least, at F in Figure 1 I open one final code island to close the else group.

This practice is quite common in PHP and lets you put conditional controls on the HTML output without using print or echo.

Run the script and you will see that only the "true" messages appear in the browser. Now edit the script to assign a different value to $x (anything except 5) and run the script in your browser again. This time you should see the "false" messages appear.

Now that you understand how this mechanism works, it's time to go back and look at how this principle applies to the output of the HTML form. In identifying the parts of the script that I want to describe, I've grouped the related HTML components with the relevant part of the PHP code by using the same initial letter. So A in the PHP script relates to A1, A2, and A3 in the HTML.

But before you look at the HTML and the PHP code behind it, take a look at the web form (Figure 2) that I'll use in this example. The form is a simple one, comprising just two input fields and a multiple selection list. (Figure 3 shows the results of running the script with the form entries from Figure 2.) There are, however, a couple of things I've done in the naming of the form fields that make it easier to work with them within the PHP script (Figure 4).

Processing the Web Input

Web input comes in the form:

          name1=value1&name2=value2&...&nameN=valueN. 

PHP translates this into an associative array, the content of which is formed just as if you had keyed in:

          array('name1'=>'value1', 'name2'=>'value2', ... , 'nameN'=>'valueN'); 

The specific array created depends on the input method you use for the form. In this case, I used the GET method you see here (A2 in Figure 4):

          <form get action="WebInput1.php"> 

The form GET method means that the data will be passed in the URL. While this is not generally good practice for form handling in the real world (the POST method is far more secure), being able to see the data is useful when learning web programming. Note also that the action script identified to process the form input is WebInput1.php. Interestingly, that is the name of the script itself! In other words, when the submit button is pushed, the data will be passed to this self-same script for processing. That may sound strange, gentle reader, but bear with me and all will be made clear.

Because the GET method is being used, all of the form input (if any) is placed in the "superglobal" associative array $_GET[ ]. I'll return to the topic of superglobals in a later article, but for now all you need to know is that the array $_GET[ ] is where you'll find all the data. Since the script (Figure 4) is required to both output the form and to process any subsequent input from it, I need to know whether the script was invoked simply by having its name entered in the browser's URL or by pressing the form's submit button. I achieve this by the simple expedient of giving the submit button a name (name="submit"), which causes its value ("Submit Answers") to be passed as input along with all the other data (A3 HTML code in Figure 4):

<input type="submit" name="submit" value="Submit Answers"> 

How is this useful? It means I can check to see whether there is a value associated with the array entry $_GET["submit"], and if there is, then I know that the submit button was pushed and I have data to process. If the variable isn't set, then this must simply be a request to output the form itself. This is such a common practice in PHP scripts that I was convinced for a while that the variable "submit" had some kind of special meaning in PHP. But it's merely a convention that a lot of people use.

The technique I discussed earlier for controlling the output of static HTML is put to use here. The test that conditions the HTML output is at A in Figure 4:

           If (!isset($_GET["submit"])) {

If the script was not invoked via the submit button, then this test will be true, and the HTML form (which begins at A1 in Figure 4) will be output. The exclamation mark in front of the isset() function is equivalent to RPG's NOT keyword, so this would be equivalent to coding something like this in RPG:

           IF NOT submitPressed;
             // Output HTML

Of course, RPG does not have any such indicator as submitPressed, but I can dream, and hopefully it makes the point.

If the script is invoked by the pressing of the submit button, there will be a number of entries in the $_GET[ ] array: the person's name, profession, and the computer languages they speak. As a result, the static HTML section will be skipped and the main script, which begins with the else clause (C in Figure 4), will be executed.

The first thing that the main PHP script does is use the count() function (B in Figure 4) to determine how many languages the user selected. Count is an array function, so for it to work I had to make sure that the selected languages formed an array. I achieve this by a simple naming convention in the input form. Look at B1 in Figure 4. The name of the input was specified as languages[ ]. Note the square brackets in the name. This tells PHP that I want any input values with this name treated as an array. So if the user selects three languages, there will be three array elements.

Once I have the count of the number of languages, I can output the initial message (D in Figure 4). Note in particular that since I didn't need to further process the name or profession entries, I can reference them for output directly from the $_GET array as $_GET["name"] and $_GET["jobTitle"].

To simplify the subsequent coding, at E in Figure 4 I copy the language array from the $_GET array into the array variable $languageList. I then apply our old friend foreach( ) to step through all the elements of the array one by one (F in Figure 4). However, I couldn't resist adding one small wrinkle to the foreach( ) process. As the script steps through the loop, it checks to see if the current item is "Other," and if it is, rather than output the language name, it outputs the text " - And other language(s)".

That is all there is to it.

Additional Thoughts

As you can see, PHP makes it pretty easy to obtain web input data, including the ability to have potentially repeating items such as language selections "automagically" treated as an array. In fact, you can go further with this array idea than I have here. For example, suppose I had a form consisting of entry fields for a person's address. It might be convenient to process all of the fields as part of an address array. To make this happen in PHP, all I need to do is use appropriate names in the form. For instance, I might choose the name Address[Street] for the Street name field and Address[City] for the City name. The result of submitting such a form would be that the contents of the Address[xxx] fields would be placed in associative array elements where the key was the name used in the [ ] array subscript delimiters. In other words, assuming the GET method was used, $_GET[Address] would contain an associative array with two elements—one with the key "Street" and another with the key "City." Similarly, such naming conventions could be used to group check boxes as arrays, or radio buttons, or ...

I mentioned earlier that $_GET was just one of a number of "superglobals" in PHP. These are variables that are always available at any point in a PHP script. There are three other superglobals that relate to basic browser input:

  • $_POST, which contains all the data submitted in a form request that used the POST method;
  • $_COOKIE, which contains all variables passed to the script via cookies. I will cover cookies in a future article in this series;
  • and $_REQUEST, which contains all the input data from all sources, i.e., it's the combination of $_GET and $_POST and $_COOKIE data.

While it may be tempting to think about using $_REQUEST because you wouldn't have to worry about how the data was passed to you, it's dangerous in production code for that very reason. You have no way of knowing whether the data came in from a form as part of a POST request, or if someone who knows (or guesses) the names of certain fields in the application has attempted to fool the scripts by passing data for those fields in the URL (i.e, in the GET data). If you use $_REQUEST, you have no way of knowing. For this reason, $_REQUEST should only be used in testing or when just "playing around."

Jon Paris has been involved in IT for over 40 years—his experience covering the spectrum from operations to compiler design. Jon joined the languages group in IBM's Toronto Lab in 1987, where he was involved in the launch of the AS/400. Subsequently, Jon was assigned to the architecture and planning group with responsibility for the Cobol and RPG languages. He was one of the "fathers" of RPG IV and played a major role in its design. Jon left IBM in 1998 and with his partner Susan Gantner now runs Partner400, a company focused on developing and delivering application modernization education in the IBM i world. Partner400 is also a member of the System i Developer educational consortium, which runs the RPG & DB2 Summit conferences. Jon is a frequent speaker at user group meetings and conferences around the world and has a number of speaker excellence awards.


Fun and Games with Arrays

In the first article in this series, "PHP from an RPG Perspective, Part 1: PHPundamentals—The Basics" (December 2009, ID 64331)I used a basic array to introduce you to the concept of associative arrays. I didn't even begin to scratch the surface of just how powerful and flexible PHP arrays can be. In fact, there are over 70 array functions in the PHP language. That's nearly as many array-oriented functions as RPG IV has in total. While I can't cover all these in one sidebar, the script in Figure 5 gives you a taste of what you can do. For a full list of array functions, check out the online manual at php.net (php.net/manual/en/ref.array.php). You'll find the online examples incredibly helpful as you study the functions.

Take a look at Figure 5. At A I start by defining the associative array $languageData, which I use in this example. Next, I sort the array at B in Figure 5 using the asort() function. Don't confuse this with RPG's SORTA (the PHP equivalent of that is sort(), which I'll get to later). It's necessary to use asort() because when working with an associative array and sorting the values, the keys should maintain their association with those values. The foreach loop following asort() displays the array in its new sequence:

First sort array in ascending value sequence

3 years of PHP
5 years of RPG/400
7 years of Java
12 years of COBOL
15 years of RPG IV

RPG uses the ASCEND and DESCEND keywords to indicate that SORTA is to sort into ascending or descending sequence. In PHP the descending key equivalent to asort() is arsort(), which is demonstrated at C in Figure 5 and produces the output:

Same array but sorted in reverse value order

15 years of RPG IV
12 years of COBOL
7 years of Java
5 years of RPG/400
3 years of PHP

But what if I want to sequence the array not by its values but by the value of the keys? One way to do this is to use the array_flip() function at D in Figure 5. This function returns a new array where the keys become the values and the values become the keys. The script output shows the switch:

Demonstrating how the keys and values can be reversed

The key is 15 and the value is RPG IV
The key is 12 and the value is COBOL
The key is 7 and the value is Java
The key is 5 and the value is RPG/400
The key is 3 and the value is PHP

The array could then be sorted using asort() or arsort as appropriate. Of course, as you've probably guessed by now, useful as this function may be, I don't need to use it just to achieve my goal. The functions ksort() and krsort() will do that for us as demonstrated at E and F respectively in Figure 5 and result in:

Now we'll sort the original array by the keys

12 years of COBOL
7 years of Java
3 years of PHP
15 years of RPG IV
5 years of RPG/400

And then in reverse key order

5 years of RPG/400
15 years of RPG IV
3 years of PHP
7 years of Java
12 years of COBOL

Hopefully by now you're getting the idea that there's an awful lot you can do with PHP arrays. Still, I have only just scratched the surface. Look at a couple other features before I wrap up.

Arrays in PHP have a cursor (just like a database), and you can manipulate that cursor through the use of a number of functions such as next() and prev().Look at the code starting at G in Figure 5 and you will see what I mean. Because the previous "foreach" loop left the cursor in an undefined position, I open with the reset() function to reposition the cursor back at the top of the array. This is verified by echoing the content of the current() element and using the key() function to display the current key. I then demonstrate the results of using the next(), end(), and prev() functions.

Next we jump around using the array cursor

After a reset(), the array cursor points to the value 5 with the key RPG/400
The next value is 15 with the key RPG IV
The last entry is 12 with the key COBOL
Finally we step back one to the value 7 with the key Java

I promised that I would return to the sort() function (H in Figure 5) before I closed this piece. In fact the only reason I delayed using it was because it will "destroy" my associative array, and I didn't want to have to copy it!

sort() works the way that RPG's SORTA does in that it sequences the values in the array; however, in doing so sort() destroys the keys and rebuilds the array using a conventional numeric index. Run the script and check it out. The resulting output doesn't make much sense, but I felt it demonstrated the principles I didn't included an example, but you've probably guessed that the function rsort() is the equivalent of SORTA with the DESCEND keyword applied. Isn't it nice to be able to sort an array in multiple ways without having to tie the sequence to the data definitions themselves as you do with RPG? You can see the "new" numeric keys in the script's output—starting at zero, of course—you did remember that, didn't you?

Finally ignore the keys and just sort the values

Value is 3 key is now 0
Value is 5 key is now 1
Value is 7 key is now 2
Value is 12 key is now 3
Value is 15 key is now 4

So there you have it: a taste of the amazing world of PHP arrays. I'll discuss some of the other features on the e-Development forum at SystemiNetwork.com (look for the Homework: PHP from an RPG Perspective thread), but if you're feeling adventurous, I suggest you look at the array_diff_...() and array_intersect_...() functions. Yes, you can indeed use PHP's arrays almost as if they were a database.

—J.P.

PHP's Conditional Control Structures

So far I've introduced you briefly to two of PHP's control structures: the basic if () and foreach (). In this sidebar I give you a little more on the use of if () and introduce you to a few more conditional logic structures.

The script in Figure 6 begins with a for () loop (A), which, while not identical to the RPG version should be relatively easy for you to decipher. The first of the three expressions in parentheses represents the starting condition, which will be evaluated once at the beginning of the loop. RPG works in the same way, but with one significant exception. In PHP it's possible to use the first part of the expression to set multiple variables by separating the individual expressions by commas (e.g., for ($x = 0, $y = 1, $z = ... ). The second expression is the "while true" condition, and as with RPG can be omitted to provide a "forever" type of loop that must be terminated by a break instruction (equivalent to an RPG LEAVE). The third part is the iteration expression, typically used to increment the variable (++) used in the earlier expressions. As with RPG, the iteration runs at the end of the loop.

A couple of additional points: first, the "forever" type of loop in PHP is a little more useful than in RPG because in PHP you can omit the iteration expression with no side effects. You can omit the expression in RPG, but the compiler will automatically add code to increment the control variable by 1 each time through, and therefore the potential exists for numeric overflow. Admittedly, it is not that likely a scenario, but ...

Secondly, some of you may be unfamiliar with the ++ notation (A in Figure 6). $x++ will cause $x to be incremented in the same way that coding $x+= 1 (or $x = $x + 1) would in RPG and is a commonly used construct in PHP. You will also encounter cases where the ++ symbols appear before the variable name (e.g., ++$x). I'll leave a discussion on the ramifications of that difference for the forum rather than complicate things further here; but if you just can't wait check out the PHP manual (php.net/manual/en/language.operators.increment.php).

Within the for loop I demonstrate PHP's switch() structure (B in Figure 6). This is similar to RPG's SELECT/WHEN construct. The RPG translation of the PHP code would be:

Select;
  When ( $x = 1 );
     Dsply 'Case was 1';
       ...
  Other;
     ...
EndSl;

The big difference is that in the RPG version the When clause can be any kind of comparison. In PHP's switch, the value of the single variable named on the switch itself is tested for equality with the value identified on the case statement. I find this less confusing than the RPG version, but that's probably just me.

One aspect of switch that always trips up RPGers is that in PHP, once a matching case() value has been found and the associated code executed, PHP will not skip to the end of the group as RPG would, but rather will continue to execute statements until such time as a break statement is encountered. While this behavior can sometimes be useful, more often than not it will bite you in the ... Well let's just say that it is a good idea to get into the habit of specifying a break at the end of each case group. At B in Figure 6, without the break statements in place, if $x has a value of 1, all 3 echo statements in the switch block would run!

While within the loop, I decided to demonstrate an additional feature of PHP's structure that I didn't mention in the main article: the elseif construct (C in Figure 6). This works exactly the same way as RPG's elseif. If you look carefully at the logic in the if group, you'll see that it exactly mirrors the behavior of the switch group above it (B in Figure 6).

The if/else structure provides an opportunity to point out another difference between the two languages: In RPG the code is If ($x = 1), but in PHP the code is If ($x == 1) since a test for equality is represented by double equal signs. This may sometimes cause problems in your early PHP explorations. Why? Because if you forget and code only a single equal sign (e.g., If ($x = 1) ) the result is perfectly valid syntax that won't do what you want because in this case the test would always be true! PHP would first assign the value 1 to $x and then test if the value in $x equated to true. Since a non-zero value is considered true in PHP, the expression would always be true. This is a mistake I still make from time to time, particularly when switching back and forth between RPG and PHP.

Next up is PHP's while loop (D in Figure 6), which maps directly to RPG's Do While (DOW) (i.e., PHP's while loop creates a top-tested loop where the controlling condition is tested before entering the loop). As a result, the code within the loop may never execute. Try using a different initial value for $w to prove this to yourself.

Contrast this with the do...while loop (E in Figure 6), which maps to RPG's Do Until (DOU). Yes, you read that correctly. At first I found this confusing until I realized that the PHP code is much easier to read. I've always had a blind spot as far as remembering which of RPG's 2 DOx operations is which, and I inevitably end up checking the manual. With PHP it is much more obvious which is which because the while phrase is located at the end of the block, so there's no problem remembering that this is the bottom-tested version of the loop.

One last point: PHP control constructs have available an alternate syntax that in some cases is a little closer to that of RPG. For this reason some RPGers prefer it. The example at C in Figure 6 recoded in this syntax would look like:

          If ($x == 1):
                 echo "If == 1 was true<br>";
            elseif ($x == 3):
                 echo "elseif == 3 was true<br>";
            else:
                 echo "Final else was true<br>";
            endif; // End of if block.

Notice how the opening bracket ( { ) has been replaced by a colon, and the closing bracket ( } ) for each group removed completely. The only other difference in this syntax is that it requires an endxx type operation as shown by the endif. Note that the endif is terminated by a semi-colon and not by a colon as are If/elseif/else. The resulting code is similar to RPG and this makes it tempting. My personal advice, however, is to stay away from it because it doesn't seem to be in widespread use in the PHP community.

I've still only scratched the surface of PHP's conditional operations, but hopefully I've covered most of the pitfalls that RPGers are likely to fall into.

—J.P.

Find Out More

Homework: PHP from an RPG Perspective
SystemiNetwork.com e-Development forum thread

PHP from an RPG Perspective, Part 1: PHPundamentals—The Basics
December 2009, article ID 64331

PHP Installation, Configuration, and Setup
February 2008, article ID 21143

Open-Source Web Dev Stack in i5/OS
February 2008, article ID 21153

Open-Source Web Deployment Tools—What's New
May 2009, article ID 63342

PHP Frameworks
January 2009, article ID 62653

ProVIP Sponsors

ProVIP Sponsors