PageRenderTime 46ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/framework/web/services/CWebService.php

https://bitbucket.org/duhajo/duhajoyii
PHP | 293 lines | 147 code | 18 blank | 128 comment | 25 complexity | 988f994a615109d8467dedbb0a3200e2 MD5 | raw file
Possible License(s): BSD-2-Clause, BSD-3-Clause, LGPL-2.1
  1. <?php
  2. /**
  3. * CWebService class file.
  4. *
  5. * @author Qiang Xue <qiang.xue@gmail.com>
  6. * @link http://www.yiiframework.com/
  7. * @copyright Copyright &copy; 2008-2011 Yii Software LLC
  8. * @license http://www.yiiframework.com/license/
  9. */
  10. /**
  11. * CWebService encapsulates SoapServer and provides a WSDL-based web service.
  12. *
  13. * PHP SOAP extension is required.
  14. *
  15. * CWebService makes use of {@link CWsdlGenerator} and can generate the WSDL
  16. * on-the-fly without requiring you to write complex WSDL. However WSDL generator
  17. * could be customized through {@link generatorConfig} property.
  18. *
  19. * To generate the WSDL based on doc comment blocks in the service provider class,
  20. * call {@link generateWsdl} or {@link renderWsdl}. To process the web service
  21. * requests, call {@link run}.
  22. *
  23. * @property string $methodName The currently requested method name. Empty if no method is being requested.
  24. *
  25. * @author Qiang Xue <qiang.xue@gmail.com>
  26. * @version $Id$
  27. * @package system.web.services
  28. * @since 1.0
  29. */
  30. class CWebService extends CComponent
  31. {
  32. const SOAP_ERROR=1001;
  33. /**
  34. * @var string|object the web service provider class or object.
  35. * If specified as a class name, it can be a path alias.
  36. */
  37. public $provider;
  38. /**
  39. * @var string the URL for WSDL. This is required by {@link run()}.
  40. */
  41. public $wsdlUrl;
  42. /**
  43. * @var string the URL for the Web service. This is required by {@link generateWsdl()} and {@link renderWsdl()}.
  44. */
  45. public $serviceUrl;
  46. /**
  47. * @var integer number of seconds that the generated WSDL can remain valid in cache. Defaults to 0, meaning no caching.
  48. */
  49. public $wsdlCacheDuration=0;
  50. /**
  51. * @var string the ID of the cache application component that is used to cache the generated WSDL.
  52. * Defaults to 'cache' which refers to the primary cache application component.
  53. * Set this property to false if you want to disable caching WSDL.
  54. */
  55. public $cacheID='cache';
  56. /**
  57. * @var string encoding of the Web service. Defaults to 'UTF-8'.
  58. */
  59. public $encoding='UTF-8';
  60. /**
  61. * @var array a list of classes that are declared as complex types in WSDL.
  62. * This should be an array with WSDL types as keys and names of PHP classes as values.
  63. * A PHP class can also be specified as a path alias.
  64. * @see http://www.php.net/manual/en/function.soap-soapserver-construct.php
  65. */
  66. public $classMap=array();
  67. /**
  68. * @var string actor of the SOAP service. Defaults to null, meaning not set.
  69. */
  70. public $actor;
  71. /**
  72. * @var string SOAP version (e.g. '1.1' or '1.2'). Defaults to null, meaning not set.
  73. */
  74. public $soapVersion;
  75. /**
  76. * @var integer the persistence mode of the SOAP server.
  77. * @see http://www.php.net/manual/en/function.soap-soapserver-setpersistence.php
  78. */
  79. public $persistence;
  80. /**
  81. * @var string|array WSDL generator configuration. This property may be useful in purpose of enhancing features
  82. * of the standard {@link CWsdlGenerator} class by extending it. For example, some developers may need support
  83. * of the <code>xsd:xsd:base64Binary</code> elements. Another use case is to change initial values
  84. * at instantiation of the default {@link CWsdlGenerator}. The value of this property will be passed
  85. * to {@link Yii::createComponent} to create the generator object. Default value is 'CWsdlGenerator'.
  86. * @since 1.1.12
  87. */
  88. public $generatorConfig='CWsdlGenerator';
  89. private $_method;
  90. /**
  91. * Constructor.
  92. * @param mixed $provider the web service provider class name or object
  93. * @param string $wsdlUrl the URL for WSDL. This is required by {@link run()}.
  94. * @param string $serviceUrl the URL for the Web service. This is required by {@link generateWsdl()} and {@link renderWsdl()}.
  95. */
  96. public function __construct($provider,$wsdlUrl,$serviceUrl)
  97. {
  98. $this->provider=$provider;
  99. $this->wsdlUrl=$wsdlUrl;
  100. $this->serviceUrl=$serviceUrl;
  101. }
  102. /**
  103. * The PHP error handler.
  104. * @param CErrorEvent $event the PHP error event
  105. */
  106. public function handleError($event)
  107. {
  108. $event->handled=true;
  109. $message=$event->message;
  110. if(YII_DEBUG)
  111. {
  112. $trace=debug_backtrace();
  113. if(isset($trace[2]) && isset($trace[2]['file']) && isset($trace[2]['line']))
  114. $message.=' ('.$trace[2]['file'].':'.$trace[2]['line'].')';
  115. }
  116. throw new CException($message,self::SOAP_ERROR);
  117. }
  118. /**
  119. * Generates and displays the WSDL as defined by the provider.
  120. * @see generateWsdl
  121. */
  122. public function renderWsdl()
  123. {
  124. $wsdl=$this->generateWsdl();
  125. header('Content-Type: text/xml;charset='.$this->encoding);
  126. header('Content-Length: '.(function_exists('mb_strlen') ? mb_strlen($wsdl,'8bit') : strlen($wsdl)));
  127. echo $wsdl;
  128. }
  129. /**
  130. * Generates the WSDL as defined by the provider.
  131. * The cached version may be used if the WSDL is found valid in cache.
  132. * @return string the generated WSDL
  133. * @see wsdlCacheDuration
  134. */
  135. public function generateWsdl()
  136. {
  137. $providerClass=is_object($this->provider) ? get_class($this->provider) : Yii::import($this->provider,true);
  138. if($this->wsdlCacheDuration>0 && $this->cacheID!==false && ($cache=Yii::app()->getComponent($this->cacheID))!==null)
  139. {
  140. $key='Yii.CWebService.'.$providerClass.$this->serviceUrl.$this->encoding;
  141. if(($wsdl=$cache->get($key))!==false)
  142. return $wsdl;
  143. }
  144. $generator=Yii::createComponent($this->generatorConfig);
  145. $wsdl=$generator->generateWsdl($providerClass,$this->serviceUrl,$this->encoding);
  146. if(isset($key))
  147. $cache->set($key,$wsdl,$this->wsdlCacheDuration);
  148. return $wsdl;
  149. }
  150. /**
  151. * Handles the web service request.
  152. */
  153. public function run()
  154. {
  155. header('Content-Type: text/xml;charset='.$this->encoding);
  156. if(YII_DEBUG)
  157. ini_set("soap.wsdl_cache_enabled",0);
  158. $server=new SoapServer($this->wsdlUrl,$this->getOptions());
  159. Yii::app()->attachEventHandler('onError',array($this,'handleError'));
  160. try
  161. {
  162. if($this->persistence!==null)
  163. $server->setPersistence($this->persistence);
  164. if(is_string($this->provider))
  165. $provider=Yii::createComponent($this->provider);
  166. else
  167. $provider=$this->provider;
  168. if(method_exists($server,'setObject'))
  169. $server->setObject($provider);
  170. else
  171. $server->setClass('CSoapObjectWrapper',$provider);
  172. if($provider instanceof IWebServiceProvider)
  173. {
  174. if($provider->beforeWebMethod($this))
  175. {
  176. $server->handle();
  177. $provider->afterWebMethod($this);
  178. }
  179. }
  180. else
  181. $server->handle();
  182. }
  183. catch(Exception $e)
  184. {
  185. if($e->getCode()!==self::SOAP_ERROR) // non-PHP error
  186. {
  187. // only log for non-PHP-error case because application's error handler already logs it
  188. // php <5.2 doesn't support string conversion auto-magically
  189. Yii::log($e->__toString(),CLogger::LEVEL_ERROR,'application');
  190. }
  191. $message=$e->getMessage();
  192. if(YII_DEBUG)
  193. $message.=' ('.$e->getFile().':'.$e->getLine().")\n".$e->getTraceAsString();
  194. // We need to end application explicitly because of
  195. // http://bugs.php.net/bug.php?id=49513
  196. Yii::app()->onEndRequest(new CEvent($this));
  197. $server->fault(get_class($e),$message);
  198. exit(1);
  199. }
  200. }
  201. /**
  202. * @return string the currently requested method name. Empty if no method is being requested.
  203. */
  204. public function getMethodName()
  205. {
  206. if($this->_method===null)
  207. {
  208. if(isset($HTTP_RAW_POST_DATA))
  209. $request=$HTTP_RAW_POST_DATA;
  210. else
  211. $request=file_get_contents('php://input');
  212. if(preg_match('/<.*?:Body[^>]*>\s*<.*?:(\w+)/mi',$request,$matches))
  213. $this->_method=$matches[1];
  214. else
  215. $this->_method='';
  216. }
  217. return $this->_method;
  218. }
  219. /**
  220. * @return array options for creating SoapServer instance
  221. * @see http://www.php.net/manual/en/function.soap-soapserver-construct.php
  222. */
  223. protected function getOptions()
  224. {
  225. $options=array();
  226. if($this->soapVersion==='1.1')
  227. $options['soap_version']=SOAP_1_1;
  228. else if($this->soapVersion==='1.2')
  229. $options['soap_version']=SOAP_1_2;
  230. if($this->actor!==null)
  231. $options['actor']=$this->actor;
  232. $options['encoding']=$this->encoding;
  233. foreach($this->classMap as $type=>$className)
  234. {
  235. $className=Yii::import($className,true);
  236. if(is_int($type))
  237. $type=$className;
  238. $options['classmap'][$type]=$className;
  239. }
  240. return $options;
  241. }
  242. }
  243. /**
  244. * CSoapObjectWrapper is a wrapper class internally used when SoapServer::setObject() is not defined.
  245. *
  246. * @author Qiang Xue <qiang.xue@gmail.com>
  247. * @version $Id$
  248. * @package system.web.services
  249. */
  250. class CSoapObjectWrapper
  251. {
  252. /**
  253. * @var object the service provider
  254. */
  255. public $object=null;
  256. /**
  257. * Constructor.
  258. * @param object $object the service provider
  259. */
  260. public function __construct($object)
  261. {
  262. $this->object=$object;
  263. }
  264. /**
  265. * PHP __call magic method.
  266. * This method calls the service provider to execute the actual logic.
  267. * @param string $name method name
  268. * @param array $arguments method arguments
  269. * @return mixed method return value
  270. */
  271. public function __call($name,$arguments)
  272. {
  273. return call_user_func_array(array($this->object,$name),$arguments);
  274. }
  275. }