<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Lon Hosford&#039;s Bitbox &#187; Php 5</title>
	<atom:link href="http://www.lonhosford.com/lonblog/category/technologies/php/php-5/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.lonhosford.com/lonblog</link>
	<description>Lon (Alonzo) Hosford&#039;s Professional Consulting Blog</description>
	<lastBuildDate>Fri, 03 Feb 2012 00:55:07 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>XCode 4 IPhone Mountains of the USA Tutorial: Lesson 2 &#8211; Load XML Data</title>
		<link>http://www.lonhosford.com/lonblog/2011/05/12/xcode-4-iphone-mountains-of-the-usa-tutorial-lesson-2-load-xml-data/</link>
		<comments>http://www.lonhosford.com/lonblog/2011/05/12/xcode-4-iphone-mountains-of-the-usa-tutorial-lesson-2-load-xml-data/#comments</comments>
		<pubDate>Fri, 13 May 2011 01:10:08 +0000</pubDate>
		<dc:creator>Lon Hosford</dc:creator>
				<category><![CDATA[IPhone]]></category>
		<category><![CDATA[Objective C]]></category>
		<category><![CDATA[Php]]></category>
		<category><![CDATA[Php 5]]></category>
		<category><![CDATA[XCode]]></category>
		<category><![CDATA[XML]]></category>

		<guid isPermaLink="false">http://www.lonhosford.com/lonblog/?p=1802</guid>
		<description><![CDATA[&#60;== Lesson 1 &#124;&#124; Overview &#124;&#124; Lesson 3 ==&#62; In this lesson you will make a requests for the Mountain data from a web site. The data is returned in an XML format. Then for testing you will display the raw XML on the phone screen and also display the XML data in the XCode [...]]]></description>
			<content:encoded><![CDATA[<div id="fb-root"></div>
<p><script src="http://connect.facebook.net/en_US/all.js#appId=105467682877384&amp;xfbml=1"></script><fb:like href="http://www.lonhosford.com/lonblog/2011/05/08/xcode-4-iphone-tutorial-mountains-of-the-usa-overview/" send="true" width="450" show_faces="true" font=""></fb:like></p>
<p><a href="http://www.lonhosford.com/lonblog/2011/05/11/xcode-4-iphone-mountains-of-the-usa-tutorial-lesson-1-setup-the-app/">&lt;== Lesson 1</a> || <a href="http://www.lonhosford.com/lonblog/2011/05/08/xcode-4-iphone-tutorial-mountains-of-the-usa-overview/">Overview</a>   || <a href="http://www.lonhosford.com/lonblog/2011/05/14/xcode-4-iphone-mountains-of-the-usa-tutorial-lesson-3-parse-xml-data/">Lesson 3 ==&gt; </a>  </p>
<p>In this lesson you will make a requests for the Mountain data from a web site. The data is returned in an XML format.  Then for testing you will display the raw XML on the phone screen and also display the XML data in the XCode console. <img class="alignleft" src="https://lh5.googleusercontent.com/_e5pwU0LJbN8/TcVF8NRLevI/AAAAAAAAF2U/dZ3fASCSYCA/s800/USAMountainsBlogImage.png" alt="" width="160" height="218" /></p>
<div class="wp-caption alignright" style="width: 215px"><img class=" " style="border: 0pt none;" src="https://lh4.googleusercontent.com/_e5pwU0LJbN8/TcuuFKLAZ2I/AAAAAAAAF5s/LW4L84EGC78/s400/USAMountains01Screen02.png" alt="" width="205" height="400" /><p class="wp-caption-text">Screen With XML Loaded From Web</p></div>
<p>The main goal is to learn to use the NSURL, NSURLRequest, NSURLConnection and NSMutableData classes. </p>
<p>NSURL defines a URL for XCode. NSURLConnection establishes a connection to a server and manages the data to and from that server.  NSURLRequest defines a network request along with data to send.  NSMutableData stores any  returning data.</p>
<p>When you load data from the web or any indeterminate process, you will want to include an activity indicator. So we will add a UIActivityIndicatorView that is the common activity indicator for Mac applications. </p>
<p>To see the data on the phone screen, we will use the UITextView which is a scrollable text component. In future lessons, we will replace the UITextView with a scrolling list of mountains in the XML data we receive.</p>
<p>You will need a web server to complete this and all future lessons in this tutorial. The tutorials use a web server with PHP that reads a comma delimited file containing the mountain data. The XML that the PHP script returns is included in this post should you not have PHP on your server. I will show you how to use that instead of the provided PHP script. However in future lessons we will want to ask the server for just partial data and we need a program to do that. Keep in mind you can also put the mountain data into a database on the server.</p>
<p><strong>Source Download</strong></p>
<ol>
<li>
<a onclick="javascript: pageTracker._trackPageview('/downloads/xcode/USAMountainsTutorial01.zip'); " href="http://www.lonhosford.com/content/xcode/iphone/USAMountainsTutorial01.zip">Starting XCode Project</a>. This is the lesson 1 project completed.</li>
<li>
<a onclick="javascript: pageTracker._trackPageview('/downloads/xcode/USAMountainsTutorial02PHP_CSV_files.zip'); " href="http://www.lonhosford.com/content/xcode/iphone/USAMountainsTutorial02PHP_CSV_files.zip">PHP and CSV Files</a>. Script to read data file and selects by elevation and returns XML.</li>
<li>
<a onclick="javascript: pageTracker._trackPageview('/downloads/xcode/USAMountainsTutorial02XML.zip.zip'); " href="http://www.lonhosford.com/content/xcode/iphone/USAMountainsTutorial02XML.zip">Mountain XML Data</a>. Alternative to hosting PHP script.</li>
<li>
<a onclick="javascript: pageTracker._trackPageview('/downloads/xcode/USAMountainsTutorial02.zip'); " href="http://www.lonhosford.com/content/xcode/iphone/USAMountainsTutorial02.zip">Completed XCode 4 Project</a></li>
</ol>
<p><div style = "text-align:center"><script type="text/javascript"><!--
google_ad_client = "pub-8926707286265620";
/* 300x250, created 7/29/10 */
google_ad_slot = "4548376258";
google_ad_width = 300;
google_ad_height = 250;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div></p>
<p><strong>Step 1:  MainViewController.h &#8211; Define properties and methods.</strong></p>
<p>Download and uncompress the <a onclick="javascript: pageTracker._trackPageview('/downloads/xcode/USAMountainsTutorial01.zip'); " href="http://www.lonhosford.com/content/xcode/iphone/USAMountainsTutorial01.zip">Starting XCode Project</a> file and open in XCode.</p>
<p>Select the MainViewController.h in the project navigation window on the left and add the highlighted lines.</p>
<p>Line 4 is a constant for the URL to the PHP script or the XML file if you choose not to host the PHP script. More on these choices in this post when we get to those files.</p>
<p>The app will enable and disable the UIButton searchButton, so we need to include it for reference in code.</p>
<p>The UIActivityIndicatorView and UITextView are being added and are also referenced from our UI. The UIActivityIndicatorView will need to be hidden and revealed when we are not and are loading data from the server as well starting and ending its animation. So we need to make it an IBOutlet. </p>
<p>The UITextView will be updated with data coming in from the server and so it also needs to be an IBOutlet.</p>
<p>The MSMutableData is needed to capture the data coming in from the server in a raw format.</p>
<p>Your implementation code will call for disabling and enabling the search button and hiding and unhiding the activity indicator in more than one place in the code. Line 26 defines a method you will use so you do not have to repeat this UI state changing code in more than one place. The method receives an int parameter to define the state of the UI components. You will define their values in the implementation code.</p>
<pre class="brush: objc; highlight: [4,10,11,12,14,15,17,18,19,22,23,26];">
//
//
//
#define kTextURL    @&quot;http://YOUR_DOMAIN/PATH_IF_ANY_TO_SCRIPT/PHP_SCRIPT_OR_XML_FILE&quot;

#import &lt;UIKit/UIKit.h&gt;

@interface MainViewController : UIViewController
{
    UIButton                *searchButton;
    UIActivityIndicatorView *activityIndicator;
    UITextView              *resultsTextView;

    NSURLConnection         *urlConnection;
    NSMutableData           *receivedData;

}
@property (nonatomic, retain) IBOutlet UIButton                 *searchButton;
@property (nonatomic, retain) IBOutlet UIActivityIndicatorView  *activityIndicator;
@property (nonatomic, retain) IBOutlet UITextView               *resultsTextView;

@property (nonatomic, retain) NSURLConnection *urlConnection;
@property (nonatomic, retain) NSMutableData *receivedData;

-(IBAction) startSearch:(id)sender;
- (void) setUIState:(int)uiState;
@end
</pre>
<p><strong>Step 2:  MainViewController.m &#8211; Add Properties and Constants</strong></p>
<p>This step basically is the implementation housekeeping prerequisites. </p>
<p>You add the getter and setters for the properties on lines 4 to 9 using synthesize. </p>
<p>Lines 12 and 14 provide constants for states of the view that are used in the setUIState method we defined in the last step. Those places in the code can make the code more readable when calling the setUIState. </p>
<pre class="brush: objc; highlight: [4,5,6,8,9,12,14];">
#import &quot;MainViewController.h&quot;

@implementation MainViewController
@synthesize searchButton;
@synthesize activityIndicator;
@synthesize resultsTextView;

@synthesize urlConnection;
@synthesize receivedData;

// State is loading data. Used to set view.
static const int LOADING_STATE = 1;
// State is active. Used to set view.
static const int ACTIVE_STATE = 0;
</pre>
<p><strong>Step 3:  MainViewController.m &#8211; Memory Management Housekeeping</strong></p>
<p>Add the memory release for the searchButton, activityIndicator, activityIndicator, resultsTextView, urlConnection and receivedData  in the dealloc method. </p>
<pre class="brush: objc; first-line: 15; highlight: [26,27,28,29,30];">

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)dealloc
{
    [searchButton release];
    [activityIndicator release];
    [resultsTextView release];
    [urlConnection release];
    [receivedData release];
    [super dealloc];
}

- (void)didReceiveMemoryWarning
{
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    // Release any cached data, images, etc that aren't in use.
}
</pre>
<p><strong>Step 4:  MainViewController.m &#8211; Navigation Top Bar Title Updated</strong></p>
<p>On line 47 you might want to update the title so you are not confused when viewing the app.</p>
<pre class="brush: objc; first-line: 41; highlight: [47];">
#pragma mark - View lifecycle

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    [self setTitle:@&quot;USA Mountains Lesson 2&quot;];
}
</pre>
<p><strong>Step 5:  MainViewController.m &#8211; More Memory Management</strong></p>
<p>In the viewDidUnload method add these lines to release the subviews you are going to link to this view in the UI.</p>
<pre class="brush: objc; first-line: 49; highlight: [54,55,56];">
- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
    self.searchButton = nil;
    self.activityIndicator = nil;
    self.resultsTextView = nil;
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
</pre>
<p><strong>Step 6:  MainViewController.m &#8211; Update the startSearch Method to Fetch Server Data</strong></p>
<p>The startSearch method is already linked to our searchButton from the last tutorial. You have the code below to get the UI in the state for loading in progress, to make a request to the data source on the server and take needed steps based on the success or failure of that connection.</p>
<p>Line 69 is calling a method you will add in the next step to set the UI state. Your constant LOADING_STATE was defined in the last step.</p>
<p>Line 71 creates a NSString for the URL. In a future lesson you are going to concatenate a parameter to send along with the URL and now this line is ready for that.</p>
<p><div style = "text-align:center"><script type="text/javascript"><!--
google_ad_client = "pub-8926707286265620";
/* 300x250, created 7/29/10 */
google_ad_slot = "4548376258";
google_ad_width = 300;
google_ad_height = 250;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div></p>
<p>The NSURLRequest object named req is created on line 74. </p>
<p>The instance object named urlConnection on line 77 is your NSURLConnection. It does all the work for communicating with the server. </p>
<p>You see on line 77 it is using our NSURLRequest req object and also sending the delegate message to make this class, self, its delegate. That means urlConnection can call NSURLConnection methods you add to this class to take action needed to handle notifications such as successful completion or failure. </p>
<p>For this lesson you need to add four methods to handle the NSURLConnection messages didReceiveResponse, didReceiveData, didFailWithError and connectionDidFinishLoading. You will do that just after creating our setUIState method. </p>
<p>Lines 79 to 83 handle a successful connection. A NSMutableData object is created and assigned to the class receivedData NSMutableData object that in later code you will convert to readable XML for display.</p>
<p>Should the connection fail, lines 85 to 97 display a UIAlertView with the error information. Generally you will want to change that to something more meaningful to the user.</p>
<pre class="brush: objc; first-line: 64; highlight: [68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98];">
#pragma mark - UI Interface
-(IBAction) startSearch:(id)sender
{
    NSLog(@&quot;startSearch&quot;);
     // Change UI to loading state
    [self setUIState:LOADING_STATE];
    // Create the URL which would be http://YOUR_DOMAIN_NAME/PATH_IF_ANY_TO/get_usa_mountain_data.php?elevation=12000
    NSString *urlAsString = [NSString stringWithFormat:@&quot;%@&quot;, kTextURL ];

    NSLog(@&quot;urlAsString: %@&quot;,urlAsString );
    NSURLRequest *req = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:urlAsString]];
    // Create the NSURLConnection con object with the NSURLRequest req object
    // and make this MountainsEx01ViewController the delegate.
    urlConnection = [[NSURLConnection alloc] initWithRequest:req delegate:self];
    // Connection successful
    if (urlConnection) {
        NSMutableData *data = [[NSMutableData alloc] init];
        self.receivedData=data;
        [data release];
    }
    // Bad news, connection failed.
    else
    {
        UIAlertView *alert = [
                              [UIAlertView alloc]
                              initWithTitle:NSLocalizedString(@&quot;Error&quot;, @&quot;Error&quot;)
                              message:NSLocalizedString(@&quot;Error connecting to remote server&quot;, @&quot;Error connecting to remote server&quot;)
                              delegate:self
                              cancelButtonTitle:NSLocalizedString(@&quot;Bummer&quot;, @&quot;Bummer&quot;)
                              otherButtonTitles:nil
                              ];
        [alert show];
        [alert release];
    }
    [req release];

}
</pre>
<p><strong>Step 7:  MainViewController.m &#8211; Create the UI State Setting Method setUIState</strong></p>
<p>This is your custom method to set the states of the UI components. </p>
<p>The UIButton has an alpha and enabled property. For your UIButton searchButtonobject, the alpha value is toggled between 50% and 100% and its enabled state is also toggled between true and false. </p>
<p>The UIActivityIndicatorView has methods on lines 108 and 116 for starting and stopping their animation. There is also a property hidesWhenStopped that you will set in the UI design that handles the hiding and showing of our UIActivityIndicator.</p>
<pre class="brush: objc; first-line: 101; highlight: [101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118];">
-(void) setUIState:(int)uiState;
{
    // Set view state to animating.
    if (uiState == LOADING_STATE)
    {
        searchButton.enabled = false;
        searchButton.alpha = 0.5f;
        [activityIndicator startAnimating];

    }
    // Set view state to not animating.
    else if (uiState == ACTIVE_STATE)
    {
        searchButton.enabled = true;
        searchButton.alpha = 1.0f;
        [activityIndicator stopAnimating];
    }
}
</pre>
<p><strong>Step 8:  MainViewController.m &#8211; Clear Received Data When Connection Is Established</strong></p>
<p>You learned about pragma marks in the last lesson. You have 4 NSURLConnection related methods to add and this mark on line 119 is an easy way in XCode to get to where you are placing them in the code.</p>
<p>The connection didReceiveResponse method occurs when a connection is established. When that happens, your data communication starts over. To be on the safe side of it occurring more than once, you clear the NSMutableData object from any previous incomplete attempts. Consider this a boilerplate block you always include in code.</p>
<pre class="brush: objc; first-line: 119; highlight: [119,120,121,122,123];">
#pragma mark - NSURLConnection Callbacks
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    [receivedData setLength:0];
}
</pre>
<p><strong>Step 9:  MainViewController.m &#8211; Accumulate Data Being Received</strong></p>
<p>The NSURLConnection calls the connection didReceiveData method as data arrives and is ready for use. This is called as often as needed depending on the amount of data. The code you need here is to append the data received to your NSMutableData object.</p>
<pre class="brush: objc; first-line: 124; highlight: [124,125,126,127];">
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    [receivedData appendData:data];
}
</pre>
<p><strong>Step 10:  MainViewController.m &#8211; Handle Network Connection Failure</strong></p>
<p>The connection didFailWithError NSURLConnection call back method is where you handled the failure of the data transmission. In your case the code displays a UIAlertView with information from the NSError class error object passed in for learning purposes. A better user error should be considered for a released app. </p>
<p>You can use the NSError class to take different action based on the type of error. This is over the scope of this tutorial.</p>
<p><div style = "text-align:center"><script type="text/javascript"><!--
google_ad_client = "pub-8926707286265620";
/* 300x250, created 7/29/10 */
google_ad_slot = "4548376258";
google_ad_width = 300;
google_ad_height = 250;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div></p>
<p>There is some housekeeping such as calling the connection object release method and terminating the NSMutableData receivedData property.</p>
<p>The last line of code calls the sertUIState method with the ACTIVE_STATE value so the UI again appears available for another search.</p>
<pre class="brush: objc; first-line: 128; highlight: [128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,144];">
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    [connection release];
    self.receivedData = nil; 

    UIAlertView *alert = [[UIAlertView alloc]
                          initWithTitle:@&quot;Error&quot;
                          message:[NSString stringWithFormat:@&quot;Connection failed! Error - %@ (URL: %@)&quot;, [error localizedDescription],[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]]
                          delegate:self
                          cancelButtonTitle:@&quot;Bummer&quot;
                          otherButtonTitles:nil];
    [alert show];
    [alert release];
    // Change UI to active state
    [self setUIState:ACTIVE_STATE];
}
</pre>
<p><strong>Step 11:  MainViewController.m &#8211; Handle Network Connection Successful Completion</strong></p>
<p>This final method is called when all the data is successfully loaded. The NSMutableData receivedData object is converted to a NSString on line 147.</p>
<p>On line 151 the UITextView text property resultsTextView is set to the data as a NSString. One the previous line the same is displayed in the XCode console window.</p>
<p>After that the NSURLConnection connection variable is released and the receivedData NSMutable object is truncated.</p>
<p>Your last line has the same task of setting the UI back to a state that the user can search again.</p>
<pre class="brush: objc; first-line: 144; highlight: [144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159];">
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    // Convert receivedData to NSString.
    NSString *receivedDataAsString = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];

    // Trace receivedData
    NSLog(@&quot;%s - %@&quot;, __FUNCTION__, receivedDataAsString);
    resultsTextView.text = receivedDataAsString;
    [receivedDataAsString release];

    // Connection resources release.
    [connection release];
    self.receivedData = nil;
    // Change UI to active state
    [self setUIState:ACTIVE_STATE];
}
</pre>
<p><strong>Step 12:  MainViewController.xib &#8211; Add the Activity Indicator</strong></p>
<p>Open the MainViewController.xib in the Project navigator and drag an Activity Indicator from the Objects library in the bottom right to place it under the button with the Search label. </p>
<div class="wp-caption aligncenter" style="width: 410px"><img class=" " src="https://lh5.googleusercontent.com/_e5pwU0LJbN8/TcxN6XSLY-I/AAAAAAAAF6M/6sJNe42oB50/s400/XCode4_ActivityIndicator.png" alt="" width="400" height="51" /><p class="wp-caption-text">Activity Indicator View</p></div>
<p>Be sure you keep the Activity Indicator you placed selected while completing the next three tasks.</p>
<p>Select the size panel in the top right and set the x and y values as shown here.</p>
<div class="wp-caption aligncenter" style="width: 410px"><img class=" " src=https://lh5.googleusercontent.com/_e5pwU0LJbN8/TcxTpBN00xI/AAAAAAAAF6o/9-6i6kBtXUU/s400/USAMountainTutorial02MainViewControllerActivityIndicatorSize.png" alt="" width="400" height="138" /><p class="wp-caption-text">Activity Indicator Size Inspector</p></div>
<p>Select the Properties inspector and set the style to Large White and check the Behavior Hides When Stopped. </p>
<div class="wp-caption aligncenter" style="width: 410px"><img class=" " src=https://lh4.googleusercontent.com/_e5pwU0LJbN8/Tcx7QJbvKGI/AAAAAAAAF68/e1QRO4bEWm0/s400/USAMountainsTutorial02MainViewControllerActivityIndicatorProperites%20.png" alt="" width="400" height="104" /><p class="wp-caption-text">Activity Indicator Properties</p></div>
<p>In the Connections Inspector panel drag from the &#8220;New Referencing Outlet&#8221; in the &#8220;Referencing Outlets&#8221; group to the File Owner&#8217;s icon and release the mouse. Then select  activityIndicator. You defined activityIndicator in your  MainViewController code as a UIActivityIndicatorView.</p>
<p>Here is how the Connections Inspector will look when you are done.</p>
<div class="wp-caption aligncenter" style="width: 410px"><img class=" " src=https://lh4.googleusercontent.com/_e5pwU0LJbN8/TcxWAczW_4I/AAAAAAAAF60/h2rIEXKhxkk/s400/USAMountainTutorial02MainViewControllerActivityIndicatorConnections.png" alt="" width="400" height="104" /><p class="wp-caption-text">Activity Indicator Connection Inspector</p></div>
<p><strong>Step 13:  MainViewController.xib &#8211; Add the TextView</strong></p>
<p>You are adding a TextView that in a future tutorial you replace with a TableView. So there is no need to get heavily invested in how it looks.</p>
<p>Now drag a TextView from the Objects library in the bottom right to place it under the button with the Activity Indicator. </p>
<div class="wp-caption aligncenter" style="width: 410px"><img class=" " src="https://lh6.googleusercontent.com/_e5pwU0LJbN8/TcxQ7H8t8QI/AAAAAAAAF6c/cbcpyO_KOR4/s400/XCode4_TextView.png" alt="" width="400" height="51" /><p class="wp-caption-text">Text View</p></div>
<p>Keep the TextView you placed selected while completing the next two tasks.</p>
<p>Select the size panel in the top right and set the X, Y, Width and Height values as shown here.</p>
<div class="wp-caption aligncenter" style="width: 410px"><img class=" " src="https://lh5.googleusercontent.com/_e5pwU0LJbN8/TcxTpGhY6lI/AAAAAAAAF6k/HXuMiEIe-ZA/s400/USAMountainTutorial02MainViewControllerTextViewSize.png" alt="" width="400" height="138" /><p class="wp-caption-text">Text View Size Inspector</p></div>
<p>In the Connections Inspector panel drag from the &#8220;New Referencing Outlet&#8221; in the &#8220;Referencing Outlets&#8221; group to the File Owner&#8217;s icon and release the mouse. Then select  resultsTextView defined activityIndicator in your MainViewController code as a UITextView.</p>
<p>Your Connections Inspector should appear as follows.</p>
<div class="wp-caption aligncenter" style="width: 410px"><img class=" " src="https://lh3.googleusercontent.com/_e5pwU0LJbN8/TcxWAUbZUdI/AAAAAAAAF6w/ARpmAOt_CQM/s400/USAMountainTutorial02MainViewControllerTextViewConnections.png" alt="" width="400" height="104" /><p class="wp-caption-text">Text View Connection Inspector</p></div>
<p><strong>Step 14:  MainViewController.xib &#8211; Review the Changes</strong></p>
<p>First you can check the layout looking as follows.</p>
<div class="wp-caption aligncenter" style="width: 285px"><img class=" " src="https://lh5.googleusercontent.com/_e5pwU0LJbN8/TcxPjal7v0I/AAAAAAAAF6U/N_zjThoItTE/s400/USAMountainTutorial02MainViewControllerFileOwnerXIB.png" alt="" width="275" height="400" /><p class="wp-caption-text">MainViewController Design Window Complete</p></div>
<p>If you select the Connections inspector and then the File Owner&#8217;s icon you should see the following. If so you are good to go.</p>
<div class="wp-caption aligncenter" style="width: 271px"><img class=" " src="https://lh4.googleusercontent.com/_e5pwU0LJbN8/TcxASzeMo4I/AAAAAAAAF6E/r9eCYxmztQk/s800/USAMountainTutorial02MainViewControllerFileOwnerConnections.png" alt="" width="261" height="243" /><p class="wp-caption-text">File Owner's Connection Inspector</p></div>
<p><strong>Step 15:  PHP Server Script or XML File</strong></p>
<p>This IPhone app loads XML data from a server. The Source Download includes an XML file you can use for this lesson. </p>
<p>However, the longer term of the Tutorial will request a query of the data from the server and at that point you can use the PHP script provided. I suggest you use that with this lesson so you are set up. But if you do not have a PHP script enabled server, you can use the XML file for a few more lessons.</p>
<p>Detailing how the PHP script works is beyond the scope of this tutorial. However what you should know it reads a CSV file. Here is a snippet of the file. The name used in the PHP script is mountain_data.csv.</p>
<pre class="brush: plain;">
Mount McKinley,20320, 63.0690,-151.00063
Mount Saint Elias,18008,60.2927,-140.9307
Mount Foraker,17400,62.9605,-151.3992
</pre>
<p>Then the PHP script returns XML. This is a snippet of what the XML data looks like when returned.</p>
<pre class="brush: xml;">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;mountains source = &quot;http://en.wikipedia.org/wiki/Table_of_the_highest_major_summits_of_the_United_States&quot; elevation_min = &quot;12000&quot; count = &quot;100&quot; &gt;
  &lt;mountain_item id = &quot;1&quot; name = &quot;Mount McKinley&quot; elevation = &quot;20320&quot; lat = &quot; 63.0690&quot; lon = &quot;-151.00063&quot; /&gt;
  &lt;mountain_item id = &quot;2&quot; name = &quot;Mount Saint Elias&quot; elevation = &quot;18008&quot; lat = &quot;60.2927&quot; lon = &quot;-140.9307&quot; /&gt;
  &lt;mountain_item id = &quot;3&quot; name = &quot;Mount Foraker&quot; elevation = &quot;17400&quot; lat = &quot;62.9605&quot; lon = &quot;-151.3992&quot; /&gt;
