Uploading to PHP

Now that we can formulate a simple XML string with the touch of a button, we are ready to send it to the server and interpret it there. There are several ways to do this.

Trying POST

Our first attempt to upload the XML stream employs the familiar POST method used by Flash and by HTML forms. Since the XML string is stored in the variable login, this seems easy. We will soon see that it is not.

First, we prepare a PHP routine that scans the incoming variables and prints each one out in variable- name => variable-value form. PHP delivers an associative array of all these variables to the script author.



An associative array (also called a hash) is a list of values that can be in dexed not only by an ordinal number (i.e., myList[3] ) but by a string ( myList ["large"] ). This string index value, often called the key, is used as a numeric index. For example, price["tulip"] might return a numeric value from an array of current prices indexed by flower types.

In PHP, even normal numerically indexed arrays are implemented as associative arrays, which decreases the speed of access but makes the arrays enormously flexible. There is no inefficiency in having two elements in array, one indexed as 0 and the other as 1001. Ordinary (scalar) array structure would require 1000 empty elements.

list() and each() allow the programmer to easily scan the contents of an associative array. The PHP keyword list() deconstructs a simple array by copying its elements into a supplied set of simple variables. List ($a,$b,$c)=$myarray assigns to a, b, and c the values of the first three elements of the array. Each is a companion function that creates a small new array from each key/value pair of a target array. Each($myarray) returns a new array whose values are the first key and the first value of myarray. To make it convenient (but confusing), this temporary array is itself an associative array, and it has four elements: two copies of the original key and two copies of the original value. The keys 0 and "key" both return the original key. The keys 1 and "value" return the value.

The keyword each() also advances an internal pointer so that subsequent calls scan through the array. Good practice, then, suggests a call to reset($myarray) before any list/each loop. (The function reset() zeroes this internal pointer.) However, many of the listings here omit unnecessary resets when they would distract readers from more relevant portions of the code.

The variables exist in an array called HTTP_POST_VARS . As we saw in Chapter 10, PHP function must declare any global variable before it can access the variable:

 global $somevar; 

Alternatively, that value is also available as a member of the $GLOBALS array. (Be cautious: GLOBALS actually contains copies of the data; they can be read but not meaningfully rewritten.) This code fragment applies each() and list() to the array HTTP_POST_VARS within the standard PHP array GLOBALS . This exposes each of the variables sent by the ActionScript.

 <HTML>    <HEAD><TITLE>Testing XML</TITLE></HEAD>    <BODY>   here are the post variables<br/> <?   while(list($key,$val) = each ($GLOBALS["HTTP_POST_VARS"]))     echo "$key => $val<br>"; ?>   <br/>   That is all.    </BODY> </HTML> 

We save this on our server under the name authorize.php.

Now let's turn our attention to the client side.The submit() function within our login actionscript must be updated slightly:

 function submit() {   login= "<LOGIN>"            + "<USERNAME>" + username + "</USERNAME>"            + "<PASSWORD>" + password + "</PASSWORD>"        +"</LOGIN>";   getURL ("authorize.php","_blank", "POST"); } 

This Flash command tells the player to open a new window ( _blank ) in which to display authorize.php served from the same subdomain as the swf file.

The POST parameter tells the player to include all the variables located on this MovieClip instance (but not those on parent or child MovieClips).

We publish the swf file on our server and run it. The result (Figure 14.7) is a bit disappointing. ActionScript transmitted all the variables on this timeline, including pointless iterators and function names. The clutter of five unwanted variable names is not optimal, but they do no harm; the waste of bandwidth is not very significant in this case. Other situations might send very large amounts of noise data and introduce terrible inefficiencies . (Imagine a MovieClip that receives a large data load and sends back an acknowledgment. It is easy to imagine the acknowledgment accidentally coded so that it retransmits the entire data stream back to the server.)

Figure 14.7. Trace Results from POST Attempt


If recognized, these situations can be avoided by building a hermetic upload MovieClip and maintaining a pristine namespace containing only the upload variable. Such coding can be difficult. And the problem that necessitates this effort is often unrecognized, because the transmission occurs automatically and invisibly .

XML send()

