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 | /** |
||
| 57 | * @param bool $stateful |
||
| 58 | */ |
||
| 59 | public function setStateful($stateful) |
||
| 63 | |||
| 64 | /** |
||
| 65 | * Check whether we are running in stateful mode (true) or in stateless mode (false) |
||
| 66 | * |
||
| 67 | * @return bool |
||
| 68 | */ |
||
| 69 | public function isStateful() |
||
| 73 | |||
| 74 | /** |
||
| 75 | * Handles authentication & sessions |
||
| 76 | * |
||
| 77 | * If authenticated, increment sequence number for next message and set session info to soapheader |
||
| 78 | * If not, set auth info to soapheader |
||
| 79 | * |
||
| 80 | * @uses $this->isAuthenticated |
||
| 81 | * @uses $this->sessionData |
||
| 82 | * @param string $messageName |
||
| 83 | * @param array $messageOptions |
||
| 84 | */ |
||
| 85 | protected function prepareForNextMessage($messageName, $messageOptions) |
||
| 96 | |||
| 97 | |||
| 98 | /** |
||
| 99 | * Handles post message actions |
||
| 100 | * |
||
| 101 | * - look for session info and set status variables |
||
| 102 | * - checks for message errors? |
||
| 103 | * - ends terminated sessions |
||
| 104 | * |
||
| 105 | * @param string $messageName |
||
| 106 | * @param string $lastResponse |
||
| 107 | * @param array $messageOptions |
||
| 108 | * @param mixed $result |
||
| 109 | * @return void |
||
| 110 | */ |
||
| 111 | protected function handlePostMessage($messageName, $lastResponse, $messageOptions, $result) |
||
| 124 | |||
| 125 | /** |
||
| 126 | * @param string $responseMsg the full response XML received. |
||
| 127 | * @return array |
||
| 128 | */ |
||
| 129 | protected function getSessionDataFromHeader($responseMsg) |
||
| 163 | |||
| 164 | /** |
||
| 165 | * Create the Soap Headers to be used on the subsequent request. |
||
| 166 | * |
||
| 167 | * This depends on the current Session Data (if there is an active session) and |
||
| 168 | * the Session Handler parameters (to create a new or stateless session) |
||
| 169 | * |
||
| 170 | * You can also terminate the session with $doEndSession = true |
||
| 171 | * |
||
| 172 | * @param array $sessionData |
||
| 173 | * @param Client\Params\SessionHandlerParams $params |
||
| 174 | * @param string $messageName |
||
| 175 | * @param array $messageOptions |
||
| 176 | * @return \SoapHeader[]|null |
||
|
|
|||
| 177 | */ |
||
| 178 | protected function createSoapHeaders($sessionData, $params, $messageName, $messageOptions) |
||
| 179 | { |
||
| 180 | $headersToSet = []; |
||
| 181 | |||
| 182 | $wsdlId = $this->getWsdlIdFor($messageName); |
||
| 183 | $wsdl = $this->wsdlIds[$wsdlId]; |
||
| 184 | |||
| 185 | //CHECK STATEFUL |
||
| 186 | $stateful = $this->isStateful(); |
||
| 187 | |||
| 188 | //Message ID header |
||
| 189 | array_push( |
||
| 190 | $headersToSet, |
||
| 191 | new \SoapHeader( |
||
| 192 | 'http://www.w3.org/2005/08/addressing', |
||
| 193 | 'MessageID', |
||
| 194 | $this->generateGuid() |
||
| 195 | ) |
||
| 196 | ); |
||
| 197 | |||
| 198 | //Action header |
||
| 199 | array_push( |
||
| 200 | $headersToSet, |
||
| 201 | new \SoapHeader( |
||
| 202 | 'http://www.w3.org/2005/08/addressing', |
||
| 203 | 'Action', |
||
| 204 | $this->getActionFromWsdl($wsdl, $messageName) |
||
| 205 | ) |
||
| 206 | ); |
||
| 207 | |||
| 208 | //To header |
||
| 209 | array_push( |
||
| 210 | $headersToSet, |
||
| 211 | new \SoapHeader( |
||
| 212 | 'http://www.w3.org/2005/08/addressing', |
||
| 213 | 'To', |
||
| 214 | $this->getEndpointFromWsdl($wsdl, $messageName) |
||
| 215 | ) |
||
| 216 | ); |
||
| 217 | |||
| 218 | //Send authentication info |
||
| 219 | if ($this->isAuthenticated === false) { |
||
| 220 | //Generate nonce, msg creation string & password digest: |
||
| 221 | $password = base64_decode($params->authParams->passwordData); |
||
| 222 | $creation = new \DateTime('now', new \DateTimeZone('UTC')); |
||
| 223 | $t = microtime(true); |
||
| 224 | $micro = sprintf("%03d", ($t - floor($t)) * 1000); |
||
| 225 | $creationString = $this->createDateTimeStringForAuth($creation, $micro); |
||
| 226 | $messageNonce = $this->generateUniqueNonce($params->authParams->nonceBase, $creationString); |
||
| 227 | $encodedNonce = base64_encode($messageNonce); |
||
| 228 | $digest = $this->generatePasswordDigest($password, $creationString, $messageNonce); |
||
| 229 | |||
| 230 | $securityHeaderXml = $this->generateSecurityHeaderRawXml( |
||
| 231 | $params->authParams->userId, |
||
| 232 | $encodedNonce, |
||
| 233 | $digest, |
||
| 234 | $creationString |
||
| 235 | ); |
||
| 236 | |||
| 237 | //Authentication header |
||
| 238 | array_push( |
||
| 239 | $headersToSet, |
||
| 240 | new \SoapHeader( |
||
| 241 | 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wsswssecurity-secext-1.0.xsd', |
||
| 242 | 'Security', |
||
| 243 | new \SoapVar($securityHeaderXml, XSD_ANYXML) |
||
| 244 | ) |
||
| 245 | ); |
||
| 246 | |||
| 247 | if ($stateful === true) { |
||
| 248 | //Not authenticated but stateful: start session! |
||
| 249 | array_push( |
||
| 250 | $headersToSet, |
||
| 251 | new \SoapHeader( |
||
| 252 | 'http://xml.amadeus.com/2010/06/Session_v3', |
||
| 253 | 'Session', |
||
| 254 | new Client\Struct\HeaderV4\Session( |
||
| 255 | null, |
||
| 256 | "Start" |
||
| 257 | ) |
||
| 258 | ) |
||
| 259 | ); |
||
| 260 | } |
||
| 261 | |||
| 262 | //AMA_SecurityHostedUser header |
||
| 263 | array_push( |
||
| 264 | $headersToSet, |
||
| 265 | new \SoapHeader( |
||
| 266 | 'http://xml.amadeus.com/2010/06/Security_v1', |
||
| 267 | 'AMA_SecurityHostedUser', |
||
| 268 | new Client\Struct\HeaderV4\SecurityHostedUser( |
||
| 269 | $params->authParams->officeId, |
||
| 270 | $params->authParams->originatorTypeCode, |
||
| 271 | 1, |
||
| 272 | $params->authParams->dutyCode |
||
| 273 | ) |
||
| 274 | ) |
||
| 275 | ); |
||
| 276 | } elseif ($stateful === true) { |
||
| 277 | //We are authenticated and stateful: provide session header to continue or terminate session |
||
| 278 | $statusCode = |
||
| 279 | (isset($messageOptions['endSession']) && $messageOptions['endSession'] === true) ? |
||
| 280 | "End" : "InSeries"; |
||
| 281 | |||
| 282 | array_push( |
||
| 283 | $headersToSet, |
||
| 284 | new \SoapHeader( |
||
| 285 | 'http://xml.amadeus.com/2010/06/Session_v3', |
||
| 286 | 'Session', |
||
| 287 | new Client\Struct\HeaderV4\Session( |
||
| 288 | $sessionData, |
||
| 289 | $statusCode |
||
| 290 | ) |
||
| 291 | ) |
||
| 292 | ); |
||
| 293 | } |
||
| 294 | |||
| 295 | return $headersToSet; |
||
| 296 | } |
||
| 297 | |||
| 298 | /** |
||
| 299 | * Get the Web Services server Endpoint from the WSDL. |
||
| 300 | * |
||
| 301 | * @param string $wsdlFilePath |
||
| 302 | * @param string $messageName |
||
| 303 | * @return string |
||
| 304 | */ |
||
| 305 | protected function getEndpointFromWsdl($wsdlFilePath, $messageName) |
||
| 306 | { |
||
| 307 | $wsdlId = $this->getWsdlIdFor($messageName); |
||
| 308 | |||
| 309 | $this->loadWsdlXpath( |
||
| 310 | $wsdlFilePath, |
||
| 311 | $wsdlId |
||
| 312 | ); |
||
| 313 | |||
| 314 | return $this->wsdlDomXpath[$wsdlId]->evaluate(self::XPATH_ENDPOINT); |
||
| 315 | } |
||
| 316 | |||
| 317 | /** |
||
| 318 | * Get the SOAPAction for a given message from the WSDL contents. |
||
| 319 | * |
||
| 320 | * @param string $wsdlFilePath |
||
| 321 | * @param string $messageName |
||
| 322 | * @return string |
||
| 323 | */ |
||
| 324 | protected function getActionFromWsdl($wsdlFilePath, $messageName) |
||
| 325 | { |
||
| 326 | $wsdlId = $this->getWsdlIdFor($messageName); |
||
| 327 | |||
| 328 | $this->loadWsdlXpath( |
||
| 329 | $wsdlFilePath, |
||
| 330 | $wsdlId |
||
| 331 | ); |
||
| 332 | |||
| 333 | $action = $this->wsdlDomXpath[$wsdlId]->evaluate(sprintf(self::XPATH_OPERATION_ACTION, $messageName)); |
||
| 334 | |||
| 335 | return $action; |
||
| 336 | } |
||
| 337 | |||
| 338 | /** |
||
| 339 | * Generate a GUID |
||
| 340 | * |
||
| 341 | * @return string |
||
| 342 | */ |
||
| 343 | protected function generateGuid() |
||
| 344 | { |
||
| 345 | mt_srand((double) microtime() * 10000); |
||
| 346 | $charId = strtoupper(md5(uniqid(rand(), true))); |
||
| 347 | $hyphen = chr(45); // "-" |
||
| 348 | |||
| 349 | $uuid = substr($charId, 0, 8) . $hyphen |
||
| 350 | .substr($charId, 8, 4) . $hyphen |
||
| 351 | .substr($charId, 12, 4) . $hyphen |
||
| 352 | .substr($charId, 16, 4) . $hyphen |
||
| 353 | .substr($charId, 20, 12); |
||
| 354 | |||
| 355 | return $uuid; |
||
| 356 | } |
||
| 357 | |||
| 358 | /** |
||
| 359 | * @param string $originator |
||
| 360 | * @param string $nonce |
||
| 361 | * @param string $pwDigest |
||
| 362 | * @param string $creationTimeString |
||
| 363 | * @return string |
||
| 364 | */ |
||
| 365 | protected function generateSecurityHeaderRawXml($originator, $nonce, $pwDigest, $creationTimeString) |
||
| 366 | { |
||
| 367 | return $xml = '<oas:Security xmlns:oas="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> |
||
| 368 | <oas:UsernameToken xmlns:oas1="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" oas1:Id="UsernameToken-1"> |
||
| 369 | <oas:Username>' . $originator . '</oas:Username> |
||
| 370 | <oas:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">' . $nonce . '</oas:Nonce> |
||
| 371 | <oas:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">' . $pwDigest . '</oas:Password> |
||
| 372 | <oas1:Created>' . $creationTimeString . '</oas1:Created> |
||
| 373 | </oas:UsernameToken> |
||
| 374 | </oas:Security>'; |
||
| 375 | } |
||
| 376 | |||
| 377 | |||
| 378 | /** |
||
| 379 | * @param string $nonceBase |
||
| 380 | * @param string $creationString |
||
| 381 | * @return string |
||
| 382 | */ |
||
| 383 | protected function generateUniqueNonce($nonceBase, $creationString) |
||
| 384 | { |
||
| 385 | return substr( |
||
| 386 | sha1( |
||
| 387 | $nonceBase . $creationString, |
||
| 388 | true |
||
| 389 | ), |
||
| 390 | 0, |
||
| 391 | 16 |
||
| 392 | ); |
||
| 393 | } |
||
| 394 | |||
| 395 | /** |
||
| 396 | * Generates a Password Digest following this algorithm: |
||
| 397 | * HashedPassword = Base64(SHA-1( nonce + created + SHA-1 ( password ))) |
||
| 398 | * as defined in |
||
| 399 | * 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 |
||
| 400 | * |
||
| 401 | * EXAMPLE: with: |
||
| 402 | * Nonce in Base 64 = 'PZgFvh5439plJpKpIyf5ucmXhNU=' |
||
| 403 | * Timestamp = '2013-01-11T09:41:03Z' |
||
| 404 | * Clear Password = 'WBSPassword' |
||
| 405 | * The digest algorithm returns the Encrypted Password in Base 64: |
||
| 406 | * HshPwd = 'ic3AOJElVpvkz9ZBKd105Siry28=' |
||
| 407 | * |
||
| 408 | * @param string $password CLEARTEXT password (NOT the base64 encoded password used in Security_Authenticate) |
||
| 409 | * @param string $creationString message creation datetime |
||
| 410 | * UTC Format: yyyy-mm-ddTHH:MM:SSZ or yyyy-mm-ddTHH:MM:SS.sssZ |
||
| 411 | * @param string $messageNonce Random unique string |
||
| 412 | * @return string The generated Password Digest |
||
| 413 | */ |
||
| 414 | protected function generatePasswordDigest($password, $creationString, $messageNonce) |
||
| 418 | |||
| 419 | /** |
||
| 420 | * @param \DateTime $creationDateTime |
||
| 421 | * @param string $micro |
||
| 422 | * @return string |
||
| 423 | */ |
||
| 424 | protected function createDateTimeStringForAuth($creationDateTime, $micro) |
||
| 429 | |||
| 430 | /** |
||
| 431 | * Make SoapClient options for Soap Header 4 handler |
||
| 432 | * |
||
| 433 | * @return array |
||
| 434 | */ |
||
| 435 | View Code Duplication | protected function makeSoapClientOptions() |
|
| 446 | } |
||
| 447 |
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.