&lt;/mountains&gt;
</pre>
<p>This XML you will learn to parse in a future tutorial.</p>
<p>This is the PHP script. The name I used for the script was get_mountain_data.php. You can name it what you like.</p>
<pre class="brush: php;">
&lt;?php
header(&quot;Expires: Mon, 26 Jul 1997 05:00:00 GMT&quot; );
header(&quot;Last-Modified: &quot; . gmdate( &quot;D, d M Y H:i:s&quot; ) . &quot;GMT&quot; );
header(&quot;Cache-Control: no-cache, must-revalidate&quot; );
header(&quot;Pragma: no-cache&quot; );
header(&quot;Content-Type: text/xml; charset=utf-8&quot;);
// XML to return.
$xml = '';
// Counter for number of mountains returned.
$mountain_count = 0;
// Filter mountains equal to or above this value.
$elevation_min = 12000;
// Check for elevation parameter as a integer.
if ($_REQUEST['elevation_min'] &amp;&amp; intval($_REQUEST['elevation_min']))
{
	$elevation_min = intval( $_REQUEST['elevation_min']);
}
// Each element contains data for one mountain.
$mountains = array();
// Read a CVS file containing mountain data.
$mountain_data_lines = file('mountain_data.csv');
// Each line read .
foreach($mountain_data_lines as $line)
{
	// Strip newline at end of line and break line by comma delimiter and
	// append to $mountains.
	$mountains[] = explode( ',', rtrim($line));
}
// Each mountain.
foreach ($mountains as $value)
{
	// Mountain elevation equals or exceeds the filter value.
	if ( intval($value[1]) &gt;= $elevation_min  )
	{
		$mountain_count++;
		// Create the mountain_item node.
		$xml .= '&lt;mountain_item ';
		$xml .= 'id = &quot;' . $mountain_count . '&quot; ';
		$xml .= 'name = &quot;' . $value[0] . '&quot; ';
		$xml .= 'elevation = &quot;' . $value[1] . '&quot; ';
		$xml .= 'lat = &quot;' . $value[2] . '&quot; ';
		$xml .= 'lon = &quot;' . $value[3] . '&quot; ';
		$xml .= '/&gt;';

	}
}
// Add mountains close node.
$xml .= '&lt;/mountains&gt;';
// Create mountains open node.
$xml_mountains = '&lt;mountains ';
$xml_mountains .= 'source = &quot;http://en.wikipedia.org/wiki/Table_of_the_highest_major_summits_of_the_United_States&quot; ' ;
$xml_mountains .= 'elevation_min = &quot;' . $elevation_min . '&quot; ';
$xml_mountains .= 'count = &quot;' . $mountain_count . '&quot; ';
$xml_mountains .= '&gt;';
// Add mountains open node.
$xml = $xml_mountains . $xml;
// Return xml
echo $xml;
?&gt;
</pre>
<p><a href="http://www.lonhosford.com/lonblog/2011/05/11/xcode-4-iphone-mountains-of-the-usa-tutorial-lesson-1-setup-the-app/">&lt;== Lesson 1</a> || <a href="http://www.lonhosford.com/lonblog/2011/05/08/xcode-4-iphone-tutorial-mountains-of-the-usa-overview/">Overview</a>   || <a href="http://www.lonhosford.com/lonblog/2011/05/14/xcode-4-iphone-mountains-of-the-usa-tutorial-lesson-3-parse-xml-data/">Lesson 3 ==&gt; </a>  </p>
<div id="fb-root"></div>
<p><script src="http://connect.facebook.net/en_US/all.js#appId=105467682877384&amp;xfbml=1"></script><fb:like href="http://www.lonhosford.com/lonblog/2011/05/08/xcode-4-iphone-tutorial-mountains-of-the-usa-overview/" send="true" width="450" show_faces="true" font=""></fb:like></p>
<div id="fb-root"></div>
<p><script src="http://connect.facebook.net/en_US/all.js#xfbml=1"></script><fb:comments href="http://www.lonhosford.com/lonblog/2011/05/08/xcode-4-iphone-tutorial-mountains-of-the-usa-overview/" num_posts="2" width="500"></fb:comments><br />
<!-- Begin MailChimp Signup Form --><br />
<!--[if IE]></p>
<style type="text/css" media="screen">
	#mc_embed_signup fieldset {position: relative;}
	#mc_embed_signup legend {position: absolute; top: -1em; left: .2em;}
