PHP SoapClient port bug workaround

PHP’s SoapClient has a bug (PHP 5.2.10 here, still not fixed apparently) when the SOAP service must be accessed on a different port other than 80. The WSDL file is fetched correctly, but all subsequent requests are made without any port in the Host field. This causes a SoapFault exception when trying to call any of the service’s methods.

So if the WSDL location is:

http://example.com:33080/soap/server/path?WSDL

All requests after fetching the WSDL file will be made to:

http://example.com/soap/server/path

The simplest way i could work around this was to extend SoapClient and intercept the constructor and the __doRequest method to inject the port in the location on each request:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?php
class My_SoapClient extends SoapClient {
 
    public function __construct($wsdl, $options) {
        $url = parse_url($wsdl);
        if ($url['port']) {
            $this->_port = $url['port'];
        }
        return parent::__construct($wsdl, $options);
    }
 
    public function __doRequest($request, $location, $action, $version) {
        $parts = parse_url($location);
        if ($this->_port) {
            $parts['port'] = $this->_port;
        }
        $location = $this->buildLocation($parts);
 
        $return = parent::__doRequest($request, $location, $action, $version);
        return $return;
    }
 
    public function buildLocation($parts = array()) {
        $location = '';
 
        if (isset($parts['scheme'])) {
            $location .= $parts['scheme'].'://';
        }
        if (isset($parts['user']) || isset($parts['pass'])) {
            $location .= $parts['user'].':'.$parts['pass'].'@';
        }
        $location .= $parts['host'];
        if (isset($parts['port'])) {
            $location .= ':'.$parts['port'];
        }
        $location .= $parts['path'];
        if (isset($parts['query'])) {
            $location .= '?'.$parts['query'];
        }
 
        return $location;
    }
}

It works for me, and I would like to know if it doesn’t cover your particular case :)

Comments

13 Responses to “PHP SoapClient port bug workaround”

  1. daniel andres miranda
    on June 28th, 2010 16:15

    Thanks, very usefully for me!

  2. Steen Larsen
    on August 10th, 2010 09:36

    This code solve my problem aswell. Thanks for sharing ;-)

  3. Mihaly Koles
    on August 23rd, 2010 19:47

    Thanks for this “little” hack!
    PHP SOAP is driving me crazy, your class helped me to solve a very frustrating issue! Thanks again pal, you saved my day, seriously! :)

  4. Ribacki
    on September 2nd, 2010 21:31

    Thanks! It worked flawlessly for my case!

  5. Mario
    on January 22nd, 2011 17:02

    Thank you! It resolved my port problem!

  6. Guy Incognito
    on June 16th, 2011 14:50

    I wouldn’t call that a PHP bug, since the service URL is defined within the WSDL file, where the port is missing already.

  7. Little Fang
    on June 21st, 2011 12:52

    Thank you! It resolved my port problem, too!

  8. Stéphaen
    on June 23rd, 2011 17:28

    Great ! it solved my problem and saved my day !!

    One point : to make it works I had to change the _doRequest declaration by :

    (…)
    function __doRequest($request, $location, $action, $version, $one_way = 0)
    (…)
    php 5.3.5

    Thank’s

  9. yusman
    on August 24th, 2011 11:59

    hi Victor Stanciu, thank u for this tutorial this verry usefull fro newbee like me, but i use codeigniter, can u give a sample how to implement this code on codeiginiter framework ..?

  10. DissidentRage
    on January 10th, 2012 21:39

    SoapClient::__doRequest now has an additional parameter, $one_way, so you get a Strict Standards warning with this code.

    To fix it, append this to the parameters of the override function:

    $one_way = 0

    Then pass it to the superclass function after parsing the URL.

  11. giulio
    on January 16th, 2012 12:44

    thank you, saved the morning!

  12. John Lindal
    on January 21st, 2012 00:29

    If $this->port is not set, you don’t need to even parse the location in __doRequest().

  13. Eric
    on January 31st, 2012 15:24

    This post inspired a solution to my SoapClient problem. Thanks!

Leave a Reply