returnTypes = $returntypes;
parent::setCapabilities();
if ($callbacks)
{
$this->callbacks = $callbacks;
}
parent::setCallbacks();
$this->DekiExtServe($data);
}
//--- class methods ---
/*
* DekiExtServe
* @param bool $data - data from the POST call to the server
*
* @note: this function behaves exactly like the IXR_Server in the IXR_Library
* except it also checks if the return type is xml, if it is, it handles the
* xml so that it can be read by DekiScript
*/
function DekiExtServe($data = false)
{
//error checking: is this call made by a GET or POST?
//This piece of the code is the same as the IXR_Library code
if (!$data)
{
global $HTTP_RAW_POST_DATA;
if (!$HTTP_RAW_POST_DATA)
{
die('XML-RPC server accepts POST requests only.');
}
$data = $HTTP_RAW_POST_DATA;
}
$this->message = new IXR_Message($data);
if (!$this->message->parse())
{
$this->error(-32700, 'parse error. not well formed');
}
if ($this->message->messageType != 'methodCall')
{
$this->error(-32600, 'server error. invalid xml-rpc. not conforming to spec. Request must be a methodCall');
}
//make a callback call to the function with the input parameters
$result = $this->call($this->message->methodName, $this->message->params);
// Is the result an error?
if (is_a($result, 'IXR_Error'))
{
$this->error($result);
exit;
}
//if the result type is supposed to be in xml, just return without
//encoding or wrapping it in XML-RPC standard method response tags
//(NOTE: this is additional we added so that the IXR_Server could also handle
//xml return types since xml return types are not part of XML-RPC)
if($this->returnTypes[$this->callbacks[$this->message->methodName]] == 'xml')
{
// Create the XML
$xml = $result;
}
else //if the code is not of xml return type, return it the standard MethodResponse way.
{
// Encode the result
$r = new IXR_Value($result);
$resultxml = $r->getXml();
$xml = "$resultxml";
}
$this->output($xml);
}
}
class DekiExt
{
//--- private static variables ---
private static $functionNames = array(); //your function names
private static $functionArgs = array(); //your function parameter and return information
//the below variables are only needed for GET calls
//title of extension
your title here
private static $title;
//description of extension your description here
private static $description;
//copyright info for extension your copyright info here
private static $copyright;
//help page uri for extension your uri help page
private static $uriLicense;
//help page uri for extension your uri help page
private static $uriHelp;
//help page uri for extension your uri help page
private static $uriLogo;
//namespace for your extension your namespace
private static $namespace;
//namespace for your extension your namespace
private static $label;
//uri link that has your php code appended with the [function name].rpc your uri
private static $uri;
//--- class constructor ---
/*
* DekiExtensionPhp constructor
* @param string $title - title of the extension xml document
* @param array $fileInfo - array with description, copyright, uri.help and namespace mapping
* @param array $args - array with key set to functionName(param1:type, param2,type, ... , ...): return_type
*
* @note return with a call to the IXR_server that will register the user created functions in the .php
* file that calls this object or will return with generated xml content that follows the
* dekiwiki extension format. Either option depends on if the user calls this object through
* a GET or POST HTTP method.
*
*/
public function dekiExtInit($title, $fileInfo, $args)
{
self::$functionNames = array_keys($args);
self::$functionArgs = $args;
if(strcmp($_SERVER['REQUEST_METHOD'], "GET") == 0)
{
if($fileInfo != null)//set the class variables
{
self::$description = $fileInfo['description'];
self::$copyright = $fileInfo['copyright'];
self::$uriHelp = $fileInfo['uri.help'];
self::$namespace = $fileInfo['namespace'];
self::$uriLogo = $fileInfo['uri.logo'];
self::$uriLicense = $fileInfo['uri.license'];
self::$label = $fileInfo['label'];
}
self::$title = $title;
// Bugfix: need to support vhosts that do not have a dedicated IP
self::$uri = 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
//call the internal method generateForGet to handle the above information
$this->generateForGet();
}
else if(strcmp($_SERVER['REQUEST_METHOD'], "POST") == 0)
{
$this->generateForPost();
}
else
{
$xml = "";
$xml = $xml . "\n";
$xml = $xml . "404\n";
$xml = $xml . "Not Found\n";
$xml = $xml . "resource not found\n";
$xml = $xml . "\n";
header('HTTP/1.0 404 Not Found');
$xml = $xml . "\n";
header('Content-type: application/xml'); //make sure the returned content is of type xml, not php
print $xml; //output the xml you just created as a string
}
}
//--- class methods ---
/*
* Handle Post call to DekiExtensionPhp
*
* @note this method parses and extracts information from the array passed in from the constructor.
* Using this information, it makes a call to the IXR_server object that is from IXR_library
* included at the top.
*/
private function generateForPost()
{
//initialize the array that will eventually store the result
$userFunctions = array();
$userReturns = array();
foreach(self::$functionNames as $entry)
{
//let handleMethod parse the function information:
$param;
$ret_type;
$entryResult= $this->handleMethod($entry, false, &$param, &$ret_type);
//if the entry does not exist or
//check if the function name is allowed in php
if( (!preg_match('/^[a-zA-z][a-zA-Z0-9]*$/', self::$functionArgs[$entry])) ||
($entryResult == null) )
{
continue;
}
//match the function information with the .php functions in your file
$userFunctions[$entryResult] = self::$functionArgs[$entry];
$userReturns[self::$functionArgs[$entry]] = $ret_type;
}
//call the IXR_server object to register the functions that are in your .php file.
new DekiExtServer($userReturns, $userFunctions);
}
/*
* Handles Get call to DekiExtensionPhp
*
* @note this method parses the given information by the user and turns it into a Dekiscript extension,
* which is formatted in xml.
*/
private function generateForGet()
{
//initalize the php xml writer
$xml = "";
//error checking for missing values that are required in order to create the correct xml
//extension document
if( (self::$title == null)|| (count(self::$functionNames) == 0) || (count(self::$functionArgs) == 0))
{
$xml = $xml . "\n";
$xml = $xml . "404\n";
$xml = $xml . "Not Found\n";
if(self::$title == null)
{
$xml = $xml . "title not found\n";
}
else if(count(self::$functionArgs) == 0)
{
$xml = $xml . "function array not found\n";
}
else if(count(self::$functionNames) == 0)
{
$xml = $xml . "function array key not found\n";
}
else
{
$xml = $xml . "resource not found\n";
}
$xml = $xml . "\n";
header("HTTP/1.1 404 Not Found");
}
else
{
$xml = $xml . "\n";
$xml = $xml . "" . self::$title . "\n";
//checks the optional tags to see if they exist, if not, then don't include them in the extension
if(self::$description != null)
{
$xml = $xml . "" . self::$description . "\n";
}
if(self::$copyright != null)
{
$xml = $xml . "" . self::$copyright . "\n";
}
if(self::$uriHelp != null)
{
$xml = $xml . "" . self::$uriHelp . "\n";
}
if(self::$uriLicense != null)
{
$xml = $xml . "" . self::$uriLicense . "\n";
}
if(self::$uriLogo != null)
{
$xml = $xml . "" . self::$uriLogo . "\n";
}
if(self::$namespace != null)
{
$xml = $xml . "" . self::$namespace . "\n";
}
if(self::$label != null)
{
$xml = $xml . "\n";
}
//create the tags for each of the function names, their parameters and their return type
foreach(self::$functionNames as $entry)
{
$functionParams = array();
$returnType = 'any'; //default type
//let handleMethod extract the function name, parameters, and return type
$result = $this->handleMethod($entry, false, &$functionParams, &$returnType);
if($result != null)
{
$xml = $xml . "\n";
$xml = $xml . "" . $result . "\n";
$xml = $xml . "" . self::$uri . '/' . $result . '.rpc' . "\n";
//take the returned parameter information [param_name]:[param_type] and parse
//it so that you have a tag with the parameter's name and a type attribute
foreach($functionParams as $paramEntry)
{
$paramParts = split(':', trim($paramEntry));
$xml = $xml . "checkType(trim($paramParts[1])))
{
$xml = $xml . $this->checkType(trim($paramParts[1])) . "\" />\n";
}
else
{
$xml = $xml . "any\" />\n";
}
}
//set the function return type
$xml = $xml . "checkType($returnType))
{
$xml = $xml . $this->checkType($returnType) . "\" />\n";
}
else
{
$xml = $xml . "any\" />\n";
}
$xml = $xml . "\n";
}
}
}
$xml = $xml . "\n";
header('Content-type: application/xml'); //make sure the returned content is of type xml, not php
print $xml;
}
/*
* Handles the array keys
*
* @param string $arg is all of the function information in one string
* @param bool $isPost is a flag to indicate if extra calculation is required in this method
* @param array $returnParam is an array that will contain all of the parameters listed in $arg
* @param string $returnType is the return type of the function, extracted from $arg. This is defaulted
* to the 'any' type.
* @return string is the function name extracted from $arg
*/
private function handleMethod($arg, $isPost, $returnParam, $returnType = 'any')
{
$results = array();
//using regex, separate out the content on both sides of the parenthesis and inside the parenthesis
$results = split('[(.*)]', trim($arg));
//the function name that exists on the left side of the left-parenthesis
$funcName = trim($results[0]);
//if the function that called handleMethod is Get
if(!$isPost)
{
//set the return type information (removes the : before the return type)
if(trim($results[2]) != '')
{
$returnType = trim(preg_replace('[:]', '', $results[2]));
}
//set the parameter information in this '[param_name]:[param_type]' format
if(trim($results[1]) != '')
{
$returnParam = explode(',', trim($results[1]));
}
}
//returns the function Name
return $funcName;
}
/*
* checks types
*
* @param string $typeVal is the type of the parameter or return value
* @return string if $typeVal matches one of the types in the switch statement, returns null if it doesn't
*/
private function checkType($typeVal)
{
$cleanTypeVal = trim(strtolower($typeVal));
//uses a switch to check if the type set for the parameters and the return exist in DekiScript
switch($cleanTypeVal)
{
case 'nil':
break;
case 'bool':
break;
case 'num':
break;
case 'str':
break;
case 'uri':
break;
case 'map':
break;
case 'list':
break;
case 'xml':
break;
default:
return null;
}
return $cleanTypeVal;
}
}
function DekiExt($title, $fileInfo, $funcArray)
{
$extension = new DekiExt();
$extension->dekiExtInit($title, $fileInfo, $funcArray);
}
?>