</style>
<p><![endif]--><br />
<!--[if IE 7]></p>
<style type="text/css" media="screen">
	.mc-field-group {overflow:visible;}
</style>
<p><![endif]--></p>
<div id="mc_embed_signup">
<form action="http://clicksystemsconsulting.us1.list-manage.com/subscribe/post?u=1d83b555f8b0ae0bef0eda6b7&amp;id=73cb4b1340" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" style="font: normal 100% Arial, sans-serif;font-size: 12pxpx;">
<fieldset style="-moz-border-radius: 4px;border-radius: 4px;-webkit-border-radius: 4px;border: 1px solid #000000;padding-top: 1.5em;margin: .5em 0;background-color: #FFFFFF;color: #333333;text-align: left;">
<legend style="white-space: normal;text-transform: capitalize;font-weight: bold;color: #666666;background: #CCCCCC;padding: .5em 1em;border: 1px solid #000000;-moz-border-radius: 4px;border-radius: 4px;-webkit-border-radius: 4px;font-size: 1.2em;"><span>Register For Updates</span></legend>
<div style="padding-left:15px"> You can opt out at anytime</div>
<div class="indicate-required" style="text-align: right;font-style: italic;overflow: hidden;color: #333333;margin: 0 9% 0 0;">* indicates required</div>
<div class="mc-field-group" style="margin: 1.3em 5%;clear: both;overflow: hidden;">
<label for="mce-EMAIL" style="display: block;margin: .3em 0;line-height: 1em;font-weight: bold;">Email Address <strong class="note-required">*</strong><br />
</label></p>
<input type="text" value="" name="EMAIL" class="required email" id="mce-EMAIL" style="margin-right: 1.5em;padding: .2em .3em;width: 90%;float: left;z-index: 999;">
</div>
<div class="mc-field-group" style="margin: 1.3em 5%;clear: both;overflow: hidden;">
<label for="mce-FNAME" style="display: block;margin: .3em 0;line-height: 1em;font-weight: bold;">First Name </label></p>
<input type="text" value="" name="FNAME" class="" id="mce-FNAME" style="margin-right: 1.5em;padding: .2em .3em;width: 90%;float: left;z-index: 999;">
</div>
<div class="mc-field-group" style="margin: 1.3em 5%;clear: both;overflow: hidden;">
<label for="mce-LNAME" style="display: block;margin: .3em 0;line-height: 1em;font-weight: bold;">Last Name </label></p>
<input type="text" value="" name="LNAME" class="" id="mce-LNAME" style="margin-right: 1.5em;padding: .2em .3em;width: 90%;float: left;z-index: 999;">
</div>
<div class="mc-field-group" style="margin: 1.3em 5%;clear: both;overflow: hidden;display: none;">
    <label class="input-group-label" style="display: block;margin: .3em 0;line-height: 1em;font-weight: bold;">Group </label></p>