The preferred solution, of course is to specify exactly what data we wish to upload. The getURL(..,.., "POST") function does not permit this. (Nor does the GET variation.) On the other hand the XML send() function provides us exquisite control over what data we present to the server. This is one of the many advantages we enjoy with XML data communication.

But first we complete the transmission of the XML string using traditional POST functions. It is important to learn this technique, even though it is regressive. Often sophisticated programmers find themselves in less sophisticated environments. It is not unusual at all to find oneself restricted to a server where the available middleware is not XML-ready (like PHP 3). The show must go on, and older technologies (like POST) can be called into play.

Returning to the output in Figure 14.7, we may be alarmed to note that the nice XML string we were sending as login has imploded. All the XML markup is gone, leaving only the naked text.

What happened ? Did Flash strip out the XML markup before POSTing the string? Or maybe PHP filtered tags from the incoming stream when processing HTTP POST requests ? Before we guess or jump to conclusions, let's inspect the HTML that the PHP page is sending. Using View Source in the browser window, we see

 <HTML>>    <HEAD><TITLE>Testing XML</TITLE></HEAD>    <BODY>   here are the post variables<br/> submit => [type Function] <br>stars => ******** <br>i =>8<br>username => Mr. Happy<br>password => euphoria<br>login =>  <LOGIN><USERNAME>Mr. Happy</USERNAME><PASSWORD>euphoria</PASSWORD></LOGIN><br><br/>   That is all.    </BODY> </HTML> 

The XML was actually sent from Flash to PHP properly, assigned to a string variable, and passed back from PHP to the client. It is the browser that stripped out the tags. If we think about this, of course, it makes sense. Although Internet Explorer 5 (the browser in use in Figure 14.7) and beyond can read XML Data Islands, they need to be properly identified as XML. The tags here look (to the browser) like unknown markup, presumably HTML.

Data Islands

We can delimit our code with the <XML> tag. (This is an HTML tag that identifies XML islands. It is not an XML tag.) The browser can read it as XML and treat it as data. In this case we inject the data into a simple HTML table.

The following PHP code extracts the POSTed variable login. It does so by selecting the $HTTP_POST_VARS array from the $GLOBALS array and then selecting from it the element keyed by login. The result is a string containing our XML data.

We wrap the string with <XML> tags and name it login. Attentive readers might realize that this login is quite distinct from the other login. In both ActionScript and PHP we have a vari able called login. In fact, the ActionScript login (both the name and the value parts ) is passed directly to PHP. In both applications, it is a string variable that happens to contain an XML string. By contrast, the new login is coded in HTML and exists only in the browser (PHP sends the tags but knows no meaning). And within the browser's DOM, it is (for the first time) actual, parsed XML data.

To demonstrate briefly , we attach the login data object to a simple table using the table attribute datasrc . We then use datafld to extract records from it and populate cells of the table. This, of course, barely scratches the surface of how XML islands can be exploited in a very simple web page using only HTML and JavaScript.

 <?   while (list ($key, $val) = each ($GLOBALS["HTTP_POST_VARS"]))     echo "$key => $val<br/>";     echo '<XML id="login">' . $GLOBALS["HTTP_POST_VARS"]["login"] . "<XML>" ;     echo '<table border="1" datasrc="#login" >';     echo '<tr><td>USERNAME</td><td>PASSWORD</td></tr>';     echo '<tr><td><span datafld="USERNAME"></span></td>';     echo     '<td><span datafld="PASSWORD"></span></td></tr></table>'; ?> 

The result is sweet (Figure 14.8). We have successfully slapped our ActionScript data into a handmade XML string and passed it up to the server and back down to a browser, where we displayed it as living data! But in truth, we took shortcuts at every step of the way. We built the XML using simple string concatenation instead of the XML constructors. We uploaded the XML using generic POST methods rather than those of the XML object. And in the end it is not on the server that the XML was parsed but in the browser. One by one, we upgrade each of these deficiencies.

Figure 14.8. Login Using POST


XML Constructor in Flash

To use the XML.send() function we need to have a legitimate XML object, so we upgrade our submit() function accordingly :

 function submit() {  login= "<LOGIN>"            + "<USERNAME>" + username + "</USERNAME>"            + " <PASSWORD>" + password + "</PASSWORD>"        +"</LOGIN>";   xmlLogin = new XML(login);   trace(login);   trace(xmlLogin.toString()); } 

The trace results are not terribly exciting (Figure 14.9). It is difficult to say that the XML constructor and the XML.toString() method did anything at all since they produced the identical text we started with! Or we might see this as an affirmation of our hand-coded XML: It made the round trip in and out of the parser unchanged. To double-check , we add a bit of harmless sloppiness to the string ”a couple of meaningless spaces in the tags. It proves that our string is really parsed into an XML data object, and then a new string is generated from the XML object. The parser ignores the spaces we put into our tags, and of course the generator makes fresh tags with no useless spaces (Figure 14.10).

Figure 14.9. XML Login String Before and After


Figure 14.10. XML Strings Before and After, Again


Now we replace getURL() with XML.send() . The functions are similar. Each addresses a window in which the results of the request are directed.

XML and HTTP Content-Types

Even though we are using this function to upload data to the server, we must continue to respect the conventions of HTTP. The server serves information. The client (browser) requests information from the server and waits to get a reply. Classically, the browser asks for a file (by specifying its URL), and the server delivers the file. This is how a page is viewed .

Sometimes the server needs more information to deliver the proper response. If the infor mation is modest and not very secret, it can be tacked onto the URL. (This is the GET method.) If the information is more bulky, the POST method is employed. In this technique, data is delivered in a block that follows the header as part of the request. This content is called the request body.

GET data, since it is appended to a URL, must follow the strict rules of a URL string as well as other rules that let it be distinguished from the resource locator portion of the URL. Only certain characters are permitted in a URL ”in particular printable, simple ASCII characters. All other characters (such as space or «) are disallowed . Then too, some characters have special meanings in a URL (such as @ , . and :), and they must be removed from the data. Finally, some characters have special meaning in the GET string itself (like & , ? and = ), and these too must be replaced . Simple escape sequences substitute for disallowed characters. The resulting none none format is called x-www-form-urlencoded .

The POST method of uploading variables derived from GET in the early days of HTML. It uses the same encoding scheme. While other encodings (or as the protocols call them, other media, or even better, content-types ) are technically permitted, this format is the default. Since many server and client software components support only this default, it becomes dangerous to use any other content-type and the default becomes ubiquitous.

XML is meant to be transmitted with different media. Its basic content-types are called text/xml or application/xml. Both are straight XML, without any of the escape sequences used by url encoding. Of course, XML also has its own set of allowable characters (and its own escape sequences). Compared to the rules of url encoding, the XML rules are far more permissive, more precisely defined, and more context sensitive.

The ubiquity of url encoding and the inflexibility of many software components (including PHP 3) created a confusing situation in which many systems were unclear (or incorrect) in the labeling and coding of XML data. Among the systems is Flash. Early versions (of 5.0) transmitted XML in url encoding under certain circumstances. (As of this writing, this is still true.) Behavior in the editor differs from swfs on the server. However, Macromedia was not carelessly in error; they were attempting to mate the output of Flash with the inconsistent implementations of various middleware packages. Much software still insists that XML arrive in the url encoded scheme.

The Macromedia solution is to leave it up to us. You need to define the content-type of your XML before transmitting it. Do not depend on the default, because the default is inconsistent! In local testing, expect text/xml, while on the server url encoded is the default. Early versions of the Flash 5 player were hardcoded incorrectly. (You might run into one of these unpatched originals ; many millions were distributed. It is likely to jam up your XML site!)

The difference between application/xml and text/xml is not sharply defined or even agreed on. However, the fundamental difference is that text/xml is supposed to be human readable: It makes sense to nontechnical readers. On the other hand, application/xml is fit only for machines ”and software engineers . PHP will read either one.

To create a true XML communication is easy now. On the ActionScript side, open the submit() function. Set the contentType property to text/XML and fire off a request to the same PHP file, targeting the same new window.

 function submit() {  login=. . . xmlLogin = new XML(login); xmlLogin.contentType="text/xml"; xmlLogin.send("authorize.php","_blank"); } 

Server Side XML Processing

