SoapServer.php
1 <?php
2 /**
3  * wCMF - wemove Content Management Framework
4  * Copyright (C) 2005-2020 wemove digital solutions GmbH
5  *
6  * Licensed under the terms of the MIT License.
7  *
8  * See the LICENSE file distributed with this work for
9  * additional information.
10  */
11 namespace wcmf\lib\service;
12 
19 
20 /**
21  * SoapServer extends nusoap server to actually process
22  * requests inside the application context.
23  *
24  * Soap requests must include credentials in the form of a wsse:UsernameToken header as
25  * described in the WS-Security UsernameToken Profile. Passwords must be sent as plain text
26  * using the PasswordText type and therefore should be sent over a confidential channel.
27  *
28  * @author ingo herwig <ingo@wemove.com>
29  */
30 class SoapServer extends \nusoap_server {
31 
32  const TNS = 'http://wcmf.sourceforge.net';
33 
34  private $application = null;
35  private $serverResponse = '';
36 
37  private static $logger = null;
38 
39  /**
40  * Constructor
41  */
42  public function __construct() {
43  if (self::$logger == null) {
44  self::$logger = LogManager::getLogger(__CLASS__);
45  }
46  $scriptURL = URIUtil::getProtocolStr().$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'];
47  $endpoint = dirname($scriptURL).'/soap';
48  $this->configureWSDL('SOAPService', self::TNS, $endpoint, 'document');
49  $this->wsdl->schemaTargetNamespace = self::TNS;
50  $this->debugLevel = 9;
51 
52  // register default complex types
53  $this->wsdl->addComplexType(
54  'OidList',
55  'complexType',
56  'array',
57  '',
58  'SOAP-ENC:Array',
59  [],
60  [['ref' => 'SOAP-ENC:arrayType', 'wsdl:arrayType' => 'xsd:string[]']],
61  'xsd:string'
62  );
63 
64  $this->wsdl->addComplexType(
65  'SearchResultList',
66  'complexType',
67  'array',
68  '',
69  'SOAP-ENC:Array',
70  [],
71  [['ref' => 'SOAP-ENC:arrayType', 'wsdl:arrayType' => 'tns:SearchResultItem[]']],
72  'tns:SearchResultItem'
73  );
74 
75  $this->wsdl->addComplexType('SearchResultItem', 'complexType', 'struct', 'sequence', '', [
76  'type' => ['name' => 'type', 'type' => 'xsd:string'],
77  'oid' => ['name' => 'oid', 'type' => 'xsd:string'],
78  'displayValue' => ['name' => 'displayValue', 'type' => 'xsd:string'],
79  'summary' => ['name' => 'summary', 'type' => 'xsd:string']
80  ]
81  );
82 
83  // initialize application
84  $this->application = new Application();
85  try {
86  $this->application->initialize();
87  }
88  catch (\Exception $ex) {
89  $this->handleException($ex);
90  }
91  }
92 
93  /**
94  * @see nusoap_server::service
95  */
96  public function service($data) {
97  if (self::$logger->isDebugEnabled()) {
98  self::$logger->debug($data);
99  }
100  try {
101  $oldErrorReporting = error_reporting(E_ALL ^ E_NOTICE ^ E_WARNING);
102  $this->debug_flag = ObjectFactory::getInstance('configuration')->getBooleanValue('debug', 'Application');
103  // call service method, but suppress output
104  ob_start(function($buffer) {
105  $this->serverResponse = $buffer;
106  return '';
107  });
108  parent::service($data);
109  ob_end_clean();
110  error_reporting($oldErrorReporting);
111  if (self::$logger->isDebugEnabled()) {
112  self::$logger->debug($this->serverResponse);
113  }
114  }
115  catch (\Exception $ex) {
116  $this->handleException($ex);
117  }
118  }
119 
120  /**
121  * Get the response headers after a call to the service method
122  * @return Array
123  */
124  public function getResponseHeaders() {
125  $headerStrings = headers_list();
126  header_remove();
127  $headers = [];
128  foreach ($headerStrings as $header) {
129  list($name, $value) = explode(':', $header, 2);
130  $headers[trim($name)] = trim($value);
131  }
132  return $headers;
133  }
134 
135  /**
136  * Get the response payload after a call to the service method
137  * @return String
138  */
139  public function getResponsePayload() {
140  return $this->serverResponse;
141  }
142 
143  /**
144  * Get a dummy object id to be used in a request
145  * @param $type The entity type
146  * @return ObjectId
147  */
148  public function getDummyOid($type) {
149  return new ObjectId($type);
150  }
151 
152  /**
153  * Process a soap call
154  * @param $action The action
155  * @param $params The action parameters
156  * @return The Response instance from the executed Controller
157  */
158  public function doCall($action, $params) {
159  if (self::$logger->isDebugEnabled()) {
160  self::$logger->debug("SoapServer action: ".$action);
161  self::$logger->debug($params);
162  }
163  $authHeader = $this->requestHeader['Security']['UsernameToken'];
164 
165  $request = ObjectFactory::getInstance('request');
166  $request->setAction('actionSet');
167  $request->setFormat('soap');
168  $request->setResponseFormat('null');
169  $request->setValues([
170  'data' => [
171  'action1' => [
172  'action' => 'login',
173  'params' => [
174  'user' => $authHeader['Username'],
175  'password' => $authHeader['Password']['!']
176  ]
177  ],
178  'action2' => [
179  'action' => $action,
180  'params' => $params
181  ],
182  'action3' => [
183  'action' => 'logout'
184  ]
185  ]
186  ]);
187 
188  // run the application
189  $actionResponse = ObjectFactory::getInstance('response');
190  try {
191  $response = $this->application->run($request);
192  if ($response->hasErrors()) {
193  $errors = $response->getErrors();
194  $this->handleException(new ApplicationException($request, $response, $errors[0]));
195  }
196  else {
197  $responseData = $response->getValue('data');
198  $data = $responseData['action2'];
199  $actionResponse->setSender($data['controller']);
200  $actionResponse->setContext($data['context']);
201  $actionResponse->setAction($data['action']);
202  $actionResponse->setFormat('soap');
203  $actionResponse->setValues($data);
204  $formatter = ObjectFactory::getInstance('formatter');
205  $formatter->serialize($actionResponse);
206  if (self::$logger->isDebugEnabled()) {
207  self::$logger->debug($actionResponse->__toString());
208  }
209  }
210  }
211  catch (\Exception $ex) {
212  $this->handleException($ex);
213  }
214  return $actionResponse;
215  }
216 
217  /**
218  * Handle an exception
219  * @param $ex
220  */
221  private function handleException($ex) {
222  self::$logger->error($ex->getMessage()."\n".$ex->getTraceAsString());
223  $this->fault('SOAP-ENV:SERVER', $ex->getMessage(), '', '');
224  }
225 }
226 ?>
getDummyOid($type)
Get a dummy object id to be used in a request.
Definition: SoapServer.php:148
getResponsePayload()
Get the response payload after a call to the service method.
Definition: SoapServer.php:139
ObjectId is the unique identifier of an object.
Definition: ObjectId.php:28
ApplicationException signals a general application exception.
SoapServer extends nusoap server to actually process requests inside the application context.
Definition: SoapServer.php:30
URIUtil provides support for uri manipulation.
Definition: URIUtil.php:18
static getLogger($name)
Get the logger with the given name.
Definition: LogManager.php:37
static getInstance($name, $dynamicConfiguration=[])
Service related interfaces and classes.
Definition: namespaces.php:92
getResponseHeaders()
Get the response headers after a call to the service method.
Definition: SoapServer.php:124
doCall($action, $params)
Process a soap call.
Definition: SoapServer.php:158
LogManager is used to retrieve Logger instances.
Definition: LogManager.php:20
static getProtocolStr()
Definition: URIUtil.php:169
ObjectFactory implements the service locator pattern by wrapping a Factory instance and providing sta...
Application is the main application class, that does all the initialization.
Definition: Application.php:22