Handling Soap timeouts in PHP

前端 未结 8 1779
囚心锁ツ
囚心锁ツ 2021-01-30 09:05

I\'m working on a project where I am verifying information from a user with a SOAP web service. I currently am taking care of errors assuming that I\'m receiving responses from

相关标签:
8条回答
  • 2021-01-30 09:29

    Guess I'm little late, but in case someone is still looking for solution to timeouts in php soap client - here's what's worked for me:

    • archived copy of <http://www.darqbyte.com/2009/10/21/timing-out-php-soap-calls/>

    Basicly replacing PHP SoapClient with cURL with set timeout. Just keep in mind, sometimes WS expects action specified in HTTP header. Original solution posted on that website doesn't include that (check comments).

    0 讨论(0)
  • 2021-01-30 09:37

    To deal with timeouts in the service

    $client = new SoapClient($wsdl, array("connection_timeout"=>10));
    
    // SET SOCKET TIMEOUT
    if(defined('RESPONSE_TIMEOUT') &&  RESPONSE_TIMEOUT != '') {
     ini_set('default_socket_timeout', RESPONSE_TIMEOUT);
    }
    
    0 讨论(0)
  • 2021-01-30 09:41

    just use the "stream_context" to set the timeout setting also for WSDL loading (you need to set the SoapClient $options['connection_timeout'] before):

    class SoapClient2 extends SoapClient
    {
      public function __construct($wsdl, $options=null)
      {
        if(isset($options['connection_timeout']))
        {
          $s_options = array(
              'http' => array(
                  'timeout' => $options['connection_timeout']
                  )
              );
          $options['stream_context'] = stream_context_create($s_options);
        }
        parent::__construct($wsdl, $options);
      }
    }
    
    0 讨论(0)
  • 2021-01-30 09:47

    Simply setting the default_socket_timeout globally via the ini may not do what you want. This would affect SOAP requests, but would also affect other outgoing connections, including DB connections. Instead, override SoapClient's __doRequest() method to make the HTTP connection yourself. You can then set your own timeout on the socket, detect it, and throw exceptions that you can trap and handle.

    class SoapClientWithTimeout extends SoapClient {
    
        public function __construct ($wsdl, $options = null) {
            if (!$options) $options = [];
    
            $this->_connectionTimeout =
                @$options['connection_timeout']
                ?: ini_get ('default_socket_timeout');
            $this->_socketTimeout =
                @$options['socket_timeout']
                ?: ini_get ('default_socket_timeout');
            unset ($options['socket_timeout']);
    
            parent::__construct($wsdl, $options);
        }
    
        /**
         * Override parent __doRequest to add a timeout.
         */
        public function __doRequest (
            $request, $location, $action, $version, $one_way = 0
        ) {
            // Extract host, port, and scheme.
            $url_parts = parse_url ($location);
            $host = $url_parts['host'];
            $port =
                @$url_parts['port']
                ?: ($url_parts['scheme'] == 'https' ? 443 : 80);
            $length = strlen ($request);
    
            // Form the HTTP SOAP request.
            $http_req = "POST $location HTTP/1.0\r\n";
            $http_req .= "Host: $host\r\n";
            $http_req .= "SoapAction: $action\r\n";
            $http_req .= "Content-Type: text/xml; charset=utf-8\r\n";
            $http_req .= "Content-Length: $length\r\n";
            $http_req .= "\r\n";
            $http_req .= $request;
    
            // Need to tell fsockopen to use SSL when requested.
            if ($url_parts['scheme'] == 'https')
                $host = 'ssl://'.$host;
    
            // Open the connection.
            $socket = @fsockopen (
                $host, $port, $errno, $errstr, $this->_connectionTimeout
            );
            if (!$socket)
                throw new SoapFault (
                    'Client',
                    "Failed to connect to SOAP server ($location): $errstr"
                );
    
            // Send the request.
            stream_set_timeout ($socket, $this->_socketTimeout);
            fwrite ($socket, $http_req);
    
            // Read the response.
            $http_response = stream_get_contents ($socket);
    
            // Close the socket and throw an exception if we timed out.
            $info = stream_get_meta_data ($socket);
            fclose ($socket);
            if ($info['timed_out'])
                throw new SoapFault (
                    'Client',
                    "HTTP timeout contacting $location"
                );
    
            // Extract the XML from the HTTP response and return it.
            $response = preg_replace (
                '/
                    \A       # Start of string
                    .*?      # Match any number of characters (as few as possible)
                    ^        # Start of line
                    \r       # Carriage Return
                    $        # End of line
                 /smx',
                '', $http_response
            );
            return $response;
        }
    
    }
    
    0 讨论(0)
  • 2021-01-30 09:49

    Looks like default_socket_timeout is not taken into account when making SOAP calls over HTTPS:

    • Bug #48524 - Timeout setting is not considered on SOAP+HTTPS calls.

    Bug open at the time of writing. As a comment on the blog post Robert Ludwick referenced in a deleted answer Timing Out PHP Soap Calls (21 Oct 2009; by Published by Robert F. Ludwick) points out, the workaround the post discusses (overriding SoapClient::__doRequest() with a curl request) works around this bug also.

    • archived copy of <http://www.darqbyte.com/2009/10/21/timing-out-php-soap-calls/>

    Another related bug is:

    • Bug #41631 - default_socket_timeout does not work with SSL

    The code mentioned in the blog post has undergone some changes and can be found in it's latest form with support of HTTP authentication here on Github:

    • SoapClientTimeout.class.php

    In any case, the workaround shouldn't be needed any longer as this problem has been fixed in the PHP SOAPClient extension.

    0 讨论(0)
  • 2021-01-30 09:50

    From my experience, if $e->getMessage is "Error Fetching http headers", you are dealing with a network timeout.

    If $e->getMessage is something like "Cannot connect to host", the service you are trying to reach is down.

    Then there is "Looks like we got no XML document", which is more cryptic an can mean different things.

    0 讨论(0)
提交回复
热议问题