-
-
Save treehousetim/3406693 to your computer and use it in GitHub Desktop.
PHP SoapClient with timeout
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<? | |
// https://gist.github.com/gists/3406693 | |
// Drop-in replacement for PHP's SoapClient class supporting connect and response/transfer timeout | |
// Usage: Exactly as PHP's SoapClient class, except that 3 new options are available: | |
// timeout The response/transfer timeout in milliseconds; 0 == default SoapClient / CURL timeout | |
// connecttimeout The connection timeout; 0 == default SoapClient / CURL timeout | |
// sslverifypeer FALSE to stop SoapClient from verifying the peer's certificate | |
// 2012-08-20 - treehousetim added an additional option to support xignite.com api key auth | |
// ->extraGet | |
// used like this: | |
/* | |
// authenticate using an API key | |
$apiKey = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'; | |
$client->extraGet = '?Header_Username=' $apiKey ); | |
*/ | |
// 2012-08-20 - treehousetim also added custom exceptions so that the different errors can be caught using multiple catch levels | |
// used like this: | |
/* | |
try | |
{ | |
// instantiate client and call wsdl method here | |
} | |
catch( stConnectionException $e ) | |
{ | |
// handle connection timeout here | |
} | |
catch( stOperationException $e ) | |
{ | |
// handle operation timeout here | |
} | |
*/ | |
class SoapClientTimeout extends SoapClient | |
{ | |
private $timeout = 10; | |
private $connecttimeout = 3; | |
private $sslverifypeer = true; | |
public $extraGet = ''; | |
public function __construct($wsdl, $options) { | |
//"POP" our own defined options from the $options array before we call our parent constructor | |
//to ensure we don't pass unknown/invalid options to our parent | |
if (isset($options['timeout'])) { | |
$this->__setTimeout($options['timeout']); | |
unset($options['timeout']); | |
} | |
if (isset($options['connecttimeout'])) { | |
$this->__setConnectTimeout($options['connecttimeout']); | |
unset($options['connecttimeout']); | |
} | |
if (isset($options['sslverifypeer'])) { | |
$this->__setSSLVerifyPeer($options['sslverifypeer']); | |
unset($options['sslverifypeer']); | |
} | |
//Now call parent constructor | |
parent::__construct($wsdl, $options); | |
} | |
public function __setTimeout($timeoutms) | |
{ | |
if (!is_int($timeoutms) && !is_null($timeoutms) || $timeoutms<0) | |
throw new Exception("Invalid timeout value"); | |
$this->timeout = $timeoutms; | |
} | |
public function __getTimeout() | |
{ | |
return $this->timeout; | |
} | |
public function __setConnectTimeout($connecttimeoutms) | |
{ | |
if (!is_int($connecttimeoutms) && !is_null($connecttimeoutms) || $connecttimeoutms<0) | |
throw new Exception("Invalid connecttimeout value"); | |
$this->connecttimeout = $connecttimeoutms; | |
} | |
public function __getConnectTimeout() | |
{ | |
return $this->connecttimeout; | |
} | |
public function __setSSLVerifyPeer($sslverifypeer) | |
{ | |
if (!is_bool($sslverifypeer)) | |
throw new Exception("Invalid sslverifypeer value"); | |
$this->sslverifypeer = $sslverifypeer; | |
} | |
public function __getSSLVerifyPeer() | |
{ | |
return $this->sslverifypeer; | |
} | |
public function __doRequest( $request, $location, $action, $version, $one_way = FALSE) | |
{ | |
if (($this->timeout===0) && ($this->connecttimeout===0)) | |
{ | |
// Call via parent because we require no timeout | |
$response = parent::__doRequest($request, $location, $action, $version, $one_way); | |
} | |
else | |
{ | |
// Call via Curl and use the timeout | |
$curl = curl_init($location . $this->extraGet ); | |
if ($curl === false) | |
throw new Exception('Curl initialization failed'); | |
$options = array( | |
CURLOPT_VERBOSE => false, | |
CURLOPT_RETURNTRANSFER => true, | |
CURLOPT_POST => true, | |
CURLOPT_POSTFIELDS => $request, | |
CURLOPT_HEADER => false, | |
CURLOPT_NOSIGNAL => true, //http://www.php.net/manual/en/function.curl-setopt.php#104597 | |
CURLOPT_HTTPHEADER => array(sprintf('Content-Type: %s', $version == 2 ? 'application/soap+xml' : 'text/xml'), sprintf('SOAPAction: %s', $action)), | |
CURLOPT_SSL_VERIFYPEER => $this->sslverifypeer | |
); | |
if (defined('CURLOPT_TIMEOUT_MS')) { //Timeout in MS supported? | |
$options[CURLOPT_TIMEOUT_MS] = $this->timeout; | |
} else { //Round(up) to second precision | |
$options[CURLOPT_TIMEOUT] = ceil($this->timeout/1000); | |
} | |
if (defined('CURLOPT_CONNECTTIMEOUT_MS')) { //ConnectTimeout in MS supported? | |
$options[CURLOPT_CONNECTTIMEOUT_MS] = $this->connecttimeout; | |
} else { //Round(up) to second precision | |
$options[CURLOPT_CONNECTTIMEOUT] = ceil($this->connecttimeout/1000); | |
} | |
if (curl_setopt_array($curl, $options) === false) | |
throw new Exception('Failed setting CURL options'); | |
$response = curl_exec($curl); | |
$errNo = curl_errno($curl); | |
if ( $errNo ) | |
{ | |
if ( $errNo == 7 ) | |
{ | |
throw new stConnectionException( curl_error( $curl ) ); | |
} | |
if ( $errNo == 28 ) | |
{ | |
throw new stOperationException( curl_error( $curl ) ); | |
} | |
// failsafe | |
throw new stGeneralException( curl_error( $curl ) ); | |
} | |
curl_close($curl); | |
} | |
// Return? | |
if (!$one_way) | |
return ($response); | |
} | |
} | |
//------------------------------------------------------------------------ | |
// custom exceptions for soap timeout by tim gallagher "treehousetim" everywhere | |
//------------------------------------------------------------------------ | |
interface stIException | |
{ | |
/* Protected methods inherited from Exception class */ | |
public function getMessage(); // Exception message | |
public function getCode(); // User-defined Exception code | |
public function getFile(); // Source filename | |
public function getLine(); // Source line | |
public function getTrace(); // An array of the backtrace() | |
public function getTraceAsString(); // Formated string of trace | |
/* Overrideable methods inherited from Exception class */ | |
public function __toString(); // formated string for display | |
public function __construct( $message = null, $code = 0 ); | |
} | |
//------------------------------------------------------------------------ | |
abstract class stException extends Exception implements stIException | |
{ | |
protected $message = 'Generic SoapTimeout Exception'; // Exception message | |
private $string; // Unknown | |
protected $code = 0; // User-defined exception code | |
protected $file; // Source filename of exception | |
protected $line; // Source line of exception | |
private $trace; // Unknown | |
protected $errno; // error number aka error level - integer | |
//------------------------------------------------------------------------ | |
public function __construct( $message = null, $code = 0 ) | |
{ | |
if ( ! $message ) | |
{ | |
throw new $this( 'Unknown '. get_class( $this ) ); | |
} | |
parent::__construct( $message, $code ); | |
} | |
//------------------------------------------------------------------------ | |
public function __toString() | |
{ | |
return PHP_EOL . get_class( $this ) . | |
":\n{$this->message}\n\nin {$this->file}({$this->line})\n" . | |
"{$this->getTraceAsString()}"; | |
} | |
} | |
//------------------------------------------------------------------------ | |
// now the actual custom exceptions | |
//------------------------------------------------------------------------ | |
class stGeneralException extends stException { } | |
class stConnectionException extends stException { } | |
class stOperationException extends stException { } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment