web/lib/Zend/Http/Client/Adapter/Socket.php
changeset 807 877f952ae2bd
parent 207 621fa6caec0c
child 1230 68c69c656a2c
equal deleted inserted replaced
805:5e7a0fedabdf 807:877f952ae2bd
    14  * to license@zend.com so we can send you a copy immediately.
    14  * to license@zend.com so we can send you a copy immediately.
    15  *
    15  *
    16  * @category   Zend
    16  * @category   Zend
    17  * @package    Zend_Http
    17  * @package    Zend_Http
    18  * @subpackage Client_Adapter
    18  * @subpackage Client_Adapter
    19  * @version    $Id: Socket.php 22576 2010-07-16 15:49:24Z dragonbe $
    19  * @version    $Id: Socket.php 24593 2012-01-05 20:35:02Z matthew $
    20  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
    20  * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
    21  * @license    http://framework.zend.com/license/new-bsd     New BSD License
    21  * @license    http://framework.zend.com/license/new-bsd     New BSD License
    22  */
    22  */
    23 
    23 
    24 /**
    24 /**
    25  * @see Zend_Uri_Http
    25  * @see Zend_Uri_Http
    39  * on almost every PHP environment, and does not require any special extensions.
    39  * on almost every PHP environment, and does not require any special extensions.
    40  *
    40  *
    41  * @category   Zend
    41  * @category   Zend
    42  * @package    Zend_Http
    42  * @package    Zend_Http
    43  * @subpackage Client_Adapter
    43  * @subpackage Client_Adapter
    44  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
    44  * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
    45  * @license    http://framework.zend.com/license/new-bsd     New BSD License
    45  * @license    http://framework.zend.com/license/new-bsd     New BSD License
    46  */
    46  */
    47 class Zend_Http_Client_Adapter_Socket implements Zend_Http_Client_Adapter_Interface, Zend_Http_Client_Adapter_Stream
    47 class Zend_Http_Client_Adapter_Socket implements Zend_Http_Client_Adapter_Interface, Zend_Http_Client_Adapter_Stream
    48 {
    48 {
    49     /**
    49     /**
    60      */
    60      */
    61     protected $connected_to = array(null, null);
    61     protected $connected_to = array(null, null);
    62 
    62 
    63     /**
    63     /**
    64      * Stream for storing output
    64      * Stream for storing output
    65      * 
    65      *
    66      * @var resource
    66      * @var resource
    67      */
    67      */
    68     protected $out_stream = null;
    68     protected $out_stream = null;
    69     
    69 
    70     /**
    70     /**
    71      * Parameters array
    71      * Parameters array
    72      *
    72      *
    73      * @var array
    73      * @var array
    74      */
    74      */
   122         foreach ($config as $k => $v) {
   122         foreach ($config as $k => $v) {
   123             $this->config[strtolower($k)] = $v;
   123             $this->config[strtolower($k)] = $v;
   124         }
   124         }
   125     }
   125     }
   126 
   126 
   127 	/**
   127     /**
   128  	 * Retrieve the array of all configuration options
   128       * Retrieve the array of all configuration options
   129  	 *
   129       *
   130  	 * @return array
   130       * @return array
   131  	 */
   131       */
   132  	public function getConfig()
   132      public function getConfig()
   133  	{
   133      {
   134  	    return $this->config;
   134          return $this->config;
   135  	}
   135      }
   136 
   136 
   137  	/**
   137      /**
   138      * Set the stream context for the TCP connection to the server
   138      * Set the stream context for the TCP connection to the server
   139      *
   139      *
   140      * Can accept either a pre-existing stream context resource, or an array
   140      * Can accept either a pre-existing stream context resource, or an array
   141      * of stream options, similar to the options array passed to the
   141      * of stream options, similar to the options array passed to the
   142      * stream_context_create() PHP function. In such case a new stream context
   142      * stream_context_create() PHP function. In such case a new stream context
   288             $request .= "\r\n";
   288             $request .= "\r\n";
   289         } else {
   289         } else {
   290             // Add the request body
   290             // Add the request body
   291             $request .= "\r\n" . $body;
   291             $request .= "\r\n" . $body;
   292         }
   292         }
   293         
   293 
   294         // Send the request
   294         // Send the request
   295         if (! @fwrite($this->socket, $request)) {
   295         if (! @fwrite($this->socket, $request)) {
   296             require_once 'Zend/Http/Client/Adapter/Exception.php';
   296             require_once 'Zend/Http/Client/Adapter/Exception.php';
   297             throw new Zend_Http_Client_Adapter_Exception('Error writing request to server');
   297             throw new Zend_Http_Client_Adapter_Exception('Error writing request to server');
   298         }
   298         }
   299         
   299 
   300         if(is_resource($body)) {
   300         if(is_resource($body)) {
   301             if(stream_copy_to_stream($body, $this->socket) == 0) {
   301             if(stream_copy_to_stream($body, $this->socket) == 0) {
   302                 require_once 'Zend/Http/Client/Adapter/Exception.php';
   302                 require_once 'Zend/Http/Client/Adapter/Exception.php';
   303                 throw new Zend_Http_Client_Adapter_Exception('Error writing request to server');
   303                 throw new Zend_Http_Client_Adapter_Exception('Error writing request to server');
   304             }
   304             }
   315     public function read()
   315     public function read()
   316     {
   316     {
   317         // First, read headers only
   317         // First, read headers only
   318         $response = '';
   318         $response = '';
   319         $gotStatus = false;
   319         $gotStatus = false;
   320         $stream = !empty($this->config['stream']);
       
   321 
   320 
   322         while (($line = @fgets($this->socket)) !== false) {
   321         while (($line = @fgets($this->socket)) !== false) {
   323             $gotStatus = $gotStatus || (strpos($line, 'HTTP') !== false);
   322             $gotStatus = $gotStatus || (strpos($line, 'HTTP') !== false);
   324             if ($gotStatus) {
   323             if ($gotStatus) {
   325                 $response .= $line;
   324                 $response .= $line;
   326                 if (rtrim($line) === '') break;
   325                 if (rtrim($line) === '') break;
   327             }
   326             }
   328         }
   327         }
   329         
   328 
   330         $this->_checkSocketReadTimeout();
   329         $this->_checkSocketReadTimeout();
   331 
   330 
   332         $statusCode = Zend_Http_Response::extractCode($response);
   331         $statusCode = Zend_Http_Response::extractCode($response);
   333 
   332 
   334         // Handle 100 and 101 responses internally by restarting the read again
   333         // Handle 100 and 101 responses internally by restarting the read again
   351             return $response;
   350             return $response;
   352         }
   351         }
   353 
   352 
   354         // If we got a 'transfer-encoding: chunked' header
   353         // If we got a 'transfer-encoding: chunked' header
   355         if (isset($headers['transfer-encoding'])) {
   354         if (isset($headers['transfer-encoding'])) {
   356             
   355 
   357             if (strtolower($headers['transfer-encoding']) == 'chunked') {
   356             if (strtolower($headers['transfer-encoding']) == 'chunked') {
   358 
   357 
   359                 do {
   358                 do {
   360                     $line  = @fgets($this->socket);
   359                     $line  = @fgets($this->socket);
   361                     $this->_checkSocketReadTimeout();
   360                     $this->_checkSocketReadTimeout();
   382                         if ($current_pos >= $read_to) break;
   381                         if ($current_pos >= $read_to) break;
   383 
   382 
   384                         if($this->out_stream) {
   383                         if($this->out_stream) {
   385                             if(stream_copy_to_stream($this->socket, $this->out_stream, $read_to - $current_pos) == 0) {
   384                             if(stream_copy_to_stream($this->socket, $this->out_stream, $read_to - $current_pos) == 0) {
   386                               $this->_checkSocketReadTimeout();
   385                               $this->_checkSocketReadTimeout();
   387                               break;   
   386                               break;
   388                              }
   387                              }
   389                         } else {
   388                         } else {
   390                             $line = @fread($this->socket, $read_to - $current_pos);
   389                             $line = @fread($this->socket, $read_to - $current_pos);
   391                             if ($line === false || strlen($line) === 0) {
   390                             if ($line === false || strlen($line) === 0) {
   392                                 $this->_checkSocketReadTimeout();
   391                                 $this->_checkSocketReadTimeout();
   403                         $response .= $chunk;
   402                         $response .= $chunk;
   404                     }
   403                     }
   405                 } while ($chunksize > 0);
   404                 } while ($chunksize > 0);
   406             } else {
   405             } else {
   407                 $this->close();
   406                 $this->close();
   408 		require_once 'Zend/Http/Client/Adapter/Exception.php';
   407         require_once 'Zend/Http/Client/Adapter/Exception.php';
   409                 throw new Zend_Http_Client_Adapter_Exception('Cannot handle "' .
   408                 throw new Zend_Http_Client_Adapter_Exception('Cannot handle "' .
   410                     $headers['transfer-encoding'] . '" transfer encoding');
   409                     $headers['transfer-encoding'] . '" transfer encoding');
   411             }
   410             }
   412             
   411 
   413             // We automatically decode chunked-messages when writing to a stream
   412             // We automatically decode chunked-messages when writing to a stream
   414             // this means we have to disallow the Zend_Http_Response to do it again
   413             // this means we have to disallow the Zend_Http_Response to do it again
   415             if ($this->out_stream) {
   414             if ($this->out_stream) {
   416                 $response = str_ireplace("Transfer-Encoding: chunked\r\n", '', $response);
   415                 $response = str_ireplace("Transfer-Encoding: chunked\r\n", '', $response);
   417             }
   416             }
   419         } elseif (isset($headers['content-length'])) {
   418         } elseif (isset($headers['content-length'])) {
   420 
   419 
   421             // If we got more than one Content-Length header (see ZF-9404) use
   420             // If we got more than one Content-Length header (see ZF-9404) use
   422             // the last value sent
   421             // the last value sent
   423             if (is_array($headers['content-length'])) {
   422             if (is_array($headers['content-length'])) {
   424                 $contentLength = $headers['content-length'][count($headers['content-length']) - 1]; 
   423                 $contentLength = $headers['content-length'][count($headers['content-length']) - 1];
   425             } else {
   424             } else {
   426                 $contentLength = $headers['content-length'];
   425                 $contentLength = $headers['content-length'];
   427             }
   426             }
   428             
   427 
   429             $current_pos = ftell($this->socket);
   428             $current_pos = ftell($this->socket);
   430             $chunk = '';
   429             $chunk = '';
   431 
   430 
   432             for ($read_to = $current_pos + $contentLength;
   431             for ($read_to = $current_pos + $contentLength;
   433                  $read_to > $current_pos;
   432                  $read_to > $current_pos;
   434                  $current_pos = ftell($this->socket)) {
   433                  $current_pos = ftell($this->socket)) {
   435 
   434 
   436                  if($this->out_stream) {
   435                  if($this->out_stream) {
   437                      if(@stream_copy_to_stream($this->socket, $this->out_stream, $read_to - $current_pos) == 0) {
   436                      if(@stream_copy_to_stream($this->socket, $this->out_stream, $read_to - $current_pos) == 0) {
   438                           $this->_checkSocketReadTimeout();
   437                           $this->_checkSocketReadTimeout();
   439                           break;   
   438                           break;
   440                      }
   439                      }
   441                  } else {
   440                  } else {
   442                     $chunk = @fread($this->socket, $read_to - $current_pos);
   441                     $chunk = @fread($this->socket, $read_to - $current_pos);
   443                     if ($chunk === false || strlen($chunk) === 0) {
   442                     if ($chunk === false || strlen($chunk) === 0) {
   444                         $this->_checkSocketReadTimeout();
   443                         $this->_checkSocketReadTimeout();
   457 
   456 
   458             do {
   457             do {
   459                 if($this->out_stream) {
   458                 if($this->out_stream) {
   460                     if(@stream_copy_to_stream($this->socket, $this->out_stream) == 0) {
   459                     if(@stream_copy_to_stream($this->socket, $this->out_stream) == 0) {
   461                           $this->_checkSocketReadTimeout();
   460                           $this->_checkSocketReadTimeout();
   462                           break;   
   461                           break;
   463                      }
   462                      }
   464                 }  else {
   463                 }  else {
   465                     $buff = @fread($this->socket, 8192);
   464                     $buff = @fread($this->socket, 8192);
   466                     if ($buff === false || strlen($buff) === 0) {
   465                     if ($buff === false || strlen($buff) === 0) {
   467                         $this->_checkSocketReadTimeout();
   466                         $this->_checkSocketReadTimeout();
   514                     Zend_Http_Client_Adapter_Exception::READ_TIMEOUT
   513                     Zend_Http_Client_Adapter_Exception::READ_TIMEOUT
   515                 );
   514                 );
   516             }
   515             }
   517         }
   516         }
   518     }
   517     }
   519     
   518 
   520     /**
   519     /**
   521      * Set output stream for the response
   520      * Set output stream for the response
   522      * 
   521      *
   523      * @param resource $stream
   522      * @param resource $stream
   524      * @return Zend_Http_Client_Adapter_Socket
   523      * @return Zend_Http_Client_Adapter_Socket
   525      */
   524      */
   526     public function setOutputStream($stream) 
   525     public function setOutputStream($stream)
   527     {
   526     {
   528         $this->out_stream = $stream;
   527         $this->out_stream = $stream;
   529         return $this;
   528         return $this;
   530     }
   529     }
   531     
   530 
   532     /**
   531     /**
   533      * Destructor: make sure the socket is disconnected
   532      * Destructor: make sure the socket is disconnected
   534      *
   533      *
   535      * If we are in persistent TCP mode, will not close the connection
   534      * If we are in persistent TCP mode, will not close the connection
   536      *
   535      *