views:

17

answers:

1

The Amazon AWS SQS WSDL (at https://sqs.us-east-1.amazonaws.com/doc/2009-02-01/QueueService.wsdl) lists multiple "ports" with different "addresses" (near the bottom of the file), which specify the HTTP and HTTPS addresses for the service.

Using the PHP SOAP object:

$aws_ns = 'http://security.amazonaws.com/doc/2007-01-01/';
$sc = new SoapClient('https://sqs.us-east-1.amazonaws.com/doc/2009-02-01/QueueService.wsdl');
$sc->__setSoapHeaders(new SoapHeader($aws_ns, 'AWSAccessKeyId', 'MyAccessKey'));
$action = "ListQueues";
$ts = date('c');
$hash = base64_encode(hash_hmac('sha1', $action.$ts, 'MyPrivateKey', true));
try {
  $rs = $sc->__soapCall($action, array(), NULL, array(
    new SoapHeader($aws_ns, 'Signature', $hash),
    new SoapHeader($aws_ns, 'Timestamp', $ts)
  ));
} catch (SoapFault $f) {
  echo "ERROR: ".$f->faultcode."-".$f->faultstring."\n";
}

Running that code gives "ERROR: aws:Client.RequiresSSL-SSL connection required for backward compatible SOAP authentication."; it's using the first "port" (the HTTP one) to contact the AWS service, which isn't allowed with this sort of authentication.

If I add a $sc->__setLocation('https://queue.amazonaws.com'); (URL copied and pasted from the WSDL file) line before the __soapCall, it works out fine, but how can I tell the SoapClient object to use the other port in the WSDL, rather than giving it as a static string, in case they change the HTTPS URL down the road?

A: 

As far as I know, there's no simple way to tell SoapClient to use the other one. If only the http to https change has to be made, and all other things are equal, you might override some method with your own class:

class HttpsPortSoapClient extends Soapclient {
  function __doRequest($request,$location,$action,$version,$one_way = 0 ){
    $locationparts = parse_url($location);
    if(isset($locationparts['scheme']) && $locationparts['scheme'] == 'http'){
      if(function_exists('http_build_url')){
        $location = http_build_url($locationparts,array('scheme'=>'https'));
      } else {
        //the long way around:
        $location = 'https://';
        if(isset($locationparts['user'])){
          $location .= $locationparts['user'];
          if(isset($locationparts['pass']))$location .= ':'.$locationparts['pass'];
          $location .= '@';
        }
        if(isset($locationparts['host']))  $location .= $locationparts['host'];
        if(isset($locationparts['port']))  $location .= ':'.$locationparts['port'];
        if(isset($locationparts['path']))  $location .= $locationparts['path'];
        if(isset($locationparts['query'])) $location .= '?'.$locationparts['query'];
      }
    }
    return parent::__doRequest($request,$location,$action,$version,$one_way);
  }
}

If the methods DO differ, you might want to override the __construct method, and load the XML, and cleanup or remove any references to the 'http' port instead of the 'https' one. It would look more and more like writing your own soapclient though :)

Wrikken