From 7254793d2bbe3f2f3d87d97172c54a54deea0a3a Mon Sep 17 00:00:00 2001 From: Fabio Bas Date: Tue, 20 Jan 2015 22:12:46 +0100 Subject: One class per file: framework/Web/Services --- framework/Web/Services/IFeedContentProvider.php | 49 +++ framework/Web/Services/TFeedService.php | 40 +- framework/Web/Services/TJsonResponse.php | 57 +++ framework/Web/Services/TJsonRpcProtocol.php | 180 ++++++++ framework/Web/Services/TJsonService.php | 50 +-- framework/Web/Services/TPageConfiguration.php | 362 ++++++++++++++++ framework/Web/Services/TPageService.php | 355 +-------------- framework/Web/Services/TRpcApiProvider.php | 86 ++++ framework/Web/Services/TRpcException.php | 31 ++ framework/Web/Services/TRpcProtocol.php | 98 +++++ framework/Web/Services/TRpcServer.php | 78 ++++ framework/Web/Services/TRpcService.php | 548 +----------------------- framework/Web/Services/TSoapServer.php | 345 +++++++++++++++ framework/Web/Services/TSoapService.php | 337 +-------------- framework/Web/Services/TXmlRpcProtocol.php | 131 ++++++ 15 files changed, 1423 insertions(+), 1324 deletions(-) create mode 100644 framework/Web/Services/IFeedContentProvider.php create mode 100644 framework/Web/Services/TJsonResponse.php create mode 100644 framework/Web/Services/TJsonRpcProtocol.php create mode 100644 framework/Web/Services/TPageConfiguration.php create mode 100644 framework/Web/Services/TRpcApiProvider.php create mode 100644 framework/Web/Services/TRpcException.php create mode 100644 framework/Web/Services/TRpcProtocol.php create mode 100644 framework/Web/Services/TRpcServer.php create mode 100644 framework/Web/Services/TSoapServer.php create mode 100644 framework/Web/Services/TXmlRpcProtocol.php (limited to 'framework/Web') diff --git a/framework/Web/Services/IFeedContentProvider.php b/framework/Web/Services/IFeedContentProvider.php new file mode 100644 index 00000000..0711330c --- /dev/null +++ b/framework/Web/Services/IFeedContentProvider.php @@ -0,0 +1,49 @@ + + * @author Knut Urdalen + * @link http://www.pradosoft.com + * @copyright Copyright © 2005-2014 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.Services + */ + +/** + * IFeedContentProvider interface. + * + * IFeedContentProvider interface must be implemented by a feed class who + * provides feed content. + * + * @author Qiang Xue + * @author Knut Urdalen + * @package System.Web.Services + * @since 3.1 + */ +interface IFeedContentProvider +{ + /** + * Initializes the feed content provider. + * This method is invoked (before {@link getFeedContent}) + * when the feed provider is requested by a user. + * @param TXmlElement configurations specified within the <feed> element + * corresponding to this feed provider when configuring {@link TFeedService}. + */ + public function init($config); + /** + * @return string feed content in proper XML format + */ + public function getFeedContent(); + /** + * Sets the content type of the feed content to be sent. + * Some examples are: + * RSS 1.0 feed: application/rdf+xml + * RSS 2.0 feed: application/rss+xml or application/xml or text/xml + * ATOM feed: application/atom+xml + * @return string the content type for the feed content. + * @since 3.1.1 + */ + public function getContentType(); +} \ No newline at end of file diff --git a/framework/Web/Services/TFeedService.php b/framework/Web/Services/TFeedService.php index 75775f49..2791c1c4 100644 --- a/framework/Web/Services/TFeedService.php +++ b/framework/Web/Services/TFeedService.php @@ -146,42 +146,4 @@ class TFeedService extends TService else throw new THttpException(404,'feedservice_feed_unknown',$id); } -} - -/** - * IFeedContentProvider interface. - * - * IFeedContentProvider interface must be implemented by a feed class who - * provides feed content. - * - * @author Qiang Xue - * @author Knut Urdalen - * @package System.Web.Services - * @since 3.1 - */ -interface IFeedContentProvider -{ - /** - * Initializes the feed content provider. - * This method is invoked (before {@link getFeedContent}) - * when the feed provider is requested by a user. - * @param TXmlElement configurations specified within the <feed> element - * corresponding to this feed provider when configuring {@link TFeedService}. - */ - public function init($config); - /** - * @return string feed content in proper XML format - */ - public function getFeedContent(); - /** - * Sets the content type of the feed content to be sent. - * Some examples are: - * RSS 1.0 feed: application/rdf+xml - * RSS 2.0 feed: application/rss+xml or application/xml or text/xml - * ATOM feed: application/atom+xml - * @return string the content type for the feed content. - * @since 3.1.1 - */ - public function getContentType(); -} - +} \ No newline at end of file diff --git a/framework/Web/Services/TJsonResponse.php b/framework/Web/Services/TJsonResponse.php new file mode 100644 index 00000000..496229f5 --- /dev/null +++ b/framework/Web/Services/TJsonResponse.php @@ -0,0 +1,57 @@ + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2014 PradoSoft + * @license http://www.pradosoft.com/license/ + * @package System.Web.Services + */ + +/** + * TJsonResponse Class + * + * TJsonResponse is the base class for all JSON response provider classes. + * + * Derived classes must implement {@link getJsonContent()} to return + * an object or literals to be converted to JSON format. The response + * will be empty if the returned content is null. + * + * @author Wei Zhuo + * @package System.Web.Services + * @since 3.1 + */ +abstract class TJsonResponse extends TApplicationComponent +{ + private $_id=''; + + /** + * Initializes the feed. + * @param TXmlElement configurations specified in {@link TJsonService}. + */ + public function init($config) + { + } + + /** + * @return string ID of this response + */ + public function getID() + { + return $this->_id; + } + + /** + * @param string ID of this response + */ + public function setID($value) + { + $this->_id=$value; + } + + /** + * @return object json response content, null to suppress output. + */ + abstract public function getJsonContent(); +} \ No newline at end of file diff --git a/framework/Web/Services/TJsonRpcProtocol.php b/framework/Web/Services/TJsonRpcProtocol.php new file mode 100644 index 00000000..b3196b13 --- /dev/null +++ b/framework/Web/Services/TJsonRpcProtocol.php @@ -0,0 +1,180 @@ + + * @link http://www.pradosoft.com/ + * @copyright 2010 Bigpoint GmbH + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @since 3.2 + * @package System.Web.Services + */ + +/** + * TJsonRpcProtocol class + * + * TJsonRpcProtocol is a class that implements JSON-Rpc protocol in {@link TRpcService}. + * Both version 1.0 and 2.0 of the specification are implemented, and the server will try + * to answer using the same version of the protocol used by the requesting client. + * + * @author Robin J. Rogge + * @author Fabio Bas + * @version $Id$ + * @package System.Web.Services + * @since 3.2 + */ +class TJsonRpcProtocol extends TRpcProtocol +{ + protected $_id=null; + protected $_specificationVersion=1.0; + + /** + * Handles the RPC request + * @param string $requestPayload + * @return string JSON RPC response + */ + public function callMethod($requestPayload) + { + try + { + $_request = $this->decode($requestPayload); + + if(isset($_request['jsonrpc'])) + { + $this->_specificationVersion=$_request['jsonrpc']; + if($this->_specificationVersion > 2.0) + throw new TRpcException('Unsupported specification version', '-32600'); + } + + if(isset($_request['id'])) + $this->_id=$_request['id']; + + if(!isset($_request['method'])) + throw new TRpcException('Missing request method', '-32600'); + + if(!isset($_request['params'])) + $parameters = array(); + else + $parameters = $_request['params']; + + if(!is_array($parameters)) + $parameters = array($parameters); + + // a request without an id is a notification that doesn't need a response + if($this->_id !== null) + { + if($this->_specificationVersion==2.0) + { + return $this->encode(array( + 'jsonrpc' => '2.0', + 'id' => $this->_id, + 'result' => $this->callApiMethod($_request['method'], $parameters), + )); + } else { + return $this->encode(array( + 'id' => $this->_id, + 'result' => $this->callApiMethod($_request['method'], $_request['params']), + 'error' => null + )); + } + } + } + catch(TRpcException $e) + { + return $this->createErrorResponse($e); + } + catch(THttpException $e) + { + throw $e; + } + catch(Exception $e) + { + return $this->createErrorResponse(new TRpcException('An internal error occured', '-32603')); + } + } + + /** + * Turns the given exception into an JSON RPC fault + * @param TRpcException $exception + * @return string JSON RPC fault + */ + public function createErrorResponse(TRpcException $exception) + { + if($this->_specificationVersion==2.0) + { + return $this->encode(array( + 'id' => $this->_id, + 'result' => null, + 'error'=> array( + 'code' => $exception->getCode(), + 'message'=> $exception->getMessage(), + 'data' => null, + ) + )); + } else { + return $this->encode(array( + 'id' => $this->_id, + 'error'=> array( + 'code' => $exception->getCode(), + 'message'=> $exception->getMessage(), + 'data' => null, + ) + )); + } + } + + /** + * Sets the correct response headers + * @param THttpResponse $response + */ + public function createResponseHeaders($response) + { + $response->setContentType('application/json'); + $response->setCharset('UTF-8'); + } + + /** + * Decodes JSON encoded data into PHP data + * @param string $data in JSON format + * @return array PHP data + */ + public function decode($data) + { + $s = json_decode($data, true); + self::checkJsonError(); + return $s; + } + + /** + * Encodes PHP data into JSON data + * @param mixed PHP data + * @return string JSON encoded PHP data + */ + public function encode($data) + { + $s = json_encode($data); + self::checkJsonError(); + return $s; + } + + private static function checkJsonError() + { + $errnum = json_last_error(); + if($errnum != JSON_ERROR_NONE) + throw new Exception("JSON error: $msg", $err); + } + + /** + * Calls the callback handler for the given method + * Overrides parent implementation to correctly handle error codes + * @param string $methodName of the RPC + * @param array $parameters for the callback handler as provided by the client + * @return mixed whatever the callback handler returns + */ + public function callApiMethod($methodName, $parameters) + { + if(!isset($this->rpcMethods[$methodName])) + throw new TRpcException('Method "'.$methodName.'" not found', '-32601'); + + return call_user_func_array($this->rpcMethods[$methodName]['method'], $parameters); + } +} \ No newline at end of file diff --git a/framework/Web/Services/TJsonService.php b/framework/Web/Services/TJsonService.php index e3b9b1cb..08d0ec3d 100644 --- a/framework/Web/Services/TJsonService.php +++ b/framework/Web/Services/TJsonService.php @@ -158,52 +158,4 @@ class TJsonService extends TService $response->write(TJavaScript::jsonEncode($content)); } } -} - -/** - * TJsonResponse Class - * - * TJsonResponse is the base class for all JSON response provider classes. - * - * Derived classes must implement {@link getJsonContent()} to return - * an object or literals to be converted to JSON format. The response - * will be empty if the returned content is null. - * - * @author Wei Zhuo - * @package System.Web.Services - * @since 3.1 - */ -abstract class TJsonResponse extends TApplicationComponent -{ - private $_id=''; - - /** - * Initializes the feed. - * @param TXmlElement configurations specified in {@link TJsonService}. - */ - public function init($config) - { - } - - /** - * @return string ID of this response - */ - public function getID() - { - return $this->_id; - } - - /** - * @param string ID of this response - */ - public function setID($value) - { - $this->_id=$value; - } - - /** - * @return object json response content, null to suppress output. - */ - abstract public function getJsonContent(); -} - +} \ No newline at end of file diff --git a/framework/Web/Services/TPageConfiguration.php b/framework/Web/Services/TPageConfiguration.php new file mode 100644 index 00000000..7f27cdc6 --- /dev/null +++ b/framework/Web/Services/TPageConfiguration.php @@ -0,0 +1,362 @@ + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2014 PradoSoft + * @license http://www.pradosoft.com/license/ + * @package System.Web.Services + */ + + +/** + * TPageConfiguration class + * + * TPageConfiguration represents the configuration for a page. + * The page is specified by a dot-connected path. + * Configurations along this path are merged together to be provided for the page. + * + * @author Qiang Xue + * @package System.Web.Services + * @since 3.0 + */ +class TPageConfiguration extends TComponent +{ + /** + * @var array list of application configurations + */ + private $_appConfigs=array(); + /** + * @var array list of page initial property values + */ + private $_properties=array(); + /** + * @var TAuthorizationRuleCollection list of authorization rules + */ + private $_rules=array(); + /** + * @var array list of included configurations + */ + private $_includes=array(); + /** + * @var string the currently request page in the format of Path.To.PageName + */ + private $_pagePath=''; + + /** + * Constructor. + * @param string the currently request page in the format of Path.To.PageName + */ + public function __construct($pagePath) + { + $this->_pagePath=$pagePath; + } + + /** + * @return array list of external configuration files. Each element is like $filePath=>$condition + */ + public function getExternalConfigurations() + { + return $this->_includes; + } + + /** + * Returns list of page initial property values. + * Each array element represents a single property with the key + * being the property name and the value the initial property value. + * @return array list of page initial property values + */ + public function getProperties() + { + return $this->_properties; + } + + /** + * Returns list of authorization rules. + * The authorization rules are aggregated (bottom-up) from configuration files + * along the path to the specified page. + * @return TAuthorizationRuleCollection collection of authorization rules + */ + public function getRules() + { + return $this->_rules; + } + + /** + * @return array list of application configurations specified along page path + */ + public function getApplicationConfigurations() + { + return $this->_appConfigs; + } + + /** + * Loads configuration for a page specified in a path format. + * @param string root path for pages + */ + public function loadFromFiles($basePath) + { + $paths=explode('.',$this->_pagePath); + $page=array_pop($paths); + $path=$basePath; + $configPagePath=''; + $fileName = Prado::getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP + ? TPageService::CONFIG_FILE_PHP + : TPageService::CONFIG_FILE_XML; + foreach($paths as $p) + { + $this->loadFromFile($path.DIRECTORY_SEPARATOR.$fileName,$configPagePath); + $path.=DIRECTORY_SEPARATOR.$p; + if($configPagePath==='') + $configPagePath=$p; + else + $configPagePath.='.'.$p; + } + $this->loadFromFile($path.DIRECTORY_SEPARATOR.$fileName,$configPagePath); + $this->_rules=new TAuthorizationRuleCollection($this->_rules); + } + + /** + * Loads a specific config file. + * @param string config file name + * @param string the page path that the config file is associated with. The page path doesn't include the page name. + */ + public function loadFromFile($fname,$configPagePath) + { + Prado::trace("Loading page configuration file $fname",'System.Web.Services.TPageService'); + if(empty($fname) || !is_file($fname)) + return; + + if(Prado::getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP) + { + $fcontent = include $fname; + $this->loadFromPhp($fcontent,dirname($fname),$configPagePath); + } + else + { + $dom=new TXmlDocument; + if($dom->loadFromFile($fname)) + $this->loadFromXml($dom,dirname($fname),$configPagePath); + else + throw new TConfigurationException('pageserviceconf_file_invalid',$fname); + } + } + + public function loadFromPhp($config,$configPath,$configPagePath) + { + $this->loadApplicationConfigurationFromPhp($config,$configPath); + $this->loadPageConfigurationFromPhp($config,$configPath,$configPagePath); + } + + /** + * Loads a page configuration. + * The configuration includes information for both application + * and page service. + * @param TXmlElement config xml element + * @param string the directory containing this configuration + * @param string the page path that the config XML is associated with. The page path doesn't include the page name. + */ + public function loadFromXml($dom,$configPath,$configPagePath) + { + $this->loadApplicationConfigurationFromXml($dom,$configPath); + $this->loadPageConfigurationFromXml($dom,$configPath,$configPagePath); + } + + public function loadApplicationConfigurationFromPhp($config,$configPath) + { + $appConfig=new TApplicationConfiguration; + $appConfig->loadFromPhp($config,$configPath); + $this->_appConfigs[]=$appConfig; + } + + /** + * Loads the configuration specific for application part + * @param TXmlElement config xml element + * @param string base path corresponding to this xml element + */ + public function loadApplicationConfigurationFromXml($dom,$configPath) + { + $appConfig=new TApplicationConfiguration; + $appConfig->loadFromXml($dom,$configPath); + $this->_appConfigs[]=$appConfig; + } + + public function loadPageConfigurationFromPhp($config, $configPath, $configPagePath) + { + // authorization + if(isset($config['authorization']) && is_array($config['authorization'])) + { + $rules = array(); + foreach($config['authorization'] as $authorization) + { + $patterns=isset($authorization['pages'])?$authorization['pages']:''; + $ruleApplies=false; + if(empty($patterns) || trim($patterns)==='*') // null or empty string + $ruleApplies=true; + else + { + foreach(explode(',',$patterns) as $pattern) + { + if(($pattern=trim($pattern))!=='') + { + // we know $configPagePath and $this->_pagePath + if($configPagePath!=='') // prepend the pattern with ConfigPagePath + $pattern=$configPagePath.'.'.$pattern; + if(strcasecmp($pattern,$this->_pagePath)===0) + { + $ruleApplies=true; + break; + } + if($pattern[strlen($pattern)-1]==='*') // try wildcard matching + { + if(strncasecmp($this->_pagePath,$pattern,strlen($pattern)-1)===0) + { + $ruleApplies=true; + break; + } + } + } + } + } + if($ruleApplies) + { + $action = isset($authorization['action'])?$authorization['action']:''; + $users = isset($authorization['users'])?$authorization['users']:''; + $roles = isset($authorization['roles'])?$authorization['roles']:''; + $verb = isset($authorization['verb'])?$authorization['verb']:''; + $ips = isset($authorization['ips'])?$authorization['ips']:''; + $rules[]=new TAuthorizationRule($action,$users,$roles,$verb,$ips); + } + } + $this->_rules=array_merge($rules,$this->_rules); + } + // pages + if(isset($config['pages']) && is_array($config['pages'])) + { + if(isset($config['pages']['properties'])) + { + $this->_properties = array_merge($this->_properties, $config['pages']['properties']); + unset($config['pages']['properties']); + } + foreach($config['pages'] as $id => $page) + { + $properties = array(); + if(isset($page['properties'])) + { + $properties=$page['properties']; + unset($page['properties']); + } + $matching=false; + $id=($configPagePath==='')?$id:$configPagePath.'.'.$id; + if(strcasecmp($id,$this->_pagePath)===0) + $matching=true; + else if($id[strlen($id)-1]==='*') // try wildcard matching + $matching=strncasecmp($this->_pagePath,$id,strlen($id)-1)===0; + if($matching) + $this->_properties=array_merge($this->_properties,$properties); + } + } + + // external configurations + if(isset($config['includes']) && is_array($config['includes'])) + { + foreach($config['includes'] as $include) + { + $when = isset($include['when'])?true:false; + if(!isset($include['file'])) + throw new TConfigurationException('pageserviceconf_includefile_required'); + $filePath = $include['file']; + if(isset($this->_includes[$filePath])) + $this->_includes[$filePath]=array($configPagePath,'('.$this->_includes[$filePath][1].') || ('.$when.')'); + else + $this->_includes[$filePath]=array($configPagePath,$when); + } + } + } + + /** + * Loads the configuration specific for page service. + * @param TXmlElement config xml element + * @param string base path corresponding to this xml element + * @param string the page path that the config XML is associated with. The page path doesn't include the page name. + */ + public function loadPageConfigurationFromXml($dom,$configPath,$configPagePath) + { + // authorization + if(($authorizationNode=$dom->getElementByTagName('authorization'))!==null) + { + $rules=array(); + foreach($authorizationNode->getElements() as $node) + { + $patterns=$node->getAttribute('pages'); + $ruleApplies=false; + if(empty($patterns) || trim($patterns)==='*') // null or empty string + $ruleApplies=true; + else + { + foreach(explode(',',$patterns) as $pattern) + { + if(($pattern=trim($pattern))!=='') + { + // we know $configPagePath and $this->_pagePath + if($configPagePath!=='') // prepend the pattern with ConfigPagePath + $pattern=$configPagePath.'.'.$pattern; + if(strcasecmp($pattern,$this->_pagePath)===0) + { + $ruleApplies=true; + break; + } + if($pattern[strlen($pattern)-1]==='*') // try wildcard matching + { + if(strncasecmp($this->_pagePath,$pattern,strlen($pattern)-1)===0) + { + $ruleApplies=true; + break; + } + } + } + } + } + if($ruleApplies) + $rules[]=new TAuthorizationRule($node->getTagName(),$node->getAttribute('users'),$node->getAttribute('roles'),$node->getAttribute('verb'),$node->getAttribute('ips')); + } + $this->_rules=array_merge($rules,$this->_rules); + } + + // pages + if(($pagesNode=$dom->getElementByTagName('pages'))!==null) + { + $this->_properties=array_merge($this->_properties,$pagesNode->getAttributes()->toArray()); + // at the page folder + foreach($pagesNode->getElementsByTagName('page') as $node) + { + $properties=$node->getAttributes(); + $id=$properties->remove('id'); + if(empty($id)) + throw new TConfigurationException('pageserviceconf_page_invalid',$configPath); + $matching=false; + $id=($configPagePath==='')?$id:$configPagePath.'.'.$id; + if(strcasecmp($id,$this->_pagePath)===0) + $matching=true; + else if($id[strlen($id)-1]==='*') // try wildcard matching + $matching=strncasecmp($this->_pagePath,$id,strlen($id)-1)===0; + if($matching) + $this->_properties=array_merge($this->_properties,$properties->toArray()); + } + } + + // external configurations + foreach($dom->getElementsByTagName('include') as $node) + { + if(($when=$node->getAttribute('when'))===null) + $when=true; + if(($filePath=$node->getAttribute('file'))===null) + throw new TConfigurationException('pageserviceconf_includefile_required'); + if(isset($this->_includes[$filePath])) + $this->_includes[$filePath]=array($configPagePath,'('.$this->_includes[$filePath][1].') || ('.$when.')'); + else + $this->_includes[$filePath]=array($configPagePath,$when); + } + } +} \ No newline at end of file diff --git a/framework/Web/Services/TPageService.php b/framework/Web/Services/TPageService.php index f0dd8c1a..ac64afcf 100644 --- a/framework/Web/Services/TPageService.php +++ b/framework/Web/Services/TPageService.php @@ -534,357 +534,4 @@ class TPageService extends TService { return $this->getRequest()->constructUrl($this->getID(),$pagePath,$getParams,$encodeAmpersand,$encodeGetItems); } -} - - -/** - * TPageConfiguration class - * - * TPageConfiguration represents the configuration for a page. - * The page is specified by a dot-connected path. - * Configurations along this path are merged together to be provided for the page. - * - * @author Qiang Xue - * @package System.Web.Services - * @since 3.0 - */ -class TPageConfiguration extends TComponent -{ - /** - * @var array list of application configurations - */ - private $_appConfigs=array(); - /** - * @var array list of page initial property values - */ - private $_properties=array(); - /** - * @var TAuthorizationRuleCollection list of authorization rules - */ - private $_rules=array(); - /** - * @var array list of included configurations - */ - private $_includes=array(); - /** - * @var string the currently request page in the format of Path.To.PageName - */ - private $_pagePath=''; - - /** - * Constructor. - * @param string the currently request page in the format of Path.To.PageName - */ - public function __construct($pagePath) - { - $this->_pagePath=$pagePath; - } - - /** - * @return array list of external configuration files. Each element is like $filePath=>$condition - */ - public function getExternalConfigurations() - { - return $this->_includes; - } - - /** - * Returns list of page initial property values. - * Each array element represents a single property with the key - * being the property name and the value the initial property value. - * @return array list of page initial property values - */ - public function getProperties() - { - return $this->_properties; - } - - /** - * Returns list of authorization rules. - * The authorization rules are aggregated (bottom-up) from configuration files - * along the path to the specified page. - * @return TAuthorizationRuleCollection collection of authorization rules - */ - public function getRules() - { - return $this->_rules; - } - - /** - * @return array list of application configurations specified along page path - */ - public function getApplicationConfigurations() - { - return $this->_appConfigs; - } - - /** - * Loads configuration for a page specified in a path format. - * @param string root path for pages - */ - public function loadFromFiles($basePath) - { - $paths=explode('.',$this->_pagePath); - $page=array_pop($paths); - $path=$basePath; - $configPagePath=''; - $fileName = Prado::getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP - ? TPageService::CONFIG_FILE_PHP - : TPageService::CONFIG_FILE_XML; - foreach($paths as $p) - { - $this->loadFromFile($path.DIRECTORY_SEPARATOR.$fileName,$configPagePath); - $path.=DIRECTORY_SEPARATOR.$p; - if($configPagePath==='') - $configPagePath=$p; - else - $configPagePath.='.'.$p; - } - $this->loadFromFile($path.DIRECTORY_SEPARATOR.$fileName,$configPagePath); - $this->_rules=new TAuthorizationRuleCollection($this->_rules); - } - - /** - * Loads a specific config file. - * @param string config file name - * @param string the page path that the config file is associated with. The page path doesn't include the page name. - */ - public function loadFromFile($fname,$configPagePath) - { - Prado::trace("Loading page configuration file $fname",'System.Web.Services.TPageService'); - if(empty($fname) || !is_file($fname)) - return; - - if(Prado::getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP) - { - $fcontent = include $fname; - $this->loadFromPhp($fcontent,dirname($fname),$configPagePath); - } - else - { - $dom=new TXmlDocument; - if($dom->loadFromFile($fname)) - $this->loadFromXml($dom,dirname($fname),$configPagePath); - else - throw new TConfigurationException('pageserviceconf_file_invalid',$fname); - } - } - - public function loadFromPhp($config,$configPath,$configPagePath) - { - $this->loadApplicationConfigurationFromPhp($config,$configPath); - $this->loadPageConfigurationFromPhp($config,$configPath,$configPagePath); - } - - /** - * Loads a page configuration. - * The configuration includes information for both application - * and page service. - * @param TXmlElement config xml element - * @param string the directory containing this configuration - * @param string the page path that the config XML is associated with. The page path doesn't include the page name. - */ - public function loadFromXml($dom,$configPath,$configPagePath) - { - $this->loadApplicationConfigurationFromXml($dom,$configPath); - $this->loadPageConfigurationFromXml($dom,$configPath,$configPagePath); - } - - public function loadApplicationConfigurationFromPhp($config,$configPath) - { - $appConfig=new TApplicationConfiguration; - $appConfig->loadFromPhp($config,$configPath); - $this->_appConfigs[]=$appConfig; - } - - /** - * Loads the configuration specific for application part - * @param TXmlElement config xml element - * @param string base path corresponding to this xml element - */ - public function loadApplicationConfigurationFromXml($dom,$configPath) - { - $appConfig=new TApplicationConfiguration; - $appConfig->loadFromXml($dom,$configPath); - $this->_appConfigs[]=$appConfig; - } - - public function loadPageConfigurationFromPhp($config, $configPath, $configPagePath) - { - // authorization - if(isset($config['authorization']) && is_array($config['authorization'])) - { - $rules = array(); - foreach($config['authorization'] as $authorization) - { - $patterns=isset($authorization['pages'])?$authorization['pages']:''; - $ruleApplies=false; - if(empty($patterns) || trim($patterns)==='*') // null or empty string - $ruleApplies=true; - else - { - foreach(explode(',',$patterns) as $pattern) - { - if(($pattern=trim($pattern))!=='') - { - // we know $configPagePath and $this->_pagePath - if($configPagePath!=='') // prepend the pattern with ConfigPagePath - $pattern=$configPagePath.'.'.$pattern; - if(strcasecmp($pattern,$this->_pagePath)===0) - { - $ruleApplies=true; - break; - } - if($pattern[strlen($pattern)-1]==='*') // try wildcard matching - { - if(strncasecmp($this->_pagePath,$pattern,strlen($pattern)-1)===0) - { - $ruleApplies=true; - break; - } - } - } - } - } - if($ruleApplies) - { - $action = isset($authorization['action'])?$authorization['action']:''; - $users = isset($authorization['users'])?$authorization['users']:''; - $roles = isset($authorization['roles'])?$authorization['roles']:''; - $verb = isset($authorization['verb'])?$authorization['verb']:''; - $ips = isset($authorization['ips'])?$authorization['ips']:''; - $rules[]=new TAuthorizationRule($action,$users,$roles,$verb,$ips); - } - } - $this->_rules=array_merge($rules,$this->_rules); - } - // pages - if(isset($config['pages']) && is_array($config['pages'])) - { - if(isset($config['pages']['properties'])) - { - $this->_properties = array_merge($this->_properties, $config['pages']['properties']); - unset($config['pages']['properties']); - } - foreach($config['pages'] as $id => $page) - { - $properties = array(); - if(isset($page['properties'])) - { - $properties=$page['properties']; - unset($page['properties']); - } - $matching=false; - $id=($configPagePath==='')?$id:$configPagePath.'.'.$id; - if(strcasecmp($id,$this->_pagePath)===0) - $matching=true; - else if($id[strlen($id)-1]==='*') // try wildcard matching - $matching=strncasecmp($this->_pagePath,$id,strlen($id)-1)===0; - if($matching) - $this->_properties=array_merge($this->_properties,$properties); - } - } - - // external configurations - if(isset($config['includes']) && is_array($config['includes'])) - { - foreach($config['includes'] as $include) - { - $when = isset($include['when'])?true:false; - if(!isset($include['file'])) - throw new TConfigurationException('pageserviceconf_includefile_required'); - $filePath = $include['file']; - if(isset($this->_includes[$filePath])) - $this->_includes[$filePath]=array($configPagePath,'('.$this->_includes[$filePath][1].') || ('.$when.')'); - else - $this->_includes[$filePath]=array($configPagePath,$when); - } - } - } - - /** - * Loads the configuration specific for page service. - * @param TXmlElement config xml element - * @param string base path corresponding to this xml element - * @param string the page path that the config XML is associated with. The page path doesn't include the page name. - */ - public function loadPageConfigurationFromXml($dom,$configPath,$configPagePath) - { - // authorization - if(($authorizationNode=$dom->getElementByTagName('authorization'))!==null) - { - $rules=array(); - foreach($authorizationNode->getElements() as $node) - { - $patterns=$node->getAttribute('pages'); - $ruleApplies=false; - if(empty($patterns) || trim($patterns)==='*') // null or empty string - $ruleApplies=true; - else - { - foreach(explode(',',$patterns) as $pattern) - { - if(($pattern=trim($pattern))!=='') - { - // we know $configPagePath and $this->_pagePath - if($configPagePath!=='') // prepend the pattern with ConfigPagePath - $pattern=$configPagePath.'.'.$pattern; - if(strcasecmp($pattern,$this->_pagePath)===0) - { - $ruleApplies=true; - break; - } - if($pattern[strlen($pattern)-1]==='*') // try wildcard matching - { - if(strncasecmp($this->_pagePath,$pattern,strlen($pattern)-1)===0) - { - $ruleApplies=true; - break; - } - } - } - } - } - if($ruleApplies) - $rules[]=new TAuthorizationRule($node->getTagName(),$node->getAttribute('users'),$node->getAttribute('roles'),$node->getAttribute('verb'),$node->getAttribute('ips')); - } - $this->_rules=array_merge($rules,$this->_rules); - } - - // pages - if(($pagesNode=$dom->getElementByTagName('pages'))!==null) - { - $this->_properties=array_merge($this->_properties,$pagesNode->getAttributes()->toArray()); - // at the page folder - foreach($pagesNode->getElementsByTagName('page') as $node) - { - $properties=$node->getAttributes(); - $id=$properties->remove('id'); - if(empty($id)) - throw new TConfigurationException('pageserviceconf_page_invalid',$configPath); - $matching=false; - $id=($configPagePath==='')?$id:$configPagePath.'.'.$id; - if(strcasecmp($id,$this->_pagePath)===0) - $matching=true; - else if($id[strlen($id)-1]==='*') // try wildcard matching - $matching=strncasecmp($this->_pagePath,$id,strlen($id)-1)===0; - if($matching) - $this->_properties=array_merge($this->_properties,$properties->toArray()); - } - } - - // external configurations - foreach($dom->getElementsByTagName('include') as $node) - { - if(($when=$node->getAttribute('when'))===null) - $when=true; - if(($filePath=$node->getAttribute('file'))===null) - throw new TConfigurationException('pageserviceconf_includefile_required'); - if(isset($this->_includes[$filePath])) - $this->_includes[$filePath]=array($configPagePath,'('.$this->_includes[$filePath][1].') || ('.$when.')'); - else - $this->_includes[$filePath]=array($configPagePath,$when); - } - } -} - +} \ No newline at end of file diff --git a/framework/Web/Services/TRpcApiProvider.php b/framework/Web/Services/TRpcApiProvider.php new file mode 100644 index 00000000..6ea1abfc --- /dev/null +++ b/framework/Web/Services/TRpcApiProvider.php @@ -0,0 +1,86 @@ + + * @link http://www.pradosoft.com/ + * @copyright 2010 Bigpoint GmbH + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @since 3.2 + * @package System.Web.Services + */ + +/** + * TRpcApiProvider class + * + * TRpcApiProvider is an abstract class the can be subclasses in order to implement an + * api for a {@link TRpcService}. A subclass of TRpcApiProvider must implement the + * {@link registerMethods} method in order to declare the available methods, their + * names and the associated callback. + * + * + * public function registerMethods() + * { + * return array( + * 'apiMethodName1' => array('method' => array($this, 'objectMethodName1')), + * 'apiMethodName2' => array('method' => array('ClassName', 'staticMethodName')), + * ); + * } + * + * + * In this example, two api method have been defined. The first refers to an object + * method that must be implemented in the same class, the second to a static method + * implemented in a 'ClassName' class. + * In both cases, the method implementation will receive the request parameters as its + * method parameters. Since the number of received parameters depends on + * external-supplied data, it's adviced to use php's func_get_args() funtion to + * validate them. + * + * Providers must be registered in the service configuration in order to be available, + * as explained in {@link TRpcService}'s documentation. + * + * @author Robin J. Rogge + * @version $Id$ + * @package System.Web.Services + * @since 3.2 + */ +abstract class TRpcApiProvider extends TModule +{ + /** + * @var TRpcServer instance + */ + protected $rpcServer; + + /** + * Must return an array of the available methods + * @abstract + */ + abstract public function registerMethods(); + + /** + * Constructor: informs the rpc server of the registered methods + */ + public function __construct(TRpcServer $rpcServer) + { + $this->rpcServer = $rpcServer; + + foreach($this->registerMethods() as $_methodName => $_methodDetails) + $this->rpcServer->addRpcMethod($_methodName, $_methodDetails); + } + + /** + * Processes the request using the server + * @return processed request + */ + public function processRequest() + { + return $this->rpcServer->processRequest(); + } + + /** + * @return rpc server instance + */ + public function getRpcServer() + { + return $this->rpcServer; + } +} \ No newline at end of file diff --git a/framework/Web/Services/TRpcException.php b/framework/Web/Services/TRpcException.php new file mode 100644 index 00000000..7c0cb65f --- /dev/null +++ b/framework/Web/Services/TRpcException.php @@ -0,0 +1,31 @@ + + * @link http://www.pradosoft.com/ + * @copyright 2010 Bigpoint GmbH + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @since 3.2 + * @package System.Web.Services + */ + +/** + * TRpcException class + * + * A TRpcException represents a RPC fault i.e. an error that is caused by the input data + * sent from the client. + * + * @author Robin J. Rogge + * @version $Id$ + * @package System.Web.Services + * @since 3.2 + */ +class TRpcException extends TException +{ + public function __construct($message, $errorCode = -1) + { + $this->setErrorCode($errorCode); + + parent::__construct($message); + } +} \ No newline at end of file diff --git a/framework/Web/Services/TRpcProtocol.php b/framework/Web/Services/TRpcProtocol.php new file mode 100644 index 00000000..ace13638 --- /dev/null +++ b/framework/Web/Services/TRpcProtocol.php @@ -0,0 +1,98 @@ + + * @link http://www.pradosoft.com/ + * @copyright 2010 Bigpoint GmbH + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @since 3.2 + * @package System.Web.Services + */ + +/** + * TRpcProtocol class + * + * TRpcProtocol is the base class used to implement a protocol in a {@link TRpcService}. + * Prado already implements two protocols: {@link TXmlRpcProtocol} for Xml-Rpc request + * and {@link TJsonRpcProtocol} for JSON-Rpc requests. + * + * @author Robin J. Rogge + * @version $Id$ + * @package System.Web.Services + * @since 3.2 + **/ +abstract class TRpcProtocol +{ + /** + * @var array containing the mapping from RPC method names to the actual handlers + */ + protected $rpcMethods = array(); + + // abstracts + + /** + * @param string request payload + * Processed the request ans returns the response, if any + * @return processed response + * @abstract + */ + abstract public function callMethod($requestPayload); + /** + * @param TRpcException the exception with error details + * Creates a proper response for an error condition + * @return a response representing the error + * @abstract + */ + abstract public function createErrorResponse(TRpcException $exception); + /** + * @param response + * Sets the needed headers for the response (eg: content-type, charset) + * @abstract + */ + abstract public function createResponseHeaders($response); + /** + * Encodes the response + * @param mixed reponse data + * @return string encoded response + * @abstract + */ + abstract public function encode($data); + /** + * Decodes the request payload + * @param string request payload + * @return mixed decoded request + * @abstract + */ + abstract public function decode($data); + + // methods + + /** + * Registers a new RPC method and handler details + * @param string $methodName + * @param array $handlerDetails containing the callback handler + */ + public function addMethod($methodName, $handlerDetails) + { + $this->rpcMethods[$methodName] = $handlerDetails; + } + + /** + * Calls the callback handler for the given method + * @param string $methodName of the RPC + * @param array $parameters for the callback handler as provided by the client + * @return mixed whatever the callback handler returns + */ + public function callApiMethod($methodName, $parameters) + { + if(!isset($this->rpcMethods[$methodName])) + throw new TRpcException('Method "'.$methodName.'" not found'); + + if($parameters === null) + $parameters = array(); + + if(!is_array($parameters)) + $parameters = array($parameters); + return call_user_func_array($this->rpcMethods[$methodName]['method'], $parameters); + } +} \ No newline at end of file diff --git a/framework/Web/Services/TRpcServer.php b/framework/Web/Services/TRpcServer.php new file mode 100644 index 00000000..ab8dd17d --- /dev/null +++ b/framework/Web/Services/TRpcServer.php @@ -0,0 +1,78 @@ + + * @link http://www.pradosoft.com/ + * @copyright 2010 Bigpoint GmbH + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @since 3.2 + * @package System.Web.Services + */ + +/** + * TRpcServer class + * + * TRpcServer is a class + * + * TRpcServer is the base class used to creare a server to be used in conjunction with + * {@link TRpcService}. + * The role of TRpcServer is to be an intermediate, moving data between the service and + * the provider. This base class should suit the most common needs, but can be sublassed for + * logging and debugging purposes, or to filter and modify the request/response on the fly. + * + * @author Robin J. Rogge + * @version $Id$ + * @package System.Web.Services + * @since 3.2 + **/ +class TRpcServer extends TModule +{ + /** + * @var TRpcProtocol instance + */ + protected $handler; + + /** + * Constructor + * @param TRpcProtocol $protocolHandler instance + */ + public function __construct(TRpcProtocol $protocolHandler) + { + $this->handler = $protocolHandler; + } + + /** + * Registers the method in the protocol handler + * @param string $methodName + * @param array $methodDetails + */ + public function addRpcMethod($methodName, $methodDetails) + { + $this->handler->addMethod($methodName, $methodDetails); + } + + /** + * Retrieves the request payload + * @return string request payload + */ + public function getPayload() + { + return file_get_contents('php://input'); + } + + /** + * Passes the request payload to the protocol handler and returns the result + * @return string rpc response + */ + public function processRequest() + { + try + { + return $this->handler->callMethod($this->getPayload()); + } + catch(TRpcException $e) + { + return $this->handler->createErrorResponse($e); + } + } +} \ No newline at end of file diff --git a/framework/Web/Services/TRpcService.php b/framework/Web/Services/TRpcService.php index a4ed3d7c..26e7471d 100644 --- a/framework/Web/Services/TRpcService.php +++ b/framework/Web/Services/TRpcService.php @@ -1,5 +1,4 @@ * @link http://www.pradosoft.com/ @@ -10,6 +9,7 @@ * @package System.Web.Services */ + /** * TRpcService class * @@ -175,548 +175,4 @@ class TRpcService extends TService $_response->write($_result); } } -} - -/** - * TRpcServer class - * - * TRpcServer is a class - * - * TRpcServer is the base class used to creare a server to be used in conjunction with - * {@link TRpcService}. - * The role of TRpcServer is to be an intermediate, moving data between the service and - * the provider. This base class should suit the most common needs, but can be sublassed for - * logging and debugging purposes, or to filter and modify the request/response on the fly. - * - * @author Robin J. Rogge - * @version $Id$ - * @package System.Web.Services - * @since 3.2 - **/ -class TRpcServer extends TModule -{ - /** - * @var TRpcProtocol instance - */ - protected $handler; - - /** - * Constructor - * @param TRpcProtocol $protocolHandler instance - */ - public function __construct(TRpcProtocol $protocolHandler) - { - $this->handler = $protocolHandler; - } - - /** - * Registers the method in the protocol handler - * @param string $methodName - * @param array $methodDetails - */ - public function addRpcMethod($methodName, $methodDetails) - { - $this->handler->addMethod($methodName, $methodDetails); - } - - /** - * Retrieves the request payload - * @return string request payload - */ - public function getPayload() - { - return file_get_contents('php://input'); - } - - /** - * Passes the request payload to the protocol handler and returns the result - * @return string rpc response - */ - public function processRequest() - { - try - { - return $this->handler->callMethod($this->getPayload()); - } - catch(TRpcException $e) - { - return $this->handler->createErrorResponse($e); - } - } -} - -/** - * TRpcException class - * - * A TRpcException represents a RPC fault i.e. an error that is caused by the input data - * sent from the client. - * - * @author Robin J. Rogge - * @version $Id$ - * @package System.Web.Services - * @since 3.2 - */ -class TRpcException extends TException -{ - public function __construct($message, $errorCode = -1) - { - $this->setErrorCode($errorCode); - - parent::__construct($message); - } -} - -/** - * TRpcApiProvider class - * - * TRpcApiProvider is an abstract class the can be subclasses in order to implement an - * api for a {@link TRpcService}. A subclass of TRpcApiProvider must implement the - * {@link registerMethods} method in order to declare the available methods, their - * names and the associated callback. - * - * - * public function registerMethods() - * { - * return array( - * 'apiMethodName1' => array('method' => array($this, 'objectMethodName1')), - * 'apiMethodName2' => array('method' => array('ClassName', 'staticMethodName')), - * ); - * } - * - * - * In this example, two api method have been defined. The first refers to an object - * method that must be implemented in the same class, the second to a static method - * implemented in a 'ClassName' class. - * In both cases, the method implementation will receive the request parameters as its - * method parameters. Since the number of received parameters depends on - * external-supplied data, it's adviced to use php's func_get_args() funtion to - * validate them. - * - * Providers must be registered in the service configuration in order to be available, - * as explained in {@link TRpcService}'s documentation. - * - * @author Robin J. Rogge - * @version $Id$ - * @package System.Web.Services - * @since 3.2 - */ -abstract class TRpcApiProvider extends TModule -{ - /** - * @var TRpcServer instance - */ - protected $rpcServer; - - /** - * Must return an array of the available methods - * @abstract - */ - abstract public function registerMethods(); - - /** - * Constructor: informs the rpc server of the registered methods - */ - public function __construct(TRpcServer $rpcServer) - { - $this->rpcServer = $rpcServer; - - foreach($this->registerMethods() as $_methodName => $_methodDetails) - $this->rpcServer->addRpcMethod($_methodName, $_methodDetails); - } - - /** - * Processes the request using the server - * @return processed request - */ - public function processRequest() - { - return $this->rpcServer->processRequest(); - } - - /** - * @return rpc server instance - */ - public function getRpcServer() - { - return $this->rpcServer; - } -} - -/** - * TRpcProtocol class - * - * TRpcProtocol is the base class used to implement a protocol in a {@link TRpcService}. - * Prado already implements two protocols: {@link TXmlRpcProtocol} for Xml-Rpc request - * and {@link TJsonRpcProtocol} for JSON-Rpc requests. - * - * @author Robin J. Rogge - * @version $Id$ - * @package System.Web.Services - * @since 3.2 - **/ -abstract class TRpcProtocol -{ - /** - * @var array containing the mapping from RPC method names to the actual handlers - */ - protected $rpcMethods = array(); - - // abstracts - - /** - * @param string request payload - * Processed the request ans returns the response, if any - * @return processed response - * @abstract - */ - abstract public function callMethod($requestPayload); - /** - * @param TRpcException the exception with error details - * Creates a proper response for an error condition - * @return a response representing the error - * @abstract - */ - abstract public function createErrorResponse(TRpcException $exception); - /** - * @param response - * Sets the needed headers for the response (eg: content-type, charset) - * @abstract - */ - abstract public function createResponseHeaders($response); - /** - * Encodes the response - * @param mixed reponse data - * @return string encoded response - * @abstract - */ - abstract public function encode($data); - /** - * Decodes the request payload - * @param string request payload - * @return mixed decoded request - * @abstract - */ - abstract public function decode($data); - - // methods - - /** - * Registers a new RPC method and handler details - * @param string $methodName - * @param array $handlerDetails containing the callback handler - */ - public function addMethod($methodName, $handlerDetails) - { - $this->rpcMethods[$methodName] = $handlerDetails; - } - - /** - * Calls the callback handler for the given method - * @param string $methodName of the RPC - * @param array $parameters for the callback handler as provided by the client - * @return mixed whatever the callback handler returns - */ - public function callApiMethod($methodName, $parameters) - { - if(!isset($this->rpcMethods[$methodName])) - throw new TRpcException('Method "'.$methodName.'" not found'); - - if($parameters === null) - $parameters = array(); - - if(!is_array($parameters)) - $parameters = array($parameters); - return call_user_func_array($this->rpcMethods[$methodName]['method'], $parameters); - } -} - -/** - * TJsonRpcProtocol class - * - * TJsonRpcProtocol is a class that implements JSON-Rpc protocol in {@link TRpcService}. - * Both version 1.0 and 2.0 of the specification are implemented, and the server will try - * to answer using the same version of the protocol used by the requesting client. - * - * @author Robin J. Rogge - * @author Fabio Bas - * @version $Id$ - * @package System.Web.Services - * @since 3.2 - */ -class TJsonRpcProtocol extends TRpcProtocol -{ - protected $_id=null; - protected $_specificationVersion=1.0; - - /** - * Handles the RPC request - * @param string $requestPayload - * @return string JSON RPC response - */ - public function callMethod($requestPayload) - { - try - { - $_request = $this->decode($requestPayload); - - if(isset($_request['jsonrpc'])) - { - $this->_specificationVersion=$_request['jsonrpc']; - if($this->_specificationVersion > 2.0) - throw new TRpcException('Unsupported specification version', '-32600'); - } - - if(isset($_request['id'])) - $this->_id=$_request['id']; - - if(!isset($_request['method'])) - throw new TRpcException('Missing request method', '-32600'); - - if(!isset($_request['params'])) - $parameters = array(); - else - $parameters = $_request['params']; - - if(!is_array($parameters)) - $parameters = array($parameters); - - // a request without an id is a notification that doesn't need a response - if($this->_id !== null) - { - if($this->_specificationVersion==2.0) - { - return $this->encode(array( - 'jsonrpc' => '2.0', - 'id' => $this->_id, - 'result' => $this->callApiMethod($_request['method'], $parameters), - )); - } else { - return $this->encode(array( - 'id' => $this->_id, - 'result' => $this->callApiMethod($_request['method'], $_request['params']), - 'error' => null - )); - } - } - } - catch(TRpcException $e) - { - return $this->createErrorResponse($e); - } - catch(THttpException $e) - { - throw $e; - } - catch(Exception $e) - { - return $this->createErrorResponse(new TRpcException('An internal error occured', '-32603')); - } - } - - /** - * Turns the given exception into an JSON RPC fault - * @param TRpcException $exception - * @return string JSON RPC fault - */ - public function createErrorResponse(TRpcException $exception) - { - if($this->_specificationVersion==2.0) - { - return $this->encode(array( - 'id' => $this->_id, - 'result' => null, - 'error'=> array( - 'code' => $exception->getCode(), - 'message'=> $exception->getMessage(), - 'data' => null, - ) - )); - } else { - return $this->encode(array( - 'id' => $this->_id, - 'error'=> array( - 'code' => $exception->getCode(), - 'message'=> $exception->getMessage(), - 'data' => null, - ) - )); - } - } - - /** - * Sets the correct response headers - * @param THttpResponse $response - */ - public function createResponseHeaders($response) - { - $response->setContentType('application/json'); - $response->setCharset('UTF-8'); - } - - /** - * Decodes JSON encoded data into PHP data - * @param string $data in JSON format - * @return array PHP data - */ - public function decode($data) - { - $s = json_decode($data, true); - self::checkJsonError(); - return $s; - } - - /** - * Encodes PHP data into JSON data - * @param mixed PHP data - * @return string JSON encoded PHP data - */ - public function encode($data) - { - $s = json_encode($data); - self::checkJsonError(); - return $s; - } - - private static function checkJsonError() - { - $errnum = json_last_error(); - if($errnum != JSON_ERROR_NONE) - throw new Exception("JSON error: $msg", $err); - } - - /** - * Calls the callback handler for the given method - * Overrides parent implementation to correctly handle error codes - * @param string $methodName of the RPC - * @param array $parameters for the callback handler as provided by the client - * @return mixed whatever the callback handler returns - */ - public function callApiMethod($methodName, $parameters) - { - if(!isset($this->rpcMethods[$methodName])) - throw new TRpcException('Method "'.$methodName.'" not found', '-32601'); - - return call_user_func_array($this->rpcMethods[$methodName]['method'], $parameters); - } -} - -/** - * TXmlRpcProtocol class - * - * TXmlRpcProtocol is a class that implements XML-Rpc protocol in {@link TRpcService}. - * It's basically a wrapper to the xmlrpc_server_* family of php methods. - * - * @author Robin J. Rogge - * @version $Id$ - * @package System.Web.Services - * @since 3.2 - */ -class TXmlRpcProtocol extends TRpcProtocol -{ - /** - * @var XML RPC server resource - */ - private $_xmlrpcServer; - - // magics - - /** - * Constructor - */ - public function __construct() - { - $this->_xmlrpcServer = xmlrpc_server_create(); - } - - /** - * Destructor - */ - public function __destruct() - { - xmlrpc_server_destroy($this->_xmlrpcServer); - } - - // methods - - /** - * Registers a new RPC method and handler details - * @param string $methodName - * @param array $handlerDetails containing the callback handler - */ - public function addMethod($methodName, $methodDetails) - { - parent::addMethod($methodName, $methodDetails); - - xmlrpc_server_register_method($this->_xmlrpcServer, $methodName, array($this, 'callApiMethod')); - } - - // methods - - /** - * Handles the RPC request - * @param string $requestPayload - * @return string XML RPC response - */ - public function callMethod($requestPayload) - { - try - { - return xmlrpc_server_call_method($this->_xmlrpcServer, $requestPayload, null); - } - catch(TRpcException $e) - { - return $this->createErrorResponse($e); - } - catch(THttpException $e) - { - throw $e; - } - catch(Exception $e) - { - return $this->createErrorResponse(new TRpcException('An internal error occured')); - } - } - - /** - * Turns the given exception into an XML RPC fault - * @param TRpcException $exception - * @return string XML RPC fault - */ - public function createErrorResponse(TRpcException $exception) - { - return $this->encode(array( - 'faultCode' => $exception->getCode(), - 'faultString' => $exception->getMessage() - )); - } - - /** - * Sets the correct response headers - * @param THttpResponse $response - */ - public function createResponseHeaders($response) - { - $response->setContentType('text/xml'); - $response->setCharset('UTF-8'); - } - - /** - * Decodes XML encoded data into PHP data - * @param string $data in XML format - * @return array PHP data - */ - public function decode($data) - { - return xmlrpc_decode($data); - } - - /** - * Encodes PHP data into XML data - * @param mixed PHP data - * @return string XML encoded PHP data - */ - public function encode($data) - { - return xmlrpc_encode($data); - } -} +} \ No newline at end of file diff --git a/framework/Web/Services/TSoapServer.php b/framework/Web/Services/TSoapServer.php new file mode 100644 index 00000000..0441e67d --- /dev/null +++ b/framework/Web/Services/TSoapServer.php @@ -0,0 +1,345 @@ + + * @author Qiang Xue + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2014 PradoSoft + * @license http://www.pradosoft.com/license/ + * @package System.Web.Services + */ + + +/** + * TSoapServer class. + * + * TSoapServer is a wrapper of the PHP SoapServer class. + * It associates a SOAP provider class to the SoapServer object. + * It also manages the URI for the SOAP service and WSDL. + * + * @author Qiang Xue + * @package System.Web.Services + * @since 3.1 + */ +class TSoapServer extends TApplicationComponent +{ + const WSDL_CACHE_PREFIX='wsdl.'; + + private $_id; + private $_provider; + + private $_version=''; + private $_actor=''; + private $_encoding=''; + private $_uri=''; + private $_classMap; + private $_persistent=false; + private $_wsdlUri=''; + + private $_requestedMethod; + + private $_server; + + /** + * @return string the ID of the SOAP server + */ + public function getID() + { + return $this->_id; + } + + /** + * @param string the ID of the SOAP server + * @throws TInvalidDataValueException if the ID ends with '.wsdl'. + */ + public function setID($id) + { + if(strrpos($this->_id,'.wsdl')===strlen($this->_id)-5) + throw new TInvalidDataValueException('soapserver_id_invalid',$id); + $this->_id=$id; + } + + /** + * Handles the SOAP request. + */ + public function run() + { + if(($provider=$this->getProvider())!==null) + { + Prado::using($provider); + $providerClass=($pos=strrpos($provider,'.'))!==false?substr($provider,$pos+1):$provider; + $this->guessMethodCallRequested($providerClass); + $server=$this->createServer(); + $server->setClass($providerClass, $this); + if($this->_persistent) + $server->setPersistence(SOAP_PERSISTENCE_SESSION); + } + else + $server=$this->createServer(); + try + { + $server->handle(); + } + catch (Exception $e) + { + if($this->getApplication()->getMode()===TApplicationMode::Debug) + $this->fault($e->getMessage(), $e->__toString()); + else + $this->fault($e->getMessage()); + } + } + + /** + * Generate a SOAP fault message. + * @param string message title + * @param mixed message details + * @param string message code, defalt is 'SERVER'. + * @param string actors + * @param string message name + */ + public function fault($title, $details='', $code='SERVER', $actor='', $name='') + { + Prado::trace('SOAP-Fault '.$code. ' '.$title.' : '.$details, 'System.Web.Services.TSoapService'); + $this->_server->fault($code, $title, $actor, $details, $name); + } + + /** + * Guess the SOAP method request from the actual SOAP message + * + * @param string $class current handler class. + */ + protected function guessMethodCallRequested($class) + { + $namespace = $class.'wsdl'; + $message = file_get_contents("php://input"); + $matches= array(); + if(preg_match('/xmlns:([^=]+)="urn:'.$namespace.'"/', $message, $matches)) + { + if(preg_match('/<'.$matches[1].':([a-zA-Z_]+[a-zA-Z0-9_]+)/', $message, $method)) + { + $this->_requestedMethod = $method[1]; + } + } + } + + /** + * Soap method guessed from the SOAP message received. + * @return string soap method request, null if not found. + */ + public function getRequestedMethod() + { + return $this->_requestedMethod; + } + + /** + * Creates the SoapServer instance. + * @return SoapServer + */ + protected function createServer() + { + if($this->_server===null) + { + if($this->getApplication()->getMode()===TApplicationMode::Debug) + ini_set("soap.wsdl_cache_enabled",0); + $this->_server = new SoapServer($this->getWsdlUri(),$this->getOptions()); + } + return $this->_server; + } + + /** + * @return array options for creating SoapServer instance + */ + protected function getOptions() + { + $options=array(); + if($this->_version==='1.1') + $options['soap_version']=SOAP_1_1; + else if($this->_version==='1.2') + $options['soap_version']=SOAP_1_2; + if(!empty($this->_actor)) + $options['actor']=$this->_actor; + if(!empty($this->_encoding)) + $options['encoding']=$this->_encoding; + if(!empty($this->_uri)) + $options['uri']=$this->_uri; + if(is_string($this->_classMap)) + { + foreach(preg_split('/\s*,\s*/', $this->_classMap) as $className) + $options['classmap'][$className]=$className; //complex type uses the class name in the wsdl + } + return $options; + } + + /** + * Returns the WSDL content of the SOAP server. + * If {@link getWsdlUri WsdlUri} is set, its content will be returned. + * If not, the {@link setProvider Provider} class will be investigated + * and the WSDL will be automatically genearted. + * @return string the WSDL content of the SOAP server + */ + public function getWsdl() + { + if($this->_wsdlUri==='') + { + $provider=$this->getProvider(); + $providerClass=($pos=strrpos($provider,'.'))!==false?substr($provider,$pos+1):$provider; + Prado::using($provider); + if($this->getApplication()->getMode()===TApplicationMode::Performance && ($cache=$this->getApplication()->getCache())!==null) + { + $wsdl=$cache->get(self::WSDL_CACHE_PREFIX.$providerClass); + if(is_string($wsdl)) + return $wsdl; + Prado::using('System.3rdParty.WsdlGen.WsdlGenerator'); + $wsdl=WsdlGenerator::generate($providerClass, $this->getUri(), $this->getEncoding()); + $cache->set(self::WSDL_CACHE_PREFIX.$providerClass,$wsdl); + return $wsdl; + } + else + { + Prado::using('System.3rdParty.WsdlGen.WsdlGenerator'); + return WsdlGenerator::generate($providerClass, $this->getUri(), $this->getEncoding()); + } + } + else + return file_get_contents($this->_wsdlUri); + } + + /** + * @return string the URI for WSDL + */ + public function getWsdlUri() + { + if($this->_wsdlUri==='') + return $this->getRequest()->getBaseUrl().$this->getService()->constructUrl($this->getID().'.wsdl',false); + else + return $this->_wsdlUri; + } + + /** + * @param string the URI for WSDL + */ + public function setWsdlUri($value) + { + $this->_wsdlUri=$value; + } + + /** + * @return string the URI for the SOAP service + */ + public function getUri() + { + if($this->_uri==='') + return $this->getRequest()->getBaseUrl().$this->getService()->constructUrl($this->getID(),false); + else + return $this->_uri; + } + + /** + * @param string the URI for the SOAP service + */ + public function setUri($uri) + { + $this->_uri=$uri; + } + + /** + * @return string the SOAP provider class (in namespace format) + */ + public function getProvider() + { + return $this->_provider; + } + + /** + * @param string the SOAP provider class (in namespace format) + */ + public function setProvider($provider) + { + $this->_provider=$provider; + } + + /** + * @return string SOAP version, defaults to empty (meaning not set). + */ + public function getVersion() + { + return $this->_version; + } + + /** + * @param string SOAP version, either '1.1' or '1.2' + * @throws TInvalidDataValueException if neither '1.1' nor '1.2' + */ + public function setVersion($value) + { + if($value==='1.1' || $value==='1.2' || $value==='') + $this->_version=$value; + else + throw new TInvalidDataValueException('soapserver_version_invalid',$value); + } + + /** + * @return string actor of the SOAP service + */ + public function getActor() + { + return $this->_actor; + } + + /** + * @param string actor of the SOAP service + */ + public function setActor($value) + { + $this->_actor=$value; + } + + /** + * @return string encoding of the SOAP service + */ + public function getEncoding() + { + return $this->_encoding; + } + + /** + * @param string encoding of the SOAP service + */ + public function setEncoding($value) + { + $this->_encoding=$value; + } + + /** + * @return boolean whether the SOAP service is persistent within session. Defaults to false. + */ + public function getSessionPersistent() + { + return $this->_persistent; + } + + /** + * @param boolean whether the SOAP service is persistent within session. + */ + public function setSessionPersistent($value) + { + $this->_persistent=TPropertyValue::ensureBoolean($value); + } + + /** + * @return string comma delimit list of complex type classes. + */ + public function getClassMaps() + { + return $this->_classMap; + } + + /** + * @return string comma delimit list of class names + */ + public function setClassMaps($classes) + { + $this->_classMap = $classes; + } +} \ No newline at end of file diff --git a/framework/Web/Services/TSoapService.php b/framework/Web/Services/TSoapService.php index c928dc06..7342eb3d 100644 --- a/framework/Web/Services/TSoapService.php +++ b/framework/Web/Services/TSoapService.php @@ -284,339 +284,4 @@ class TSoapService extends TService $server->run(); } } -} - - -/** - * TSoapServer class. - * - * TSoapServer is a wrapper of the PHP SoapServer class. - * It associates a SOAP provider class to the SoapServer object. - * It also manages the URI for the SOAP service and WSDL. - * - * @author Qiang Xue - * @package System.Web.Services - * @since 3.1 - */ -class TSoapServer extends TApplicationComponent -{ - const WSDL_CACHE_PREFIX='wsdl.'; - - private $_id; - private $_provider; - - private $_version=''; - private $_actor=''; - private $_encoding=''; - private $_uri=''; - private $_classMap; - private $_persistent=false; - private $_wsdlUri=''; - - private $_requestedMethod; - - private $_server; - - /** - * @return string the ID of the SOAP server - */ - public function getID() - { - return $this->_id; - } - - /** - * @param string the ID of the SOAP server - * @throws TInvalidDataValueException if the ID ends with '.wsdl'. - */ - public function setID($id) - { - if(strrpos($this->_id,'.wsdl')===strlen($this->_id)-5) - throw new TInvalidDataValueException('soapserver_id_invalid',$id); - $this->_id=$id; - } - - /** - * Handles the SOAP request. - */ - public function run() - { - if(($provider=$this->getProvider())!==null) - { - Prado::using($provider); - $providerClass=($pos=strrpos($provider,'.'))!==false?substr($provider,$pos+1):$provider; - $this->guessMethodCallRequested($providerClass); - $server=$this->createServer(); - $server->setClass($providerClass, $this); - if($this->_persistent) - $server->setPersistence(SOAP_PERSISTENCE_SESSION); - } - else - $server=$this->createServer(); - try - { - $server->handle(); - } - catch (Exception $e) - { - if($this->getApplication()->getMode()===TApplicationMode::Debug) - $this->fault($e->getMessage(), $e->__toString()); - else - $this->fault($e->getMessage()); - } - } - - /** - * Generate a SOAP fault message. - * @param string message title - * @param mixed message details - * @param string message code, defalt is 'SERVER'. - * @param string actors - * @param string message name - */ - public function fault($title, $details='', $code='SERVER', $actor='', $name='') - { - Prado::trace('SOAP-Fault '.$code. ' '.$title.' : '.$details, 'System.Web.Services.TSoapService'); - $this->_server->fault($code, $title, $actor, $details, $name); - } - - /** - * Guess the SOAP method request from the actual SOAP message - * - * @param string $class current handler class. - */ - protected function guessMethodCallRequested($class) - { - $namespace = $class.'wsdl'; - $message = file_get_contents("php://input"); - $matches= array(); - if(preg_match('/xmlns:([^=]+)="urn:'.$namespace.'"/', $message, $matches)) - { - if(preg_match('/<'.$matches[1].':([a-zA-Z_]+[a-zA-Z0-9_]+)/', $message, $method)) - { - $this->_requestedMethod = $method[1]; - } - } - } - - /** - * Soap method guessed from the SOAP message received. - * @return string soap method request, null if not found. - */ - public function getRequestedMethod() - { - return $this->_requestedMethod; - } - - /** - * Creates the SoapServer instance. - * @return SoapServer - */ - protected function createServer() - { - if($this->_server===null) - { - if($this->getApplication()->getMode()===TApplicationMode::Debug) - ini_set("soap.wsdl_cache_enabled",0); - $this->_server = new SoapServer($this->getWsdlUri(),$this->getOptions()); - } - return $this->_server; - } - - /** - * @return array options for creating SoapServer instance - */ - protected function getOptions() - { - $options=array(); - if($this->_version==='1.1') - $options['soap_version']=SOAP_1_1; - else if($this->_version==='1.2') - $options['soap_version']=SOAP_1_2; - if(!empty($this->_actor)) - $options['actor']=$this->_actor; - if(!empty($this->_encoding)) - $options['encoding']=$this->_encoding; - if(!empty($this->_uri)) - $options['uri']=$this->_uri; - if(is_string($this->_classMap)) - { - foreach(preg_split('/\s*,\s*/', $this->_classMap) as $className) - $options['classmap'][$className]=$className; //complex type uses the class name in the wsdl - } - return $options; - } - - /** - * Returns the WSDL content of the SOAP server. - * If {@link getWsdlUri WsdlUri} is set, its content will be returned. - * If not, the {@link setProvider Provider} class will be investigated - * and the WSDL will be automatically genearted. - * @return string the WSDL content of the SOAP server - */ - public function getWsdl() - { - if($this->_wsdlUri==='') - { - $provider=$this->getProvider(); - $providerClass=($pos=strrpos($provider,'.'))!==false?substr($provider,$pos+1):$provider; - Prado::using($provider); - if($this->getApplication()->getMode()===TApplicationMode::Performance && ($cache=$this->getApplication()->getCache())!==null) - { - $wsdl=$cache->get(self::WSDL_CACHE_PREFIX.$providerClass); - if(is_string($wsdl)) - return $wsdl; - Prado::using('System.3rdParty.WsdlGen.WsdlGenerator'); - $wsdl=WsdlGenerator::generate($providerClass, $this->getUri(), $this->getEncoding()); - $cache->set(self::WSDL_CACHE_PREFIX.$providerClass,$wsdl); - return $wsdl; - } - else - { - Prado::using('System.3rdParty.WsdlGen.WsdlGenerator'); - return WsdlGenerator::generate($providerClass, $this->getUri(), $this->getEncoding()); - } - } - else - return file_get_contents($this->_wsdlUri); - } - - /** - * @return string the URI for WSDL - */ - public function getWsdlUri() - { - if($this->_wsdlUri==='') - return $this->getRequest()->getBaseUrl().$this->getService()->constructUrl($this->getID().'.wsdl',false); - else - return $this->_wsdlUri; - } - - /** - * @param string the URI for WSDL - */ - public function setWsdlUri($value) - { - $this->_wsdlUri=$value; - } - - /** - * @return string the URI for the SOAP service - */ - public function getUri() - { - if($this->_uri==='') - return $this->getRequest()->getBaseUrl().$this->getService()->constructUrl($this->getID(),false); - else - return $this->_uri; - } - - /** - * @param string the URI for the SOAP service - */ - public function setUri($uri) - { - $this->_uri=$uri; - } - - /** - * @return string the SOAP provider class (in namespace format) - */ - public function getProvider() - { - return $this->_provider; - } - - /** - * @param string the SOAP provider class (in namespace format) - */ - public function setProvider($provider) - { - $this->_provider=$provider; - } - - /** - * @return string SOAP version, defaults to empty (meaning not set). - */ - public function getVersion() - { - return $this->_version; - } - - /** - * @param string SOAP version, either '1.1' or '1.2' - * @throws TInvalidDataValueException if neither '1.1' nor '1.2' - */ - public function setVersion($value) - { - if($value==='1.1' || $value==='1.2' || $value==='') - $this->_version=$value; - else - throw new TInvalidDataValueException('soapserver_version_invalid',$value); - } - - /** - * @return string actor of the SOAP service - */ - public function getActor() - { - return $this->_actor; - } - - /** - * @param string actor of the SOAP service - */ - public function setActor($value) - { - $this->_actor=$value; - } - - /** - * @return string encoding of the SOAP service - */ - public function getEncoding() - { - return $this->_encoding; - } - - /** - * @param string encoding of the SOAP service - */ - public function setEncoding($value) - { - $this->_encoding=$value; - } - - /** - * @return boolean whether the SOAP service is persistent within session. Defaults to false. - */ - public function getSessionPersistent() - { - return $this->_persistent; - } - - /** - * @param boolean whether the SOAP service is persistent within session. - */ - public function setSessionPersistent($value) - { - $this->_persistent=TPropertyValue::ensureBoolean($value); - } - - /** - * @return string comma delimit list of complex type classes. - */ - public function getClassMaps() - { - return $this->_classMap; - } - - /** - * @return string comma delimit list of class names - */ - public function setClassMaps($classes) - { - $this->_classMap = $classes; - } -} - +} \ No newline at end of file diff --git a/framework/Web/Services/TXmlRpcProtocol.php b/framework/Web/Services/TXmlRpcProtocol.php new file mode 100644 index 00000000..4e287675 --- /dev/null +++ b/framework/Web/Services/TXmlRpcProtocol.php @@ -0,0 +1,131 @@ + + * @link http://www.pradosoft.com/ + * @copyright 2010 Bigpoint GmbH + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @since 3.2 + * @package System.Web.Services + */ + +/** + * TXmlRpcProtocol class + * + * TXmlRpcProtocol is a class that implements XML-Rpc protocol in {@link TRpcService}. + * It's basically a wrapper to the xmlrpc_server_* family of php methods. + * + * @author Robin J. Rogge + * @version $Id$ + * @package System.Web.Services + * @since 3.2 + */ +class TXmlRpcProtocol extends TRpcProtocol +{ + /** + * @var XML RPC server resource + */ + private $_xmlrpcServer; + + // magics + + /** + * Constructor + */ + public function __construct() + { + $this->_xmlrpcServer = xmlrpc_server_create(); + } + + /** + * Destructor + */ + public function __destruct() + { + xmlrpc_server_destroy($this->_xmlrpcServer); + } + + // methods + + /** + * Registers a new RPC method and handler details + * @param string $methodName + * @param array $handlerDetails containing the callback handler + */ + public function addMethod($methodName, $methodDetails) + { + parent::addMethod($methodName, $methodDetails); + + xmlrpc_server_register_method($this->_xmlrpcServer, $methodName, array($this, 'callApiMethod')); + } + + // methods + + /** + * Handles the RPC request + * @param string $requestPayload + * @return string XML RPC response + */ + public function callMethod($requestPayload) + { + try + { + return xmlrpc_server_call_method($this->_xmlrpcServer, $requestPayload, null); + } + catch(TRpcException $e) + { + return $this->createErrorResponse($e); + } + catch(THttpException $e) + { + throw $e; + } + catch(Exception $e) + { + return $this->createErrorResponse(new TRpcException('An internal error occured')); + } + } + + /** + * Turns the given exception into an XML RPC fault + * @param TRpcException $exception + * @return string XML RPC fault + */ + public function createErrorResponse(TRpcException $exception) + { + return $this->encode(array( + 'faultCode' => $exception->getCode(), + 'faultString' => $exception->getMessage() + )); + } + + /** + * Sets the correct response headers + * @param THttpResponse $response + */ + public function createResponseHeaders($response) + { + $response->setContentType('text/xml'); + $response->setCharset('UTF-8'); + } + + /** + * Decodes XML encoded data into PHP data + * @param string $data in XML format + * @return array PHP data + */ + public function decode($data) + { + return xmlrpc_decode($data); + } + + /** + * Encodes PHP data into XML data + * @param mixed PHP data + * @return string XML encoded PHP data + */ + public function encode($data) + { + return xmlrpc_encode($data); + } +} \ No newline at end of file -- cgit v1.2.3