Now we need to attend to the server side of this transaction. PHP processes HTTP requests before the script is invoked. Typical requests use POST or GET to send data to the script. As we have seen, this data is available to the script in predefined global arrays. The PHP has parsed the GET (or POST) string, peformed url decoding, and created all the requested variables and assigned them their specified values.

PHP 4 cannot interpret any other content types. If a block of data is received along with the request and it is not www-form-urlencoded , PHP simply leaves the data untranslated and supplies a pointer to it as the global variable HTTP_RAW_POST_DATA . So we can use this in our new PHP code.

 <HTML>    <HEAD><TITLE>Testing XML</TITLE></HEAD>    <BODY> Here is the XMLfrom raw data <br/> <?     echo '<XML id="xmlpacket">' . $GLOBALS["HTTP_RAW_POST_DATA"]. "</XML>" ;     echo '<br/><br/><br/><table border="1" datasrc="#xmlpacket"  >';     etc. . . 

We no longer use any variable name/value pairs but deal directly with the data (Figure 14.11).

Figure 14.11. The Server Echoes the XML without Processing It


Handling Raw XML

It is time we removed an unnecessary translation from our view of this data. We have always coded PHP to display its results on our browser using HTML. There are a few reasons that this shortcut might make us uncomfortable.

First, a real-world project rarely sends an XML data object to the server and then opens an HTML results window. Rather, we expect mature software to conduct two-way conversations entirely in XML exchanges. Therefore, we need to learn to send pure, well- formed XML from PHP.

Second, note that the HTML generated by PHP (in our authorize.php script) has become increasingly sophisticated. Now it uses not only straight HTML but an XML Data Island and invokes esoteric data linkage features of HTML 4. These techniques are certainly interesting ”and very powerful and useful. But this direction takes us away from the main path of our development, the Flash/XML axis.

Finally, this technique does not allow us to freely examine the data. We print out the con tents of certain defined data fields. If the XML that we are receiving includes any other elements (or other instances of these same elements), we will never know, since we never asked the browser to display them. A complete display of all the XML will be more valuable for our purposes.

Fortunately we can easily browse pure XML if we are using Internet Explorer 5.0 or better. We can eliminate the clever table usage that depends on dataflds and datasrc . In fact, we can simply erase all the HTML and send simply the data island:

 <?   echo "<XML>". $GLOBALS["HTTP_RAW_POST_DATA"]. "</XML>";        ?> 

This code sends a legitimate XML island to the browser, which expected an HTML page. But nothing at all displays. This is because it is still indeed an HTML page with zero visible contents and an XML island that is still an island, even though it is 100 percent of the file.

Just as PHP required the data package to be clearly labeled as text/xml before it could be rec ognized, a similar problem occurs in the opposite direction. The server, as part of its HTTP response to an HTTP request, first sends a header. (Typically the header is followed by a requested file.) The header includes a "content-type" property that tells the browser how to interpret the bytes that follow. The default PHP content type is HTML, and it automatically puts in the header

 Content-type: text/html 

The PHP function header() was written to override any of the statements in PHP's default response header. Note that the header() function must be called before any other response is issued. This not only means the explicit responses like

 echo("Some text"); 

but also implicit responses, such as any text outside the <$php delimiters. Most often the header function is torpedoed by a stray blank line before the first <$ tag. This whitespace becomes HTML output that precedes and frustrates the header command.

So the first characters in our PHP file are

 <?php   header("Content-type: application/xml");   echo $GLOBALS["HTTP_RAW_POST_DATA"]; ?> 

(Note that we have also dispensed with the <XML> </XML> tags with which we wrapped the raw POST data in our previous examples. That's because the earlier examples were using the data island feature to enclose a bubble of XML in an HTML page. Here the entire content is solid XML; it is exactly the XML fragment created in ActionScript, and labeled as such by PHP.) The two lines of code trigger the straightforward and interactive display of XML within the IE browser (Figure 14.12).

Figure 14.12. XML Viewed in a Browser


Flash and XML[c] A Developer[ap]s Guide
Flash and XML[c] A Developer[ap]s Guide
ISBN: 201729202
Year: 2005
Pages: 160

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net