PHP and WDDX
As previously stated, a WDDX module has been available for PHP since version 4.0 of the language. Created by Andrei Zmievski, this WDDX module includes standard serialization and deserialization functions to convert PHP variables and arrays into WDDX-compatible data structures.
If you're using a stock PHP binary, it's quite likely that you'll need to recompile PHP to add support for this library to your PHP build (detailed instructions for accomplishing this are available in Appendix A, "Recompiling PHP to Add XML Support").
Encoding Data with WDDX
PHP's WDDX module offers a number of different ways to encode data into WDDX. The following sections demonstrate this by using the following:
The wddx_serialize_value() function
The wddx_serialize_vars() function
The wddx_add_vars() function
The wddx_serialize_value() Function
The simplest way to encode data into WDDX (and the one I will use most frequently in this chapter) is via the wddx_serialize_value() function, which is used to encode a single variable into WDDX. Listing 5.3 demonstrates its application.
Listing 5.3 Serializing a Single Variable with wddx_serialize_value()
<?php $flavor = "strawberry"; print wddx_serialize_value($flavor); ?>
Listing 5.4 demonstrates the result.
Listing 5.4 A WDDX Packet Generated via wddx_serialize_value()
<wddxPacket version='1.0'> <header/> <data> <string>strawberry</string> </data> </wddxPacket>
Manual Labor
Note that PHP typically generates the WDDX packet as one long string. This can sometimes get confusing, so I manually indented and spaced out some of the output listings in this chapter for greater readability. Whitespace within a WDDX packet, but outside WDDX elements, is ignored by the WDDX deserializer; whitespace embedded within a WDDX element is, obviously, preserved.
As Listings 5.5 and 5.6 demonstrate, this works with arrays, too.
Listing 5.5 Serializing a PHP Array with wddx_serialize_value()
<?php $flavors = array("strawberry", "chocolate", "raspberry", "peach"); print wddx_serialize_value($flavors); ?>
Listing 5.6 A WDDX Packet Representing an Array
<wddxPacket version='1.0'> <header/> <data> <array length='4'> <string>strawberry</string> <string>chocolate</string> <string>raspberry</string> <string>peach</string> </array> </data> </wddxPacket>
An optional second parameter to wddx_serialize_value() lets you add a human- readable comment to the resulting packet. Listing 5.7 is a variant of Listing 5.5 that demonstrates this, with the output shown in Listing 5.8.
Going to the Source
If you're using your web browser to view the examples in the section, you may wonder why the output you see on your screen doesn't match the output shown here. Well, that's because web browsers tend to hide tags that they don't know about; consequently, the WDDX tags generated during the serialization process are not displayed in the rendered web page.
The solution is fairly simple: use the browser's View Source command to view the raw source for the web page, and you should see the full uncensored output.
Listing 5.7 Adding a Comment to a WDDX Packet
<?php $flavors = array("strawberry", "chocolate", "raspberry", "peach"); print wddx_serialize_value($flavors, "A WDDX representation of my favorite
icecream flavors"); ?>
Listing 5.8 A WDDX Packet with a Human-Readable Comment in the Header
<wddxPacket version='1.0'> <header> <comment>A WDDX representation of my favorite icecream flavors</comment> </header> <data> <array length='4'> <string>strawberry</string> <string>chocolate</string> <string>raspberry</string> <string>peach</string> </array> </data> </wddxPacket>
The wddx_serialize_vars() Function
The wddx_serialize_value() function cannot accept more than a single variable. However, it's also possible to serialize more than one variable at a time with the wddx_serialize_vars() function, which can accept multiple variables for serialization as function arguments. Listing 5.9 demonstrates how this works.
Listing 5.9 Serializing Multiple Values with wddx_serialize_vars()
<?php $phrase = "The game's afoot"; $animals = array("parrot" => "Polly", "hippo" => "Hal", "dog" => "Rover",
"squirrel" => "Sparky"); print wddx_serialize_vars("phrase", "animals"); ?>
Note that wddx_serialize_vars() requires the names of the variables to be serialized as string arguments.
Listing 5.10 displays the result of a wddx_serialize_vars() run.
Listing 5.10 A WDDX Packet Generated via wddx_serialize_vars()
<wddxPacket version='1.0'> <header/> <data> <struct> <var name='phrase'> <string>The game's afoot</string> </var> <var name='animals'> <struct> <var name='parrot'> <string>Polly</string> </var> <var name='hippo'> <string>Hal</string> </var> <var name='dog'> <string>Rover</string> </var> <var name='squirrel'> <string>Sparky</string> </var> </struct> </var> </struct> </data> </wddxPacket>
It's interesting to note, also, that wddx_serialize_value() and wddx_serialize_vars() generate significantly different (though valid) WDDX packets. Consider Listing 5.11, which creates a WDDX packet containing the same variable-value pair as Listing 5.3, and compare the resulting output in Listing 5.12 with that in Listing 5.4.
Listing 5.11 Serializing a Single Variable with wddx_serialize_vars()
<?php $flavor = "strawberry"; print wddx_serialize_vars("flavor"); ?>
Listing 5.12 A WDDX Packet Generated via wddx_serialize_vars()
<wddxPacket version='1.0'> <header/> <data> <struct> <var name='flavor'> <string>strawberry</string> </var> </struct> </data> </wddxPacket>
The wddx_add_vars() Function
PHP also allows you to build a WDDX packet incrementally, adding variables to it as they become available, with the wddx_add_vars() function. Listing 5.13 demonstrates this approach, building a WDDX packet from the results of a form POST operation.
Listing 5.13 Building a WDDX Packet Incrementally with wddx_add_vars()
<?php // create a packet handle // the argument here is an optional comment $wp = wddx_packet_start("A packet containing a list of form fields with values"); // iterate through POSTed fields // add variables to packet wddx_add_vars($wp, "HTTP_POST_VARS"); // end the packet // you can now assign the generated packet to a variable // and print it wddx_packet_end($wp); ?>
This is a slightly more complicated technique than the ones described previously. Let's go through it step by step:
-
The first order of business is to create an empty WDDX packet to hold the data; this is accomplished with the aptly named wddx_packet_start() function, which returns a handle for the newly minted packet.
-
With the packet created, the next step is to add data to it. In Listing 5.13, the data is generated dynamically from a form submission, and each value is then added to the packet via the wddx_add_vars() function.
-
After all the required data has been inserted into the packet, the final step is to close the packet, accomplished via the wddx_packet_end() function. Again, the packet handle is used to identify the packet to be closed.
$wp = wddx_packet_start("A packet containing a list of form fields with _values");
This handle is used in all subsequent operations. Note that the wddx_packet_start() function can be passed an optional comment string, which is used to add a comment to the header of the generated packet.
wddx_add_vars($wp, "HTTP_POST_VARS");
This function works in much the same way as wddx_serialize_vars()it accepts multiple variable names as argument (although I've only used one here), serializes these variables into WDDX structures, and adds them to the packet. Note, however, that wddx_add_vars() requires, as first argument, the handle representing the packet to which the data is to be added.
wddx_packet_end($wp);
Note that the wddx_packet_end() function returns the contents of the newly minted packet; this return value can be assigned to a variable and used in subsequent lines of the PHP script.
This approach comes in particularly handy if you're dealing with dynamically generated data, either from a database or elsewhere.
With your data now safely encoded into WDDX, let's now look at how you can convert it back into usable PHP data structures.
Decoding Data with WDDX
Although there are five different functions available to encode data into WDDX, PHP has only a single function to perform the deserialization of WDDX packets. This function is named wddx_deserialize(), and it accepts a string containing a WDDX packet as its only argument.
Listing 5.14 demonstrates how a PHP variable encoded in WDDX can be deserialized by wddx_deserialize().
Listing 5.14 Deserializing a WDDX Packet into a Native PHP Structure
<?php $flavor = "blueberry"; // print value before converting to WDDX echo "Before serialization, \$flavor = $flavor <br>"; // serialize into WDDX packet $packet = wddx_serialize_value($flavor); // deserialize generated packet and display value echo "After serialization, \$flavor = " . wddx_deserialize($packet); ?>
This works with arrays, tooin Listing 5.15, the deserialized result $output is an array containing the same elements as the original array $stooges.
Listing 5.15 Deserializing a WDDX Packet into a PHP Array
<?php $stooges = array("larry", "curly", "moe"); // serialize into WDDX packet $packet = wddx_serialize_value($stooges); // deserialize generated packet $output = wddx_deserialize($packet); // view it print_r($output); ?>
Buyer Beware!
There's an important caveat to keep in mind when using PHP's WDDX module. As shown in Listings 5.4 and 5.12, the wddx_serialize_vars() and wddx_add_vars() functions work in a slightly different manner from the wddx_serialize_value() function. Both wddx_serialize_vars() and wddx_add_vars() use WDDX structures (represented by <struct> elements) to store variables and their values, regardless of whether the variable is a string, number, or array. On the other hand, wddx_serialize_value() uses a <struct> only if the variable is an associative array.
This variation in the serialization process can significantly impact the deserialization process because PHP's wddx_deserialize() function automatically converts <struct>s into associative arrays. Consequently, the manner in which you access the original value of the variable will change, depending on how it was originally serialized.
Consider Table 5.1, which demonstrates the difference.
Table 5.1 A Comparison of Serialization with wddx_serialize_value() and wddx_serialize_vars()
wddx_serialize_value() |
wddx_serialize_vars() |
<?php |
<?php |
$lang = array("PHP", "Perl", "Python", "XML", "JSP"); |
$lang = array("PHP", "Perl", "Python", "XML", "JSP"); |
$alpha = wddx_serialize_value($lang); |
$alpha = wddx_serialize_vars("lang"); |
$beta = wddx_deserialize($alpha) |
$beta = wddx_deserialize($alpha); |
// returns "PHP" |
// returns "PHP" |
print $beta[0]; |
print $beta["lang"][0]; |
// returns "Python" |
// returns "Python" |
print $beta[2]; |
print $beta["lang"][2]; |
?> |
?> |