File indexing completed on 2024-05-12 06:03:07

0001 <?php
0002 /**
0003  * Zend Framework
0004  *
0005  * LICENSE
0006  *
0007  * This source file is subject to the new BSD license that is bundled
0008  * with this package in the file LICENSE.txt.
0009  * It is also available through the world-wide-web at this URL:
0010  * http://framework.zend.com/license/new-bsd
0011  * If you did not receive a copy of the license and are unable to
0012  * obtain it through the world-wide-web, please send an email
0013  * to license@zend.com so we can send you a copy immediately.
0014  *
0015  * @category   Zend
0016  * @package    Zend_Soap
0017  * @subpackage Server
0018  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0019  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0020  */
0021 
0022 /**
0023  * @see Zend_Server_Interface
0024  */
0025 // require_once 'Zend/Server/Interface.php';
0026 
0027 /** @see Zend_Xml_Security */
0028 // require_once 'Zend/Xml/Security.php';
0029 
0030 /** @see Zend_Xml_Exception */
0031 // require_once 'Zend/Xml/Exception.php';
0032 
0033 /**
0034  * Zend_Soap_Server
0035  *
0036  * @category   Zend
0037  * @package    Zend_Soap
0038  * @subpackage Server
0039  * @uses       Zend_Server_Interface
0040  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0041  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0042  * @version    $Id$
0043  */
0044 class Zend_Soap_Server implements Zend_Server_Interface
0045 {
0046     /**
0047      * Actor URI
0048      * @var string URI
0049      */
0050     protected $_actor;
0051 
0052     /**
0053      * Class registered with this server
0054      * @var string
0055      */
0056     protected $_class;
0057 
0058     /**
0059      * Arguments to pass to {@link $_class} constructor
0060      * @var array
0061      */
0062     protected $_classArgs = array();
0063 
0064     /**
0065      * Object registered with this server
0066      */
0067     protected $_object;
0068 
0069     /**
0070      * Array of SOAP type => PHP class pairings for handling return/incoming values
0071      * @var array
0072      */
0073     protected $_classmap;
0074 
0075     /**
0076      * Encoding
0077      * @var string
0078      */
0079     protected $_encoding;
0080 
0081     /**
0082      * SOAP Server Features
0083      *
0084      * @var int
0085      */
0086     protected $_features;
0087 
0088     /**
0089      * WSDL Caching Options of SOAP Server
0090      *
0091      * @var mixed
0092      */
0093     protected $_wsdlCache;
0094 
0095     /**
0096      * WS-I compliant
0097      * 
0098      * @var boolean 
0099      */
0100     protected $_wsiCompliant;
0101     
0102     /**
0103      * Registered fault exceptions
0104      * @var array
0105      */
0106     protected $_faultExceptions = array();
0107 
0108     /**
0109      * Functions registered with this server; may be either an array or the SOAP_FUNCTIONS_ALL
0110      * constant
0111      * @var array|int
0112      */
0113     protected $_functions = array();
0114 
0115     /**
0116      * Persistence mode; should be one of the SOAP persistence constants
0117      * @var int
0118      */
0119     protected $_persistence;
0120 
0121     /**
0122      * Request XML
0123      * @var string
0124      */
0125     protected $_request;
0126 
0127     /**
0128      * Response XML
0129      * @var string
0130      */
0131     protected $_response;
0132 
0133     /**
0134      * Flag: whether or not {@link handle()} should return a response instead
0135      * of automatically emitting it.
0136      * @var boolean
0137      */
0138     protected $_returnResponse = false;
0139 
0140     /**
0141      * SOAP version to use; SOAP_1_2 by default, to allow processing of headers
0142      * @var int
0143      */
0144     protected $_soapVersion = SOAP_1_2;
0145 
0146     /**
0147      * URI or path to WSDL
0148      * @var string
0149      */
0150     protected $_wsdl;
0151 
0152     /**
0153      * URI namespace for SOAP server
0154      * @var string URI
0155      */
0156     protected $_uri;
0157 
0158     /**
0159      * Constructor
0160      *
0161      * Sets display_errors INI setting to off (prevent client errors due to bad
0162      * XML in response). Registers {@link handlePhpErrors()} as error handler
0163      * for E_USER_ERROR.
0164      *
0165      * If $wsdl is provided, it is passed on to {@link setWsdl()}; if any
0166      * options are specified, they are passed on to {@link setOptions()}.
0167      *
0168      * @param string $wsdl
0169      * @param array $options
0170      * @return void
0171      */
0172     public function __construct($wsdl = null, array $options = null)
0173     {
0174         if (!extension_loaded('soap')) {
0175             // require_once 'Zend/Soap/Server/Exception.php';
0176             throw new Zend_Soap_Server_Exception('SOAP extension is not loaded.');
0177         }
0178 
0179         if (null !== $wsdl) {
0180             $this->setWsdl($wsdl);
0181         }
0182 
0183         if (null !== $options) {
0184             $this->setOptions($options);
0185         }
0186     }
0187 
0188     /**
0189      * Set Options
0190      *
0191      * Allows setting options as an associative array of option => value pairs.
0192      *
0193      * @param  array|Zend_Config $options
0194      * @return Zend_Soap_Server
0195      */
0196     public function setOptions($options)
0197     {
0198         if($options instanceof Zend_Config) {
0199             $options = $options->toArray();
0200         }
0201 
0202         foreach ($options as $key => $value) {
0203             switch ($key) {
0204                 case 'actor':
0205                     $this->setActor($value);
0206                     break;
0207                 case 'classmap':
0208                 case 'classMap':
0209                     $this->setClassmap($value);
0210                     break;
0211                 case 'encoding':
0212                     $this->setEncoding($value);
0213                     break;
0214                 case 'soapVersion':
0215                 case 'soap_version':
0216                     $this->setSoapVersion($value);
0217                     break;
0218                 case 'uri':
0219                     $this->setUri($value);
0220                     break;
0221                 case 'wsdl':
0222                     $this->setWsdl($value);
0223                     break;
0224                 case 'featues':
0225                     trigger_error(__METHOD__ . ': the option "featues" is deprecated as of 1.10.x and will be removed with 2.0.0; use "features" instead', E_USER_NOTICE);
0226                 case 'features':
0227                     $this->setSoapFeatures($value);
0228                     break;
0229                 case 'cache_wsdl':
0230                     $this->setWsdlCache($value);
0231                     break;
0232                 case 'wsi_compliant':
0233                     $this->setWsiCompliant($value);
0234                     break;
0235                 default:
0236                     break;
0237             }
0238         }
0239 
0240         return $this;
0241     }
0242 
0243     /**
0244      * Return array of options suitable for using with SoapServer constructor
0245      *
0246      * @return array
0247      */
0248     public function getOptions()
0249     {
0250         $options = array();
0251         if (null !== $this->_actor) {
0252             $options['actor'] = $this->_actor;
0253         }
0254 
0255         if (null !== $this->_classmap) {
0256             $options['classmap'] = $this->_classmap;
0257         }
0258 
0259         if (null !== $this->_encoding) {
0260             $options['encoding'] = $this->_encoding;
0261         }
0262 
0263         if (null !== $this->_soapVersion) {
0264             $options['soap_version'] = $this->_soapVersion;
0265         }
0266 
0267         if (null !== $this->_uri) {
0268             $options['uri'] = $this->_uri;
0269         }
0270 
0271         if (null !== $this->_features) {
0272             $options['features'] = $this->_features;
0273         }
0274 
0275         if (null !== $this->_wsdlCache) {
0276             $options['cache_wsdl'] = $this->_wsdlCache;
0277         }
0278 
0279         if (null !== $this->_wsiCompliant) {
0280             $options['wsi_compliant'] = $this->_wsiCompliant;
0281         }
0282         
0283         return $options;
0284     }
0285     /**
0286      * Set WS-I compliant
0287      * 
0288      * @param  boolean $value
0289      * @return Zend_Soap_Server 
0290      */
0291     public function setWsiCompliant($value)
0292     {
0293         if (is_bool($value)) {
0294             $this->_wsiCompliant = $value;
0295         }
0296         return $this;
0297     }
0298     /**
0299      * Gt WS-I compliant
0300      * 
0301      * @return boolean
0302      */
0303     public function getWsiCompliant() 
0304     {
0305         return $this->_wsiCompliant;
0306     }
0307     /**
0308      * Set encoding
0309      *
0310      * @param  string $encoding
0311      * @return Zend_Soap_Server
0312      * @throws Zend_Soap_Server_Exception with invalid encoding argument
0313      */
0314     public function setEncoding($encoding)
0315     {
0316         if (!is_string($encoding)) {
0317             // require_once 'Zend/Soap/Server/Exception.php';
0318             throw new Zend_Soap_Server_Exception('Invalid encoding specified');
0319         }
0320 
0321         $this->_encoding = $encoding;
0322         return $this;
0323     }
0324 
0325     /**
0326      * Get encoding
0327      *
0328      * @return string
0329      */
0330     public function getEncoding()
0331     {
0332         return $this->_encoding;
0333     }
0334 
0335     /**
0336      * Set SOAP version
0337      *
0338      * @param  int $version One of the SOAP_1_1 or SOAP_1_2 constants
0339      * @return Zend_Soap_Server
0340      * @throws Zend_Soap_Server_Exception with invalid soap version argument
0341      */
0342     public function setSoapVersion($version)
0343     {
0344         if (!in_array($version, array(SOAP_1_1, SOAP_1_2))) {
0345             // require_once 'Zend/Soap/Server/Exception.php';
0346             throw new Zend_Soap_Server_Exception('Invalid soap version specified');
0347         }
0348 
0349         $this->_soapVersion = $version;
0350         return $this;
0351     }
0352 
0353     /**
0354      * Get SOAP version
0355      *
0356      * @return int
0357      */
0358     public function getSoapVersion()
0359     {
0360         return $this->_soapVersion;
0361     }
0362 
0363     /**
0364      * Check for valid URN
0365      *
0366      * @param  string $urn
0367      * @return true
0368      * @throws Zend_Soap_Server_Exception on invalid URN
0369      */
0370     public function validateUrn($urn)
0371     {
0372         $scheme = parse_url($urn, PHP_URL_SCHEME);
0373         if ($scheme === false || $scheme === null) {
0374             // require_once 'Zend/Soap/Server/Exception.php';
0375             throw new Zend_Soap_Server_Exception('Invalid URN');
0376         }
0377 
0378         return true;
0379     }
0380 
0381     /**
0382      * Set actor
0383      *
0384      * Actor is the actor URI for the server.
0385      *
0386      * @param  string $actor
0387      * @return Zend_Soap_Server
0388      */
0389     public function setActor($actor)
0390     {
0391         $this->validateUrn($actor);
0392         $this->_actor = $actor;
0393         return $this;
0394     }
0395 
0396     /**
0397      * Retrieve actor
0398      *
0399      * @return string
0400      */
0401     public function getActor()
0402     {
0403         return $this->_actor;
0404     }
0405 
0406     /**
0407      * Set URI
0408      *
0409      * URI in SoapServer is actually the target namespace, not a URI; $uri must begin with 'urn:'.
0410      *
0411      * @param  string $uri
0412      * @return Zend_Soap_Server
0413      * @throws Zend_Soap_Server_Exception with invalid uri argument
0414      */
0415     public function setUri($uri)
0416     {
0417         $this->validateUrn($uri);
0418         $this->_uri = $uri;
0419         return $this;
0420     }
0421 
0422     /**
0423      * Retrieve URI
0424      *
0425      * @return string
0426      */
0427     public function getUri()
0428     {
0429         return $this->_uri;
0430     }
0431 
0432     /**
0433      * Set classmap
0434      *
0435      * @param  array $classmap
0436      * @return Zend_Soap_Server
0437      * @throws Zend_Soap_Server_Exception for any invalid class in the class map
0438      */
0439     public function setClassmap($classmap)
0440     {
0441         if (!is_array($classmap)) {
0442             /**
0443              * @see Zend_Soap_Server_Exception
0444              */
0445             // require_once 'Zend/Soap/Server/Exception.php';
0446             throw new Zend_Soap_Server_Exception('Classmap must be an array');
0447         }
0448         foreach ($classmap as $type => $class) {
0449             if (!class_exists($class)) {
0450                 /**
0451                  * @see Zend_Soap_Server_Exception
0452                  */
0453                 // require_once 'Zend/Soap/Server/Exception.php';
0454                 throw new Zend_Soap_Server_Exception('Invalid class in class map');
0455             }
0456         }
0457 
0458         $this->_classmap = $classmap;
0459         return $this;
0460     }
0461 
0462     /**
0463      * Retrieve classmap
0464      *
0465      * @return mixed
0466      */
0467     public function getClassmap()
0468     {
0469         return $this->_classmap;
0470     }
0471 
0472     /**
0473      * Set wsdl
0474      *
0475      * @param string $wsdl  URI or path to a WSDL
0476      * @return Zend_Soap_Server
0477      */
0478     public function setWsdl($wsdl)
0479     {
0480         $this->_wsdl = $wsdl;
0481         return $this;
0482     }
0483 
0484     /**
0485      * Retrieve wsdl
0486      *
0487      * @return string
0488      */
0489     public function getWsdl()
0490     {
0491         return $this->_wsdl;
0492     }
0493 
0494     /**
0495      * Set the SOAP Feature options.
0496      *
0497      * @param  string|int $feature
0498      * @return Zend_Soap_Server
0499      */
0500     public function setSoapFeatures($feature)
0501     {
0502         $this->_features = $feature;
0503         return $this;
0504     }
0505 
0506     /**
0507      * Return current SOAP Features options
0508      *
0509      * @return int
0510      */
0511     public function getSoapFeatures()
0512     {
0513         return $this->_features;
0514     }
0515 
0516     /**
0517      * Set the SOAP Wsdl Caching Options
0518      *
0519      * @param string|int|boolean $caching
0520      * @return Zend_Soap_Server
0521      */
0522     public function setWsdlCache($options)
0523     {
0524         $this->_wsdlCache = $options;
0525         return $this;
0526     }
0527 
0528     /**
0529      * Get current SOAP Wsdl Caching option
0530      */
0531     public function getWsdlCache()
0532     {
0533         return $this->_wsdlCache;
0534     }
0535 
0536     /**
0537      * Attach a function as a server method
0538      *
0539      * @param array|string $function Function name, array of function names to attach,
0540      * or SOAP_FUNCTIONS_ALL to attach all functions
0541      * @param  string $namespace Ignored
0542      * @return Zend_Soap_Server
0543      * @throws Zend_Soap_Server_Exception on invalid functions
0544      */
0545     public function addFunction($function, $namespace = '')
0546     {
0547         // Bail early if set to SOAP_FUNCTIONS_ALL
0548         if ($this->_functions == SOAP_FUNCTIONS_ALL) {
0549             return $this;
0550         }
0551 
0552         if (is_array($function)) {
0553             foreach ($function as $func) {
0554                 if (is_string($func) && function_exists($func)) {
0555                     $this->_functions[] = $func;
0556                 } else {
0557                     // require_once 'Zend/Soap/Server/Exception.php';
0558                     throw new Zend_Soap_Server_Exception('One or more invalid functions specified in array');
0559                 }
0560             }
0561             $this->_functions = array_merge($this->_functions, $function);
0562         } elseif (is_string($function) && function_exists($function)) {
0563             $this->_functions[] = $function;
0564         } elseif ($function == SOAP_FUNCTIONS_ALL) {
0565             $this->_functions = SOAP_FUNCTIONS_ALL;
0566         } else {
0567             // require_once 'Zend/Soap/Server/Exception.php';
0568             throw new Zend_Soap_Server_Exception('Invalid function specified');
0569         }
0570 
0571         if (is_array($this->_functions)) {
0572             $this->_functions = array_unique($this->_functions);
0573         }
0574 
0575         return $this;
0576     }
0577 
0578     /**
0579      * Attach a class to a server
0580      *
0581      * Accepts a class name to use when handling requests. Any additional
0582      * arguments will be passed to that class' constructor when instantiated.
0583      *
0584      * See {@link setObject()} to set preconfigured object instances as request handlers.
0585      *
0586      * @param string $class Class Name which executes SOAP Requests at endpoint.
0587      * @return Zend_Soap_Server
0588      * @throws Zend_Soap_Server_Exception if called more than once, or if class
0589      * does not exist
0590      */
0591     public function setClass($class, $namespace = '', $argv = null)
0592     {
0593         if (isset($this->_class)) {
0594             // require_once 'Zend/Soap/Server/Exception.php';
0595             throw new Zend_Soap_Server_Exception('A class has already been registered with this soap server instance');
0596         }
0597 
0598         if (!is_string($class)) {
0599             // require_once 'Zend/Soap/Server/Exception.php';
0600             throw new Zend_Soap_Server_Exception('Invalid class argument (' . gettype($class) . ')');
0601         }
0602 
0603         if (!class_exists($class)) {
0604             // require_once 'Zend/Soap/Server/Exception.php';
0605             throw new Zend_Soap_Server_Exception('Class "' . $class . '" does not exist');
0606         }
0607 
0608         $this->_class = $class;
0609         if (1 < func_num_args()) {
0610             $argv = func_get_args();
0611             array_shift($argv);
0612             $this->_classArgs = $argv;
0613         }
0614 
0615         return $this;
0616     }
0617 
0618     /**
0619      * Attach an object to a server
0620      *
0621      * Accepts an instanciated object to use when handling requests.
0622      *
0623      * @param object $object
0624      * @return Zend_Soap_Server
0625      */
0626     public function setObject($object)
0627     {
0628         if(!is_object($object)) {
0629             // require_once 'Zend/Soap/Server/Exception.php';
0630             throw new Zend_Soap_Server_Exception('Invalid object argument ('.gettype($object).')');
0631         }
0632 
0633         if(isset($this->_object)) {
0634             // require_once 'Zend/Soap/Server/Exception.php';
0635             throw new Zend_Soap_Server_Exception('An object has already been registered with this soap server instance');
0636         }
0637 
0638         if ($this->_wsiCompliant) {
0639             // require_once 'Zend/Soap/Server/Proxy.php';
0640             $this->_object = new Zend_Soap_Server_Proxy($object);
0641         } else {
0642             $this->_object = $object;
0643         }    
0644 
0645         return $this;
0646     }
0647 
0648     /**
0649      * Return a server definition array
0650      *
0651      * Returns a list of all functions registered with {@link addFunction()},
0652      * merged with all public methods of the class set with {@link setClass()}
0653      * (if any).
0654      *
0655      * @access public
0656      * @return array
0657      */
0658     public function getFunctions()
0659     {
0660         $functions = array();
0661         if (null !== $this->_class) {
0662             $functions = get_class_methods($this->_class);
0663         } elseif (null !== $this->_object) {
0664             $functions = get_class_methods($this->_object);
0665         }
0666 
0667         return array_merge((array) $this->_functions, $functions);
0668     }
0669 
0670     /**
0671      * Unimplemented: Load server definition
0672      *
0673      * @param array $array
0674      * @return void
0675      * @throws Zend_Soap_Server_Exception Unimplemented
0676      */
0677     public function loadFunctions($definition)
0678     {
0679         // require_once 'Zend/Soap/Server/Exception.php';
0680         throw new Zend_Soap_Server_Exception('Unimplemented');
0681     }
0682 
0683     /**
0684      * Set server persistence
0685      *
0686      * @param int $mode
0687      * @return Zend_Soap_Server
0688      */
0689     public function setPersistence($mode)
0690     {
0691         if (!in_array($mode, array(SOAP_PERSISTENCE_SESSION, SOAP_PERSISTENCE_REQUEST))) {
0692             // require_once 'Zend/Soap/Server/Exception.php';
0693             throw new Zend_Soap_Server_Exception('Invalid persistence mode specified');
0694         }
0695 
0696         $this->_persistence = $mode;
0697         return $this;
0698     }
0699 
0700     /**
0701      * Get server persistence
0702      *
0703      * @return Zend_Soap_Server
0704      */
0705     public function getPersistence()
0706     {
0707         return $this->_persistence;
0708     }
0709 
0710     /**
0711      * Set request
0712      *
0713      * $request may be any of:
0714      * - DOMDocument; if so, then cast to XML
0715      * - DOMNode; if so, then grab owner document and cast to XML
0716      * - SimpleXMLElement; if so, then cast to XML
0717      * - stdClass; if so, calls __toString() and verifies XML
0718      * - string; if so, verifies XML
0719      *
0720      * @param DOMDocument|DOMNode|SimpleXMLElement|stdClass|string $request
0721      * @return Zend_Soap_Server
0722      */
0723     protected function _setRequest($request)
0724     {
0725         if ($request instanceof DOMDocument) {
0726             $xml = $request->saveXML();
0727         } elseif ($request instanceof DOMNode) {
0728             $xml = $request->ownerDocument->saveXML();
0729         } elseif ($request instanceof SimpleXMLElement) {
0730             $xml = $request->asXML();
0731         } elseif (is_object($request) || is_string($request)) {
0732             if (is_object($request)) {
0733                 $xml = $request->__toString();
0734             } else {
0735                 $xml = $request;
0736             }
0737 
0738             $dom = new DOMDocument();
0739             try {
0740                 if(strlen($xml) == 0 || (!$dom = Zend_Xml_Security::scan($xml, $dom))) {
0741                     // require_once 'Zend/Soap/Server/Exception.php';
0742                     throw new Zend_Soap_Server_Exception('Invalid XML');
0743                 }
0744             } catch (Zend_Xml_Exception $e) {
0745                 // require_once 'Zend/Soap/Server/Exception.php';
0746                 throw new Zend_Soap_Server_Exception(
0747                     $e->getMessage()
0748                 );
0749             }
0750         }
0751         $this->_request = $xml;
0752         return $this;
0753     }
0754 
0755     /**
0756      * Retrieve request XML
0757      *
0758      * @return string
0759      */
0760     public function getLastRequest()
0761     {
0762         return $this->_request;
0763     }
0764 
0765     /**
0766      * Set return response flag
0767      *
0768      * If true, {@link handle()} will return the response instead of
0769      * automatically sending it back to the requesting client.
0770      *
0771      * The response is always available via {@link getResponse()}.
0772      *
0773      * @param boolean $flag
0774      * @return Zend_Soap_Server
0775      */
0776     public function setReturnResponse($flag)
0777     {
0778         $this->_returnResponse = ($flag) ? true : false;
0779         return $this;
0780     }
0781 
0782     /**
0783      * Retrieve return response flag
0784      *
0785      * @return boolean
0786      */
0787     public function getReturnResponse()
0788     {
0789         return $this->_returnResponse;
0790     }
0791 
0792     /**
0793      * Get response XML
0794      *
0795      * @return string
0796      */
0797     public function getLastResponse()
0798     {
0799         return $this->_response;
0800     }
0801 
0802     /**
0803      * Get SoapServer object
0804      *
0805      * Uses {@link $_wsdl} and return value of {@link getOptions()} to instantiate
0806      * SoapServer object, and then registers any functions or class with it, as
0807      * well as peristence.
0808      *
0809      * @return SoapServer
0810      */
0811     protected function _getSoap()
0812     {
0813         $options = $this->getOptions();
0814         $server  = new SoapServer($this->_wsdl, $options);
0815 
0816         if (!empty($this->_functions)) {
0817             $server->addFunction($this->_functions);
0818         }
0819 
0820         if (!empty($this->_class)) {
0821             $args = $this->_classArgs;
0822             array_unshift($args, $this->_class);
0823             if ($this->_wsiCompliant) {
0824                 // require_once 'Zend/Soap/Server/Proxy.php';
0825                 array_unshift($args, 'Zend_Soap_Server_Proxy');
0826             } 
0827             call_user_func_array(array($server, 'setClass'), $args);
0828         }
0829 
0830         if (!empty($this->_object)) {
0831             $server->setObject($this->_object);
0832         }
0833 
0834         if (null !== $this->_persistence) {
0835             $server->setPersistence($this->_persistence);
0836         }
0837 
0838         return $server;
0839     }
0840 
0841     /**
0842      * Handle a request
0843      *
0844      * Instantiates SoapServer object with options set in object, and
0845      * dispatches its handle() method.
0846      *
0847      * $request may be any of:
0848      * - DOMDocument; if so, then cast to XML
0849      * - DOMNode; if so, then grab owner document and cast to XML
0850      * - SimpleXMLElement; if so, then cast to XML
0851      * - stdClass; if so, calls __toString() and verifies XML
0852      * - string; if so, verifies XML
0853      *
0854      * If no request is passed, pulls request using php:://input (for
0855      * cross-platform compatability purposes).
0856      *
0857      * @param DOMDocument|DOMNode|SimpleXMLElement|stdClass|string $request Optional request
0858      * @return void|string
0859      */
0860     public function handle($request = null)
0861     {
0862         if (null === $request) {
0863             $request = file_get_contents('php://input');
0864         }
0865 
0866         // Set Zend_Soap_Server error handler
0867         $displayErrorsOriginalState = $this->_initializeSoapErrorContext();
0868 
0869         $setRequestException = null;
0870         /**
0871          * @see Zend_Soap_Server_Exception
0872          */
0873         // require_once 'Zend/Soap/Server/Exception.php';
0874         try {
0875             $this->_setRequest($request);
0876         } catch (Zend_Soap_Server_Exception $e) {
0877             $setRequestException = $e;
0878         }
0879         
0880         $soap = $this->_getSoap();
0881 
0882         $fault = false;
0883         ob_start();
0884         if ($setRequestException instanceof Exception) {
0885             // Create SOAP fault message if we've caught a request exception
0886             $fault = $this->fault($setRequestException->getMessage(), 'Sender');
0887         } else {
0888             try {
0889                 $soap->handle($this->_request);
0890             } catch (Exception $e) {
0891                 $fault = $this->fault($e);
0892             }
0893         }
0894         $this->_response = ob_get_clean();
0895 
0896         // Restore original error handler
0897         restore_error_handler();
0898         ini_set('display_errors', $displayErrorsOriginalState);
0899 
0900         // Send a fault, if we have one
0901         if ($fault) {
0902             $soap->fault($fault->faultcode, $fault->faultstring);
0903         }
0904 
0905         if (!$this->_returnResponse) {
0906             echo $this->_response;
0907             return;
0908         }
0909 
0910         return $this->_response;
0911     }
0912 
0913     /**
0914      * Method initalizes the error context that the SOAPServer enviroment will run in.
0915      *
0916      * @return boolean display_errors original value
0917      */
0918     protected function _initializeSoapErrorContext()
0919     {
0920         $displayErrorsOriginalState = ini_get('display_errors');
0921         ini_set('display_errors', false);
0922         set_error_handler(array($this, 'handlePhpErrors'), E_USER_ERROR);
0923         return $displayErrorsOriginalState;
0924     }
0925 
0926     /**
0927      * Register a valid fault exception
0928      *
0929      * @param  string|array $class Exception class or array of exception classes
0930      * @return Zend_Soap_Server
0931      */
0932     public function registerFaultException($class)
0933     {
0934         $this->_faultExceptions = array_merge($this->_faultExceptions, (array) $class);
0935         return $this;
0936     }
0937 
0938     /**
0939      * Deregister a fault exception from the fault exception stack
0940      *
0941      * @param  string $class
0942      * @return boolean
0943      */
0944     public function deregisterFaultException($class)
0945     {
0946         if (in_array($class, $this->_faultExceptions, true)) {
0947             $index = array_search($class, $this->_faultExceptions);
0948             unset($this->_faultExceptions[$index]);
0949             return true;
0950         }
0951 
0952         return false;
0953     }
0954 
0955     /**
0956      * Return fault exceptions list
0957      *
0958      * @return array
0959      */
0960     public function getFaultExceptions()
0961     {
0962         return $this->_faultExceptions;
0963     }
0964 
0965     /**
0966      * Generate a server fault
0967      *
0968      * Note that the arguments are reverse to those of SoapFault.
0969      *
0970      * If an exception is passed as the first argument, its message and code
0971      * will be used to create the fault object if it has been registered via
0972      * {@Link registerFaultException()}.
0973      *
0974      * @link   http://www.w3.org/TR/soap12-part1/#faultcodes
0975      * @param  string|Exception $fault
0976      * @param  string $code SOAP Fault Codes
0977      * @return SoapFault
0978      */
0979     public function fault($fault = null, $code = "Receiver")
0980     {
0981         if ($fault instanceof Exception) {
0982             $class = get_class($fault);
0983             if (in_array($class, $this->_faultExceptions)) {
0984                 $message = $fault->getMessage();
0985                 $eCode   = $fault->getCode();
0986                 $code    = empty($eCode) ? $code : $eCode;
0987             } else {
0988                 $message = 'Unknown error';
0989             }
0990         } elseif(is_string($fault)) {
0991             $message = $fault;
0992         } else {
0993             $message = 'Unknown error';
0994         }
0995 
0996         $allowedFaultModes = array(
0997             'VersionMismatch', 'MustUnderstand', 'DataEncodingUnknown',
0998             'Sender', 'Receiver', 'Server'
0999         );
1000         if(!in_array($code, $allowedFaultModes)) {
1001             $code = "Receiver";
1002         }
1003 
1004         return new SoapFault($code, $message);
1005     }
1006 
1007     /**
1008      * Throw PHP errors as SoapFaults
1009      *
1010      * @param int $errno
1011      * @param string $errstr
1012      * @param string $errfile
1013      * @param int $errline
1014      * @param array $errcontext
1015      * @return void
1016      * @throws SoapFault
1017      */
1018     public function handlePhpErrors($errno, $errstr, $errfile = null, $errline = null, array $errcontext = null)
1019     {
1020         throw $this->fault($errstr, "Receiver");
1021     }
1022 }