Friday, June 5, 2009

Making Webservices with NuSoap

Php can make an excellent webservice. NuSoap is an excellent library to provide standards compilant web services to your audience.

It took me some time to find out recent versions of PHP (5.2+) do not populate
the $HTTP_RAW_POST_DATA properly.So in this case the server part will use
file_get_contents('php://input') to get its data.

Here is a working example.
Server Part:

date_default_timezone_set('Europe/Amsterdam');
require_once('nusoap/lib/nusoap.php');
$server = new soap_server;

function hello($name, $role)
{
return "Hi ".$name." you are a ".$role;
}

$server->register('hello', // method name
array('name' => 'xsd:string', 'role' => 'xsd:string'),
array('return' => 'xsd:string'),
'uri:helloapp',
'uri:helloapp/hello',
'rpc',
'encoded');

$server->service(file_get_contents('php://input'));


Client Part:

date_default_timezone_set('Europe/Amsterdam');
require_once('nusoap/lib/nusoap.php');

$objClient = new soapclient('http://work/soap/server.php');
echo $objClient->call('hello', array('name' => 'John','role' => 'programmer'));

Find out absolute path of PHP script, cross platform 100% reliable

Ever had the problem wanting to include a php file 1 from within php file 2 regardless where php file 2 is included from?

$strPath = substr(__FILE__,0,strrpos(__FILE__,DIRECTORY_SEPARATOR)).DIRECTORY_SEPARATOR;

Wednesday, June 3, 2009

Using Arrays in PHP constants

Sooner or later you wil run into the following construction:

define('MY_ARRAY', array(1 => 'foo', 2 => 'bar', 3 => 'baz');

PHP will not allow this construction.

Warning: Constants may only evaluate to scalar values

This can be anoying. The solution: a static constants class

How to use this solution?
1- Include the file staticconstants.php (see below)
2- Define a constant (no need to instanciate since the class is static)

Constants::AddStructure('MY_ARRAY','id','value');'
Constants::Define(1,'foo');
Constants::Define(2,'bar');
Constants::Define(3,'baz');

3- Acces the constant array

$arrMyArray = Constants::Get('MY_ARRAY');
print_r($arrMyArray);

this will return: Array ( [1] => foo [2] => bar [3] => baz )

4- Or access a single member

$strMyString = Constants::Get('MY_ARRAY',1);
print_r($strMyString);

this will return: foo

It is also possible to store any other kind of php variable like multi dimensional array's and objects etc.Example with more fields;

Constants::AddStructure('MY_CARS',array('id','brand','color'));
Constants::Define(1,'toyota','red');
Constants::Define(2,'buick','green');
Constants::Define(3,'honda','yellow');
print_r(Constants::Get('MY_CARS'));

this will return:
Array
(
[1] => Array
(
[brand] => toyota
[color] => red
)
[2] => Array
(
[brand] => buick
[color] => green
)
[3] => Array
(
[brand] => honda
[color] => yellow
)
)

This class will never replace a relational database system. But for small code-related data structures this solution is excellent. Alternatively one could use global variables, but this has unique naming issues and requires scoping commands within functions and class methods (global etc.).

The static class construction provides encapsulation and is accessible from anywhere with just a single command (Constants::Get).

Compacted source code of static constants Class

/** Constants Class,
Copyright Pim Koeman 2009 (c)
License: GPL3
**/
class Constants
{
static $arrContent = array();
static $arrStructure = array();
static $strCurrentStructure = '';

// Set the Section (Array Name) and the PHP constant prefix for this section
static function AddStructure($strName, $arrStructure)
{
// remove the id fieldname
array_shift($arrStructure);
self::$strCurrentStructure = $strName;
self::$arrStructure[$strName] = $arrStructure;
}

/**
* Define a member within the currently selected structure
* Define($strConstantName, $strConstantValue, $varContent1, $varContent2, $varContentN ....)
* First parameter is array index, more parameters are array content
**/
static function Define()
{
$arrArgs = func_get_args();
$strId = array_shift($arrArgs);

// one arg ? do not store array but only own value
if (count($arrArgs) == 1) $arrArgs = $arrArgs[0];

foreach($arrArgs as $strKey => $strValue)
{
self::$arrContent[self::$strCurrentStructure][$strId][self::$arrStructure[self::$strCurrentStructure][$strKey]] = $strValue;
}
}

/**
* Read structure
* Return value depends on the number of parameters, see below
**/
static function Get($strStructure = '', $strIndex = '')
{
if ($strStructure == '')
{
// No parameters : Get all
return self::$arrContent;
}
elseif ($strIndex == '')
{
// Structurename : Get Full Structure
return self::$arrContent[$strStructure];
}
else
{
// Both : Get Single member
return self::$arrContent[$strStructure][$strIndex];
}
}

static function GetObjects($strStructure)
{
$arrOut = array();

foreach(self::$arrContent[$strStructure] as $varKey => $arrValue)
{
$arrOut[$varKey] = new stdClass;
foreach($arrValue as $strMemberKey => $varMemberValue)
{
$arrOut[$varKey]->$strMemberKey = $varMemberValue;
}
}

return $arrOut;
}


/**
* Search the structure by value
* Returns member id (first field in structure definition)
**/
static function Search($strStructure, $strField, $strValue)
{
$varOut = FALSE;

foreach(self::$arrContent[$strStructure] as $varKey => $varValue)
{
if ($varValue[$strField] == $strValue) $varOut = $varKey;
}

return $varOut;
}
}