Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/lib/zend/Zend/Http/Client/Adapter/Socket.php
Go to the documentation of this file.
00001 <?php
00002 
00027 require_once 'Zend/Uri/Http.php';
00031 require_once 'Zend/Http/Client/Adapter/Interface.php';
00035 require_once 'Zend/Http/Client/Adapter/Stream.php';
00036 
00047 class Zend_Http_Client_Adapter_Socket implements Zend_Http_Client_Adapter_Interface, Zend_Http_Client_Adapter_Stream
00048 {
00054     protected $socket = null;
00055 
00061     protected $connected_to = array(null, null);
00062 
00068     protected $out_stream = null;
00069     
00075     protected $config = array(
00076         'persistent'    => false,
00077         'ssltransport'  => 'ssl',
00078         'sslcert'       => null,
00079         'sslpassphrase' => null,
00080         'sslusecontext' => false
00081     );
00082 
00088     protected $method = null;
00089 
00095     protected $_context = null;
00096 
00101     public function __construct()
00102     {
00103     }
00104 
00110     public function setConfig($config = array())
00111     {
00112         if ($config instanceof Zend_Config) {
00113             $config = $config->toArray();
00114 
00115         } elseif (! is_array($config)) {
00116             require_once 'Zend/Http/Client/Adapter/Exception.php';
00117             throw new Zend_Http_Client_Adapter_Exception(
00118                 'Array or Zend_Config object expected, got ' . gettype($config)
00119             );
00120         }
00121 
00122         foreach ($config as $k => $v) {
00123             $this->config[strtolower($k)] = $v;
00124         }
00125     }
00126 
00132         public function getConfig()
00133         {
00134             return $this->config;
00135         }
00136 
00150     public function setStreamContext($context)
00151     {
00152         if (is_resource($context) && get_resource_type($context) == 'stream-context') {
00153             $this->_context = $context;
00154 
00155         } elseif (is_array($context)) {
00156             $this->_context = stream_context_create($context);
00157 
00158         } else {
00159             // Invalid parameter
00160             require_once 'Zend/Http/Client/Adapter/Exception.php';
00161             throw new Zend_Http_Client_Adapter_Exception(
00162                 "Expecting either a stream context resource or array, got " . gettype($context)
00163             );
00164         }
00165 
00166         return $this;
00167     }
00168 
00176     public function getStreamContext()
00177     {
00178         if (! $this->_context) {
00179             $this->_context = stream_context_create();
00180         }
00181 
00182         return $this->_context;
00183     }
00184 
00192     public function connect($host, $port = 80, $secure = false)
00193     {
00194         // If the URI should be accessed via SSL, prepend the Hostname with ssl://
00195         $host = ($secure ? $this->config['ssltransport'] : 'tcp') . '://' . $host;
00196 
00197         // If we are connected to the wrong host, disconnect first
00198         if (($this->connected_to[0] != $host || $this->connected_to[1] != $port)) {
00199             if (is_resource($this->socket)) $this->close();
00200         }
00201 
00202         // Now, if we are not connected, connect
00203         if (! is_resource($this->socket) || ! $this->config['keepalive']) {
00204             $context = $this->getStreamContext();
00205             if ($secure || $this->config['sslusecontext']) {
00206                 if ($this->config['sslcert'] !== null) {
00207                     if (! stream_context_set_option($context, 'ssl', 'local_cert',
00208                                                     $this->config['sslcert'])) {
00209                         require_once 'Zend/Http/Client/Adapter/Exception.php';
00210                         throw new Zend_Http_Client_Adapter_Exception('Unable to set sslcert option');
00211                     }
00212                 }
00213                 if ($this->config['sslpassphrase'] !== null) {
00214                     if (! stream_context_set_option($context, 'ssl', 'passphrase',
00215                                                     $this->config['sslpassphrase'])) {
00216                         require_once 'Zend/Http/Client/Adapter/Exception.php';
00217                         throw new Zend_Http_Client_Adapter_Exception('Unable to set sslpassphrase option');
00218                     }
00219                 }
00220             }
00221 
00222             $flags = STREAM_CLIENT_CONNECT;
00223             if ($this->config['persistent']) $flags |= STREAM_CLIENT_PERSISTENT;
00224 
00225             $this->socket = @stream_socket_client($host . ':' . $port,
00226                                                   $errno,
00227                                                   $errstr,
00228                                                   (int) $this->config['timeout'],
00229                                                   $flags,
00230                                                   $context);
00231 
00232             if (! $this->socket) {
00233                 $this->close();
00234                 require_once 'Zend/Http/Client/Adapter/Exception.php';
00235                 throw new Zend_Http_Client_Adapter_Exception(
00236                     'Unable to Connect to ' . $host . ':' . $port . '. Error #' . $errno . ': ' . $errstr);
00237             }
00238 
00239             // Set the stream timeout
00240             if (! stream_set_timeout($this->socket, (int) $this->config['timeout'])) {
00241                 require_once 'Zend/Http/Client/Adapter/Exception.php';
00242                 throw new Zend_Http_Client_Adapter_Exception('Unable to set the connection timeout');
00243             }
00244 
00245             // Update connected_to
00246             $this->connected_to = array($host, $port);
00247         }
00248     }
00249 
00260     public function write($method, $uri, $http_ver = '1.1', $headers = array(), $body = '')
00261     {
00262         // Make sure we're properly connected
00263         if (! $this->socket) {
00264             require_once 'Zend/Http/Client/Adapter/Exception.php';
00265             throw new Zend_Http_Client_Adapter_Exception('Trying to write but we are not connected');
00266         }
00267 
00268         $host = $uri->getHost();
00269         $host = (strtolower($uri->getScheme()) == 'https' ? $this->config['ssltransport'] : 'tcp') . '://' . $host;
00270         if ($this->connected_to[0] != $host || $this->connected_to[1] != $uri->getPort()) {
00271             require_once 'Zend/Http/Client/Adapter/Exception.php';
00272             throw new Zend_Http_Client_Adapter_Exception('Trying to write but we are connected to the wrong host');
00273         }
00274 
00275         // Save request method for later
00276         $this->method = $method;
00277 
00278         // Build request headers
00279         $path = $uri->getPath();
00280         if ($uri->getQuery()) $path .= '?' . $uri->getQuery();
00281         $request = "{$method} {$path} HTTP/{$http_ver}\r\n";
00282         foreach ($headers as $k => $v) {
00283             if (is_string($k)) $v = ucfirst($k) . ": $v";
00284             $request .= "$v\r\n";
00285         }
00286 
00287         if(is_resource($body)) {
00288             $request .= "\r\n";
00289         } else {
00290             // Add the request body
00291             $request .= "\r\n" . $body;
00292         }
00293         
00294         // Send the request
00295         if (! @fwrite($this->socket, $request)) {
00296             require_once 'Zend/Http/Client/Adapter/Exception.php';
00297             throw new Zend_Http_Client_Adapter_Exception('Error writing request to server');
00298         }
00299         
00300         if(is_resource($body)) {
00301             if(stream_copy_to_stream($body, $this->socket) == 0) {
00302                 require_once 'Zend/Http/Client/Adapter/Exception.php';
00303                 throw new Zend_Http_Client_Adapter_Exception('Error writing request to server');
00304             }
00305         }
00306 
00307         return $request;
00308     }
00309 
00315     public function read()
00316     {
00317         // First, read headers only
00318         $response = '';
00319         $gotStatus = false;
00320         $stream = !empty($this->config['stream']);
00321 
00322         while (($line = @fgets($this->socket)) !== false) {
00323             $gotStatus = $gotStatus || (strpos($line, 'HTTP') !== false);
00324             if ($gotStatus) {
00325                 $response .= $line;
00326                 if (rtrim($line) === '') break;
00327             }
00328         }
00329         
00330         $this->_checkSocketReadTimeout();
00331 
00332         $statusCode = Zend_Http_Response::extractCode($response);
00333 
00334         // Handle 100 and 101 responses internally by restarting the read again
00335         if ($statusCode == 100 || $statusCode == 101) return $this->read();
00336 
00337         // Check headers to see what kind of connection / transfer encoding we have
00338         $headers = Zend_Http_Response::extractHeaders($response);
00339 
00344         if ($statusCode == 304 || $statusCode == 204 ||
00345             $this->method == Zend_Http_Client::HEAD) {
00346 
00347             // Close the connection if requested to do so by the server
00348             if (isset($headers['connection']) && $headers['connection'] == 'close') {
00349                 $this->close();
00350             }
00351             return $response;
00352         }
00353 
00354         // If we got a 'transfer-encoding: chunked' header
00355         if (isset($headers['transfer-encoding'])) {
00356             
00357             if (strtolower($headers['transfer-encoding']) == 'chunked') {
00358 
00359                 do {
00360                     $line  = @fgets($this->socket);
00361                     $this->_checkSocketReadTimeout();
00362 
00363                     $chunk = $line;
00364 
00365                     // Figure out the next chunk size
00366                     $chunksize = trim($line);
00367                     if (! ctype_xdigit($chunksize)) {
00368                         $this->close();
00369                         require_once 'Zend/Http/Client/Adapter/Exception.php';
00370                         throw new Zend_Http_Client_Adapter_Exception('Invalid chunk size "' .
00371                             $chunksize . '" unable to read chunked body');
00372                     }
00373 
00374                     // Convert the hexadecimal value to plain integer
00375                     $chunksize = hexdec($chunksize);
00376 
00377                     // Read next chunk
00378                     $read_to = ftell($this->socket) + $chunksize;
00379 
00380                     do {
00381                         $current_pos = ftell($this->socket);
00382                         if ($current_pos >= $read_to) break;
00383 
00384                         if($this->out_stream) {
00385                             if(stream_copy_to_stream($this->socket, $this->out_stream, $read_to - $current_pos) == 0) {
00386                               $this->_checkSocketReadTimeout();
00387                               break;   
00388                              }
00389                         } else {
00390                             $line = @fread($this->socket, $read_to - $current_pos);
00391                             if ($line === false || strlen($line) === 0) {
00392                                 $this->_checkSocketReadTimeout();
00393                                 break;
00394                             }
00395                                     $chunk .= $line;
00396                         }
00397                     } while (! feof($this->socket));
00398 
00399                     $chunk .= @fgets($this->socket);
00400                     $this->_checkSocketReadTimeout();
00401 
00402                     if(!$this->out_stream) {
00403                         $response .= $chunk;
00404                     }
00405                 } while ($chunksize > 0);
00406             } else {
00407                 $this->close();
00408                 throw new Zend_Http_Client_Adapter_Exception('Cannot handle "' .
00409                     $headers['transfer-encoding'] . '" transfer encoding');
00410             }
00411             
00412             // We automatically decode chunked-messages when writing to a stream
00413             // this means we have to disallow the Zend_Http_Response to do it again
00414             if ($this->out_stream) {
00415                 $response = str_ireplace("Transfer-Encoding: chunked\r\n", '', $response);
00416             }
00417         // Else, if we got the content-length header, read this number of bytes
00418         } elseif (isset($headers['content-length'])) {
00419 
00420             // If we got more than one Content-Length header (see ZF-9404) use
00421             // the last value sent
00422             if (is_array($headers['content-length'])) {
00423                 $contentLength = $headers['content-length'][count($headers['content-length']) - 1]; 
00424             } else {
00425                 $contentLength = $headers['content-length'];
00426             }
00427             
00428             $current_pos = ftell($this->socket);
00429             $chunk = '';
00430 
00431             for ($read_to = $current_pos + $contentLength;
00432                  $read_to > $current_pos;
00433                  $current_pos = ftell($this->socket)) {
00434 
00435                  if($this->out_stream) {
00436                      if(@stream_copy_to_stream($this->socket, $this->out_stream, $read_to - $current_pos) == 0) {
00437                           $this->_checkSocketReadTimeout();
00438                           break;   
00439                      }
00440                  } else {
00441                     $chunk = @fread($this->socket, $read_to - $current_pos);
00442                     if ($chunk === false || strlen($chunk) === 0) {
00443                         $this->_checkSocketReadTimeout();
00444                         break;
00445                     }
00446 
00447                     $response .= $chunk;
00448                 }
00449 
00450                 // Break if the connection ended prematurely
00451                 if (feof($this->socket)) break;
00452             }
00453 
00454         // Fallback: just read the response until EOF
00455         } else {
00456 
00457             do {
00458                 if($this->out_stream) {
00459                     if(@stream_copy_to_stream($this->socket, $this->out_stream) == 0) {
00460                           $this->_checkSocketReadTimeout();
00461                           break;   
00462                      }
00463                 }  else {
00464                     $buff = @fread($this->socket, 8192);
00465                     if ($buff === false || strlen($buff) === 0) {
00466                         $this->_checkSocketReadTimeout();
00467                         break;
00468                     } else {
00469                         $response .= $buff;
00470                     }
00471                 }
00472 
00473             } while (feof($this->socket) === false);
00474 
00475             $this->close();
00476         }
00477 
00478         // Close the connection if requested to do so by the server
00479         if (isset($headers['connection']) && $headers['connection'] == 'close') {
00480             $this->close();
00481         }
00482 
00483         return $response;
00484     }
00485 
00490     public function close()
00491     {
00492         if (is_resource($this->socket)) @fclose($this->socket);
00493         $this->socket = null;
00494         $this->connected_to = array(null, null);
00495     }
00496 
00503     protected function _checkSocketReadTimeout()
00504     {
00505         if ($this->socket) {
00506             $info = stream_get_meta_data($this->socket);
00507             $timedout = $info['timed_out'];
00508             if ($timedout) {
00509                 $this->close();
00510                 require_once 'Zend/Http/Client/Adapter/Exception.php';
00511                 throw new Zend_Http_Client_Adapter_Exception(
00512                     "Read timed out after {$this->config['timeout']} seconds",
00513                     Zend_Http_Client_Adapter_Exception::READ_TIMEOUT
00514                 );
00515             }
00516         }
00517     }
00518     
00525     public function setOutputStream($stream) 
00526     {
00527         $this->out_stream = $stream;
00528         return $this;
00529     }
00530     
00537     public function __destruct()
00538     {
00539         if (! $this->config['persistent']) {
00540             if ($this->socket) $this->close();
00541         }
00542     }
00543 }
 All Data Structures Namespaces Files Functions Variables Enumerations