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 us
Trang 1Listing 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
Trang 2that 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 + ": ";
}
Trang 3/* 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/>";
Trang 4echo "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
Trang 5Table 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
Trang 6SuperGlobals
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
null
Byte
Character
Short
Long
Float
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
Trang 7Figure 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
Trang 8Figure 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 duplidupli-cate 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
Trang 9Figure 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
Trang 10Listing 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