<div class="input-group" style="padding: .7em .7em .7em 0;font-size: .9em;margin: 0 0 1em 0;">
<ul style="margin: 0;padding: 0;">
<li style="list-style: none;overflow: hidden;padding: .2em 0;clear: left;display: block;margin: 0;">
<input type="checkbox" value="1" name="group[1][1]" id="mce-group[1]-1-0" style="margin-right: 2%;padding: .2em .3em;width: auto;float: left;z-index: 999;"><label for="mce-group[1]-1-0" style="display: block;margin: .4em 0 0 0;line-height: 1em;font-weight: bold;width: auto;float: left;text-align: left !important;">RVCC Course Student</label></li>
<li style="list-style: none;overflow: hidden;padding: .2em 0;clear: left;display: block;margin: 0;">
<input type="checkbox" checked value="2" name="group[1][2]" id="mce-group[1]-1-1" style="margin-right: 2%;padding: .2em .3em;width: auto;float: left;z-index: 999;"><label for="mce-group[1]-1-1" style="display: block;margin: .4em 0 0 0;line-height: 1em;font-weight: bold;width: auto;float: left;text-align: left !important;">XCode IPhone Mountains Tutorial</label></li>
<li style="list-style: none;overflow: hidden;padding: .2em 0;clear: left;display: block;margin: 0;">
<input type="checkbox" checked value="4" name="group[1][4]" id="mce-group[1]-1-2" style="margin-right: 2%;padding: .2em .3em;width: auto;float: left;z-index: 999;"><label for="mce-group[1]-1-2" style="display: block;margin: .4em 0 0 0;line-height: 1em;font-weight: bold;width: auto;float: left;text-align: left !important;">New Blog Articles</label></li>
</ul></div>
</div>
<div id="mce-responses" style="float: left;top: -1.4em;padding: 0em .5em 0em .5em;overflow: hidden;width: 90%;margin: 0 5%;clear: both;">
<div class="response" id="mce-error-response" style="display: none;margin: 1em 0;padding: 1em .5em .5em 0;font-weight: bold;float: left;top: -1.5em;z-index: 1;width: 80%;background: FBE3E4;color: #D12F19;"></div>
<div class="response" id="mce-success-response" style="display: none;margin: 1em 0;padding: 1em .5em .5em 0;font-weight: bold;float: left;top: -1.5em;z-index: 1;width: 80%;background: #E3FBE4;color: #529214;"></div>
</p></div>
<div>
<input type="submit" value="Subscribe" name="subscribe" id="mc-embedded-subscribe" class="btn" style="clear: both;width: auto;display: block;margin: 1em 0 1em 5%;"></div>
</fieldset>
<p>	<a href="#" id="mc_embed_close" class="mc_embed_close" style="display: none;">Close</a><br />
</form>
</div>
<p><script type="text/javascript">
var fnames = new Array();var ftypes = new Array();fnames[0]='EMAIL';ftypes[0]='email';fnames[1]='FNAME';ftypes[1]='text';fnames[2]='LNAME';ftypes[2]='text';
try {
    var jqueryLoaded=jQuery;
    jqueryLoaded=true;
} catch(err) {
    var jqueryLoaded=false;
}
var head= document.getElementsByTagName('head')[0];
if (!jqueryLoaded) {
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js';
    head.appendChild(script);
    if (script.readyState &#038;&#038; script.onload!==null){
        script.onreadystatechange= function () {
              if (this.readyState == 'complete') mce_preload_check();
        }    
    }
}
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'http://downloads.mailchimp.com/js/jquery.form-n-validate.js';
head.appendChild(script);
var err_style = '';
try{
    err_style = mc_custom_error_style;
} catch(e){
    err_style = 'margin: 1em 0 0 0; padding: 1em 0.5em 0.5em 0.5em; background: FFEEEE none repeat scroll 0% 0%; font-weight: bold; float: left; z-index: 1; width: 80%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: FF0000;';
}
var head= document.getElementsByTagName('head')[0];
var style= document.createElement('style');
style.type= 'text/css';
if (style.styleSheet) {
  style.styleSheet.cssText = '.mce_inline_error {' + err_style + '}';
} else {
  style.appendChild(document.createTextNode('.mce_inline_error {' + err_style + '}'));
}
head.appendChild(style);
setTimeout('mce_preload_check();', 250);</p>
<p>var mce_preload_checks = 0;
function mce_preload_check(){
    if (mce_preload_checks>40) return;
    mce_preload_checks++;
    try {
        var jqueryLoaded=jQuery;
    } catch(err) {
        setTimeout('mce_preload_check();', 250);
        return;
    }
    try {
        var validatorLoaded=jQuery("#fake-form").validate({});
    } catch(err) {
        setTimeout('mce_preload_check();', 250);
        return;
    }
    mce_init_form();
}
function mce_init_form(){
    jQuery(document).ready( function($) {
      var options = { errorClass: 'mce_inline_error', errorElement: 'div', onkeyup: function(){}, onfocusout:function(){}, onblur:function(){}  };
      var mce_validator = $("#mc-embedded-subscribe-form").validate(options);
      options = { url: 'http://clicksystemsconsulting.us1.list-manage1.com/subscribe/post-json?u=1d83b555f8b0ae0bef0eda6b7&#038;id=73cb4b1340&#038;c=?', type: 'GET', dataType: 'json', contentType: "application/json; charset=utf-8",
                    beforeSubmit: function(){
                        $('#mce_tmp_error_msg').remove();
                        $('.datefield','#mc_embed_signup').each(
                            function(){
                                var txt = 'filled';
                                var fields = new Array();
                                var i = 0;
                                $(':text', this).each(
                                    function(){
                                        fields[i] = this;
                                        i++;
                                    });
                                $(':hidden', this).each(
                                    function(){
                                    	if ( fields[0].value=='MM' &#038;&#038; fields[1].value=='DD' &#038;&#038; fields[2].value=='YYYY' ){
                                    		this.value = '';
									    } else if ( fields[0].value=='' &#038;&#038; fields[1].value=='' &#038;&#038; fields[2].value=='' ){
                                    		this.value = '';
									    } else {
	                                        this.value = fields[0].value+'/'+fields[1].value+'/'+fields[2].value;
	                                    }
                                    });
                            });
                        return mce_validator.form();
                    }, 
                    success: mce_success_cb
                };
      $('#mc-embedded-subscribe-form').ajaxForm(options);      </p>
<p>    });
}
function mce_success_cb(resp){
    $('#mce-success-response').hide();
    $('#mce-error-response').hide();
    if (resp.result=="success"){
        $('#mce-'+resp.result+'-response').show();
        $('#mce-'+resp.result+'-response').html(resp.msg);
        $('#mc-embedded-subscribe-form').each(function(){
            this.reset();
    	});
    } else {
        var index = -1;
        var msg;
        try {
            var parts = resp.msg.split(' - ',2);
            if (parts[1]==undefined){
                msg = resp.msg;
            } else {
                i = parseInt(parts[0]);
                if (i.toString() == parts[0]){
                    index = parts[0];
                    msg = parts[1];
                } else {
                    index = -1;
                    msg = resp.msg;
                }
            }
        } catch(e){
            index = -1;
            msg = resp.msg;
        }
        try{
            if (index== -1){
                $('#mce-'+resp.result+'-response').show();
                $('#mce-'+resp.result+'-response').html(msg);            
            } else {
                err_id = 'mce_tmp_error_msg';
                html = '
<div id="'+err_id+'" style="'+err_style+'"> '+msg+'</div>
<p>';</p>
<p>                var input_id = '#mc_embed_signup';
                var f = $(input_id);
                if (ftypes[index]=='address'){
                    input_id = '#mce-'+fnames[index]+'-addr1';
                    f = $(input_id).parent().parent().get(0);
                } else if (ftypes[index]=='date'){
                    input_id = '#mce-'+fnames[index]+'-month';
                    f = $(input_id).parent().parent().get(0);
                } else {
                    input_id = '#mce-'+fnames[index];
                    f = $().parent(input_id).get(0);
                }
                if (f){
                    $(f).append(html);
                    $(input_id).focus();
                } else {
                    $('#mce-'+resp.result+'-response').show();
                    $('#mce-'+resp.result+'-response').html(msg);
                }
            }
        } catch(e){
            $('#mce-'+resp.result+'-response').show();
            $('#mce-'+resp.result+'-response').html(msg);
        }
    }
}</p>
<p></script><br />
<!--End mc_embed_signup--></p>
]]></content:encoded>
			<wfw:commentRss>http://www.lonhosford.com/lonblog/2011/05/12/xcode-4-iphone-mountains-of-the-usa-tutorial-lesson-2-load-xml-data/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP SimpleXML: Load XML File, Preserve CDATA, Remove Whitespace Between Nodes and Return JSON</title>
		<link>http://www.lonhosford.com/lonblog/2011/01/07/php-simplexml-load-xml-file-preserve-cdata-remove-whitespace-between-nodes-and-return-json/</link>
		<comments>http://www.lonhosford.com/lonblog/2011/01/07/php-simplexml-load-xml-file-preserve-cdata-remove-whitespace-between-nodes-and-return-json/#comments</comments>
		<pubDate>Fri, 07 Jan 2011 21:16:05 +0000</pubDate>
		<dc:creator>Lon Hosford</dc:creator>
				<category><![CDATA[Php 5]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[XML]]></category>

		<guid isPermaLink="false">http://www.lonhosford.com/lonblog/?p=1179</guid>
		<description><![CDATA[I needed to create an indented easy to read and edit XML file that a novice web owner could edit. This entailed having the nodes nicely indented so the user could find them easily. The XML file required CDATA nodes. The CDATA nodes I wanted on a separate line again so the user could easily [...]]]></description>
			<content:encoded><![CDATA[<p>I needed to create an indented easy to read and edit XML file that a novice web owner could edit. This entailed having the nodes nicely indented so the user could find them easily. The XML file required CDATA nodes. <img alt="" src="http://lh5.ggpht.com/_e5pwU0LJbN8/TSeCQ4dqa0I/AAAAAAAAFw8/gBzNFjP-GME/s800/cdata_strip_white_space_published.png" class="alignleft" width="400" height="242" />The CDATA nodes I wanted on a separate line again so the user could easily find them. Finally I needed to send the loaded XML data in JSON format to the client side. </p>
<p> I chose <a href="http://www.php.net/manual/en/function.simplexml-load-file.php" target = "_blank">SimpleXML simplexml_load_file method</a> to handle the XML file and data. The problem with simplexml_load_file is that it ignores CDATA nodes.  This is not immediately clear when reading the documentation. You do find references to the CDATA issue in the user comments. </p>
<p>The documentation also provides a hint should you decide to explore the <a href="http://www.php.net/manual/en/libxml.constants.php"  target = "_blank">simplexml_load_file options argument</a>. Here you see the LIBXML_NOCDATA value which includes this explanation: &#8220;Merge CDATA as text nodes.&#8221; Using this option value converts the node containing the CDATA node into a text node using the container node name. Thus </p>
<pre class="brush: xml; wrap-lines: false;">
&lt;info&gt;
	&lt;![CDATA[&lt;b&gt;Help&lt;/b&gt;]]&gt;
&lt;/info&gt;
</pre>
<p>becomes</p>
<pre class="brush: xml; wrap-lines: false;">
&lt;info&gt;
	&lt;b&gt;Help&lt;/b&gt;
&lt;/info&gt;
</pre>
<p>This is fine since the data returning to the client is in JSON format. Here is how the solution would look:</p>
<pre class="brush: php; wrap-lines: false;">
$xml = simplexml_load_file($xml_filename, 'SimpleXMLElement', LIBXML_NOCDATA);
</pre>
<p><div style = "text-align:center"><script type="text/javascript"><!--
google_ad_client = "pub-8926707286265620";
/* 300x250, created 7/29/10 */
google_ad_slot = "4548376258";
google_ad_width = 300;
google_ad_height = 250;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div><br />
This solution creates another problem. The tabs and new line characters between the CDATA containing node are added to the new text node when converting to JSON. </p>
<pre class="brush: xml; wrap-lines: false;">
\n\t\t\t\t&lt;b&gt;help&lt;/b&gt;
</pre>
<p>Clearly, information between nodes is NOT data.  Since my goal was to have a nicely formatted XML file for a user to update manually, this created the need to strip the whitespace added. </p>
<p>The approach I selected was to use a regular expression to remove the whitespace characters before and after the < > tag delimters  as follows:</p>
<pre class="brush: php; wrap-lines: false;">
'~\s*(&lt;([^&gt;]*)&gt;[^&lt;]*&lt;/\2&gt;|&lt;[^&gt;]*&gt;)\s*~','$1'
</pre>
<p>One caveat is that if you decide to include html in the cdata node, the regular expression removes the whitespace before and after those tags.</p>
<p>Also is this needs to be applied before converting to SimpleXML. So I used <a href="http://php.net/manual/en/function.file-get-contents.php" target = "_blank">file_get_contents</a> to load the xml data file, applied the regular expression and then converted to a SimpleXML object. </p>
<p>The completed PHP script is as follows:</p>
<pre class="brush: php; wrap-lines: false;">
&lt;?php
// The XML data file with whitespace such as tabs
$xml_file = &quot;user_formatted_xml_data.xml&quot;;
// Load xml data.
$xml = file_get_contents($xml_file);
// Strip whitespace between xml tags
$xml = preg_replace('~\s*(&lt;([^&gt;]*)&gt;[^&lt;]*&lt;/\2&gt;|&lt;[^&gt;]*&gt;)\s*~','$1',$xml);
// Convert CDATA into xml nodes.
$xml = simplexml_load_string($xml,'SimpleXMLElement', LIBXML_NOCDATA);
// Return JSON.
echo json_encode($xml);
?&gt;
</pre>
<p><div style = "text-align:center"><script type="text/javascript"><!--
google_ad_client = "pub-8926707286265620";
/* 300x250, created 7/29/10 */
google_ad_slot = "4548376258";
google_ad_width = 300;
google_ad_height = 250;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div><br />
Here is a sample data file to try.</p>
<pre class="brush: xml; wrap-lines: false;">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;news_items&gt;
	&lt;news_item&gt;
		&lt;title&gt;
			&lt;![CDATA[News item title #1 with &lt;br/&gt;html added.]]&gt;
		&lt;/title&gt;
		&lt;content&gt;
			&lt;![CDATA[This is the &lt;b&gt;CDATA content&lt;/b&gt; for news item&lt;strong&gt; #1 &lt;/strong&gt; with some &quot;html&quot; included.]]&gt;
		&lt;/content&gt;
	&lt;/news_item&gt;
	&lt;news_item&gt;
		&lt;title&gt;
			&lt;![CDATA[News item title #2 with &lt;br/&gt;html added.]]&gt;
		&lt;/title&gt;
		&lt;content&gt;
			&lt;![CDATA[This is the &lt;b&gt;CDATA content&lt;/b&gt; for news item&lt;strong&gt; #2 &lt;/strong&gt; with some &quot;html&quot; included.]]&gt;
		&lt;/content&gt;
	&lt;/news_item&gt;
&lt;/news_items&gt;
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.lonhosford.com/lonblog/2011/01/07/php-simplexml-load-xml-file-preserve-cdata-remove-whitespace-between-nodes-and-return-json/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Parsley MVC, RemoteObject, Zend AMF and MySQL Basic Flex Example</title>
		<link>http://www.lonhosford.com/lonblog/2010/09/27/parsley-mvc-remoteobject-zend-amf-and-mysql-basic-flex-example/</link>
		<comments>http://www.lonhosford.com/lonblog/2010/09/27/parsley-mvc-remoteobject-zend-amf-and-mysql-basic-flex-example/#comments</comments>
		<pubDate>Mon, 27 Sep 2010 17:31:11 +0000</pubDate>
		<dc:creator>Lon Hosford</dc:creator>
				<category><![CDATA[Actionscript 3]]></category>
		<category><![CDATA[Flex]]></category>
		<category><![CDATA[Parsley]]></category>
		<category><![CDATA[Php 5]]></category>
		<category><![CDATA[Zend AMF]]></category>
		<category><![CDATA[Actionscript]]></category>
		<category><![CDATA[AMF]]></category>
		<category><![CDATA[Flex 4]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.lonhosford.com/lonblog/?p=898</guid>
		<description><![CDATA[After conquering a basic Parsley Framework Flex example I wanted to create a minimal example of using the Flex Parsley framework, Zend AMF and MySQL. The Flex implementation goal is to mold a model view controller framework using Parsley and to communicate via Flex RemoteObject to Zend AMF. Eventually I applied what I learned to [...]]]></description>
			<content:encoded><![CDATA[<div id="fb-root"></div>
<p><script src="http://connect.facebook.net/en_US/all.js#appId=105467682877384&amp;xfbml=1"></script><fb:like href="http://www.lonhosford.com/lonblog/2010/09/27/parsley-mvc-remoteobject-zend-amf-and-mysql-basic-flex-example/" send="true" width="450" show_faces="true" font=""></fb:like></p>
<p>After conquering <a href="http://www.lonhosford.com/lonblog/2010/09/14/basic-parsley-framework-flex-example-explained/">a basic Parsley Framework Flex example</a> I wanted to create a minimal example of using the Flex Parsley framework, Zend AMF and MySQL. The Flex implementation goal is to mold a model view controller framework using Parsley and to communicate via Flex RemoteObject to Zend AMF. Eventually I applied what I learned to revamp <a href="http://www.defineit.com" target = "_blank">DefineIt.com</a> with Parsley and Zend AMF.</p>
<p>There are many approached to using Parsley for MVC. The Parsley documentation is very light on the subject. <img alt="" src="http://lh3.ggpht.com/_e5pwU0LJbN8/TKDUAky8sUI/AAAAAAAAFt8/eYNi96PU-hA/s800/ParselyZendAmfHelloWorld_published.png" class="alignleft" width="380" height="199" />These also entail including using other frameworks like Caringorm. In this example I kept it simply by just using the Parsley messaging features and creating my own controller class.</p>
<p>I found other examples of Parsley that go further into its features. You might look at <a href="http://coenraets.org/blog/2009/07/building-a-flex-application-with-the-parsley-framework/">Christophe Coenraets&#8217;</a> example. This is referenced from the <a href="http://www.spicefactory.org/parsley/docs/2.3/manual/" target = "_blank">Parsley documentation</a> . Christophe includes an update and add feature to the application. It also contains a dynamically loaded image class. It is a bit over featured and thus over involved for a pure beginner. It is void of substantive explanation leaving you to explore the Parsley documentation to try to understand why one approach was chosen over another in code. Worse code has no comments. This should be a minimum requirement for any referenced sample code. However there are some good Flex and Parsley techniques in there that can be helpful and one to bookmark for your learning process.</p>
<div class="wp-caption alignright" style="width: 144px"><a href="http://www.amazon.com/gp/product/0321660501?ie=UTF8&#038;tag=hosfordusa&#038;linkCode=as2&#038;camp=1789&#038;creative=390957&#038;creativeASIN=0321660501" target="_blank"><img border="0" src="http://lh3.ggpht.com/_e5pwU0LJbN8/TI93JgBp5AI/AAAAAAAAFtU/2oU3O6g1mvg/s800/41N912-mmWL._SL160_.jpg"></a><p class="wp-caption-text">Learn More About Flex 4 From Adobe</p></div>
<p>Parsley 2.3 is used and the SWCs are included in the example Flex 4 project download I have here. I did appreciate these SWCs also being included in the downloads from the <a href="http://www.spicefactory.org/parsley/download.php"  target = "_blank">Parsley download page</a>. Lets you get to learning faster. </p>
<p>You can build this with the free Flex SDK by using the code in the src folder and be sure to include a path to the Parsley and Spicelib library. </p>
<ul style = "padding-top:10px">
<li><a href="http://www.lonhosford.com/content/flex/Parsley/ParsleyAndZendFramework_HelloWorld.fxp" onClick="javascript: pageTracker._trackPageview('/downloads/ParsleyAndZendFramework_HelloWorld.fxp'); ">Flex Builder 4 Flex Project</a></li>
</ul>
<p>When you run this application, the trace log will show you the interactions between the model, controller, view and service.</p>
<p><strong>Application Class &#8211; Parsley_Configuration.mxml</strong><br />
This is the main MXML file. Line 15 links the Parsley_Configuration.mxml file that configures Parsley framework. </p>
<p>Line 16 tells Parsley to include this mxml file and thus allows us to inject the ApplicationModel data.</p>
<p>I put all locale language into the model to simplify the example. In the effort the ApplicationModel class for application level data only contains the locale language title for the application you can see referenced in the Label on lines 26 and 39. </p>
<p>Line 40 contains the Panel to display the data grid.</p>
<pre class="brush: as3; wrap-lines: false;">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;s:Application xmlns:fx=&quot;http://ns.adobe.com/mxml/2009&quot;
			   xmlns:s=&quot;library://ns.adobe.com/flex/spark&quot;
			   xmlns:hellozend=&quot;com.alh.parsley.example.hellozend.*&quot;
			   xmlns:parsley=&quot;http://www.spicefactory.org/parsley&quot;
			   xmlns:mx=&quot;library://ns.adobe.com/flex/mx&quot;
			   xmlns:sf=&quot;http://www.spicefactory.org/parsley&quot;
			   minWidth=&quot;955&quot; minHeight=&quot;600&quot;
			   xmlns:views=&quot;com.alh.parsley.example.hellozend.views.*&quot;
			   &gt;
	&lt;fx:Declarations&gt;
		&lt;!--
		Parsley configuration MXML file
		--&gt;
		&lt;parsley:ContextBuilder config=&quot;Parsley_Configuration&quot; /&gt;
		&lt;sf:Configure/&gt;
	&lt;/fx:Declarations&gt;
	&lt;fx:Script&gt;
		&lt;![CDATA[
			import com.alh.parsley.example.hellozend.model.ApplicationModel;
			/**
			 * Parsley injects the ApplicationModel here.
			 * */
			[Inject]
			[Bindable]
			public var model:ApplicationModel;

		]]&gt;
	&lt;/fx:Script&gt;
	&lt;!--
		UI
	--&gt;
	&lt;s:layout&gt;
		&lt;s:VerticalLayout gap=&quot;10&quot;
						  horizontalAlign=&quot;center&quot;
						  paddingLeft=&quot;12&quot; paddingRight=&quot;12&quot; paddingBottom=&quot;12&quot; paddingTop=&quot;12&quot;
						  /&gt;
	&lt;/s:layout&gt;
	&lt;s:Label text=&quot;{model.lang_AppTitle}&quot; fontSize=&quot;20&quot;/&gt;
	&lt;views:AllMembersGrid/&gt;
&lt;/s:Application&gt;
</pre>
<p><strong>Parsley Configuration &#8211; Parsley_Configuration.mxml</strong><br />
This is the file Parsley reads for configuration. </p>
<p>I included  the RemoteObject definitions here as well. I am following Christophe Coenraets&#8217; example on this. It makes sense to me to have this as part of the configuration file. Remember to change the YOUR_GATEWAY_URL on line 13 to reflect your link to the Zend AMF or other RemoteObject service. </p>
<p>You may note there is no services xml or configuration file. The channel information is in the MXML instead. You can learn more on this by reading <a href="http://www.lonhosford.com/lonblog/2010/08/26/zend-amf-action-message-format-minimalist-example-using-remoteobject-and-mysql/"><br />
ZEND AMF (Action Message Format) Minimalist Example Using RemoteObject and MySQL</a></p>
<p>On lines 27 &#8211; 30 I have four Actionscript classes handling the model, view and controller. They are listed here so we can use the [Inject] metatag for Parsley.</p>
<pre class="brush: as3; wrap-lines: false;">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;Objects
	xmlns:fx=&quot;http://ns.adobe.com/mxml/2009&quot;
	xmlns=&quot;http://www.spicefactory.org/parsley&quot;
	xmlns:s=&quot;library://ns.adobe.com/flex/spark&quot;
	xmlns:hellozend=&quot;com.alh.parsley.example.hellozend.*&quot;
	xmlns:model=&quot;com.alh.parsley.example.hellozend.model.*&quot;
	xmlns:services=&quot;com.alh.parsley.example.hellozend.services.*&quot;
	xmlns:controller=&quot;com.alh.parsley.example.hellozend.controller.*&quot;&gt;
	&lt;fx:Declarations&gt;
		&lt;s:ChannelSet id = &quot;zend_amf_channel_set&quot;&gt;
			&lt;s:channels&gt;
				&lt;s:AMFChannel uri=&quot;YOUR_GATEWAY_URL&quot;/&gt;
			&lt;/s:channels&gt;
		&lt;/s:ChannelSet&gt;
		&lt;!-- MembershipService RemoteObject --&gt;
		&lt;s:RemoteObject	id=&quot;membershipService_ro&quot;
						destination=&quot;zend-amf&quot;
						source=&quot;MembershipService&quot;
						channelSet=&quot;{zend_amf_channel_set}&quot;
						showBusyCursor=&quot;true&quot;
						&gt;
		&lt;/s:RemoteObject&gt;
		&lt;!--
			Parsley defined objects slated for injection where [Inject] metatag appears.
		--&gt;
		&lt;model:ApplicationModel/&gt;
		&lt;model:MembershipModel/&gt;
		&lt;services:MembershipServiceRemote/&gt;
		&lt;controller:MembershipController/&gt;
&lt;/fx:Declarations&gt;
&lt;/Objects&gt;
</pre>
<p><strong>Application Model Class &#8211; ApplicationModel.as</strong><br />
This class defines application level data and we only have a language variable to simplify the example for localization.</p>
<pre class="brush: as3; wrap-lines: false;">
package com.alh.parsley.example.hellozend.model
{
	/**
	 * Model for application level data
	 * */
	public class ApplicationModel
	{
		/**
		 * UI language in model to simplify example
		 *
		 * Language for Application
		 * */
		[Bindable]
		public var lang_AppTitle:String = &quot;Minimalist Parsley Zend AMF Example Using RemoteObject&quot;;;
	}
}
</pre>
<p><strong>Membership Model Class &#8211; MembershipModel.as</strong><br />
This class defines membership data. Again you can see the variables to simplify the example for localization. </p>
<p>The key data here is the ArrayCollection on line 13 for the member data.</p>
<pre class="brush: as3; wrap-lines: false;">
package com.alh.parsley.example.hellozend.model
{
	import mx.collections.ArrayCollection;
	/**
	 * Model for membership
	 * */
	public class MembershipModel
	{
		/**
		 * List of members;
		 * */
		[Bindable]
		public var members:ArrayCollection;
		/**
		 * UI language in model to simplify example
		 *
		 * Language for AllMembersGrid view
		 * */
		[Bindable]
		public var lang_AllMembersGridTitle:String = &quot;Membership Listing&quot;;
		[Bindable]
		public var lang_MemberKey:String = &quot;Member Key&quot;;
		[Bindable]
		public var lang_FirstName:String = &quot;First Name&quot;;
		[Bindable]
		public var lang_LastName:String = &quot;Last Name&quot;;
		[Bindable]
		public var lang_EmailAddress:String = &quot;Email Address&quot;;
		[Bindable]
		public var lang_GetMembers:String = &quot;Get Members&quot;;
		[Bindable]
		public var lang_ClearMembers:String = &quot;Clear&quot;;
	}
}
</pre>
<p><strong>IMembershipService Class &#8211; IMembershipService.as</strong><br />
Interface to define methods for membership service classes. We only have one in the example: MembershipServiceRemote.</p>
<pre class="brush: as3; wrap-lines: false;">
package com.alh.parsley.example.hellozend.services
{
	import mx.rpc.AsyncToken;
	/**
	 * Interface to define MembershipService classes
	 * */
	public interface IMembershipService
	{
		function getAllMembers():AsyncToken;
	}
}
</pre>
<p><div style = "text-align:center"><script type="text/javascript"><!--
google_ad_client = "pub-8926707286265620";
/* 300x250, created 7/29/10 */
google_ad_slot = "4548376258";
google_ad_width = 300;
google_ad_height = 250;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div><br />
<strong>MembershipServiceRemote Class &#8211; MembershipServiceRemote.as</strong><br />
This class deals with the server service. Only the controller communicates with this class by calling the get getAllMembers() method.</p>
<p>Line 46 is the interface back to the MVC or to the application however you want to look at it. Here a Parsley message is created for the MembershipGetAllMembersEvent.GET_ALL_MEMBERS event that you will see the MembershipController class handles. </p>
<p>You could have the controller pass its own result and fault handlers to the getAllMembers() method and eliminate the MembershipGetAllMembersEvent.GET_ALL_MEMBERS message. </p>
<p>As a further simplification, the faults are all routed to the catchAllServiceErrorHandler(&#8230;) method where a view component is inserted breaking a clean MVC. You could create a message for the fault handler to dispatch and have the controller to handle this. </p>
<pre class="brush: as3; wrap-lines: false;">
package com.alh.parsley.example.hellozend.services
{
	import com.alh.parsley.example.hellozend.events.MembershipGetAllMembersEvent;
	import com.alh.parsley.example.hellozend.services.IMembershipService;
	import mx.controls.Alert;
	import mx.rpc.AsyncResponder;
	import mx.rpc.AsyncToken;
	import mx.rpc.events.FaultEvent;
	import mx.rpc.events.ResultEvent;
	import mx.rpc.remoting.RemoteObject;
	/**
	 * IMembershipService class to handle RemoteObject data communications with server.
	 * */
	public class MembershipServiceRemote implements IMembershipService
	{
		/**
		 * Specify the remote service for Parsley to inject.
		 * */
		[Inject(id=&quot;membershipService_ro&quot;)]
		public var service:RemoteObject;
		/**
		 * Parsley creates an event dispatcher function
		 * */
		[MessageDispatcher]
		public var dispatcher:Function;

		/**
		 * Get all members from RemoteObject service.
		 * */
		public function getAllMembers():AsyncToken
		{
			trace (&quot;SERVICE: MembershipServiceRemote.getAllMembers()&quot;);
			var token:AsyncToken = service.getAllMembers();
			token.addResponder(
				new AsyncResponder(getAllMembersResultsHandler, catchAllServiceErrorHandler));
			return token;
		}
		/**
		 * ResultEvent handler for service.getAllMembers()
		 * */
		protected function getAllMembersResultsHandler(event:ResultEvent, result:Object):void
		{
			trace (&quot;SERVICE: MembershipServiceRemote.getAllMembersResultsHandler()&quot;);
			//event.result == Array.
			var members:Array = event.result as Array;
			dispatcher( new MembershipGetAllMembersEvent(MembershipGetAllMembersEvent.GET_ALL_MEMBERS, members));
		}
		/**
		 * Default handler for MembershipServiceRemote calls
		 * */
		protected function catchAllServiceErrorHandler(e:FaultEvent):void
		{
			Alert.show(e.toString());
		}
	}
}
</pre>
<p><strong>MembershipController Class &#8211; MembershipController.as</strong><br />
This controller ties in the MembershipModel class and the MembershipServiceRemote class on line 18 and 24 respectively.</p>
<p>The controller listens for the MembershipEvent events on line 29. The Parsley [MessageHandler] tag makes this happen. These events are dispatched in the view.</p>
<p>On line 46 the controller listens for the MembershipGetAllMembersEvent dispatched from the MembershipServiceRemote class.</p>
<pre class="brush: as3; wrap-lines: false;">
package com.alh.parsley.example.hellozend.controller
{
	import com.alh.parsley.example.hellozend.events.MembershipEvent;
	import com.alh.parsley.example.hellozend.events.MembershipGetAllMembersEvent;
	import com.alh.parsley.example.hellozend.model.MembershipModel;
	import com.alh.parsley.example.hellozend.services.MembershipServiceRemote;
	import mx.collections.ArrayCollection;
	/**
	 * Controller for Membership model and views.
	 * */
	public class MembershipController
	{
		/**
		 * Parsley injects the MembershipModel here.
		 * */
		[Inject]
		[Bindable]
		public var model:MembershipModel;
		/**
		 * Parsley injects the MembershipService here.
		 * */
		[Inject]
		[Bindable]
		public var service:MembershipServiceRemote;
		/**
		 * Parsley identified handler for MembershipEvent
		 * */
		[MessageHandler]
		public function membershipEventHandler( message:MembershipEvent ):void
		{
			trace (&quot;CONTROLLER: MembershipController.membershipEventHandler(...) - message.type:&quot; + message.type);
			switch (message.type )
			{
				case MembershipEvent.GET_ALL_MEMBERS:
					service.getAllMembers();
					break
				case MembershipEvent.CLEAR_ALL_MEMBERS:
					model.members.removeAll();
					break
			}
		}
		/**
		 * Parsley identified handler for MembershipGetAllMembersEvent
		 * */
		[MessageHandler]
		public function membershipGetAllMembersEventHandler( message:MembershipGetAllMembersEvent ):void
		{
			trace (&quot;CONTROLLER: MembershipController.membershipGetAllMembersEventHandler(...)&quot;);
			model.members = new ArrayCollection(message.members);
		}
	}
}
</pre>
<p><div style = "text-align:center"><script type="text/javascript"><!--
google_ad_client = "pub-8926707286265620";
/* 300x250, created 7/29/10 */
google_ad_slot = "4548376258";
google_ad_width = 300;
google_ad_height = 250;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div><br />
<strong>Membership Grid View &#8211; AllMembersGrid.mxml</strong><br />
This is a Panel containing a DataGrid and Buttons for the user interaction.</p>
<p>Lines 27 and 28 sets up the class to dispatch Parsley messages. Line 35 dispatches the MembershipEvent.CLEAR_ALL_MEMBERS event and line 43 dispatches the MembershipEvent.GET_ALL_MEMBERS event. The MembershipController class handles these messages to update the model and communicate with the service as needed.</p>
<p>This view is tied to the MembershipModel class via Parsley on line 23. The DataGrid binds to the model members variable.</p>
<p>Other bindings for the language localizations appear as well.</p>
<pre class="brush: as3; wrap-lines: false;">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;s:Panel xmlns:fx=&quot;http://ns.adobe.com/mxml/2009&quot;
		 xmlns:s=&quot;library://ns.adobe.com/flex/spark&quot;
		 xmlns:mx=&quot;library://ns.adobe.com/flex/mx&quot;
		 xmlns:sf=&quot;http://www.spicefactory.org/parsley&quot;
		 title = &quot;{model.lang_AllMembersGridTitle}&quot;
		&gt;
	&lt;fx:Declarations&gt;
		&lt;!--
		Parsely will manage this component.
		--&gt;
		&lt;sf:Configure/&gt;
	&lt;/fx:Declarations&gt;
	&lt;fx:Script&gt;
		&lt;![CDATA[
			import com.alh.parsley.example.hellozend.events.MembershipEvent;
			import com.alh.parsley.example.hellozend.model.MembershipModel;
			/**
			 * Parsley injects the MembershipModel here.
			 * */
			[Inject]
			[Bindable]
			public var model:MembershipModel;
			/**
			 * Parsley creates an event dispatcher function
			 * */
			[MessageDispatcher]
			public var dispatcher:Function;
			/**
			 * Dispatch MembershipEvent.CLEAR_ALL_MEMBERS event
			 * */
			protected function clearDataGrid():void
			{
				trace(&quot;VIEW: &quot; + className + &quot;.clearDataGrid()&quot;);
				dispatcher( new MembershipEvent( MembershipEvent.CLEAR_ALL_MEMBERS ));
			}
			/**
			 * Dispatch MembershipEvent.GET_ALL_MEMBERS event
			 * */
			protected function getAllMembers():void
			{
				trace(&quot;VIEW: &quot; + className + &quot;.getAllMembers()&quot;);
				dispatcher( new MembershipEvent( MembershipEvent.GET_ALL_MEMBERS ));
			}
		]]&gt;
	&lt;/fx:Script&gt;
	&lt;s:layout&gt;
		&lt;s:VerticalLayout gap=&quot;10&quot;
						  paddingLeft=&quot;12&quot; paddingRight=&quot;12&quot; paddingBottom=&quot;12&quot; paddingTop=&quot;12&quot;
						  /&gt;
	&lt;/s:layout&gt;
	&lt;mx:DataGrid  id=&quot;member_dg&quot;  height=&quot;100&quot; dataProvider=&quot;{model.members}&quot;&gt;
		&lt;mx:columns&gt;
			&lt;mx:DataGridColumn headerText=&quot;{model.lang_MemberKey}&quot; dataField=&quot;memberKey&quot;/&gt;
			&lt;mx:DataGridColumn headerText=&quot;{model.lang_FirstName}&quot; dataField=&quot;firstName&quot;/&gt;
			&lt;mx:DataGridColumn headerText=&quot;{model.lang_LastName}&quot; dataField=&quot;lastName&quot;/&gt;
			&lt;mx:DataGridColumn headerText=&quot;{model.lang_EmailAddress}&quot; dataField=&quot;emailAddress&quot; width=&quot;200&quot;/&gt;
		&lt;/mx:columns&gt;
	&lt;/mx:DataGrid&gt;
	&lt;s:HGroup horizontalAlign=&quot;center&quot; width=&quot;100%&quot;&gt;
		&lt;s:Button label=&quot;{model.lang_GetMembers}&quot; click=&quot;{getAllMembers();}&quot;/&gt;
		&lt;s:Button label=&quot;{model.lang_ClearMembers}&quot; click=&quot;{clearDataGrid();}&quot;/&gt;
	&lt;/s:HGroup&gt;

&lt;/s:Panel&gt;
</pre>
<p><strong>MembershipEvent.as</strong><br />
This is a standard Event class to inform the MVC framework all membership data is required or needs to be cleared. These free the view from being coupled with the service or updating the model.</p>
<pre class="brush: as3; wrap-lines: false;">
package com.alh.parsley.example.hellozend.events
{
	import flash.events.Event;
	/**
	 * Events related to membership.
	 * */
	public class MembershipEvent extends Event
	{
		/**
		 * Request to retrieve all membership data
		 * */
		public static const GET_ALL_MEMBERS:String = &quot;com.alh.parsley.example.hellozend.events.MembershipEvent.getAllMembers&quot;;
		/**
		 * Request to clear all membership data
		 * */
		public static const CLEAR_ALL_MEMBERS:String = &quot;com.alh.parsley.example.hellozend.events.MembershipEvent.clearAllMembers&quot;;

		public function MembershipEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
		{
			super(type, bubbles, cancelable);
		}
	}
}
</pre>
<p><strong>MembershipGetAllMembersEvent.as</strong><br />
This event message signals success retrieval of members data from the service. </p>
<pre class="brush: as3; wrap-lines: false;">
package com.alh.parsley.example.hellozend.events
{
	import flash.events.Event;
	/**
	 * Event defining service receipt of membership data.
	 * */
	public class MembershipGetAllMembersEvent extends Event
	{
		public static const GET_ALL_MEMBERS:String = &quot;com.alh.parsley.example.hellozend.events.MembershipGetAllMembersEvent.getAllMembers&quot;;
		/**
		 * Membership data
		 * */
		public var members:Array;

		public function MembershipGetAllMembersEvent(type:String, members:Array, bubbles:Boolean=false, cancelable:Boolean=false)
		{
			super(type, bubbles, cancelable);
			this.members = members;
		}
	}
}
</pre>
<p><strong>Zend AMF Gateway PHP Script</strong><br />
This is the gateway program for the Zend Amf. This is the file that you reference on line 13 of the Parsley_Configuration.mxml file. In this example it was named index.php.</p>
<pre class="brush: php;">
&lt;?php
/**
*  Sample Zend AMF gateway
*  @return Endpoint [Zend Amf Endpoint]
* */

// Configurable values
// Debugging values
$debug = true;                             // Debugging status
if ($debug)
{
	// Report all errors, warnings, interoperability and compatibility
	error_reporting(E_ALL|E_STRICT);
	// Show errors with output
	ini_set(&quot;display_errors&quot;, &quot;on&quot;);
}
else
{
	error_reporting(0);
	ini_set(&quot;display_errors&quot;, &quot;off&quot;);
}
// Add the Zend AMF installation folder to the include path.
// In this example the frameworks folder is a sibling folder to
// this application folder. The frameworks folder contains the Zend
// folder that is extracted from http://framework.zend.com/download/amf
ini_set(&quot;include_path&quot;, ini_get(&quot;include_path&quot;) . PATH_SEPARATOR . &quot;..\\frameworks&quot; );

// Instantiate the Zend Amf server
require_once 'Zend/Amf/Server.php';
$server = new Zend_Amf_Server();

// Register your service classes
require_once 'MembershipService.php';
$server-&gt;setClass(&quot;MembershipService&quot;);

//Map ActionScript value objects to the PHP value objects.
$server-&gt;setClassMap(&quot;MemberData&quot;, &quot;MemberData&quot;);

// Return the handle.
echo ($server-&gt;handle());

?&gt;
</pre>
<p><div style = "text-align:center"><script type="text/javascript"><!--
google_ad_client = "pub-8926707286265620";
/* 300x250, created 7/29/10 */
google_ad_slot = "4548376258";
google_ad_width = 300;
google_ad_height = 250;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div><br />
<strong>MembershipService Class</strong><br />
This is the service class that contains remote methods. Generally a the database and business logic is delegated to another API you write. In this case they are all together for simplicity.</p>
<pre class="brush: php;">
&lt;?php
/**
*	Service class exposing the methods to deal with membership.
*   This example includes business logic for simplicity of study.
*/
require_once 'MemberData.php';
class MembershipService
{
	public function MembershipService()
	{
		// Connect to MySql database.
		// Supply your own MySQL access values.
		// These are defaults when running on your own private computer.
		mysql_connect(&quot;localhost&quot;, &quot;root&quot;, &quot;&quot;);
		// Select the database.
		// Supply your own database name.
		mysql_select_db(&quot;test&quot;);
	}
	/**
	*	Get all members and all fields.
	*/
	public function getAllMembers()
	{
		// Array of MemberData objects.
		$members = array();
		// Selecting all fields and all records from table.
		// Supply your own table name and optionally your own SQL statement.
		$result = mysql_query(&quot;SELECT * FROM zend_amf_members&quot;);
		// Assuming mysql_query success. Slog through records.
		while ($row = mysql_fetch_assoc($result))
		{
			// Create a MemberData value object and populate.
			$member = new MemberData();
			$member-&gt;memberKey = $row[&quot;memberKey&quot;];
			$member-&gt;firstName = $row[&quot;firstName&quot;];
			$member-&gt;lastName = $row[&quot;lastName&quot;];
			$member-&gt;emailAddress = $row[&quot;emailAddress&quot;];
			array_push($members, $member);
		}
		// Return the members array to client.
		return $members;
	}
}
?&gt;
</pre>
<p><strong>MemberData Value Object Class for PHP</strong><br />
This is the value object on the server side to define the field names for a member object. This is mapped to the client side on line 37 of the Zend AMF gateway script.</p>
<pre class="brush: php;">
&lt;?php
/**
 * Value object defining the member data
 * */
class MemberData
{
  public $memberKey;	// uint
  public $firstName;	// String
  public $lastName;		// String
  public $emailAddress;	// String
}
?&gt;
</pre>
<p><strong>SQL To Create Testing Table</strong><br />
The PHP script uses zend_amf_members for the table and this is the SQL to create that table. In this example the database was called test.</p>
<pre class="brush: sql;">
SET SQL_MODE=&quot;NO_AUTO_VALUE_ON_ZERO&quot;;

--
-- Database: `test`
--

-- --------------------------------------------------------

--
-- Table structure for table `zend_amf_members`
--

CREATE TABLE IF NOT EXISTS `zend_amf_members` (
  `memberKey` int(10) unsigned NOT NULL auto_increment,
  `firstName` varchar(30) NOT NULL default '',
  `lastName` varchar(30) NOT NULL default '',
  `emailAddress` varchar(50) NOT NULL default '',
  PRIMARY KEY  (`memberKey`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='Zend Amf Examples' AUTO_INCREMENT=7 ;

--
-- Dumping data for table `zend_amf_members`
--

INSERT INTO `zend_amf_members` (`memberKey`, `firstName`, `lastName`, `emailAddress`) VALUES
(1, 'Donald', 'Duck', 'quacker@pond.com'),
(2, 'Daffy', 'Duck', 'daft_2x@farm.org'),
(3, 'Elmer', 'Fudd', 'elmer.fudd@hunters.net'),
(4, 'Bugs', 'Bunny', 'whats_up_doc@underground.org'),
(5, 'Yosemite', 'Sam', 'varmint_chaser@forest.com'),
(6, 'Wile', 'Coyote', 'ceo@acme.com');
</pre>
<div id="fb-root"></div>
<p><script src="http://connect.facebook.net/en_US/all.js#xfbml=1"></script><fb:comments href="http://www.lonhosford.com/lonblog/2010/09/27/parsley-mvc-remoteobject-zend-amf-and-mysql-basic-flex-example" num_posts="2" width="500"></fb:comments></p>
]]></content:encoded>
			<wfw:commentRss>http://www.lonhosford.com/lonblog/2010/09/27/parsley-mvc-remoteobject-zend-amf-and-mysql-basic-flex-example/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>ZEND AMF (Action Message Format) Minimalist Example Using RemoteObject and MySQL</title>
		<link>http://www.lonhosford.com/lonblog/2010/08/26/zend-amf-action-message-format-minimalist-example-using-remoteobject-and-mysql/</link>
		<comments>http://www.lonhosford.com/lonblog/2010/08/26/zend-amf-action-message-format-minimalist-example-using-remoteobject-and-mysql/#comments</comments>
		<pubDate>Thu, 26 Aug 2010 18:10:46 +0000</pubDate>
		<dc:creator>Lon Hosford</dc:creator>
				<category><![CDATA[AIR (Adobe Integrated Runtime)]]></category>
		<category><![CDATA[Actionscript 3]]></category>
		<category><![CDATA[Flex]]></category>
		<category><![CDATA[Php 5]]></category>
		<category><![CDATA[Actionscript]]></category>
		<category><![CDATA[Air]]></category>
		<category><![CDATA[AMF]]></category>
		<category><![CDATA[Flex 4]]></category>
		<category><![CDATA[RemoteObject]]></category>

		<guid isPermaLink="false">http://www.lonhosford.com/lonblog/?p=787</guid>
		<description><![CDATA[I always liked and appreciated the AMFPHP implementation of Adobe Action Message Format. I have seen it implemented in some robust applications and it held its own. Among its best features is the browser which is very handy for testing. However Adobe has now gotten involved with Zend AMF and this is a quick shot [...]]]></description>
			<content:encoded><![CDATA[<p>I always liked and appreciated the <a href="http://www.amfphp.org/" target="_blank">AMFPHP implementation</a> of Adobe Action Message Format. I have seen it implemented in some robust applications and it held its own. <img class="alignleft" style="margin-right: 5px; border: 1px solid black;" src="http://lh5.ggpht.com/_e5pwU0LJbN8/THaPGSfNSzI/AAAAAAAAFsA/cPvKMfUdzR4/s800/Zend_AMF_Minimalist_8-26-2010%2011-56-17%20AM.png" alt="" width="232" height="171" /> Among its best features is the browser which is very handy for testing. However Adobe has now gotten involved with <a href="http://framework.zend.com/download/amf" target = "_blank">Zend AMF</a> and this is a quick shot at putting it together using the RemoteObject class.</p>
<p>The first example I looked at is from Lee Brimelow&#8217;s <a href="http://gotoandlearn.com/play.php?id=90" target="_blank">Introduction to ZendAMF</a> at gotoAndLearn.com. This is a great example and worth the watch to get a rounded view of using Zend AMF. He uses NetConnection and Responder classes in Flash CS4.  You can use his example in Flex and Air.</p>
<div class="wp-caption alignright" style="width: 121px"><a href="http://www.amazon.com/gp/product/B003KG2HLG?ie=UTF8&amp;tag=hosfordusa&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=B003KG2HLG5" target="_blank"><img class="  " title="Adobe Flash Builder 4 and Flex 4 - Essential Training" src="http://lh5.ggpht.com/_e5pwU0LJbN8/THaJ7e_VZDI/AAAAAAAAFr4/6gLBuTgzkq0/s800/FlashBuilder4AndFlex441KcCjdUF%2BL._SL160_.jpg" alt="Adobe Flash Builder 4 and Flex 4 - Essential Training" " width="111"  height="160" /></a><p class="wp-caption-text">Learn More About Flex&nbsp;4</p></div>
<p>Eventually I put Zend AMF to practical use by revamping <a href="http://www.defineit.com" target = "_blank">DefineIt.com</a> to use it along with the <a href="http://www.lonhosford.com/lonblog/2010/09/27/parsley-mvc-remoteobject-zend-amf-and-mysql-basic-flex-example/">Parsley framework</a>.</p>
<p>Flash CS4 does not have a native RemoteObject class, so that leads us to using Flex.</p>
<p><strong>Download files</strong><br />
You can build this with the free Flex SDK by using the code in the src folder. This example was built with Flex 4.</p>
<ul style="padding-top: 5px;">
<li><a href="http://www.lonhosford.com/content/flex/amf/zend/ZendAMFRemoteObjectGetTable_Air.fxp">Flex Builder 4 Air Project</a></li>
<li><a href="http://www.lonhosford.com/content/flex/amf/zend/ZendAMFRemoteObjectGetTable_Flex.fxp">Flex Builder 4 Flex Project</a></li>
<li><a href="http://framework.zend.com/download/amf" target = "_blank">Zend AMF</a> &#8211; Download and decompress into a folder on your web server. You need to adjust line 26 of the Zend AMF gateway script shown below to account for the path the Zend folder&#8217;s parent folder.</li>
</ul>
<p>The following uses the code from the Flex example, but other than the Application and WindowedApplication tags the code is the same.</p>
<p><strong>Application Class &#8211; ZendAMFRemoteObjectGetTable_Flex</strong><br />
Rather than use a services-config.xml file linked to the compiler line, I choose to include the channel information in the MXML. More on this method is detailed by Chris Callendar&#8217;s post <a href="http://flexdevtips.blogspot.com/2009/05/using-flex-and-amfphp-without-services.html" target = "_blank">Using Flex and AMFPHP without a services-config.xml file</a>.</p>
<pre class="brush: as3; highlight: [32]; wrap-lines: false;">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;!--
Demonstrates use of the RemoteObject to communicate with Zend AMF.
&lt;p&gt;Author: Lon Hosford http://www.lonhosford.com 908 996 3773&lt;/p&gt;
--&gt;
&lt;s:Application xmlns:fx=&quot;http://ns.adobe.com/mxml/2009&quot;
			   xmlns:s=&quot;library://ns.adobe.com/flex/spark&quot;
			   xmlns:mx=&quot;library://ns.adobe.com/flex/mx&quot; minWidth=&quot;955&quot; minHeight=&quot;600&quot;&gt;
	&lt;fx:Declarations&gt;
		&lt;!-- Alternative to services-config.xml added to the compiler option services --&gt;
		&lt;s:ChannelSet id = &quot;zend_amf_channel_set&quot;&gt;
			&lt;s:channels&gt;
				&lt;s:AMFChannel uri=&quot;{GATEWAY_URL}&quot;/&gt;
			&lt;/s:channels&gt;
		&lt;/s:ChannelSet&gt;
		&lt;!-- MembershipService RemoteObject --&gt;
		&lt;s:RemoteObject	id=&quot;members_ro&quot;
						destination=&quot;zend-amf&quot;
						source=&quot;MembershipService&quot;
						channelSet=&quot;{zend_amf_channel_set}&quot;
						showBusyCursor=&quot;true&quot;
						fault=&quot;membersError(event)&quot;&gt;
			&lt;s:method name=&quot;getAllMembers&quot; result=&quot;getAllMembersResult(event)&quot;/&gt;
		&lt;/s:RemoteObject&gt;
	&lt;/fx:Declarations&gt;
</pre>
<p><div style = "text-align:center"><script type="text/javascript"><!--
google_ad_client = "pub-8926707286265620";
/* 300x250, created 7/29/10 */
google_ad_slot = "4548376258";
google_ad_width = 300;
google_ad_height = 250;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div><br />
On line 33 you need to set the GATEWAY_URL to match your configuration. You might want to use a default file name such as index.php for the gateway script so you only need a path to the folder.</p>
<pre class="brush: as3; first-line: 26; wrap-lines: false;">
	&lt;fx:Script&gt;
		&lt;![CDATA[
			import mx.controls.Alert;
			import mx.events.FlexEvent;
			import mx.rpc.events.FaultEvent;
			import mx.rpc.events.ResultEvent;
			// [ADD YOUR HTTP URL TO THE GATEWAY PHP SCRIPT]
			private const GATEWAY_URL:String = &quot;http://YOUR_DOMAIN/PATH_TO_GATEWAY SCRIPT/&quot;;
			/**
			 * Member value object. Not used in this example. Included for information only.
			 * Use this to convert the data received. In this example the DataGrid dataprovider
			 * property converted the incoming amf array to an ArrayCollection and we mapped
			 * using the DataGridColumn dataField property.
			 * */
			private var memberData:MemberData;
			[Bindable]
			private var lang_title:String = &quot;Minimalist Zend AMF Example Using RemoteObject&quot;;
			/**
			 * Invoke RemoteObject members_ro getAllMembers method.
			 * */
			protected function getAllMembers():void
			{
				members_ro.getAllMembers();
			}
			/**
			 * Empties the member_dg DataGrid.
			 * */
			protected function clearDataGrid():void
			{
				member_dg.dataProvider = {};
			}
			/**
			 * RemoteObject members_ro ResultEvent handler for the remote getAllMembers method.
			 * &lt;p&gt;Data arrives as an array and dataProvider property converts to ArrayCollection.
			 * The member_dg DataGrid contains DataGridColumn to match the expected field using
			 * the dataField property.&lt;/p&gt;
			 * */
			protected function getAllMembersResult(e:ResultEvent):void
			{
				member_dg.dataProvider = e.result; // ResultEvent result property is an array
			}
			/**
			 * RemoteObject members_ro default FaultEvent handler.
			 * */
			protected function membersError(e:FaultEvent):void
			{
				Alert.show(e.toString());
			}
		]]&gt;
	&lt;/fx:Script&gt;
</pre>
<p><div style = "text-align:center"><script type="text/javascript"><!--
google_ad_client = "pub-8926707286265620";
/* 300x250, created 7/29/10 */
google_ad_slot = "4548376258";
google_ad_width = 300;
google_ad_height = 250;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div><br />
This is the UI. The member_dg DataGrid contains DataGridColumn to match the expected fields in the MemberData object using the dataField property. This is a one to one relationship, however you may find times where you need to construct your own fields such as a concatenation of first and last name and thus populate the DataGrid with your own collection object.</p>
<pre class="brush: as3; first-line: 76; wrap-lines: false;">
	&lt;s:VGroup horizontalAlign=&quot;center&quot; width=&quot;100%&quot; paddingTop=&quot;25&quot;&gt;
		&lt;s:Label text=&quot;{lang_title}&quot; fontSize=&quot;20&quot;/&gt;

		&lt;mx:DataGrid  id=&quot;member_dg&quot;  height=&quot;100&quot;&gt;
			&lt;mx:columns&gt;
				&lt;mx:DataGridColumn headerText=&quot;Member Key&quot; dataField=&quot;memberKey&quot; width = &quot;100&quot;/&gt;
				&lt;mx:DataGridColumn headerText=&quot;First Name&quot; dataField=&quot;firstName&quot;/&gt;
				&lt;mx:DataGridColumn headerText=&quot;Last Name&quot; dataField=&quot;lastName&quot;/&gt;
				&lt;mx:DataGridColumn headerText=&quot;Email Address&quot; dataField=&quot;emailAddress&quot; width=&quot;200&quot;/&gt;
			&lt;/mx:columns&gt;
		&lt;/mx:DataGrid&gt;
		&lt;s:HGroup&gt;
			&lt;s:Button label=&quot;Get Members&quot; click=&quot;{getAllMembers();}&quot;/&gt;
			&lt;s:Button label=&quot;Clear&quot; click=&quot;{clearDataGrid();}&quot;/&gt;
		&lt;/s:HGroup&gt;
	&lt;/s:VGroup&gt;

&lt;/s:Application&gt;
</pre>
<p><strong>MemberData Value Object Class for Actionscript</strong><br />
This is the value object on the client side to define the field names for a member object. This is mapped to the server side on line 37 of the Zend AMF gateway script.</p>
<pre class="brush: as3; wrap-lines: false;">
package
{
	/**
	 * Value object defining the member data
	 * */
	[RemoteClass(alias=&quot;MemberData&quot;)]
	[Bindable]
	public class MemberData
	{
		public var memberKey:uint;
		public var firstName:String;
		public var lastName:String;
		public var emailAddress:String;
	}
}
</pre>
<p><strong>Zend AMF Gateway PHP Script</strong><br />
This is the gateway program for the Zend Amf. This is the file that is referenced on line 13 of the MXML file. In this example it was named index.php.</p>
<pre class="brush: php;">
&lt;?php
/**
*  Sample Zend AMF gateway
*  @return Endpoint [Zend Amf Endpoint]
* */

// Configurable values
// Debugging values
$debug = true;                             // Debugging status
if ($debug)
{
	// Report all errors, warnings, interoperability and compatibility
	error_reporting(E_ALL|E_STRICT);
	// Show errors with output
	ini_set(&quot;display_errors&quot;, &quot;on&quot;);
}
else
{
	error_reporting(0);
	ini_set(&quot;display_errors&quot;, &quot;off&quot;);
}
// Add the Zend AMF installation folder to the include path.
// In this example the frameworks folder is a sibling folder to
// this application folder. The frameworks folder contains the Zend
// folder that is extracted from http://framework.zend.com/download/amf
ini_set(&quot;include_path&quot;, ini_get(&quot;include_path&quot;) . PATH_SEPARATOR . &quot;..\\frameworks&quot; );

// Instantiate the Zend Amf server
require_once 'Zend/Amf/Server.php';
$server = new Zend_Amf_Server();

// Register your service classes
require_once 'MembershipService.php';
$server-&gt;setClass(&quot;MembershipService&quot;);

//Map ActionScript value objects to the PHP value objects.
$server-&gt;setClassMap(&quot;MemberData&quot;, &quot;MemberData&quot;);

// Return the handle.
echo ($server-&gt;handle());

?&gt;
</pre>
<p><div style = "text-align:center"><script type="text/javascript"><!--
google_ad_client = "pub-8926707286265620";
/* 300x250, created 7/29/10 */
google_ad_slot = "4548376258";
google_ad_width = 300;
google_ad_height = 250;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div><br />
<strong>MembershipService Class</strong><br />
This is the service class that contains remote methods. Generally a the database and business logic is delegated to another API you write. In this case they are all together for simplicity.</p>
<pre class="brush: php;">
&lt;?php
/**
*	Service class exposing the methods to deal with membership.
*   This example includes business logic for simplicity of study.
*/
require_once 'MemberData.php';
class MembershipService
{
	public function MembershipService()
	{
		// Connect to MySql database.
		// Supply your own MySQL access values.
		// These are defaults when running on your own private computer.
		mysql_connect(&quot;localhost&quot;, &quot;root&quot;, &quot;&quot;);
		// Select the database.
		// Supply your own database name.
		mysql_select_db(&quot;test&quot;);
	}
	/**
	*	Get all members and all fields.
	*/
	public function getAllMembers()
	{
		// Array of MemberData objects.
		$members = array();
		// Selecting all fields and all records from table.
		// Supply your own table name and optionally your own SQL statement.
		$result = mysql_query(&quot;SELECT * FROM zend_amf_members&quot;);
		// Assuming mysql_query success. Slog through records.
		while ($row = mysql_fetch_assoc($result))
		{
			// Create a MemberData value object and populate.
			$member = new MemberData();
			$member-&gt;memberKey = $row[&quot;memberKey&quot;];
			$member-&gt;firstName = $row[&quot;firstName&quot;];
			$member-&gt;lastName = $row[&quot;lastName&quot;];
			$member-&gt;emailAddress = $row[&quot;emailAddress&quot;];
			array_push($members, $member);
		}
		// Return the members array to client.
		return $members;
	}
}
?&gt;
</pre>
<p><strong>MemberData Value Object Class for PHP</strong><br />
This is the value object on the server side to define the field names for a member object. This is mapped to the client side on line 37 of the Zend AMF gateway script.</p>
<pre class="brush: php;">
&lt;?php
/**
 * Value object defining the member data
 * */
class MemberData
{
  public $memberKey;	// uint
  public $firstName;	// String
  public $lastName;		// String
  public $emailAddress;	// String
}
?&gt;
</pre>
<p><strong>SQL To Create Testing Table</strong><br />
The PHP script uses zend_amf_members for the table and this is the SQL to create that table. In this example the database was called test.</p>
<pre class="brush: sql;">
SET SQL_MODE=&quot;NO_AUTO_VALUE_ON_ZERO&quot;;

--
-- Database: `test`
--

-- --------------------------------------------------------

--
-- Table structure for table `zend_amf_members`
--

CREATE TABLE IF NOT EXISTS `zend_amf_members` (
  `memberKey` int(10) unsigned NOT NULL auto_increment,
  `firstName` varchar(30) NOT NULL default '',
  `lastName` varchar(30) NOT NULL default '',
  `emailAddress` varchar(50) NOT NULL default '',
  PRIMARY KEY  (`memberKey`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='Zend Amf Examples' AUTO_INCREMENT=7 ;

--
-- Dumping data for table `zend_amf_members`
--

INSERT INTO `zend_amf_members` (`memberKey`, `firstName`, `lastName`, `emailAddress`) VALUES
(1, 'Donald', 'Duck', 'quacker@pond.com'),
(2, 'Daffy', 'Duck', 'daft_2x@farm.org'),
(3, 'Elmer', 'Fudd', 'elmer.fudd@hunters.net'),
(4, 'Bugs', 'Bunny', 'whats_up_doc@underground.org'),
(5, 'Yosemite', 'Sam', 'varmint_chaser@forest.com'),
(6, 'Wile', 'Coyote', 'ceo@acme.com');
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.lonhosford.com/lonblog/2010/08/26/zend-amf-action-message-format-minimalist-example-using-remoteobject-and-mysql/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Amazon Web Service (AWS) Signed Request Using PHP For Flex HTTPService</title>
		<link>http://www.lonhosford.com/lonblog/2010/08/09/amazon-web-service-aws-signed-request-using-php-for-flex-httpservice/</link>
		<comments>http://www.lonhosford.com/lonblog/2010/08/09/amazon-web-service-aws-signed-request-using-php-for-flex-httpservice/#comments</comments>
		<pubDate>Mon, 09 Aug 2010 16:15:37 +0000</pubDate>
		<dc:creator>Lon Hosford</dc:creator>
				<category><![CDATA[AWS]]></category>
		<category><![CDATA[Actionscript 3]]></category>
		<category><![CDATA[Amazon]]></category>
		<category><![CDATA[Flex]]></category>
		<category><![CDATA[Php]]></category>
		<category><![CDATA[Php 5]]></category>

		<guid isPermaLink="false">http://www.lonhosford.com/lonblog/?p=486</guid>
		<description><![CDATA[By Lon (Alonzo) Hosford I am in the process of updating my Flex Caringorm example that makes an ItemSearch operation to Amazon AWS to fetch data. AWS changed the security August 2009 to include a secret key value. Using this you need to create Signature parameter. You also need a Timestamp parameter. The Signature parameter [...]]]></description>
			<content:encoded><![CDATA[<p><strong>By Lon (Alonzo) Hosford</strong></p>
<p>I am in the process of updating my Flex Caringorm example that makes an ItemSearch operation to Amazon AWS to fetch data.  AWS changed the security August 2009 to include a secret key value. Using this you need to create Signature parameter. You also need a Timestamp parameter. </p>
<p>The Signature parameter you need to generate and they have a <a href="http://associates-amazon.s3.amazonaws.com/signed-requests/helper/index.html" target = "_blank">utility helper</a> to demonstrate should you need it. </p>
<div style = "float:left;padding-right:5px;" ><div style = "text-align:center"><script type="text/javascript"><!--
google_ad_client = "pub-8926707286265620";
/* 300x250, created 7/29/10 */
google_ad_slot = "4548376258";
google_ad_width = 300;
google_ad_height = 250;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div></div>
<p>There is an Actionscript example of how to generate the signed request at <a href="http://www.brendonwilson.com/blog/2009/07/31/signing-amazon-web-service-requests-in-actionscript/" target = "_blank">Brendon Wilson&#8217;s blog</a>. I did not try it. There is a discussion in the blog comments about placing the security key in the Actionscript code. The idea of a security key implies it is to be protected. Placing it in the Actionscript code is not wise because there are tools that can open the contents of a published swf. </p>
<p>Another plan is to store all the AWS information on a server and place the signature code there. So this is an example on how to do that with PHP. The AWS access ID and secret key are removed from the client side and are better protected. The secert key is in plain text and as such you may want to take more action to protect that if you think the PHP script is vulnerable. </p>
<p>Here is the PHP version of signing an AWS request. I had to cobble various examples I found and added the references at the end of this blog article. This example  designed to work with Flex HTTPService and returns XML. The script allows placing test AWS parameters in the file for testing with a browser. You might want to try other AWS operations and parameters.</p>
<p>Configuration is easy. Lines 9 and 10 require your AWS codes. That is it.</p>
<p>To generate an error from AWS keep $useTestData on line 18 as false and run the script in a web browser. Your response will show AWS balking at a missing parameter because nothing is being sent for it to process. To see a positive result change $useTestData to true and the supplied test data will produce a nice pile of XML.</p>
<pre class="brush: php; wrap-lines: false;">
&lt;?php
/**
*  Creats AWS request and signs the request
*  Wraps AWS response in user defined XML.
*  To test add your AWS access key code ID and secrete access key and set $useTestData = true;
*/
header (&quot;content-type: text/xml&quot;);
// Configurable values
$public_key = &quot;{PLACE YOUR AWS ACCESS KEY HERE}&quot;;	// AWS access key code ID
$private_key = &quot;{PLACE YOUR AWS SECRET KEY HERE}&quot;;	// AWS secret access key)
$amazonErrorRootNode = &quot;&lt;Errors&quot;;					// First node with &lt; from amazon for error  response.

// Developer values
$version = &quot;v.01.00.00&quot;;						// Version of this script

// Debugging values
$debug = false;								// Debugging status
$useTestData = false;							// Use embedded testing data

// Program controlled values
$success = &quot;false&quot;;							// Default success value.
$params = array();							// The parameters to pass to AWS
$returnXML = &quot;&quot;;								// XML returned

if ($useTestData)
{
	$params =  array(	&quot;Operation&quot;=&gt;&quot;ItemSearch&quot;,
                        &quot;Keywords&quot;=&gt;&quot;Beatles Abbey Road&quot;,
                        &quot;Service&quot;=&gt;&quot;AWSECommerceService&quot;,
                        &quot;Sort&quot;=&gt;&quot;salesrank&quot;,
                        &quot;SearchIndex&quot;=&gt;&quot;Music&quot;,
                        &quot;Count&quot;=&gt;&quot;25&quot;,
						&quot;ResponseGroup&quot;=&gt;&quot;Medium,Tracks,Offers&quot;);
}
else
{
	$params = $_REQUEST;
}

$returnXML .= &quot;&lt;response&gt;&quot;;

$returnXML .= &quot;&lt;version&gt;&quot;;
$returnXML .= $version;
$returnXML .= &quot;&lt;/version&gt;&quot;;
if ($debug)
{
	$returnXML .= &quot;&lt;isTestData&gt;&quot;;
	$returnXML .= $useTestData ? &quot;true&quot;:&quot;false&quot;;
	$returnXML .= &quot;&lt;/isTestData&gt;&quot;;
}

function aws_signed_request( $public_key, $private_key, $params)
{
	$method = &quot;GET&quot;;
	$host = &quot;ecs.amazonaws.com&quot;;
	$uri = &quot;/onca/xml&quot;;

	$timestamp = gmstrftime(&quot;%Y-%m-%dT%H:%M:%S.000Z&quot;);
	$timestamp = &quot;&amp;Timestamp=&quot; . rawurlencode($timestamp);

	$params[&quot;AWSAccessKeyId&quot;] = $public_key;

	$workurl=&quot;&quot;;
    foreach ($params as $param=&gt;$value)
    {
		$workurl .= ((strlen($workurl) == 0)? &quot;&quot; : &quot;&amp;&quot;) . $param . &quot;=&quot; . rawurlencode($value);
    }
	//$workurl = str_replace(&quot; &quot;,&quot;%20&quot;,$workurl);
	$workurl = str_replace(&quot;,&quot;,&quot;%2C&quot;,$workurl);
	$workurl = str_replace(&quot;:&quot;,&quot;%3A&quot;,$workurl);
	$workurl .= $timestamp;
	$params = explode(&quot;&amp;&quot;,$workurl);
	sort($params);

	$signstr = &quot;GET\n&quot; . $host . &quot;\n/onca/xml\n&quot; . implode(&quot;&amp;&quot;,$params);
	$signstr = base64_encode(hash_hmac('sha256', $signstr, $private_key, true));
	$signstr = rawurlencode($signstr);
	$signedurl = &quot;http://&quot; .$host . $uri . &quot;?&quot; . $workurl  . &quot;&amp;Signature=&quot; . $signstr;
	return $signedurl;
}

// Make the signed url for AWS
$signedurl = aws_signed_request( $public_key, $private_key, $params);

if ($debug)
{
	$returnXML .= &quot;&lt;signed_url&gt;&quot;;
	$returnXML .= $signedurl;
	$returnXML .= &quot;&lt;/signed_url&gt;&quot;;
}

// Make request to AWS
$response = @file_get_contents($signedurl);

// The file_get_contents has failed. See PHP documentation for that.
if ($response === false) // Equal and same data type
{
	$success = &quot;false&quot;;
}
// AWS returned a response
else
{
	$returnXML .= &quot;&lt;results&gt;&quot;;
	// AWS did not return an error code
	if (strpos($response, $amazonErrorRootNode) == 0)
	{
		$success = &quot;true&quot;;

		$returnXML .= substr($response, strpos($response, &quot;?&gt;&quot;)+2); // Strip Amazon XML header
	}
	// AWS returned an error code
	else
	{
		$success = &quot;false&quot;;
		$returnXML .= substr($response, strpos($response, &quot;?&gt;&quot;)+2); // Strip Amazon XML header
	}
	$returnXML .= &quot;&lt;/results&gt;&quot;;

}

$returnXML .= &quot;&lt;success&gt;&quot;;
$returnXML .= $success;
$returnXML .= &quot;&lt;/success&gt;&quot;;

$returnXML .= &quot;&lt;/response&gt;&quot;;

echo $returnXML;

?&gt;
</pre>
<p>References</p>
<ul>
<li> <a href="http://www.thewhyandthehow.com/signing-aws-requests-in-php/" target = "_blank">Signing AWS requests in PHP</a></li>
<li> <a href="http://mierendo.com/software/aws_signed_query/" target = "_blank">Amazon® AWS HMAC signed request using PHP</a></li>
<li> <a href="http://www.chrisrossi.com/2009/05/09/how-to-use-the-new-amazon-aws-signature-in-php/" target = "_blank">How to use the new Amazon AWS Signature in PHP</a></li>
<li> <a href="http://www.brendonwilson.com/blog/2009/07/31/signing-amazon-web-service-requests-in-actionscript/" target = "_blank">Signing Amazon Web Service Requests in ActionScript</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.lonhosford.com/lonblog/2010/08/09/amazon-web-service-aws-signed-request-using-php-for-flex-httpservice/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

