<?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>HirdWeb</title>
	<atom:link href="http://www.hirdweb.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.hirdweb.com</link>
	<description>Another Blog clogging up the already crowded internet</description>
	<lastBuildDate>Wed, 28 Jul 2010 16:05:05 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Code Standards</title>
		<link>http://www.hirdweb.com/2010/07/28/code-standards/</link>
		<comments>http://www.hirdweb.com/2010/07/28/code-standards/#comments</comments>
		<pubDate>Wed, 28 Jul 2010 16:05:05 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Ideas and Sorts]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=290</guid>
		<description><![CDATA[As I have been going through different code bases, I keep seeing things that just really amaze me. It all surrounds coding standards, or the lack thereof. Different places have different ideas of what is best, and I can only offer mine to the fray. However, once a standard is in place, no matter how [...]]]></description>
			<content:encoded><![CDATA[<p>As I have been going through different code bases, I keep seeing things that just really amaze me. It all surrounds coding standards, or the lack thereof. Different places have different ideas of what is best, and I can only offer mine to the fray. However, once a standard is in place, no matter how odd it may be, it is important to keep to those standards. This is for a few reasons. </p>
<p>First, it is important for readability. By seeing the code in the same format and structure it helps to get through lines of code quickly. It helps because all of the code is in the same format throughout the code. The person looking at the code can quickly understand without having to go back and figure out what is happening because the code is all of a sudden out of whack and what you may think is happening may not be happening. Especially when indentation may also be out of line and brackets are not used. Take for example the two examples below</p>
<pre>$fin=0;
foreach($var as $v){
if($v==3){$fin=$v+3}
unset($fin);echo $v;
}</pre>
<p>As a stand alone example it may be easy to decipher what is happening. In a file that has over 3000 lines of code, it may be overlooked and even cause issues if changes are made that affect that block. By breaking from the set coding standards and doing it &#8220;your own way&#8221;, sure it may be quicker for you, but it creates havoc, even for you later on.<br />
<span id="more-290"></span><br />
Second, it is about cleanliness. Using the same block of code above, that looks absolutely horrid to me. I know some people code this way because &#8220;it takes up less space&#8221;, some even make a claim that it makes the code process faster. To that point, if you need to cut down on whitespace in the code in order to get the application to go faster, then maybe you ought to look at the code again, because it is likely something else that is causing problems, not the whitespace. If that code block again had been done with a few standards in place, it could look like this instead:</p>
<pre>$fin = 0;
foreach ( $var as $v ) {
    if ( $v == 3 ) {
        $fin = $v + 3;
    }

    unset($fin);
    echo $v;
}</pre>
<p>By doing this, the code looks cleaner, which adds to its readability. Clean code not only looks good, but is very easy to do. It helps to maintain the flow of work, especially in larger projects. By sticking to a clean code standard, all developers can jump in at any time and pick up easily, as everything is nicely placed, and easy to understand. There will be times when you write some code, then do not touch it for months, maybe years, and have to go back to review something. You will be very glad if you kept to standards and kept your code clean. </p>
<p>Third, it is about working in the team. If you are alone in the project, then great. You get to choose how you want to work. Most times it is more than just you, so it is important that everyone works in the same standards. This can be up to the team to determine. This can include spacing, indentation, bracket use, variable naming conventions, ternary use, etc. But whatever the team decides, stick to it. Do not be a rogue and do it your own way just because you think it is better. Having the code in a standardized format really, really helps in the long run. Teams are able to debug code quicker because they do not have to decipher different standards. Coding can happen in a dynamic environment where you may be working on a data object one day, then have to switch to help with the controller layer the next. You will not have to go through the code and decipher the different styles. </p>
<p>With that being said, some of the standards that I use may not work for everyone. I am a little neurotic and OCD when it comes to code, so I like a specific style, but can adapt as needed. Here are some of the things I use:</p>
<ul>
<li />Variables names must be descriptive of what they represent, the only exception being is for counters/iterators<br />
for example, a variable for total amount would be $total, or the variable for tax would be $tax, or the variable for a unique identifier would be $uid.  </p>
<li />For loops, If and Switch statements must be bracketed, must have spaces between the parenthesis, and must be indented. The length of indentation I usually use 4 spaces (or set the tab stops to 4 spaces). Switch statements must have indentations for each case. Example:
<pre>if ( $var = 0 ) {
    // do something
}

for ( $c = 0; $c <=5; $c++ ) {
    // do something
}

switch ( $var ) {
    case 1:
        // do something
        break;
    case 2:
        // do something
        break;
    default:
        // do something
} </pre>
<p>There should never be any If statement or loop that is never bracketed, ever. I think that is lazy coding, I think it looks atrocious, and when more code is needing to be added to the struct, it causes more time wasted to ensure that the proper items are included. </p>
<li />Functions should be bracketed, and indented, even if it is only one line of code in the function. Comments should also be done on every function describing the purpose of the function.
<li />Comments describing functions/objects/classes should follow the same format. If PHPDoc is used, then use it throughout. Do not change the way you comment these. I have seen functions in a file commented using PHPDoc, using the "// ----- description", and then surrounded by "//" around the entire comments. I really do not care which one to use, but when one is decided to be used, use only that.
<li />Never, ever use short tags, or short echo tags. They are just bad form, another example of lazy coding, and will cause problems here soon. Even though PHP6 is all but dead, the "enhancement" to remove short tag/short echo tag will make it to a release here soon. I understand the old PHP4 was all over it, but should not have been. Use the full tag and do not use "&lt;?=" to echo something out.
<li />Do not just copy and paste code to other parts of the application. If you find that a code block can be re-used in other areas, then wrap it in a function, or an object/class, and keep the code centralized. When the code needs to be updated, you then only have to update one section, instead of multiple files.
</ul>
<p>OK, so my rant is over. The list above is my standards. This may not always work in every project. Some of the good areas to look at for ideas or practices for code standards are:<br />
<a href='http://pear.php.net/manual/en/standards.php' target='_blank'>http://pear.php.net/manual/en/standards.php</a><br />
<a href='http://framework.zend.com/manual/en/coding-standard.html' target='_blank'>http://framework.zend.com/manual/en/coding-standard.html</a><br />
<a href='https://trac.cakephp.org/wiki/Developement/CodingStandards' target='_blank'>https://trac.cakephp.org/wiki/Developement/CodingStandards</a></p>
<p>Most of the standards I use are located in these documents. </p>

<!-- Wordpress Connect Modules v1.05 -->]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2010/07/28/code-standards/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP 5 News</title>
		<link>http://www.hirdweb.com/2010/07/26/php-5-news/</link>
		<comments>http://www.hirdweb.com/2010/07/26/php-5-news/#comments</comments>
		<pubDate>Tue, 27 Jul 2010 01:42:58 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=286</guid>
		<description><![CDATA[I am going to take a break from the NuSOAP server finish up, and that will come soon. Instead, the update to PHP 5.2.14 has come out. What is really odd about this news, is that according to the release of the news, it also &#8220;marks the end of the active support for PHP 5.2. [...]]]></description>
			<content:encoded><![CDATA[<p>I am going to take a break from the NuSOAP server finish up, and that will come soon. Instead, the update to PHP 5.2.14 has come out. What is really odd about this news, is that according to the <a href='http://www.php.net/archive/2010.php#id2010-07-22-1'>release of the news</a>, it also<br />
<blockquote>&#8220;marks the end of the active support for PHP 5.2. Following this release the PHP 5.2 series will receive no further active bug maintenance. Security fixes for PHP 5.2 might be published on a case by cases basis. All users of PHP 5.2 are encouraged to upgrade to PHP 5.3.&#8221;</p></blockquote>
<p>There are a lot of different applications that are just now adopting 5.2, and it will not be actively supported.<br />
<span id="more-286"></span><br />
Marco Tabini posted a really great article on this, and I highly suggest to review this. It is located at <a href='http://blog.tabini.ca/2010/07/php-5-2-support-ends-just-as-its-adoption-begins/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=php-5-2-support-ends-just-as-its-adoption-begins'>his blog: blog.tabini.ca</a>. While Marco makes great points in his article, the comments on the article are also a good thing to read. </p>
<p>One idea that is important to remember, is that 5.3 will (in theory) work even if the code was made for 5.2. This is of course, the code is well written. But that is the case no matter what code or library, or base you may use. That is the most important aspect, write good code. However, by not providing support when a possible major group of users come on board, can be risky. However, this is where the whole argument of open source and paid services can come back to play in political office meeting rooms. </p>
<p>Paid services, like Microsoft&#8217;s .NET libraries for example, are expensive, but are still supported. Sure it is expensive. Think of this in an enterprise application environment. A company has invested a lot of man hours on a major project upgrade (from 4 to 5.2 for whatever reason they had to stay at 4 for the time), and then find out that the major project they undertook to move to 5.2 will now need further evaluation to determine if 5.3 is acceptable to the company. More cost of investing time, energy, resources, and money can be a huge thing when the &#8220;powers that be&#8221; decide if they want to continue to use open source for their applications. </p>
<p>I know this is a very simplistic example, and there are even more questions with this, like if it was an enterprise app why did it stay on php4 for so long. But since 5.3 has been out for a little over a year, it seems shocking that they would be so quickly retiring active support for this. </p>
<p>It may have more to do with other things, including shelving PHP6. I am not as worried about 5.2 retiring. But it is an interesting event. Some will say this is really nothing, and that there is really nothing to this. And they may be entirely correct. </p>

<!-- Wordpress Connect Modules v1.05 -->]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2010/07/26/php-5-news/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Finishing up the NuSOAP server</title>
		<link>http://www.hirdweb.com/2010/07/20/finishing-up-the-nusoap-server/</link>
		<comments>http://www.hirdweb.com/2010/07/20/finishing-up-the-nusoap-server/#comments</comments>
		<pubDate>Tue, 20 Jul 2010 15:57:09 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[NuSOAP]]></category>
		<category><![CDATA[webservices]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=269</guid>
		<description><![CDATA[In the last post, the NuSOAP server introduced a new level of complexity, and had a multidimensional array, along with creating a more robust status message for the client to help determine the success or failure of the request. This post will examine the remaining functions in the NuSOAP server, and making the rest of [...]]]></description>
			<content:encoded><![CDATA[<p>In the last post, the NuSOAP server introduced a new level of complexity, and had a multidimensional array, along with creating a more robust status message for the client to help determine the success or failure of the request. This post will examine the remaining functions in the NuSOAP server, and making the rest of the functions work, and more complex types including third and fourth level complexities along with a non-named (integer) array for the result. </p>
<p>We will be building on the code we used last time, so as a refresher, the code from the last post can be located at:<br />
<a href="http://www.hirdweb.com/webservice/20100710_server.txt" target="_top">http://www.hirdweb.com/webservice/20100710_server.txt</a><br />
<a href="http://www.hirdweb.com/webservice/20100710.txt" target="_top">http://www.hirdweb.com/webservice/20100710.txt</a></p>
<p>First off, here are the remaining functions to be exposed in the service:
<ul>
<li><strong>showGroupItems</strong> – Shows what is needed based on a set event, all items are made up of course</li>
<li><strong>showMadLib</strong> – Returns a mad lib based on passing in a number of different items</li>
<li><strong>showNumbers</strong> – Returns a non associative array of numbers, requires an ID, and returns the numbers associated with that ID</li>
</ul>
<p>Each of these webservices will require a little different structure.<br />
showGroupItems will have a third level of complexity<br />
showMadLib will require a long list of strings as the input<br />
showNumbers will return an array of string elements, integer value for the element, instead of a named element<br />
<span id="more-269"></span><br />
Make sure to save the file with a different name. I named it &#8220;20100720_server.php&#8221;. You will need to also update the WSDL call, otherwise it will still reference an older file name. Here is what I updated my location with:
<pre>$wsdl_addr = 'http://www.hirdweb.com/webservice/20100720_server.php';</pre>
<p>Let&#8217;s first tackle the showGroupItems. The idea behind this is to show an example of a complex type for the returned result. We already have a complex type, but we need to make a returned result with a multidimensional array. The required input is:<br />
id = a specific event name, in this case, we limit it to: movie, picnic, drive, shopping</p>
<p>For each of these events, we have a set of items that will go with it:<br />
food &#8211; this is an array of items for food, drink and treat<br />
equip &#8211; string containing a comma separated list of equipment needed<br />
transport &#8211; string for the transport to/of the event<br />
people &#8211; string of a comma separated list (or a single item) of people involved in the activity</p>
<p>First we need the list, so add this to the file named <em>items.php</em> that contains all the data for the services. We created this file in a previous post. (<em>Just a note: in a &#8220;real world&#8221; application, these would likely be stored in a database and you would need to query the information you need in order to build the array</em>). </p>
<pre>$items = array(
	'movie' => array(
		'food'	=> array('food' => 'nachos with jalepenos and cheese', 'drink' => 'soda', 'treat' => 'candy'),
		'equip' => 'ticket, 3D glasses',
		'transport' => 'car',
		'people' => 'friend A, friend B, friend C',
	),
	'picnic' => array(
		'food'	=> array('food' => 'sandwiches', 'drink' => 'sports drinks', 'treat' => 'granola bars'),
		'equip' => 'basket, blanket',
		'transport' => 'van',
		'people' => 'Mom, Dad, brothers, sisters, cousins',
	),
	'drive' => array(
		'food'	=> array('food' => 'snacks', 'drink' => 'water', 'treat' => 'crackers'),
		'equip' => 'gloves, sunglasses',
		'transport' => 'sports car',
		'people' => 'myself, hot date',
	),
	'shopping' => array(
		'food'	=> array('food' => 'grapes', 'drink' => 'juice box', 'treat' => 'candybar'),
		'equip' => 'cart, list',
		'transport' => 'moving van',
	)
);</pre>
<p>We will create a function with some very basic error checking, and be able to use our error function if there are errors. </p>
<pre>function showGroupItems($id){
	require('items.php');
	// Make sure the id is lowercase
	$id = strtolower($id);
	if ( $id == '' ){
		return error('empty');
	}
	// make sure the item is in the array keys
	if ( !array_key_exists($id, $items) ){
		// return an error
		return error("not_found");
	}
	$final = $items[$id];

	$fin_data['status'] = array('status'=>'ok','message'=>'');
	$fin_data['group_items'] = $final;

	return $fin_data;
}</pre>
<p>Now we need to tackle the registration of this function to the webservice. This is where we really need to think about what we need to return. First, we need to set the registration and the base complex type:</p>
<pre>// ================================================
// === showGroupItems register
$in = array(
	'id' => 'xsd:string',
);
$out = array('return' => 'tns:showGroupItems');
$namespace = 'uri:hirdwebservice';
$soapaction = 'uri:hirdwebservice/showGroupItems';
$doc = 'Simplistic service to return an array of items for a specific event, the ones available are: movie, picnic, drive, shopping';
$server->register('showGroupItems', $in, $out, $namespace, $soapaction, 'rpc', 'encoded', $doc);
// ================================================</pre>
<p>In this registration, we defined a &#8220;showGroupItems&#8221; type. So we need to create that to pull in the status type, and start building the showGroupItems result</p>
<pre>// showGroupItems types ++++++++++++++++++++++++++++++++++++++++++
$server->wsdl->addComplexType('showGroupItems','complexType','struct','all','',
    array(
        'status' => array('name' => 'head', 'type' => 'tns:status_mssg'),
        'group_items' => array('name' => 'message', 'type' => 'tns:groupItems')
    )
);
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++</pre>
<p>In this one, we set the next level complex type to &#8220;groupItems&#8221;. In this type, we will split it into two parts. One will be for the string portions of the result, the other into the next level complex type. Add the following to the showGroupItems types code block. </p>
<pre>$server->wsdl->addComplexType(
	'all_food','complexType','struct','all','',
	array(
		'food' => array('name' => 'food', 'type' => 'xsd:string', 'minOccurs' => "0"),
		'drink' => array('name' => 'drink', 'type' => 'xsd:string', 'minOccurs' => "0"),
		'treat' => array('name' => 'treat', 'type' => 'xsd:string', 'minOccurs' => "0"),
	)
);

$server->wsdl->addComplexType(
	'groupItems','complexType','struct','all','',
	array(
		'food' => array('name' => 'food', 'type' => 'tns:all_food'),
		'equip' => array('name' => 'equip', 'type' => 'xsd:string', 'minOccurs' => "0"),
		'transport' => array('name' => 'transport', 'type' => 'xsd:string', 'minOccurs' => "0"),
		'people' => array('name' => 'people', 'type' => 'xsd:string', 'minOccurs' => "0"),
	)
);</pre>
<p>This definition splits the returned result. The first element item in the array is defined by a separate complex type &#8220;all_food&#8221;. The rest are regular strings. We can update all of these to be arrays as well, and that is something to try on your own. The &#8220;minOccurs&#8221; definition tells the webservice that the item is optional and may not appear. Which is ok if it does not, then the service will ignore the empty space and go on. In our data list, the last item, &#8220;shopping&#8221; does not have a &#8216;people&#8217; element. So by defining the minOccurs as 0, it will not be required to print out. Now add the following to the client:</p>
<pre>$try4 = $proxy->showGroupItems('Picnic');
$try5 = $proxy->showGroupItems('Shopping');</pre>
<p>And print those out you should receive something similar to the following:</p>
<pre>showGroupItems
"Picnic"
Array
(
    [status] =>
    [group_items] => Array
        (
            [food] => Array
                (
                    [food] => sandwiches
                    [drink] => sports drinks
                    [treat] => granola bars
                )

            [equip] => basket, blanket
            [transport] => van
            [people] => Mom, Dad, brothers, sisters, cousins
        )
)
"Shopping"
Array
(
    [status] =>
    [group_items] => Array
        (
            [food] => Array
                (
                    [food] => grapes
                    [drink] => juice box
                    [treat] => candybar
                )

            [equip] => cart, list
            [transport] => moving van
        )
)</pre>
<p>Now we are completed with this function, now on to the last two. These are pretty simple. I will give you the functions, and the registration for this one, and the complexTypes definitions should be easy by now, so I will skip posting this one.  Since this one is a mad lib, there is nothing to add in, we can just insert the input elements into the string. </p>
<pre>function showMadLib($adj1, $adj2, $adj3, $adj4, $adverb1, $adverb2, $noun1, $noun2, $noun3, $verb1, $verb_past1, $verb_past2 ){
	// Put all validation code here
	if ( ($adj1 == '')||($noun1 == '')||($verb_past1 == '')||($adverb1 == '')||($adj2 == '')||($noun2 == '')||
			($noun3 == '')||($adj3 == '')||($verb1 == '')||($adverb2 == '')||($verb_past2 == '')||($adj4 == '') ){
		return error("partial");
	}

	// example submission:
	// "disagreeable","dilapidated","evanescent","ubiquitous","obediently","painfully","monkey","spaceship","boogey man","answer","photographed", "knitted"

	$mad_lib = "Today I went to the zoo. I saw a $adj1 $noun1 jumping up and down in its tree. He $verb_past1 $adverb1 through the " .
			"large tunnel that led to its $adj2 $noun2. I got some peanuts and passed them through the cage to a gigantic gray $noun3 " .
			"towering above my head. Feeding that animal made me hungry. I went to get a $adj3 scoop of ice cream. It filled my stomach." .
			"Afterwards I had to $verb1 $adverb2 to catch our bus. When I got home I $verb_past2 my mom for a $adj4 day at the zoo.";

	$fin_data['status'] = array('status'=>'ok','message'=>'');
	$fin_data['mad_lib'] = $mad_lib;

	return $fin_data;
}</pre>
<p>The function is in place, and as you can see, it takes a lot of different input. It returns only a string as the final message, so when you build the complexType, remember that. Here is the registration:</p>
<pre>// ================================================
// === showMadLib register
$in = array(
	'adj1' => 'xsd:string',
	'adj2' => 'xsd:string',
	'adj3' => 'xsd:string',
	'adj4' => 'xsd:string',
	'adverb1' => 'xsd:string',
	'adverb2' => 'xsd:string',
	'noun1' => 'xsd:string',
	'noun2' => 'xsd:string',
	'noun3' => 'xsd:string',
	'verb1' => 'xsd:string',
	'verb_past1' => 'xsd:string',
	'verb_past2' => 'xsd:string',
);
$out = array('return' => 'tns:showMadLib');
$namespace = 'uri:hirdwebservice';
$soapaction = 'uri:hirdwebservice/showMadLib';
$doc = 'Returns a mad lib based on the data it is sent. Need 4 Adjectives, 2 Adverbs, 3 Nouns, 1 Verb, and 2 Verb: Past Tense. It replies with a string that contains the madlib. ';
$server->register('showMadLib', $in, $out, $namespace, $soapaction, 'rpc', 'encoded', $doc);
// ================================================</pre>
<p>Now after you build the complexType add the following to the client:</p>
<pre>$try6 = $proxy->showMadLib("disagreeable","dilapidated","evanescent","ubiquitous","obediently","painfully","monkey","spaceship","boogey man","answer","photographed", "knitted");
$try7 = $proxy->showMadLib("hello","","","","","","",""," ","","", "");</pre>
<p>And now you can test the function. </p>
<p>Lastly, we need to do a service that returns an array of data (numbers for this example) that has no associative type array. Add this to the &#8220;items.php&#8221; file:</p>
<pre>$various = array (
	array(
		array('number' => "01"),
		array('number' => "02"),
		array('number' => "03"),
		array('number' => "04"),
		array('number' => "05"),
		array('number' => "06"),
		array('number' => "07"),
		array('number' => "08"),
		array('number' => "09"),
	),
	array(
		array('number' => "121654898"),
		array('number' => "11151"),
		array('number' => "18852"),
		array('number' => "1114885111111"),
		array('number' => "11111111111111111111"),
	),
	array(
		array('number' => "2654846354684654"),
	),
	array(
		array('number' => "303030303030303030"),
		array('number' => "32323232323232323232323232"),
	),
	array(
		array('number' => "44444444"),
		array('number' => "41414141"),
		array('number' => "42424242"),
		array('number' => "43434343"),
		array('number' => "40404040"),
	),
	array(
		array('number' => "5"),
		array('number' => "10"),
		array('number' => "15"),
		array('number' => "20"),
		array('number' => "25"),
	),
);</pre>
<p>As you can see, it is just a regular array with numbers and nothing else. Based on the number they send to the service, it will return the string of numbers. After planning, build out the function. </p>
<pre>function showNumbers($id){
	require("items.php");

	// place all validation code here
	if ( ($id < 0) || ($id > 5)  ){
		// return an error
		return error("custom", "numbers", "You need to enter an ID that is 0, 1, 2, 3, 4, or 5.");
	}

	$numbers = $various[$id];

	$fin_data['head'] = array('status'=>'ok','message'=>'');
	$fin_data['numbers'] = $numbers;

	return $fin_data;
}</pre>
<p>We only want numbers from 0 to 5, so if there is anything else, then return an error. Now we need to register the function. </p>
<pre>// ================================================
// === showNumbers register
$in = array(
	'id' => 'xsd:string',
);
$out = array('return' => 'tns:showNumbers');
$namespace = 'uri:hirdwebservice';
$soapaction = 'uri:hirdwebservice/showNumbers';
$doc = 'Returns an array of numbers in a non-assoc array key format';
$server->register('showNumbers', $in, $out, $namespace, $soapaction, 'rpc', 'encoded', $doc);
// ================================================</pre>
<p>This is basically the same, we need an ID, and we will return a formatted complexType named &#8220;showNumbers&#8221;. But now we need to actually format those. Since we are using a non associative array for the return, we need to format a new type. This is still a complexType, but it is not a struct, but an &#8220;array&#8221;. Start with the base complexType to build off of, then add the array type which references a regular struct complexType. This is done as follows:</p>
<pre>// showNumbers types ++++++++++++++++++++++++++++++++++++++++++
$server->wsdl->addComplexType(
	'number','complexType','struct','all','',
	array(
		'number' => array('name' => 'number', 'type' => 'xsd:string'),
	)
);

<strong>$server->wsdl->addComplexType(
	'numbers','complexType','array','',
	'SOAP-ENC:Array',
	array(),
	array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'tns:number[]')), 'tns:number'
);</strong>

$server->wsdl->addComplexType('showNumbers','complexType','struct','all','',
    array(
        'status' => array('name' => 'head', 'type' => 'tns:status_mssg'),
        'numbers' => array('name' => 'message', 'type' => 'tns:numbers')
    )
);
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++</pre>
<p>The new array type will have different items we need to declare. The first being is that it is an array not a struct, we do not want all, so will do &#8220;&#8221; instead of passing &#8220;all&#8221;. Next, we need to tell the class that we want a SOAP-ENC:Array. Since we are not defining a struct, the normal position where we would put our return data is now a blank array. Finally we need to build the array type, reference in the SOAP-ENC:arrayType. Add the wsdl def to it, then make sure you add the square brackets to the named array. Now build the regular struct we already know. Add the following to the client to test the service:</p>
<pre>$try8 = $proxy->showNumbers(2);
$try9 = $proxy->showNumbers(5);</pre>
<p>And you should get something similar to:
<pre>showNumbers
"2"
Array
(
    [status] =>
    [numbers] => Array
        (
            [0] => Array
                (
                    [number] => 2654846354684654
                )
        )
)
"5"
Array
(
    [status] =>
    [numbers] => Array
        (
            [0] => Array
                (
                    [number] => 5
                )
            [1] => Array
                (
                    [number] => 10
                )
            [2] => Array
                (
                    [number] => 15
                )
            [3] => Array
                (
                    [number] => 20
                )
            [4] => Array
                (
                    [number] => 25
                )
        )
)</pre>
<p>and that will complete the server side of this. These are very simplistic examples, but can be used to build on for more applicable items. For example, You may have a database full of authors and the books they wrote, along with prices, ISBN numbers, publishers, and excerpts from the book. By using a combo of the previous examples, you can create a service that allows others to query the DB based on author, that will return each book, publisher, price with tax for the state they are requesting along with an excerpt of each book. </p>
<p>The server for this post is located at <a href='http://www.hirdweb.com/webservice/20100720_server.php' target="_top">http://www.hirdweb.com/webservice/20100720_server.php</a><br />
The client for this post is located at <a href='http://www.hirdweb.com/webservice/20100720.php' target='_top'>http://www.hirdweb.com/webservice/20100720.php</a></p>
<p>Code for this post is located at:<br />
server: <a href='http://www.hirdweb.com/webservice/20100720_server.txt' target='_top'>http://www.hirdweb.com/webservice/20100720_server.txt</a><br />
client: <a href='http://www.hirdweb.com/webservice/20100720.txt' target='_top'>http://www.hirdweb.com/webservice/20100720.txt</a><br />
items: <a href='http://www.hirdweb.com/webservice/items.txt' target='_top'>http://www.hirdweb.com/webservice/items.txt</a></p>
<p>Next we will test these in ASP.NET and figure out how to really use these. </p>

<!-- Wordpress Connect Modules v1.05 -->]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2010/07/20/finishing-up-the-nusoap-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Building on the NuSOAP Server</title>
		<link>http://www.hirdweb.com/2010/07/10/building-on-the-nusoap-server/</link>
		<comments>http://www.hirdweb.com/2010/07/10/building-on-the-nusoap-server/#comments</comments>
		<pubDate>Sun, 11 Jul 2010 03:37:25 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[NuSOAP]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[webservices]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=257</guid>
		<description><![CDATA[The NuSOAP server consists of a function that will take an ID and a name/phrase and inserts that into the Shakespeare quote. The function returns a semi-complex type which consists of 2 array elements, a status message and the phrase. However, the webservice needs to expand, add a new function, and make error messages dynamic. [...]]]></description>
			<content:encoded><![CDATA[<p>The NuSOAP server consists of a function that will take an ID and a name/phrase and inserts that into the Shakespeare quote. The function returns a semi-complex type which consists of 2 array elements, a status message and the phrase. However, the webservice needs to expand, add a new function, and make error messages dynamic. So the first thing we will tackle is getting the status message into a more dynamic format. </p>
<p>First, plan it out, always plan it out. The status message will need to accept an &#8220;error code&#8221;, a string for the struct name, and a variable for a custom message if it does fit in within the specified error codes. Now, just as a disclaimer here, this is just an example of how it can be planned. Some services may not need this extent, some may need a lot more. Remember that it needs to be able to handle the requirements of your application. </p>
<p>With that planned out, here is a possible solution to the function. </p>
<pre>
function error($err, $struct = 'phrase', $message = ''){
	$error['status']['status']='error';
	$error[$struct]= '';
	switch ($err) {
		case "empty":
			$error['status']['message']='There was nothing passed to the webservice, so nothing can be returned.';
			break;
		case "partial":
			$error['status']['message']="Not all required parameters were passed, so the webservice can not return any information.";
			break;
		case "not_found":
			$error['status']['message']='The parameter you passed was not found, please try again.';
			break;
		case "bounds":
			$error['status']['message']='The ID that was passed is out of the allowable boundaires. Please try your request again.';
			break;
		case "less_than_zero":
			$error['status']['message']='The number recieved is less than zero, and will not work with this service. Please double check the number and try again.';
			break;
		case 'custom':
			$error['status']['message'] = $message;
			break;
		default:
			$error['status']['message'] = 'There was a problem with your request, please try again.';
			break;
	}
	return $error;
}
</pre>
<p><span id="more-257"></span><br />
In this example, I have created the basic array structure for the error, and defined a few different error codes. I am using strings for my codes, but it is possible to use integers. I am doing this mainly for readability. Each error has a specific message, and may be generic on all functions, and the best thing, this can be expanded if needed. The parameters for this function include the error code variable, setting the struct variable to use the showPhrases &#8220;phrase&#8221; structure, and setting message to null. </p>
<p>The codes are:<br />
empty &#8211; used when parameters are not passed to the service<br />
partial &#8211; when only some of the parameters are passed<br />
not_found &#8211; the identifier was not matched to anything on the server side<br />
bounds &#8211; the ID is outside of allowable number ranges<br />
less_than_zero &#8211; the number is a negative number and can not be used<br />
custom &#8211; self defined error with self defined message<br />
default &#8211; when any of the codes do not match up, return a generic error message</p>
<p>After unit testing this function, and make sure the function does behave the way we need it to behave, we need to alter the function for showPhrases to allow this error functionality. The code we did before can be located at:<br />
<a href='http://www.hirdweb.com/webservice/20100707_server.txt' target='_top'>http://www.hirdweb.com/webservice/20100707_server.txt</a></p>
<p>We are going to modify the function for showPhrases now. Here is a possible alteration using the new error function. I added a couple more validation points as an example. </p>
<pre>
function showPhrases($id, $name){
	// Set up the phrases
	$phrases = array(
		'O NnnnnnnnnN, NnnnnnnnnN! wherefore art thou NnnnnnnnnN?',
		'But NnnnnnnnnN, If you prick us, do we not bleed? if you tickle us, do we not laugh? if you poison us, do we not die? and if you wrong us, shall we not revenge?',
		'Will all great NnnnnnnnnN\'s ocean wash this blood clean from my hand? No, this my hand will rather the multitudinous seas incarnadine, making the green one red',
		'Love looks not with the eyes, but with the mind, NnnnnnnnnN, and therefore is winged Cupid painted blind',
		'Men at some time are masters of their fates: The fault, dear NnnnnnnnnN, is not in our stars, but in ourselves, that we are underlings',
	);

	// check for empty parameters
	if ( ($name == '') || (!isset($name)) ) {
		return error("partial");
	}

	if ( $id == 100 ) {
		return error("not_found");
	}

	// place all validation code here
	if ( ($id < 0) || ($id > 4)  ){
		return error('bounds');
	}

	// Check the name for swear words
	if ( strtolower($name) == 'ass'){
		return error('custom', '', 'Please do not use drunken sailor language when using the webservice.');
	}	

	// replace all the needles with the name
	$phrase = preg_replace("/NnnnnnnnnN/", $name, $phrases[$id]);
	$fin_data['status'] = array('status'=>'ok','message'=>'');
	$fin_data['phrase'] = $phrase;

	return $fin_data;
}
</pre>
<p>In this function we have the phrases we will use, and then we start to do some validation. This is pretty basic and could probably be retooled to work a little better, but we are checking for the following:<br />
empty parameters<br />
id = 100 (to trigger a not found error for the example)<br />
number range boundary violations<br />
derogatory words (this one only including &#8220;ass&#8221;)</p>
<p>After it passes the checks, it does the normal process of building the response message structure. Only this time, we also need to change the status structure to:</p>
<pre>$fin_data['status'] = array('status'=>'ok','message'=>'');</pre>
<p>Before we can use this, though, we need to change the complexType structures in the $server object. </p>
<pre>
// Status Message Array ++++++++++++++++++++++++++++++++++++++++++
$server->wsdl->addComplexType('status_mssg','complexType','struct','all','',
    array(
    	'status' => array('name' => 'status', 'type' => 'xsd:string'),
    	'message' => array('name' => 'message', 'type' => 'xsd:string')
    )
);

// showPhrases types ++++++++++++++++++++++++++++++++++++++++++
$server->wsdl->addComplexType('showPhrases','complexType','struct','all','',
    array(
        'status' => array('name' => 'head', 'type' => 'tns:status_mssg'),
        'phrase' => array('name' => 'message', 'type' => 'xsd:string')
    )
);
</pre>
<p>We change the &#8216;status&#8217; element in the showPhrases type from an xsd:string to a tns:struct-name, in this case, tns:status_mssg. The TNS name is important, because that tells the struct where to get the complex type definition. We added a new complex type. In this one, we defined two elements. Now when the response is given, it provides a multidimensional array. An example of the returned response with an error:</p>
<pre>
Array
(
    [status] => Array
        (
            [status] => error
            [message] => Not all required parameters were passed, so the webservice can not return any information.
        )

    [phrase] =>
)
</pre>
<p>You do not have to structure the status message this way, and you can keep it as a string, that is up to you. Or you can make it have even more elements, for example: the status, the message, the code to report it, url for documentation on the error, and company contact information. But by doing this, we have run through a basic complex type. If the response needs to have a multidimensional array, we know how to do this. Remember, as a good practice habit, the bottom of the WSDL is the basic, and build more complex types on top. </p>
<p>Now we can start on the taxes portion. I promise I will be less long winded on this one. </p>
<p>A function that will take a price (float type) and then calculate the tax and return it back with the original amount, tax amount and total amount with state name. I created a file, named items.php, that contains the arrays for the values of the taxes and the phrases. Here are the items for the taxes:</p>
<pre>
$tax_rates = array(
	'az'	=> '0.056',
	'al'	=> '0.04',
	'ak'	=> '0.05',
	'ca'	=> '0.0875',
	'or'	=> '0.00',
	'wa'	=> '0.065',
	'ut'	=> '0.047',
	'id'	=> '0.06',
	'wy'	=> '0.04',
);

$states = array(
	'az'	=> 'Arizona',
	'al'	=> 'Alabam',
	'ak'	=> 'Alaska',
	'ca'	=> 'California',
	'or'	=> 'Oregon',
	'wa'	=> 'Washington',
	'ut'	=> 'Utah',
	'id'	=> 'Idaho',
	'wy'	=> 'Wyoming',
);</pre>
<p>Next we need to create the function. I am setting the default state to CA, so that if an empty string is passed, it will be set to CA automatically. Since we have already seen the error functionality in action, we can do this for brevity. I want to make sure the string is all lowercase, the price is greater than 0, and make sure that the state sent is in our array. So the following solution should be acceptable. </p>
<pre>
function showTaxes($price, $state = "ca"){
	require('items.php');

	// Make sure the state is lowercase
	$state = strtolower($state);

	// Check the array keys to validate
	$validate = array_keys($tax_rates);

	// place all validation code here
	if ( strlen($state) > 2 ){
		return error('custom', '', 'The state that was passed is not in the correct format. It should only be 2 characters');
	}

	if ( !in_array($state, $validate) ){
		// return an error
		return error("not_found");
	}

	if ( $price < 0 ){
		return error('less_than_zero');
	}

	if ( $price == '' ){
		return error('empty');
	}

	$tax = $tax_rates[$state] * $price;
	$final_price = $tax + $price;

	// set the array
	$final = array(
		'price' => $price,
		'tax'	=> money_format('%i',$tax),
		'total' => money_format('%i',$final_price),
		'state' => $states[$state],
	);

	$fin_data['status'] = array('status'=>'ok','message'=>'');
	$fin_data['taxes'] = $final;

	return  $fin_data;
}
</pre>
<p>The function validates the input, returns errors as needed. Again, I am sure there are more ways to validate, and more things to validate. If it passes all the validation, then it starts the final array formatting. In this array, there are four elements:<br />
price<br />
tax<br />
total<br />
state</p>
<p>So we need to create the same type of structure in our $server object.<br />
First build the variables to register the function:</p>
<pre>
$in = array(
	'price' => 'xsd:string',
	'state' => 'xsd:string',
);
$out = array('return' => 'tns:showTaxes');
$namespace = 'uri:hirdwebservice';
$soapaction = 'uri:hirdwebservice/showTaxes';
$doc = 'Shows the taxes based on state taxes. Currently, the only states available in this are: AZ,AL,AK, CA, OR, WA, UT, ID, WY, Defaults to CA if no state is provided.';
$server->register('showTaxes', $in, $out, $namespace, $soapaction, 'rpc', 'encoded', $doc);
</pre>
<p>Now we need to build the structures. This will require 3 structures: the base complex type that splits the status and response, and the status structure, and the response structure. Since we already have the status structure in place, we need to worry about the response structure. </p>
<pre>
$server->wsdl->addComplexType(<strong>'taxes'</strong>,'complexType','struct','all','',
	array(
		'price' => array('name' => 'price', 'type' => 'xsd:float', 'minOccurs' => "0"),
		'tax' => array('name' => 'tax', 'type' => 'xsd:float', 'minOccurs' => "0"),
		'total' => array('name' => 'total', 'type' => 'xsd:float', 'minOccurs' => "0"),
		'state' => array('name' => 'state', 'type' => 'xsd:string', 'minOccurs' => "0"),
	)
);

$server->wsdl->addComplexType('showTaxes','complexType','struct','all','',
    array(
        'status' => array('name' => 'head', 'type' => 'tns:status_mssg'),
        'taxes' => array('name' => 'message', 'type' => <strong>'tns:taxes'</strong>)
    )
);</pre>
<p>The base structure defines the status structure and sets the type the <em>tns:status_mssg</em>. The response sets the name to &#8220;taxes&#8221; and the type to <em>tns:taxes</em>. Now the name of the TNS structure can be whatever you really want to call it, but it must be the same as the complex type that is defined. For example, you can not call a complex type of &#8220;type1forme&#8221; and have the actual complex type added as &#8216;type_for_me&#8217;. I made this bold in the example above so you can see the connection between the two. The <em>taxes</em> structure has four elements, just like the function returns. When the response is given, it will show up as:</p>
<pre>
Array
(
    [status] => Array
        (
            [status] => ok
            [message] =>
        )

    [taxes] => Array
        (
            [price] => 12.18
            [tax] => 0.68
            [total] => 12.86
            [state] => Arizona
        )

)</pre>
<p>I created a test client for this entry, and this is located at:<br />
<a href='http://www.hirdweb.com/webservice/20100710.php' target='_top'>http://www.hirdweb.com/webservice/20100710.php</a></p>
<p>It shows the response for the examples with showPhrases (1 good call, 1 error), and showTaxes (2 good calls, 2 errors). </p>
<p>The next post will include the rest of the functions, with one of them adding a third level of complexity to the response, and completing the server. </p>
<p>The code for the server portion of this post: <a href='http://www.hirdweb.com/webservice/20100710_server.txt' target='_top'>http://www.hirdweb.com/webservice/20100710_server.txt</a></p>
<p>The code for the client side of this post: <a href='http://www.hirdweb.com/webservice/20100710.txt' target='_top'>http://www.hirdweb.com/webservice/20100710.txt</a></p>

<!-- Wordpress Connect Modules v1.05 -->]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2010/07/10/building-on-the-nusoap-server/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Simple NuSOAP Server</title>
		<link>http://www.hirdweb.com/2010/07/07/simple-nusoap-server/</link>
		<comments>http://www.hirdweb.com/2010/07/07/simple-nusoap-server/#comments</comments>
		<pubDate>Wed, 07 Jul 2010 16:00:25 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[NuSOAP]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[webservices]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=238</guid>
		<description><![CDATA[In the previous post, we examined the client side of NuSOAP. In this post, we examine a very simplistic approach to building a server. In this example, it is going to use a very basic set up, and will return only a string. No complex data will be returned, and it will be a quick [...]]]></description>
			<content:encoded><![CDATA[<p>In the previous post, we examined the client side of NuSOAP. In this post, we examine a very simplistic approach to building a server. In this example, it is going to use a very basic set up, and will return only a string. No complex data will be returned, and it will be a quick look at how to create a NuSOAP server. The more complex approaches will come later. </p>
<p>Using the previous information in the post, we have a client that we can text the service on. Before I complete the webservice server, I always do some quick testing of the functionality before sending it to the web service. In this example, we will use one of the services built previously:<br />
<strong>showPhrases</strong> – Phrases from Shakespeare plays that replace the names in the phrase with the passed in name/string</p>
<p>This webservice requires 2 items to be passed:<br />
id &#8211; A number from 0 to 4 (In this example I only used 5 phrases)<br />
name &#8211; A name or variable that can be used to replace the names in the phrases</p>
<p>The first thing we should always do, is map out the plan for this function.<br />
<span id="more-238"></span><br />
This webservice will take the ID and the name, and then return the phrase that has been ID&#8217;d, with the personalization of the name. So the first thing we need is the phrases, then we need to set up a function to do this. </p>
<p>So with the phrases, I took 5 different Shakespeare phrases, and removed the names, and put in a placeholder value that is uniform throughout the phrases. These phrases are listed below:</p>
<pre>
$phrases = array(
	'O NnnnnnnnnN, NnnnnnnnnN! wherefore art thou NnnnnnnnnN?',
	'But NnnnnnnnnN, If you prick us, do we not bleed? if you tickle us, do we not laugh? if you poison us, do we not die? and if you wrong us, shall we not revenge?',
	'Will all great NnnnnnnnnN\'s ocean wash this blood clean from my hand? No, this my hand will rather the multitudinous seas incarnadine, making the green one red',
	'Love looks not with the eyes, but with the mind, NnnnnnnnnN, and therefore is winged Cupid painted blind',
	'Men at some time are masters of their fates: The fault, dear NnnnnnnnnN, is not in our stars, but in ourselves, that we are underlings',
);
</pre>
<p>Next we need to create the function for this. Since this series of posts are about the webservices and not general PHP security, logic, or structure, we will quickly pass over this.<br />
1. We want to make sure that the ID is between 0 and 4.<br />
2. We want to replace all the placeholder values with the passed in name<br />
3. We want to format the response to the client that lets them know it is either a success or failure</p>
<p>So with this function, it could look something like this:</p>
<pre>function showPhrases($id, $name){
	// Set up the phrases
	$phrases = array(
		'O NnnnnnnnnN, NnnnnnnnnN! wherefore art thou NnnnnnnnnN?',
		'But NnnnnnnnnN, If you prick us, do we not bleed? if you tickle us, do we not laugh? if you poison us, do we not die? and if you wrong us, shall we not revenge?',
		'Will all great NnnnnnnnnN\'s ocean wash this blood clean from my hand? No, this my hand will rather the multitudinous seas incarnadine, making the green one red',
		'Love looks not with the eyes, but with the mind, NnnnnnnnnN, and therefore is winged Cupid painted blind',
		'Men at some time are masters of their fates: The fault, dear NnnnnnnnnN, is not in our stars, but in ourselves, that we are underlings',
	);

	// place all validation code here
	if ( ($id < 0) || ($id > 4)  ){
		// return an error
		$fin_data['status'] = "Error!";
		$fin_data['phrase'] = "The ID was outside of the allowed range.";
		return $fin_data;
	}

	// replace all the needles with the name
	$phrase = preg_replace("/NnnnnnnnnN/", $name, $phrases[$id]);

	$fin_data['status'] = "Success!";
	$fin_data['phrase'] = $phrase;

	return $fin_data;
}</pre>
<p>We can do a quick test to make sure this works:</p>
<pre>
// Good call
$test1 = showPhrases(0, "HEY YOU GUYS!");
// Will return an error
$test2 = showPhrases(30, "Alexander the Great");

echo "&lt;pre&gt;";
print_r($test1);
print_r($test2);
echo "&lt;/pre&gt;";
</pre>
<p>OK, we know the function works. In the real world, you would want to sanitize the string a little better and make sure there is no other attempts to grab data, or compromise your application. Now we can start to build the actual server. </p>
<p>We need to set up some basic stuff in the server, namely, we need to include the libraries, set the WSDL to the proper address, and  register the new function. I have set this WSDL server at the following location:<br />
<a href='http://www.hirdweb.com/webservice/20100707_server.php' title='http://www.hirdweb.com/webservice/20100707_server.php'>http://www.hirdweb.com/webservice/20100707_server.php</a></p>
<pre>
$server = new soap_server();
// Create the WSDL
$wsdl_addr = 'http://www.hirdweb.com/webservice/20100707_server.php';
// Set the name that will be displayed in the WSDL, and the namespace
$server->configureWSDL('HirdWeb Basic Webservice Example','HirdWeb Basic Webservice Example', $wsdl_addr);
</pre>
<p>One of the most important things to remember when creating WSDLs, either manually (or using Zend Studio&#8217;s tool), or by using a library such as NuSOAP, is that you need to start from the bottom and work your way up. The bottom of the WSDL will always be the most base, and working up it will get more complex. </p>
<p>In this example, we are using a pseudo-complex/simplistic structure. The service is returning an array, but a non-complex array that does not need much, other than strings. So we need to register the function with the server first, then move to the more complex items. </p>
<p>First, I like to set variables for registration, this way I know what needs to go where, and what it needs to call. It is basically in this vein:<br />
register(<br />
 &nbsp; &nbsp; Function Name / Name of service provided<br />
 &nbsp; &nbsp; What needs to be passed in<br />
 &nbsp; &nbsp; What is going to be passed back<br />
 &nbsp; &nbsp; Namespace<br />
 &nbsp; &nbsp; SOAP Action to do this<br />
 &nbsp; &nbsp; RPC<br />
 &nbsp; &nbsp; Encoded / Encoding<br />
 &nbsp; &nbsp; Documentation on this service function<br />
)<br />
Translating that to code, and I have this:</p>
<pre>
// Set up all the items to register the function
$in = array(
	'id' => 'xsd:string',
	'name' => 'xsd:string',
);
$out = array('return' => 'tns:showPhrases');
$namespace = 'uri:hirdwebservice';
$soapaction = 'uri:hirdwebservice/showPhrases';
$doc = 'Shows a phrase from Shakespeare and replaces the name with the supplied name. ID is a number from 0 - 4';

$server->register('showPhrases', $in, $out, $namespace, $soapaction, 'rpc', 'encoded', $doc);
</pre>
<p>Now close the service and exit so only the service is exposed. </p>
<pre>
$server->service($HTTP_RAW_POST_DATA);
exit;
</pre>
<p>But, we are not completed. If you notice the <i>$out</i> variable, it is setting the returned values as an array set to<br />
<strong>tns:showPhrases</strong></p>
<p>Which means we have our first complex type. If we want to just return a phrase, then we could have just left it at<br />
<strong>xsd:string</strong><br />
However, I have found that by doing that, it can leave an opening in understanding what is being returned. Has the service worked, it returned a phrase, so it must be correct, right? Maybe, not sure. I always find it a good practice to make sure you tell the clients whether or not the call was successful. It just cuts down on the possibility of returning bad data. </p>
<p>We now have to create a type that can be returned. The naming convention should mirror that of the function. In the function, we have two named array elements:<br />
status<br />
phrase</p>
<p>We need to create a complex type that defines these elements. Using the $server object, we can add a complex type, defined as &#8220;showPhrases&#8221;. This function is called in the WSDL class:<br />
$server->wsdl->addComplexType();<br />
The parameters for this function are (taken straight from the code):<br />
* @param string	$name<br />
* @param string $typeClass (complexType|simpleType|attribute)<br />
* @param string $phpType currently supported are <em>array</em> and <em>struct</em> (php assoc array)<br />
* @param string $compositor (all|sequence|choice)<br />
* @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)<br />
* @param array $elements e.g. array ( name => array(name=>&#8221;,type=>&#8221;) )<br />
* @param array $attrs e.g. array(array(&#8216;ref&#8217;=>&#8217;SOAP-ENC:arrayType&#8217;,'wsdl:arrayType&#8217;=>&#8217;xsd:string[]&#8216;))<br />
* @param string $arrayType as namespace:name (xsd:string)<br />
* @see nusoap_xmlschema<br />
* @access public</p>
<p>For our complex type, we need to use the name, complexType, struct, all, &#8221; (or default), our array setup<br />
We will use the defaults for any items after our array. </p>
<pre>$server->wsdl->addComplexType('showPhrases','complexType','struct','all','',
    array(
        'status' => array('name' => 'status', 'type' => 'xsd:string'),
        'phrase' => array('name' => 'message', 'type' => 'xsd:string')
    )
);</pre>
<p>So the entire service looks like this:</p>
<pre>// Instantiate the server
$server = new soap_server();
// Create the WSDL
$wsdl_addr = 'http://www.hirdweb.com/webservice/20100707_server.php';
$server->configureWSDL('HirdWeb Basic Webservice Example','HirdWeb Basic Webservice Example', $wsdl_addr);
$server->wsdl->addComplexType('showPhrases','complexType','struct','all','',
    array(
        'status' => array('name' => 'status', 'type' => 'xsd:string'),
        'phrase' => array('name' => 'message', 'type' => 'xsd:string')
    )
);
// Set up all the items to register the function
$in = array(
	'id' => 'xsd:string',
	'name' => 'xsd:string',
);
$out = array('return' => 'tns:showPhrases');
$namespace = 'uri:hirdwebservice';
$soapaction = 'uri:hirdwebservice/showPhrases';
$doc = 'Shows a phrase from Shakespeare and replaces the name with the supplied name. ID is a number from 0 - 4';
$server->register('showPhrases', $in, $out, $namespace, $soapaction, 'rpc', 'encoded', $doc);
$server->service($HTTP_RAW_POST_DATA);
exit; </pre>
<p>And now the webservice server is ready to be tested using the client, which we created a sample previously.<br />
Make sure that you update the WSDL to point to the server we created today.<br />
The entire file for the server, and the function can be found at<br />
<a href='http://www.hirdweb.com/webservice/20100707_server.txt'>http://www.hirdweb.com/webservice/20100707_server.txt</a></p>
<p>I created a test page that will show the results of the call:<br />
<a href='http://www.hirdweb.com/webservice/20100707.php'>http://www.hirdweb.com/webservice/20100707.php</a><br />
The client makes 6 calls to the server, 0-5. It returns 5 good results, and 1 error. </p>
<p>Next we will examine two services provided by a webservice service. We will have the one we created today, and add a more complex type, the showTaxes service (which we saw briefly in the client example), and expand the status message with a little more information and provide a dynamic ability for error messages. </p>

<!-- Wordpress Connect Modules v1.05 -->]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2010/07/07/simple-nusoap-server/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Web Services with NuSOAP</title>
		<link>http://www.hirdweb.com/2010/07/02/web-services-with-nusoap/</link>
		<comments>http://www.hirdweb.com/2010/07/02/web-services-with-nusoap/#comments</comments>
		<pubDate>Fri, 02 Jul 2010 14:31:19 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[NuSOAP]]></category>
		<category><![CDATA[webservices]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=220</guid>
		<description><![CDATA[Doing a lot with webservices lately. Which is really a great thing if there is a central repository of information that needs to be disseminated between different external systems. I am doing a lot with NuSOAP and php SOAP. But this tutorial is going to be about the NuSOAP libraries. You can get these libraries [...]]]></description>
			<content:encoded><![CDATA[<p>Doing a lot with webservices lately. Which is really a great thing if there is a central repository of information that needs to be disseminated between different external systems. I am doing a lot with NuSOAP and php SOAP. But this tutorial is going to be about the NuSOAP libraries. You can get these libraries from:<br />
<a title="http://sourceforge.net/projects/nusoap/" href="http://sourceforge.net/projects/nusoap/" target="_blank">http://sourceforge.net/projects/nusoap/</a></p>
<p>First thing to do is to download this, and install into a directory that you can access. For different security reasons, it may be needed to keep these libraries outside of the accessible web directories.</p>
<p>The next step is to determine what needs to be required to get the data. This may include authentication and credentials, id&#8217;s, phrases, or anything else. It could be possible to not have anything required and just return all records. And that is the next step: determine what to expose. What type of information would you want to send back to the world? Hopefully it is not sensitive data, and only the data that needs to be exposed.</p>
<p>Now with that in mind, we are ready to go. I have set up a webservice server that has five different functions:</p>
<p><strong>showPhrases</strong> &#8211; Phrases from Shakespeare plays that replace the names in the phrase with the passed in name/string<br />
<strong>showTaxes</strong> &#8211; Calculates the tax based on the passed in price and state<br />
<strong>showGroupItems</strong> &#8211; Shows what is needed based on a set event, all items are made up of course<br />
<strong>showMadLib</strong> &#8211; Returns a mad lib based on passing in a number of different items<br />
<strong>showNumbers</strong> &#8211; Returns a non associative array of numbers, requires an ID, and returns the numbers associated with that ID</p>
<p>Each of these functions provides a little more to view based on the webservice. The first and fourth functions will return a string of data. The second function returns an array with different data types. The third returns a complex type of a multidimensional array. I did this because there are many different tutorials out there using NuSOAP, but only seem to return a basic type and has very little to help when setting up the WSDL when it needs to be more complex. The fifth function demonstrates how to return a non associative array with the webservice in a complex type.</p>
<p>I will break down each function per post. But now we need a way that we can test these functions when we get them going. So the first thing to do is create a NuSOAP client to grab the exposed data. For the client, we will use the showTaxes example that has been created.</p>
<p><span id="more-220"></span></p>
<p>Remember, the first thing we need to do, is determine what we are going to do with code. Never just start putting down code without a plan. Always have a plan, and include requirements for the code in the plan. Our plan for the client will be as follows:</p>
<ol>
<li>Require the NuSOAP libraries</li>
<li>Identify the WSDL we are to use</li>
<li>Create the client with UTF-8 enabled</li>
<li>Create a proxy</li>
<li>Call the webservice server</li>
<li>Grab the results</li>
<li>Print them to the screen</li>
</ol>
<p>This is a very basic and generic plan. When you use webservices, it is highly unlikely that you will ever just print/dump the returned data to the screen. Whatever is needed by the application for the returned data needs to be included in the plan.</p>
<p>So the first part, we need to create a client file wherever this will reside, so create a client.php or whatever you want to name the file. Then we need to include the NuSOAP libraries:</p>
<pre>
&lt;?php
ini_set('display_errors',1);

require_once('nusoap/nusoap.php');
</pre>
<p>In the snippet above, I have turned on errors right now so that I can see exactly what may be going wrong. In the real world, you really do not want to do this to expose the errors. They should always be handled gracefully. </p>
<p>We next want to define the WSDL. The WSDL for the examples I have created is located at: http://www.hirdweb.com/webservice/index.php?wsdl. </p>
<pre>
// Set the WSDL location
$wsdl='http://www.hirdweb.com/webservice/index.php?wsdl';
</pre>
<p>Next, we want to create the client, set the UTF-8 parameters, and do a little error trapping to make sure the client is good. </p>
<pre>
$client = new nusoap_client($wsdl, 'wsdl');
$client->decode_utf8 = false;
$client->xml_encoding = 'UTF-8';

$err = $client->getError();
if ($err) {
    echo '&lt;h2&gt;Error Found While Connecting&lt;/h2&gt;&lt;pre&gt;' . $err . '&lt;/pre&gt;\n';
}
</pre>
<p>This will create the client, using the WSDL (I put the WSDL in a variable for readability, but you can pass the WSDL right in the instantiation call). We are not going to decode UTF-8, but we are going to encode any XML in UTF-8. The error handler looks to see if there is an error in establishing the client. If there is one found, then it will dump that to the screen. Again, for the live world, a better error handler is needed. </p>
<p>Next, we set up a proxy to call the function we want, which is showTaxes. A little about this function, in case you want to explore more before the next post: This function calculates the taxes based on 9 different states in the US. They are: AZ, AL, AK, CA, OR, WA, UT, ID, WY. Any other state passed in will result in an error being spit back by the service. This webservice function needs two parameters passed to it: The price and the state. The price should be a float value, and we will get into the server more later to write in validation code to make sure it is a float. The following code would create the proxy and then make the call. (I put in a couple different examples so you can see the difference and the errors)</p>
<pre>
$proxy = $client->getProxy();

$returned_data_ca = $proxy->showTaxes("199.99", "CA");
$returned_data_or = $proxy->showTaxes("199.99", "OR");
// This will return an error
$returned_data_ny = $proxy->showTaxes("199.99", "NY");
</pre>
<p>This will make the call to the service three times for different states, and then store the returned data in the variables. Now to print them to the screen and close the file:</p>
<pre>
echo "&lt;br /&gt;&lt;hr /&gt;&lt;h1&gt;showTaxes CA Results&lt;/h1&gt;";
echo '&lt;pre&gt;';
print_r($returned_data_ca);
echo '&lt;/pre&gt;';

echo "&lt;br /&gt;&lt;hr /&gt;&lt;h1&gt;showTaxes OR Results&lt;/h1&gt;";
echo '&lt;pre&gt;';
print_r($returned_data_or);
echo '&lt;/pre&gt;';

echo "&lt;br /&gt;&lt;hr /&gt;&lt;h1&gt;showTaxes NY Results&lt;/h1&gt;";
echo '&lt;pre&gt;';
print_r($returned_data_ny);
echo '&lt;/pre&gt;';
?>
</pre>
<p>And just like that, you have a webservice client that you can now use as we get into the server. </p>
<p>The result has been put up at the following location:<a href='http://www.hirdweb.com/webservice/20100702.php' target='_blank'>http://www.hirdweb.com/webservice/20100702.php</a>.</p>
<p>Next, we will look at the creation of the NuSOAP server. </p>

<!-- Wordpress Connect Modules v1.05 -->]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2010/07/02/web-services-with-nusoap/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Back in the Swing of Things</title>
		<link>http://www.hirdweb.com/2010/06/21/back-in-the-swing-of-things/</link>
		<comments>http://www.hirdweb.com/2010/06/21/back-in-the-swing-of-things/#comments</comments>
		<pubDate>Mon, 21 Jun 2010 15:58:13 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Everything Else]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=206</guid>
		<description><![CDATA[For the past year or so, I have been tremendously busy and unable to keep up with the blog. However, now more free time is available to me. So starting next week, I will be posting more about PHP frameworks, including Cake and Symfony, security issues I see come up, and different ideas about databases, [...]]]></description>
			<content:encoded><![CDATA[<p>For the past year or so, I have been tremendously busy and unable to keep up with the blog. However, now more free time is available to me. So starting next week, I will be posting more about PHP frameworks, including Cake and Symfony, security issues I see come up, and different ideas about databases, searches and other items. I will also be posting more about C# and ASP items. As I get through more development for the Apple platform, I will also post those as well. Hopefully this will be a good resource for others, as I use this to post when I learn something, so that I can go back and find what I used in order to keep things going.<br />
And if there is anything that needs to be discussed, please let me know. We can always start up a discussion on anything.</p>

<!-- Wordpress Connect Modules v1.05 -->]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2010/06/21/back-in-the-swing-of-things/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Good Resources &#8211; PHP Advent 2009</title>
		<link>http://www.hirdweb.com/2009/12/07/good-resources-php-advent-2009/</link>
		<comments>http://www.hirdweb.com/2009/12/07/good-resources-php-advent-2009/#comments</comments>
		<pubDate>Mon, 07 Dec 2009 17:06:36 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Everything Else]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=203</guid>
		<description><![CDATA[The PHP Advent Calendar 2009 is going on, and it is a tremendous resource for the community. http://phpadvent.org/2009 I highly suggest subscribing to the feed, and/or following on Twitter. It is a great read every day.]]></description>
			<content:encoded><![CDATA[<p>The PHP Advent Calendar 2009 is going on, and it is a tremendous resource for the community. </p>
<p>http://phpadvent.org/2009</p>
<p>I highly suggest subscribing to the feed, and/or following on Twitter. It is a great read every day. </p>

<!-- Wordpress Connect Modules v1.05 -->]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2009/12/07/good-resources-php-advent-2009/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>GBP and Euro Symbols in Excel</title>
		<link>http://www.hirdweb.com/2009/10/20/gbp-and-euro-symbols-in-excel/</link>
		<comments>http://www.hirdweb.com/2009/10/20/gbp-and-euro-symbols-in-excel/#comments</comments>
		<pubDate>Tue, 20 Oct 2009 15:47:56 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[PEAR]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=201</guid>
		<description><![CDATA[Have you used the Spreadsheet_Excel_Writer PEAR package to output data to a spreadsheet? In this data that is being exported, have you needed to format the data? What about numbers, and then formatting further to a currency format. The currency formats for this data: one for Great British Pounds (£) and one for the Euro [...]]]></description>
			<content:encoded><![CDATA[<p>Have you used the Spreadsheet_Excel_Writer PEAR package to output data to a spreadsheet? In this data that is being exported, have you needed to format the data? What about numbers, and then formatting further to a currency format. The currency formats for this data: one for Great British Pounds (£) and one for the Euro (€). The formatting needs to happen with those symbols. So here is the journey . . .</p>
<p>Since this post is not about the querying of the data, that is not going to be covered, but rather just the issues with formatting the currency symbols for Euro and GBP in the Writer. And since this is not about the Spreadsheet writer ins and outs, if you would like to know more about that, please see <a title="Spreadsheet_Excel_Writer" href="http://pear.php.net/package/Spreadsheet_Excel_Writer/docs" target="_blank">Package Information: Spreadsheet_Excel_Writer</a><br />
<span id="more-201"></span><br />
First off, include the PEAR library:</p>
<pre>require_once('Spreadsheet/Excel/Writer.php');</pre>
<p>Set up the Writer, and set the formats up.</p>
<pre>$workbook = new Spreadsheet_Excel_Writer($this-&gt;fileSrc);
$worksheet =&amp; $workbook-&gt;addWorksheet('Data Info');
// Set the formats for text
$formatText =&amp; $workbook-&gt;addFormat(array('Size' =&gt; 30));
// Set the formats for two numeric values for currency
$formatUKCurr =&amp; $workbook-&gt;addFormat(array('Size' =&gt; 12));
$formatEUROCurr =&amp; $workbook-&gt;addFormat(array('Size' =&gt; 12));
// now we need to format the numbers
$formatUKCurr-&gt;setNumFormat('#,##0.00');
$formatEUROCurr-&gt;setNumFormat('#,##0.00');
/**
All other writer code would go here.
**/</pre>
<p>This sets up the spreadsheet library object, added a couple of formats, and then extended it. With the numeric formats, we extended it so that the number will show up in that decimal format. What this means, is that if a number, for example 50, is retrieved from the database, then it will show up in the spreadsheet as 50.00. However, we need to put in the currency symbol in that format.</p>
<p>So, one would think that it would be easy enough, because all we would need to do is:</p>
<pre>$formatUKCurr-&gt;setNumFormat('£#,##0.00');
$formatEUROCurr-&gt;setNumFormat('€#,##0.00');</pre>
<p>Right?<br />
Wrong. Let&#8217;s say the GBP amount is 50, and the Euro amount is 23.5. When the spreadsheet is opened in Excel, what happens to that formatting is the following:<br />
GBP: Â£ 50.00<br />
Euro: â‚¬ 23.50</p>
<p>Yikes, there is an extra character before the pound symbol, and the Euro symbol has been warped.<br />
1. PHP, at least not until version 6, does not support UTF-8 natively. So this means that the character set that defines these symbols is incapable of being displayed properly in the current encode that PHP understands. Thus the extra characters<br />
2. To get more detailed info on why this character encoding is a problem, see <a title="Fun with UTF-8, PHP and MySQL" href="http://www.byteflex.co.uk/en/fun_with_utf8_php_and_mysql.html" target="_blank">Fun with UTF-8, PHP and MySQL</a>. This explains a good deal about UTF-8, ASCII, and ISO 8859-1.</p>
<p>So the first thing I tried was to force the headers to use UTF-8. That was a no go.</p>
<p>The next thing was to use the <a title="iconv encoding" href="http://us3.php.net/manual/en/book.iconv.php" target="_blank">ICONV</a>.</p>
<pre>$pound = iconv("ISO-8859-1", "UTF-8", "£");
$formatUKCurr-&gt;setNumFormat($pound . '#,##0.00');</pre>
<p>That was a no go as well.</p>
<p>I changed the font family of the destination cell. That also did not work.</p>
<p>So I took a walk to the kitchen to clear my head. I was clearly on the wrong track. I may as well try to put everything into an array, explode it, then implode it, then echo it, then die(). So I got back from the kitchen getting some water.</p>
<p>The thought came to me to try using the chr() function. It could not hurt. So I looked at the <a title=" PHP chr()" href="http://us3.php.net/manual/en/function.chr.php" target="_blank">PHP manual for chr()</a> to get the <a title="ASCII Table" href="http://www.asciitable.com/" target="_blank">ASCII code list</a>. The code for the pound symbol according to that site, is 156, so</p>
<pre>$formatUKCurr-&gt;setNumFormat( chr(156) . '#,##0.00' );</pre>
<p>Well, good news and bad news. First good news, no more additional characters. Bad news, the output for the GBP was :<br />
œ 50.00</p>
<p>OK, close, very close. Now I went hunting for the correct code. It is 163, so</p>
<pre>$formatUKCurr-&gt;setNumFormat( chr(163) . '#,##0.00' );</pre>
<p>After a couple of searches for the Euro symbol, as it is a newer symbol and not in the regular lists, I found it could be 128. So I tested it out</p>
<pre>$formatUKCurr-&gt;setNumFormat( chr(163) . '#,##0.00' );
$formatEUROCurr-&gt;setNumFormat(  chr(128) . '#,##0.00');</pre>
<p>And the output:<br />
£ 50.00<br />
€ 23.50</p>
<p>SUCCESS!</p>
<p>So, if you are struggling with this, using the Spreadsheet_Excel_Writer formatting to get the currency symbols for the GBP  and the Euro, that is the fix that I have found.</p>

<!-- Wordpress Connect Modules v1.05 -->]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2009/10/20/gbp-and-euro-symbols-in-excel/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>PEAR and CakePHP</title>
		<link>http://www.hirdweb.com/2009/05/04/pear-and-cakephp/</link>
		<comments>http://www.hirdweb.com/2009/05/04/pear-and-cakephp/#comments</comments>
		<pubDate>Tue, 05 May 2009 02:23:41 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[cakePHP]]></category>
		<category><![CDATA[PEAR]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=185</guid>
		<description><![CDATA[This post is about my experience with loading in PEAR to a CakePHP 1.2.x application. This may be the right way or the wrong way, but I got it to work throughout the application. I had to do some changes, and if there is a better way of doing this, please let me know. First [...]]]></description>
			<content:encoded><![CDATA[<p>This post is about my experience with loading in PEAR to a CakePHP 1.2.x application. This may be the right way or the wrong way, but I got it to work throughout the application. I had to do some changes, and if there is a better way of doing this, please let me know. </p>
<p>First off, here is the issue. I needed to be able to export a group of records from the database to an excel spreadsheet. I have tried to use the <a href="http://bakery.cakephp.org/articles/view/excel-xls-helper" target="_blank">Excel Spreadsheet add in that is listed on the Bakery</a>. It works nice, and I had to do some modification for 1.2, but it worked. But not the way I wanted it. I have used the PEAR library Spreadsheet_Excel_Writer before and I like the type of control that I wanted, over the cells, the formatting, the merging, etc etc etc. It provides the type of control that I wanted. So here is what I did to get this to work with the CakePHP framework. </p>
<p>First, I have to download the PEAR library and the Spreadsheet_Excel_Writer libraries to use. Since I use a local system to help develop, I could download these libraries to the local system and transport these over to the CakePHP application. So I went to PEAR site to get the libraries. To download these I ran the following commands:</p>
<pre>
pear install PEAR-1.8.1
pear install OLE-1.0.0RC1
pear install Spreadsheet_Excel_Writer-0.9.1
</pre>
<p>URL&#8217;s are listed below:</p>
<p>http://pear.php.net/package/PEAR/download</p>
<p>http://pear.php.net/package/Spreadsheet_Excel_Writer/download</p>
<p>http://pear.php.net/package/OLE/download</p>
<p><span id="more-185"></span><br />
These downloaded the to local drives and I copied them over to the CakePHP area. Here is where it gets a little tricky. And I thank &#8220;brian&#8221; who helped me on the <a href="http://groups.google.com/group/cake-php">Cake Google group</a> to get past this when I got into a problem. So here we go, diving in to this. </p>
<p>First off, the PEAR libraries need to be put in the vendors directory. If you look at the directory structure for Cake, it appears like this:<br />
/app<br />
/cake<br />
/vendors</p>
<p>Inside of the /app directory, there is another vendors directory. This is where I put the PEAR libraries. This causes problems, because in the /cake/config/paths.php file, there is a path defined for VENDORS, and for PEAR:</p>
<pre>
if (!defined('VENDORS')) {
	define('VENDORS', CAKE_CORE_INCLUDE_PATH.DS.'vendors'.DS);
}

define('PEAR', VENDORS.'Pear'.DS);
</pre>
<p>Now, I have put the PEAR libraries in the top level vendor directory. If you choose to put it in the app/vendors directory, then you may need to change a core file, which is not advisable, because you would need to change the path above to</p>
<pre>
if (!defined('VENDORS')) {
	define('VENDORS', CAKE_CORE_INCLUDE_PATH.DS.'app/vendors'.DS);
}
</pre>
<p>So back to the PEAR libraries. Here is what I needed to do. I moved the PEAR directories to the /vendors directory. So here is what that directory looks like:</p>
<pre>
/vendors
    /css
    /js
   /Pear   <--- Look at this, case sensitive based on those paths above
        /OLE
        /OS
        /PEAR
        /scripts
        /Spreadsheet
        INSTALL
        LICENSE
        OLE.php
        package.dtd
        PEAR.php
        PEAR5.php
        README
        System.php
        template.spec
    /shells
</pre>
<p>This is part of the PEAR install we need to do. Now we need to update the paths in some of these files so that CakePHP can find them and include them. </p>
<p>**** ORIGINAL ENTRY THAT HAS BEEN EDITED/DEPRECATED ********************<br />
**** EDIT: Based on the original post this is the method I originally used. This way works, but requires a<br />
**** little too much overhead and editing the files in the PEAR libraries which is never really a good idea<br />
**** and should only be used sparingly. To see the way that it should be done, please see below this<br />
**** section.<br />
****<br />
**** In the file /vendors/Pear/Spreadsheet/Excel/Writer.php there is 2 requires<br />
**** require_once 'PEAR.php';<br />
**** require_once 'Spreadsheet/Excel/Writer/Workbook.php';<br />
****<br />
**** In order for the Cake App to see these, at least in my set up, I needed to change these to the<br />
**** following:<br />
**** require_once 'PEAR.php';<br />
**** require_once PEAR . 'Spreadsheet/Excel/Writer/Workbook.php';<br />
****<br />
**** I needed to add "PEAR . " to the require_once call. Now I needed to add this to the following files:<br />
**** /vendors/Pear/Spreadsheet/Excel/Writer.php<br />
**** require_once 'PEAR.php';<br />
**** require_once PEAR . 'Spreadsheet/Excel/Writer/Workbook.php';<br />
****<br />
**** /vendors/Pear/Spreadsheet/Excel/Writer/Workbook.php<br />
**** require_once PEAR . 'Spreadsheet/Excel/Writer/Format.php';<br />
**** require_once PEAR . 'Spreadsheet/Excel/Writer/BIFFwriter.php';<br />
**** require_once PEAR . 'Spreadsheet/Excel/Writer/Worksheet.php';<br />
**** require_once PEAR . 'Spreadsheet/Excel/Writer/Parser.php';<br />
**** require_once PEAR . 'OLE/PPS/Root.php';<br />
**** require_once PEAR . 'OLE/PPS/File.php';<br />
****<br />
**** /vendors/Pear/OLE/PPS.php<br />
**** require_once 'PEAR.php';<br />
**** require_once PEAR . 'OLE.php';<br />
****<br />
**** This had helped the application find my PEAR libraries when trying to do this<br />
**** END ORIGINAL ENTRY ***********************************************</p>
<p><strong><em>Now, a word about the edit. The above method works, but is not a preferred method. The best method for this, so there is no need to edit PEAR library files is the following. And a big thanks to <a href="http://cakebaker.42dh.com/">Daniel Hofstetter</a> for pointing this out. </em></strong></p>
<p>I put this at the top of my controller file. I am sure there is better places for this, probably even the app_controller file so that all controllers get the needed include path set. Here is what I did. </p>
<p>I needed to append the include path so that the new PEAR path would be found. After the php opening, I added this line:</p>
<pre>
ini_set("include_path", PEAR . PATH_SEPARATOR . ini_get("include_path"));
</pre>
<p>I am going to go over this just a little. First off, the ini_set is called to set the include_path. But we do not want to destroy any other include paths that are set up as well. So when we add the PEAR path, we need to also include the other paths as well. So the initial include_path was as follows (given in example form only, where the directory "test" is where I have CakePHP installed)<br />
ini_get("include_path") = </p>
<pre>
/www/htdocs/html/test:/www/htdocs/html/test/app/:.:/usr/local/php5/lib/php
</pre>
<p>Since CakePHP already defines the variable for the PEAR path as "PEAR", we can use that to add to the include path, like shown above. After setting the path using ini_set(), we run ini_get("include_path") it would = </p>
<pre>
/www/htdocs/html/test/vendors/Pear/:/www/htdocs/html/test:/www/htdocs/html/test/app/:.:/usr/local/php5/lib/php
</pre>
<p>By doing it this way, there is no need to edit the PEAR library files, and we can add new PEAR libraries without having to worry about editing those files as well. </p>
<p>Now, I needed to make the controller aware of the vendor library. In my controller file I added this line before the class declaration:</p>
<pre>
App::import('vendor', 'Spreadsheet_Excel_Writer', array('file' => '../vendors/Pear/Spreadsheet/Excel/Writer.php'));
</pre>
<p>In Cake 1.2, this is how the vendor's are imported. The vendor() declaration has been deprecated. This imports a vendor, gives the class a name (I choose the base one that it is usually called), and the location of the of the file. In my set up, I needed to add the "../", you may not have to. </p>
<p>In the function, (I called "export"), I did not want to have a "view" page for it. The first thing I did was grab the information I needed. For this example, I needed all users that signed up for a conference. So I grabbed that information and put it in an array $registrations. </p>
<pre>
function export ($id = null){
       // I only want to get a specific conference, not all of them
	if ( $id == 'all' ){
		$this->Session->setFlash('Please select a specific conference to export the registrations.');
		$this->redirect(array('action' => 'index'));
	}

	// Now get the registrations for the conference
	$registrations = $this->Registration->find('all',
		array(
			'conditions' => array('conference_id' => $id),
			'fields' => array('*'),
			'recursive' => '-1',
			'order' => array('Registration.created'),
		)
	);
</pre>
<p>Now comes the fun part, building the column heading array, and then instantiating the writer</p>
<pre>
	// Set up the header array
	$titles = array(
		'Name' => 15,
		'Address' => 20,
		'City' => 20,
		'State' => 7,
		'Zip Code' => 10,
		'Email' => 20,
		'Phone' => 13,
	);

	$rn = 0; // row number
	// Build the XLS file using PEAR
	$xlsBook = new Spreadsheet_Excel_Writer();
	$xlsBook->send("registrations.xls");
	$xls =&#038; $xlsBook->addWorksheet('Registrations');
</pre>
<p>Everything else is now just as the same as it would be with the Spreadsheet-Excel_writer. Create the formats as you would like, for text, numerics, specialized strings, colors, etc. Write the sheet headings, if you so desire</p>
<pre>
	/* Create styles for the spreadsheet */
	$format_bold =&#038; $xlsBook->addFormat();
	$format_bold->setBold();

	$main =&#038; $xlsBook->addFormat(
		array('Size' => 14,
			'Align' => 'center',
			'Color' => 'black',
			'Bold' => 'true'
		));
	$main->setBold();

	$formatText =&#038; $xlsBook->addFormat(array('Size' => 11));

	$cn = 0;
	$xls->write($rn, 0, "CONFERENCE REGISTRATIONS", $main);
	$xls->mergeCells($rn,0,$rn,11);
	$rn++;
</pre>
<p>As you can see, just use the writer calls to write the data, format it, and do what you need. To get more information on this, please <a href="http://pear.php.net/package/Spreadsheet_Excel_Writer/docs">check the PEAR documentation for this library</a>. </p>
<p>Finish up the column headings by doing a quick little loop</p>
<pre>
	// Set up the headings of the columns
	foreach ( $titles as $t => $val){
		$xls->setColumn($cn, $cn, $val);
		$xls->write($rn, $cn++, $t, $format_bold);
	}
	$rn++;
	// reset the column num
	$cn = 0;
</pre>
<p>Now you can do the actual rows in a loop:</p>
<pre>
	foreach ( $registrations as $r ){
		$xls->write($rn, $cn++, $r['Registration']['name'], $formatText);
	    $xls->write($rn, $cn++, $r['Registration']['address'], $formatText);
	    $xls->write($rn, $cn++, $r['Registration']['city'], $formatText);
	    $xls->write($rn, $cn++, $r['Registration']['state'], $formatText);
	    $xls->write($rn, $cn++, $r['Registration']['zip_code'], $formatText);
	    $xls->write($rn, $cn++, $r['Registration']['email'], $formatText);
	    $xls->write($rn, $cn++, $r['Registration']['contact_phone1'], $formatText);
	    // cycle to the next row
	    $rn++;
	    // Reset the column
	    $cn = 0;
	}

	$xlsBook->close();
	exit();
} // end of function
</pre>
<p>Now, this does the work for me on my code. To call it in the view, I have a page that shows all registrations on the page, the function name is "registrations". I set a variable in this function for the ID number to be passed to the view. In the view for this function, I have put the following:</p>
<pre>
if ( $param != 'all') {
	echo "&lt;p&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; - - &lt;b&gt;";
	echo $html->link(__('EXPORT DATA', true), array('action' => 'export', $param) );
	echo "&lt;/b&gt; - - &lt;br /&gt;&lt;br /&gt;&lt;/p&gt;";
}
</pre>
<p>So I want a specific conference. If there is not one, and they are viewing all registrations for all conferences, then it does not show the link. But if it is a specific id, then it shows the link to export with the corresponding parameter for the ID. </p>
<p>And there it is. Using the Spreadsheet_Excel_Writer PEAR library with CakePHP 1.2. </p>
<p>Again, this works for me, and there may be a better way of doing things, and if so, please feel free to tell me. I am always looking for new things to learn. </p>

<!-- Wordpress Connect Modules v1.05 -->]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2009/05/04/pear-and-cakephp/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
	</channel>
</rss>
