Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
| 1 | <?php |
||
| 33 | class SoapHeader4 extends Base |
||
| 34 | { |
||
| 35 | /** |
||
| 36 | * XPATH query to retrieve the SOAPAction from the WSDL for a given message. |
||
| 37 | * |
||
| 38 | * @var string |
||
| 39 | */ |
||
| 40 | const XPATH_OPERATION_ACTION = 'string(//wsdl:operation[./@name="%s"]/soap:operation/@soapAction)'; |
||
| 41 | /** |
||
| 42 | * XPATH query to retrieve the server endpoint from the WSDL. |
||
| 43 | * |
||
| 44 | * @var string |
||
| 45 | */ |
||
| 46 | const XPATH_ENDPOINT = 'string(/wsdl:definitions/wsdl:service/wsdl:port/soap:address/@location)'; |
||
| 47 | |||
| 48 | |||
| 49 | /** |
||
| 50 | * Switch between stateful & stateless sessions. Default: stateful |
||
| 51 | * |
||
| 52 | * @var bool |
||
| 53 | */ |
||
| 54 | protected $isStateful = true; |
||
| 55 | |||
| 56 | protected $enableTransactionFlowLink = false; |
||
| 57 | |||
| 58 | /** |
||
| 59 | * TransactionFlowLink Consumer ID |
||
| 60 | * |
||
| 61 | * @var string|null |
||
| 62 | */ |
||
| 63 | protected $consumerId; |
||
| 64 | |||
| 65 | /** |
||
| 66 | * @param bool $stateful |
||
| 67 | */ |
||
| 68 | 184 | public function setStateful($stateful) |
|
| 72 | |||
| 73 | /** |
||
| 74 | * Check whether we are running in stateful mode (true) or in stateless mode (false) |
||
| 75 | * |
||
| 76 | * @return bool |
||
| 77 | */ |
||
| 78 | 76 | public function isStateful() |
|
| 82 | |||
| 83 | /** |
||
| 84 | * Is the TransactionFlowLink header enabled? |
||
| 85 | * |
||
| 86 | * @return bool |
||
| 87 | */ |
||
| 88 | 52 | public function isTransactionFlowLinkEnabled() |
|
| 92 | |||
| 93 | /** |
||
| 94 | * Enable or disable TransactionFlowLink header |
||
| 95 | * |
||
| 96 | * @param bool $enabled |
||
| 97 | */ |
||
| 98 | 184 | public function setTransactionFlowLink($enabled) |
|
| 102 | |||
| 103 | /** |
||
| 104 | * Get the TransactionFlowLink Consumer ID |
||
| 105 | * |
||
| 106 | * @param bool $generate Whether to generate a consumer ID |
||
| 107 | * @return string|null |
||
| 108 | */ |
||
| 109 | 12 | public function getConsumerId($generate = false) |
|
| 117 | |||
| 118 | /** |
||
| 119 | * Set the TransactionFlowLink Consumer ID |
||
| 120 | * |
||
| 121 | * @param string $id |
||
| 122 | * @return void |
||
| 123 | */ |
||
| 124 | 184 | public function setConsumerId($id) |
|
| 128 | |||
| 129 | /** |
||
| 130 | * Handles authentication & sessions |
||
| 131 | * |
||
| 132 | * If authenticated, increment sequence number for next message and set session info to soapheader |
||
| 133 | * If not, set auth info to soapheader |
||
| 134 | * |
||
| 135 | * @uses $this->isAuthenticated |
||
| 136 | * @uses $this->sessionData |
||
| 137 | * @param string $messageName |
||
| 138 | * @param array $messageOptions |
||
| 139 | */ |
||
| 140 | 32 | protected function prepareForNextMessage($messageName, $messageOptions) |
|
| 151 | |||
| 152 | |||
| 153 | /** |
||
| 154 | * Handles post message actions |
||
| 155 | * |
||
| 156 | * - look for session info and set status variables |
||
| 157 | * - checks for message errors? |
||
| 158 | * - ends terminated sessions |
||
| 159 | * |
||
| 160 | * @param string $messageName |
||
| 161 | * @param string $lastResponse |
||
| 162 | * @param array $messageOptions |
||
| 163 | * @param mixed $result |
||
| 164 | * @return void |
||
| 165 | */ |
||
| 166 | 32 | protected function handlePostMessage($messageName, $lastResponse, $messageOptions, $result) |
|
| 179 | |||
| 180 | /** |
||
| 181 | * @param string $responseMsg the full response XML received. |
||
| 182 | * @return array |
||
| 183 | */ |
||
| 184 | 20 | protected function getSessionDataFromHeader($responseMsg) |
|
| 218 | |||
| 219 | /** |
||
| 220 | * Create the Soap Headers to be used on the subsequent request. |
||
| 221 | * |
||
| 222 | * This depends on the current Session Data (if there is an active session) and |
||
| 223 | * the Session Handler parameters (to create a new or stateless session) |
||
| 224 | * |
||
| 225 | * You can also terminate the session with $doEndSession = true |
||
| 226 | * |
||
| 227 | * @param array $sessionData |
||
| 228 | * @param Client\Params\SessionHandlerParams $params |
||
| 229 | * @param string $messageName |
||
| 230 | * @param array $messageOptions |
||
| 231 | * @return \SoapHeader[]|null |
||
|
|
|||
| 232 | */ |
||
| 233 | 52 | protected function createSoapHeaders($sessionData, $params, $messageName, $messageOptions) |
|
| 234 | { |
||
| 235 | 52 | $headersToSet = []; |
|
| 236 | |||
| 237 | 52 | $wsdlId = $this->getWsdlIdFor($messageName); |
|
| 238 | 52 | $wsdl = WsdlAnalyser::$wsdlIds[$wsdlId]; |
|
| 239 | |||
| 240 | //CHECK STATEFUL |
||
| 241 | 52 | $stateful = $this->isStateful(); |
|
| 242 | |||
| 243 | //Message ID header |
||
| 244 | 52 | array_push( |
|
| 245 | 52 | $headersToSet, |
|
| 246 | 52 | new \SoapHeader( |
|
| 247 | 52 | 'http://www.w3.org/2005/08/addressing', |
|
| 248 | 52 | 'MessageID', |
|
| 249 | 52 | $this->generateGuid() |
|
| 250 | 26 | ) |
|
| 251 | 26 | ); |
|
| 252 | |||
| 253 | //Action header |
||
| 254 | 52 | array_push( |
|
| 255 | 52 | $headersToSet, |
|
| 256 | 52 | new \SoapHeader( |
|
| 257 | 52 | 'http://www.w3.org/2005/08/addressing', |
|
| 258 | 52 | 'Action', |
|
| 259 | 52 | $this->getActionFromWsdl($wsdl, $messageName) |
|
| 260 | 26 | ) |
|
| 261 | 26 | ); |
|
| 262 | |||
| 263 | //To header |
||
| 264 | 52 | array_push( |
|
| 265 | 52 | $headersToSet, |
|
| 266 | 52 | new \SoapHeader( |
|
| 267 | 52 | 'http://www.w3.org/2005/08/addressing', |
|
| 268 | 52 | 'To', |
|
| 269 | 52 | $this->getEndpointFromWsdl($wsdl, $messageName) |
|
| 270 | 26 | ) |
|
| 271 | 26 | ); |
|
| 272 | |||
| 273 | //TransactionFlowLink header |
||
| 274 | 52 | $tfl = $this->isTransactionFlowLinkEnabled(); |
|
| 275 | 52 | if ($tfl) { |
|
| 276 | 8 | $consumerId = $this->getConsumerId(true); |
|
| 277 | |||
| 278 | 8 | array_push( |
|
| 279 | 8 | $headersToSet, |
|
| 280 | 8 | new \SoapHeader( |
|
| 281 | 8 | 'http://wsdl.amadeus.com/2010/06/ws/Link_v1', |
|
| 282 | 8 | 'TransactionFlowLink', |
|
| 283 | 8 | new Client\Struct\HeaderV4\TransactionFlowLink($consumerId) |
|
| 284 | 4 | ) |
|
| 285 | 4 | ); |
|
| 286 | 4 | } |
|
| 287 | |||
| 288 | //Send authentication info headers if not authenticated and not Security_Authenticate message call |
||
| 289 | 52 | if ($this->isAuthenticated === false && $this->isNotSecurityAuthenticateMessage($messageName)) { |
|
| 290 | //Generate nonce, msg creation string & password digest: |
||
| 291 | 44 | $password = base64_decode($params->authParams->passwordData); |
|
| 292 | 44 | $creation = new \DateTime('now', new \DateTimeZone('UTC')); |
|
| 293 | 44 | $t = microtime(true); |
|
| 294 | 44 | $micro = sprintf("%03d", ($t - floor($t)) * 1000); |
|
| 295 | 44 | $creationString = $this->createDateTimeStringForAuth($creation, $micro); |
|
| 296 | 44 | $messageNonce = $this->generateUniqueNonce($params->authParams->nonceBase, $creationString); |
|
| 297 | 44 | $encodedNonce = base64_encode($messageNonce); |
|
| 298 | 44 | $digest = $this->generatePasswordDigest($password, $creationString, $messageNonce); |
|
| 299 | |||
| 300 | 44 | $securityHeaderXml = $this->generateSecurityHeaderRawXml( |
|
| 301 | 44 | $params->authParams->userId, |
|
| 302 | 44 | $encodedNonce, |
|
| 303 | 44 | $digest, |
|
| 304 | 22 | $creationString |
|
| 305 | 22 | ); |
|
| 306 | |||
| 307 | //Authentication header |
||
| 308 | 44 | array_push( |
|
| 309 | 44 | $headersToSet, |
|
| 310 | 44 | new \SoapHeader( |
|
| 311 | 44 | 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wsswssecurity-secext-1.0.xsd', |
|
| 312 | 44 | 'Security', |
|
| 313 | 44 | new \SoapVar($securityHeaderXml, XSD_ANYXML) |
|
| 314 | 22 | ) |
|
| 315 | 22 | ); |
|
| 316 | |||
| 317 | 44 | if ($stateful === true) { |
|
| 318 | //Not authenticated but stateful: start session! |
||
| 319 | 8 | array_push( |
|
| 320 | 8 | $headersToSet, |
|
| 321 | 8 | new \SoapHeader( |
|
| 322 | 8 | 'http://xml.amadeus.com/2010/06/Session_v3', |
|
| 323 | 8 | 'Session', |
|
| 324 | 8 | new Client\Struct\HeaderV4\Session( |
|
| 325 | 8 | null, |
|
| 326 | 4 | "Start" |
|
| 327 | 4 | ) |
|
| 328 | 4 | ) |
|
| 329 | 4 | ); |
|
| 330 | 4 | } |
|
| 331 | |||
| 332 | //AMA_SecurityHostedUser header |
||
| 333 | 44 | array_push( |
|
| 334 | 44 | $headersToSet, |
|
| 335 | 44 | new \SoapHeader( |
|
| 336 | 44 | 'http://xml.amadeus.com/2010/06/Security_v1', |
|
| 337 | 44 | 'AMA_SecurityHostedUser', |
|
| 338 | 44 | new Client\Struct\HeaderV4\SecurityHostedUser( |
|
| 339 | 44 | $params->authParams->officeId, |
|
| 340 | 44 | $params->authParams->originatorTypeCode, |
|
| 341 | 44 | 1, |
|
| 342 | 44 | $params->authParams->dutyCode |
|
| 343 | 22 | ) |
|
| 344 | 22 | ) |
|
| 345 | 22 | ); |
|
| 346 | 30 | } elseif ($stateful === true) { |
|
| 347 | //We are authenticated and stateful: provide session header to continue or terminate session |
||
| 348 | $statusCode = |
||
| 349 | 4 | (isset($messageOptions['endSession']) && $messageOptions['endSession'] === true) ? |
|
| 350 | 4 | "End" : "InSeries"; |
|
| 351 | |||
| 352 | 4 | array_push( |
|
| 353 | 4 | $headersToSet, |
|
| 354 | 4 | new \SoapHeader( |
|
| 355 | 4 | 'http://xml.amadeus.com/2010/06/Session_v3', |
|
| 356 | 4 | 'Session', |
|
| 357 | 4 | new Client\Struct\HeaderV4\Session( |
|
| 358 | 4 | $sessionData, |
|
| 359 | 2 | $statusCode |
|
| 360 | 2 | ) |
|
| 361 | 2 | ) |
|
| 362 | 2 | ); |
|
| 363 | 2 | } |
|
| 364 | |||
| 365 | 52 | return $headersToSet; |
|
| 366 | } |
||
| 367 | |||
| 368 | /** |
||
| 369 | * Get the Web Services server Endpoint from the WSDL. |
||
| 370 | * |
||
| 371 | * @param string $wsdlFilePath |
||
| 372 | * @param string $messageName |
||
| 373 | * @return string|null |
||
| 374 | */ |
||
| 375 | 52 | protected function getEndpointFromWsdl($wsdlFilePath, $messageName) |
|
| 385 | |||
| 386 | /** |
||
| 387 | * Get the SOAPAction for a given message from the WSDL contents. |
||
| 388 | * |
||
| 389 | * @param string $wsdlFilePath |
||
| 390 | * @param string $messageName |
||
| 391 | * @return string|null |
||
| 392 | */ |
||
| 393 | 52 | protected function getActionFromWsdl($wsdlFilePath, $messageName) |
|
| 403 | |||
| 404 | /** |
||
| 405 | * Generate a GUID |
||
| 406 | * |
||
| 407 | * @return string |
||
| 408 | */ |
||
| 409 | 52 | protected function generateGuid() |
|
| 423 | |||
| 424 | /** |
||
| 425 | * @param string $originator |
||
| 426 | * @param string $nonce |
||
| 427 | * @param string $pwDigest |
||
| 428 | * @param string $creationTimeString |
||
| 429 | * @return string |
||
| 430 | */ |
||
| 431 | 48 | protected function generateSecurityHeaderRawXml($originator, $nonce, $pwDigest, $creationTimeString) |
|
| 442 | |||
| 443 | |||
| 444 | /** |
||
| 445 | * @param string $nonceBase |
||
| 446 | * @param string $creationString |
||
| 447 | * @return string |
||
| 448 | */ |
||
| 449 | 44 | protected function generateUniqueNonce($nonceBase, $creationString) |
|
| 460 | |||
| 461 | /** |
||
| 462 | * Generates a Password Digest following this algorithm: |
||
| 463 | * HashedPassword = Base64(SHA-1( nonce + created + SHA-1 ( password ))) |
||
| 464 | * as defined in |
||
| 465 | * https://webservices.amadeus.com/extranet/kdbViewDocument.do?externalId=wikidoc_web_services_embedded_security_implementation_guide_header_entries_ws-security_usernametoken&docStatus=Published&mpId=fla__1__technical |
||
| 466 | * |
||
| 467 | * EXAMPLE: with: |
||
| 468 | * Nonce in Base 64 = 'PZgFvh5439plJpKpIyf5ucmXhNU=' |
||
| 469 | * Timestamp = '2013-01-11T09:41:03Z' |
||
| 470 | * Clear Password = 'WBSPassword' |
||
| 471 | * The digest algorithm returns the Encrypted Password in Base 64: |
||
| 472 | * HshPwd = 'ic3AOJElVpvkz9ZBKd105Siry28=' |
||
| 473 | * |
||
| 474 | * @param string $password CLEARTEXT password (NOT the base64 encoded password used in Security_Authenticate) |
||
| 475 | * @param string $creationString message creation datetime |
||
| 476 | * UTC Format: yyyy-mm-ddTHH:MM:SSZ or yyyy-mm-ddTHH:MM:SS.sssZ |
||
| 477 | * @param string $messageNonce Random unique string |
||
| 478 | * @return string The generated Password Digest |
||
| 479 | */ |
||
| 480 | 68 | protected function generatePasswordDigest($password, $creationString, $messageNonce) |
|
| 484 | |||
| 485 | /** |
||
| 486 | * @param \DateTime $creationDateTime |
||
| 487 | * @param string $micro |
||
| 488 | * @return string |
||
| 489 | */ |
||
| 490 | 44 | protected function createDateTimeStringForAuth($creationDateTime, $micro) |
|
| 496 | |||
| 497 | /** |
||
| 498 | * Make SoapClient options for Soap Header 4 handler |
||
| 499 | * |
||
| 500 | * @return array |
||
| 501 | */ |
||
| 502 | 8 | View Code Duplication | protected function makeSoapClientOptions() |
| 513 | |||
| 514 | /** |
||
| 515 | * Check is called message is not Security_Authenticate. |
||
| 516 | * |
||
| 517 | * @param $messageName |
||
| 518 | * @return bool |
||
| 519 | */ |
||
| 520 | 44 | protected function isNotSecurityAuthenticateMessage($messageName) |
|
| 524 | } |
||
| 525 |
This check compares the return type specified in the
@returnannotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.