123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355 |
- <?php
- /**
- * CWebService class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.yiiframework.com/
- * @copyright 2008-2013 Yii Software LLC
- * @license http://www.yiiframework.com/license/
- */
- /**
- * CWebService encapsulates SoapServer and provides a WSDL-based web service.
- *
- * PHP SOAP extension is required.
- *
- * CWebService makes use of {@link CWsdlGenerator} and can generate the WSDL
- * on-the-fly without requiring you to write complex WSDL. However WSDL generator
- * could be customized through {@link generatorConfig} property.
- *
- * To generate the WSDL based on doc comment blocks in the service provider class,
- * call {@link generateWsdl} or {@link renderWsdl}. To process the web service
- * requests, call {@link run}.
- *
- * @property string $methodName The currently requested method name. Empty if no method is being requested.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @package system.web.services
- * @since 1.0
- */
- class CWebService extends CComponent
- {
- const SOAP_ERROR=1001;
- /**
- * @var string|object the web service provider class or object.
- * If specified as a class name, it can be a path alias.
- */
- public $provider;
- /**
- * @var string the URL for WSDL. This is required by {@link run()}.
- */
- public $wsdlUrl;
- /**
- * @var string the URL for the Web service. This is required by {@link generateWsdl()} and {@link renderWsdl()}.
- */
- public $serviceUrl;
- /**
- * @var integer number of seconds that the generated WSDL can remain valid in cache. Defaults to 0, meaning no caching.
- */
- public $wsdlCacheDuration=0;
- /**
- * @var string the ID of the cache application component that is used to cache the generated WSDL.
- * Defaults to 'cache' which refers to the primary cache application component.
- * Set this property to false if you want to disable caching WSDL.
- */
- public $cacheID='cache';
- /**
- * @var string encoding of the Web service. Defaults to 'UTF-8'.
- */
- public $encoding='UTF-8';
- /**
- * @var array a list of classes that are declared as complex types in WSDL.
- * This should be an array with WSDL types as keys and names of PHP classes as values.
- * A PHP class can also be specified as a path alias.
- * @see http://www.php.net/manual/en/soapserver.soapserver.php
- */
- public $classMap=array();
- /**
- * @var string actor of the SOAP service. Defaults to null, meaning not set.
- */
- public $actor;
- /**
- * @var string SOAP version (e.g. '1.1' or '1.2'). Defaults to null, meaning not set.
- */
- public $soapVersion;
- /**
- * @var integer the persistence mode of the SOAP server.
- * @see http://www.php.net/manual/en/soapserver.setpersistence.php
- */
- public $persistence;
- /**
- * @var string|array WSDL generator configuration. This property may be useful in purpose of enhancing features
- * of the standard {@link CWsdlGenerator} class by extending it. For example, some developers may need support
- * of the <code>xsd:xsd:base64Binary</code> elements. Another use case is to change initial values
- * at instantiation of the default {@link CWsdlGenerator}. The value of this property will be passed
- * to {@link Yii::createComponent} to create the generator object. Default value is 'CWsdlGenerator'.
- * @since 1.1.12
- */
- public $generatorConfig='CWsdlGenerator';
- private $_method;
- /**
- * Constructor.
- * @param mixed $provider the web service provider class name or object
- * @param string $wsdlUrl the URL for WSDL. This is required by {@link run()}.
- * @param string $serviceUrl the URL for the Web service. This is required by {@link generateWsdl()} and {@link renderWsdl()}.
- */
- public function __construct($provider,$wsdlUrl,$serviceUrl)
- {
- $this->provider=$provider;
- $this->wsdlUrl=$wsdlUrl;
- $this->serviceUrl=$serviceUrl;
- }
- /**
- * The PHP error handler.
- * @param CErrorEvent $event the PHP error event
- */
- public function handleError($event)
- {
- $event->handled=true;
- $message=$event->message;
- if(YII_DEBUG)
- {
- $trace=debug_backtrace();
- if(isset($trace[2]) && isset($trace[2]['file']) && isset($trace[2]['line']))
- $message.=' ('.$trace[2]['file'].':'.$trace[2]['line'].')';
- }
- throw new CException($message,self::SOAP_ERROR);
- }
- /**
- * Generates and displays the WSDL as defined by the provider.
- * @see generateWsdl
- */
- public function renderWsdl()
- {
- $wsdl=$this->generateWsdl();
- header('Content-Type: text/xml;charset='.$this->encoding);
- header('Content-Length: '.(function_exists('mb_strlen') ? mb_strlen($wsdl,'8bit') : strlen($wsdl)));
- echo $wsdl;
- }
- /**
- * Generates the WSDL as defined by the provider.
- * The cached version may be used if the WSDL is found valid in cache.
- * @return string the generated WSDL
- * @see wsdlCacheDuration
- */
- public function generateWsdl()
- {
- $providerClass=is_object($this->provider) ? get_class($this->provider) : Yii::import($this->provider,true);
- if($this->wsdlCacheDuration>0 && $this->cacheID!==false && ($cache=Yii::app()->getComponent($this->cacheID))!==null)
- {
- $key='Yii.CWebService.'.$providerClass.$this->serviceUrl.$this->encoding;
- if(($wsdl=$cache->get($key))!==false)
- return $wsdl;
- }
- $generator=Yii::createComponent($this->generatorConfig);
- $wsdl=$generator->generateWsdl($providerClass,$this->serviceUrl,$this->encoding);
- if(isset($key))
- $cache->set($key,$wsdl,$this->wsdlCacheDuration);
- return $wsdl;
- }
- /**
- * Handles the web service request.
- */
- public function run()
- {
- header('Content-Type: text/xml;charset='.$this->encoding);
- if(YII_DEBUG)
- ini_set("soap.wsdl_cache_enabled",0);
- $server=new SoapServer($this->wsdlUrl,$this->getOptions());
- Yii::app()->attachEventHandler('onError',array($this,'handleError'));
- try
- {
- if($this->persistence!==null)
- $server->setPersistence($this->persistence);
- if(is_string($this->provider))
- $provider=Yii::createComponent($this->provider);
- else
- $provider=$this->provider;
- if(method_exists($server,'setObject'))
- {
- if (is_array($this->generatorConfig) && isset($this->generatorConfig['bindingStyle'])
- && $this->generatorConfig['bindingStyle']==='document')
- {
- $server->setObject(new CDocumentSoapObjectWrapper($provider));
- }
- else
- {
- $server->setObject($provider);
- }
- }
- else
- {
- if (is_array($this->generatorConfig) && isset($this->generatorConfig['bindingStyle'])
- && $this->generatorConfig['bindingStyle']==='document')
- {
- $server->setClass('CDocumentSoapObjectWrapper',$provider);
- }
- else
- {
- $server->setClass('CSoapObjectWrapper',$provider);
- }
- }
- if($provider instanceof IWebServiceProvider)
- {
- if($provider->beforeWebMethod($this))
- {
- $server->handle();
- $provider->afterWebMethod($this);
- }
- }
- else
- $server->handle();
- }
- catch(Exception $e)
- {
- if($e->getCode()!==self::SOAP_ERROR) // non-PHP error
- {
- // only log for non-PHP-error case because application's error handler already logs it
- // php <5.2 doesn't support string conversion auto-magically
- Yii::log($e->__toString(),CLogger::LEVEL_ERROR,'application');
- }
- $message=$e->getMessage();
- if(YII_DEBUG)
- $message.=' ('.$e->getFile().':'.$e->getLine().")\n".$e->getTraceAsString();
- // We need to end application explicitly because of
- // http://bugs.php.net/bug.php?id=49513
- Yii::app()->onEndRequest(new CEvent($this));
- $server->fault(get_class($e),$message);
- exit(1);
- }
- }
- /**
- * @return string the currently requested method name. Empty if no method is being requested.
- */
- public function getMethodName()
- {
- if($this->_method===null)
- {
- if(isset($HTTP_RAW_POST_DATA))
- $request=$HTTP_RAW_POST_DATA;
- else
- $request=file_get_contents('php://input');
- if(preg_match('/<.*?:Body[^>]*>\s*<.*?:(\w+)/mi',$request,$matches))
- $this->_method=$matches[1];
- else
- $this->_method='';
- }
- return $this->_method;
- }
- /**
- * @return array options for creating SoapServer instance
- * @see http://www.php.net/manual/en/soapserver.soapserver.php
- */
- protected function getOptions()
- {
- $options=array();
- if($this->soapVersion==='1.1')
- $options['soap_version']=SOAP_1_1;
- elseif($this->soapVersion==='1.2')
- $options['soap_version']=SOAP_1_2;
- if($this->actor!==null)
- $options['actor']=$this->actor;
- $options['encoding']=$this->encoding;
- foreach($this->classMap as $type=>$className)
- {
- $className=Yii::import($className,true);
- if(is_int($type))
- $type=$className;
- $options['classmap'][$type]=$className;
- }
- return $options;
- }
- }
- /**
- * CSoapObjectWrapper is a wrapper class internally used when SoapServer::setObject() is not defined.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @package system.web.services
- */
- class CSoapObjectWrapper
- {
- /**
- * @var object the service provider
- */
- public $object=null;
- /**
- * Constructor.
- * @param object $object the service provider
- */
- public function __construct($object)
- {
- $this->object=$object;
- }
- /**
- * PHP __call magic method.
- * This method calls the service provider to execute the actual logic.
- * @param string $name method name
- * @param array $arguments method arguments
- * @return mixed method return value
- */
- public function __call($name,$arguments)
- {
- return call_user_func_array(array($this->object,$name),$arguments);
- }
- }
- /**
- * CDocumentSoapObjectWrapper is a wrapper class internally used
- * when generatorConfig contains bindingStyle key set to document value.
- *
- * @author Jan Was <jwas@nets.com.pl>
- * @package system.web.services
- */
- class CDocumentSoapObjectWrapper
- {
- /**
- * @var object the service provider
- */
- public $object=null;
- /**
- * Constructor.
- * @param object $object the service provider
- */
- public function __construct($object)
- {
- $this->object=$object;
- }
- /**
- * PHP __call magic method.
- * This method calls the service provider to execute the actual logic.
- * @param string $name method name
- * @param array $arguments method arguments
- * @return mixed method return value
- */
- public function __call($name,$arguments)
- {
- if (is_array($arguments) && isset($arguments[0]))
- {
- $result = call_user_func_array(array($this->object, $name), (array)$arguments[0]);
- }
- else
- {
- $result = call_user_func_array(array($this->object, $name), $arguments);
- }
- return $result === null ? $result : array($name . 'Result' => $result);
- }
- }
|