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); } ?>