ptg 312 Chapter 13 PHP in WebSphere sMash Listing 13.5 Common Template for PHP Extension Classes import com.ibm.phpj.xapi.ExtensionBaseImpl; import com.ibm.phpj.xapi.RuntimeContext; import com.ibm.phpj.xapi.annotations.XAPIExtension; import com.ibm.phpj.xapi.annotations.XAPIFunction; @XAPIExtension("MyExtensionClass") public class MyExtensionClass extends ExtensionBaseImpl { @XAPIArguments(MandatoryArguments = 1, PassSemantics = { XAPIPassSemantics.ByReference }) @XAPIFunction("myFunction") public void myFunction(RuntimeContext ctx) { // Extract arguments from context String arg1 = ctx.getStringArgument(0).getString(); // Do something here String something = someFunction( arg1 ); // Optionally Set return value ctx.setReturnValue( something ); } // remaining code removed } A couple items are worthy of mention in this template sample. First, notice how the class and function have their own XAPI annotations. Although in this template, the annotation and the class/function names match, they do not need to. You can choose to have a public “PHP” function name, and a private “Java” name. For example, the PHP annotation of the function could be called my_function, whereas the actual Java function name could remain myfunction. The second thing of note is how we obtain the function arguments from the RuntimeContext. The context has several getXxxArgument() functions based on the type of object you are attempt- ing to access. RuntimeContext arguments are zero-based. The last item of interest in this template is the optional XAPIArguments annotation. This is useful when you want to explicitly require a set number of arguments by a function. The default behavior of the PHP extension’s argument handling is to pass all arguments by value, meaning Download from www.wowebook.com ptg Extending PHP 313 that the source PHP variable cannot be altered by the extension functions. If you want to enable the extension function to modify the argument source values, the XAPIArguments->Pass Semantics value needs to be set to XAPIPassSemantics.ByReference, as shown in the pre- ceding template. Typically, you will want normal behavior and will not include this entry or even the XAPIArguments annotation for most functions. Logger Extension Sample The easiest way to illustrate the process is to create a sample extension. Typically, when creating extensions, a new WebSphere sMash project would be created to hold the extensions, but to keep things simple, we’ll just reuse the existing project we’ve been using in this chapter. If we had cre- ated this Logger extension as a standalone project, the project that would be using the Logger would need to add the extension project as a dependency. Start by creating a new Java file in a new directory called phpext, under the Java directory. Call this file Logger.java. Listing 13.6 shows the initial contents of this file. The rest is essentially a duplication of the two "fatal" functions. Listing 13.6 Logger PHP Extension Fragment package phpext; import com.ibm.phpj.xapi.ExtensionBaseImpl; import com.ibm.phpj.xapi.RuntimeContext; import com.ibm.phpj.xapi.annotations.XAPIExtension; import com.ibm.phpj.xapi.annotations.XAPIFunction; // Produce standard Log4J logging calls. import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @XAPIExtension("Logger") public class Logger extends ExtensionBaseImpl { private Log log; private String prefix; @XAPIFunction("initLogger") public void init(RuntimeContext ctx) { String arg1 = ctx.getStringArgument(0).getString(); log = LogFactory.getLogger( arg1 ); prefix = arg1 + ": "; } Download from www.wowebook.com ptg 314 Chapter 13 PHP in WebSphere sMash /* FATAL */ @XAPIFunction("fatal") public void fatal(RuntimeContext ctx) { log.fatal( prefix + ctx.getStringArgument(0).getString() ); } @XAPIFunction("isFatalEnabled") public void isFatalEnabled(RuntimeContext ctx) { ctx.setReturnValue( log.isFatalEnabled() ); } // repeat previous two functions for: // error, warn, info, debug, trace } When the extension is completed, we need to tell the application PHP runtime about it. This is done in the php.ini file, by adding the following line: ; Book Sample Commons Logging extension extension = phpext.Logger The next thing to do is write a new PHP script to perform some logging calls using the new Logger extension, as shown in Listing 13.7. Listing 13.7 Logging_extension.php—PHP Script Using Logger Extension <?php initLogger("logging_extension.php"); fatal("Fatal message from PHP"); error("Error message from PHP"); warn("Warn message from PHP"); info("Info message from PHP"); debug("Debug message from PHP"); trace("Trace message from PHP"); echo "ACL logging levels check<br/>"; echo "Fatal enabled = ".isFatalEnabled()."<br/>"; echo "Error enabled = ".isErrorEnabled()."<br/>"; echo "Warn enabled = ".isWarnEnabled()."<br/>"; echo "Info enabled = ".isInfoEnabled()."<br/>"; Download from www.wowebook.com ptg Data Conversion Between PHP and Java in Extensions 315 echo "debug enabled = ".isDebugEnabled()."<br/>"; echo "Trace enabled = ".isTraceEnabled()."<br/>"; ?> All this extension does is provide a façade for the Apache Commons Logging Java code. The main advantage is that we have abstracted the actual Java code so that the PHP developer can make direct “PHP” function calls to perform his logging. As you can see, this is much cleaner from a pure PHP point of view rather than using either the Java or Groovy bridge. Figure 13.6 shows the WebSphere sMash output log from loading the logging_extension.php script in a browser. Figure 13.6 logging_extension.php—console log output Data Conversion Between PHP and Java in Extensions PHP and Java are different languages and have different concepts of data types. To properly pass values back and forth, data conversion on function arguments and return types must occur. The WebSphere sMash PHP Extension APIs provide a full range of conversion functions to assist in this regard as shown next. PHP Arguments to Java Variables Conversion from PHP variables to Java variables performs as you would expect for numeric and boolean values. Strings in PHP are handled specially due to PHP allowing nontext values in string types. The XAPIString internally holds a byte array and, using the toString() method, attempts to coerce the bytes to Unicode text. Arrays in PHP serve a dual purpose of standard indexed lists and associative array maps. The XAPIArray object has custom methods that enable you to deal with these arrays in a properly classified manner. Table 13.3 describes the full data conversion reference. Download from www.wowebook.com ptg 316 Chapter 13 PHP in WebSphere sMash Table 13.3 PHP to Java Data Conversion Map PHP Type RuntimeContext Access Conversion Java Type Comments Int getIntegerArgument() Integer Bool getBooleanArgument() Boolean double getDoubleArgument() Double getFloatArgument() Float string getStringArgument() com.ibm.phpj. xapi.XAPIString Use toString() to convert to a Java String. Array getArrayArgument() com.ibm.phpj. xapi.XAPIArray Custom Array type with func- tions for other conversions, iterators, and key/value accessors. getArrayArgument(). getMap() com.ibm.phpj. xapi.XAPIArrayMap The getMap() function con- verts from XAPIArray to XAPIArrayMap, which implements Java Map inter- face, without a full copy being created. getArrayArgument(). copyOut() LinkedHashMap The copyOut() function con- verts XAPIArray to a LinkedHashMap. Sub-arrays are also converted to LinkedHashMap. getArrayArgument(). copyOutArray() Object[] The copyOutArray() func- tion converts XAPIArray to an Object List. Objects are converted according to this table. Any PHP array keys or indexes are dropped, so order is not preserved. object com.ibm.phpj. xapi.XAPIObject This object is not currently implemented. resource com.ibm.phpj. resources.Resource This object is not currently implemented. Download from www.wowebook.com ptg SuperGlobals 317 SuperGlobals PHP supports the concept of SuperGlobals, which as the name implies, provides variables that are available anywhere within a PHP script. WebSphere sMash extends this concept with several custom SuperGlobals. Think of these variable sets in relation to the global context used elsewhere within WebSphere sMash applications. Examine and load the interactive snoop.php script located in the public directory in the provided Book.PHP sample. This should properly illustrate the information available from each SuperGlobal. Here are the main SuperGlobals provided by WebSphere sMash. Table 13.4 Data Type Conversions Between PHP and Java Java Type PHP Type Comments null Integer int Byte Character Short Long Double double Float Boolean bool String string Byte[] com.ibm.phpj.xapi.XAPIString Map array All children are converted per this table, as well as child maps. com.ibm.phpj.xapi.XAPIArray Object[] com.ibm.phpj.resources.Resource Resource Java to PHP Variable Conversion The conversion from Java variables back to PHP variables is straightforward. Any Java values not listed in Table 13.4 will throw an XAPIException during the conversion. Download from www.wowebook.com ptg 318 Chapter 13 PHP in WebSphere sMash Figure 13.7 snoop.php—$_SERVER SuperGlobal sample $_SERVER The $_SERVER SuperGlobal provides information derived primarily from the request object. This variable consists of a map of key/value pairs that offer insight into the request and server environment. Figure 13.7 shows a small sample of the values available within the $_SERVER SuperGlobal. $_GET and $_POST The $_GET and $_POST SuperGlobals provide maps containing the key/value of the query argu- ments provided on the request URL. The $_GET values are those presented on the URL as query parameters, whereas the $_POST contains values as part of a POST submission of form data. Figure 13.8 shows the results of snoop passing in query arguments on the URL and submitting a form POST. Download from www.wowebook.com ptg SuperGlobals 319 Figure 13.8 snoop.php—$_GET and $_POST sample Be aware that when testing the snoop script, it was discovered that the $_GET and $_POST SuperGlobals do not currently support duplicate query keys. So, a GET URL of “http://local- host:8080?a=1&b=0&b=2&a=3” will produce $_GET values of “a=3” and “b=2”. Likewise, duplicate input names on a form POST will truncate down to a single value. Logically, the dupli- cate values should be an array containing each of the duplicate values. Although this is not a terri- bly common scenario apart from check box groups and multiselect inputs in forms, it is one to take note of when using $_GET and $_POST. $HTTP_RAW_POST_DATA This SuperGlobal provides direct access to the raw POST data stream. This is common when streaming binary data to a server. The value of this variable is a byte stream. To replicate this in a form submission, we need to override the default encoding to text/plain or some other value. By default, form submission will automatically encode form fields prior to submission. $_FILES This SuperGlobal provides access to any files uploaded as part of a "multipart/form-data" encoded form submission. This variable is a map of maps of the files. The first level keys are the name of the form file input field, whereas the second provide information on the filename, size, type, and other details. Figure 13.9 shows the results of uploading an image file. Download from www.wowebook.com ptg 320 Chapter 13 PHP in WebSphere sMash Figure 13.9 snoop.php—$_FILES SuperGlobal sample $_COOKIE The $_COOKIE SuperGlobal provides access to a map of the cookie data sent along with the request. The keys for the $_COOKIE variable vary based on the cookies stored on your browser for the domain. $_REQUEST The $_REQUEST SuperGlobal contains a combination of the $_GET, $_POST, and $_COOKIE variables. Be aware that any keys that are duplicates within the three groups will be dropped. XML Processing Using PHP and WebSphere sMash The WebSphere sMash implementation of PHP provides a couple of simple XML accessor meth- ods that can be utilized to integrate with XML-based resources. The xml_decode() method will read and parse an XML document and return a map of variables that can be accessed directly using normal PHP syntax. The converse method of the xml_encode() method takes a PHP map and transforms it into an XML document. With that said, you probably don’t want to bother with these, as they don’t deal with common XML issues such as CDATA blocks and namespaces. There is another solution standard to PHP called SimpleXML (http://www.php.net/man- ual/en/book.simplexml.php), which makes it a snap to process XML data. The following sample PHP script will consume an RSS feed and display it on the browser. Listing 13.7 shows how we fetch a remote XML document, parse it using SimpleXML, and then output the result in a fairly nice structure. In this example, we pull in the Project Zero Blog feed and display the latest article to the user. This file is called /public/simple_xml.php in the Book.PHP.XML project. Download from www.wowebook.com ptg XML Processing Using PHP and WebSphere sMash 321 Listing 13.7 Using SimpleXML to Process RSS Feed <?php ini_set('display_errors',1); $xml = connection_get("http://www.projectzero.org/blog/index.php/feed/"); $rss = simplexml_load_string($xml['body']); //var_dump($rss); echo "<h1>"; echo $rss->channel[0]->title[0]; echo "</h1>"; $items=$rss->channel[0]->item; echo "<h3>Article count: ".count($items)."</h3>"; echo "<hr/>"; foreach($items as $item) { //var_dump($item); echo "<h3><a href='".$item->link[0]."'>". $item->title[0]. "</a></h3>". $item->description[0]; } echo "<br/><hr/>RSS Version: ".$rss['version']; ?> From an XML perspective, all this script does is parse an XML string into mapped array. This is performed by the simplexml_load_string() function. The rest is normal XML and data access processing. The input to the load function is the “body” member of the results of the connection_get command. This command fetches the contents of a URL and returns a three element mapped array, consisting of the “status” of the call, the “headers,” and finally the “body” string. This “body” content is what we pass into the xml load function. All nodes in an XML map are considered arrays, which you can iterate as you would any other list. Working with attributes is done by accessing them as a direct array member, as shown in the final line of the script. They call it SimpleXML for a reason. For more information on XML processing in PHP, refer to the online SimpleXML manual. The results of loading this script in your browser is shown in Figure 13.10. Download from www.wowebook.com . ptg 312 Chapter 13 PHP in WebSphere sMash Listing 13.5 Common Template for PHP Extension Classes import com .ibm. phpj.xapi.ExtensionBaseImpl; import com .ibm. phpj.xapi.RuntimeContext; import. essentially a duplication of the two "fatal" functions. Listing 13.6 Logger PHP Extension Fragment package phpext; import com .ibm. phpj.xapi.ExtensionBaseImpl; import com .ibm. phpj.xapi.RuntimeContext;. /public/simple_xml.php in the Book.PHP.XML project. Download from www.wowebook.com ptg XML Processing Using PHP and WebSphere sMash 321 Listing 13.7 Using SimpleXML to Process RSS Feed <?php