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”
Leave a Reply
Sunt Victor Stanciu, web developer, si scriu despre dezvoltare, standarde, tehnici si tehnologii. (
on June 28th, 2010 16:15
Thanks, very usefully for me!
on August 10th, 2010 09:36
This code solve my problem aswell. Thanks for sharing ;-)
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! :)
on September 2nd, 2010 21:31
Thanks! It worked flawlessly for my case!
on January 22nd, 2011 17:02
Thank you! It resolved my port problem!
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.
on June 21st, 2011 12:52
Thank you! It resolved my port problem, too!
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
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 ..?
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.
on January 16th, 2012 12:44
thank you, saved the morning!
on January 21st, 2012 00:29
If $this->port is not set, you don’t need to even parse the location in __doRequest().
on January 31st, 2012 15:24
This post inspired a solution to my SoapClient problem. Thanks!