Source for file Socket.php
Documentation is available at Socket.php
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
* @package Microsoft_Http
* @subpackage Client_Adapter
* @version $Id: Socket.php 19219 2009-11-24 22:25:36Z stas $
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @see Microsoft_AutoLoader
require_once dirname(__FILE__ ) . '/../../../AutoLoader.php';
* A sockets based (stream_socket_client) adapter class for Microsoft_Http_Client. Can be used
* on almost every PHP environment, and does not require any special extensions.
* @package Microsoft_Http
* @subpackage Client_Adapter
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* The socket for server connection
* What host/port are we connected to?
* Stream for storing output
* Request method - will be set by write() and might be used by read()
* Adapter constructor, currently empty. Config is set using setConfig()
* Set the configuration array for the adapter
require_once 'Microsoft/Http/Client/Adapter/Exception.php';
'Array expected, got ' . gettype($config)
foreach ($config as $k => $v) {
* Retrieve the array of all configuration options
* Set the stream context for the TCP connection to the server
* Can accept either a pre-existing stream context resource, or an array
* of stream options, similar to the options array passed to the
* stream_context_create() PHP function. In such case a new stream context
* will be created using the passed options.
* @since Zend Framework 1.9
* @param mixed $context Stream context or array of context options
* @return Microsoft_Http_Client_Adapter_Socket
require_once 'Microsoft/Http/Client/Adapter/Exception.php';
"Expecting either a stream context resource or array, got " . gettype($context)
* Get the stream context for the TCP connection to the server.
* If no stream context is set, will create a default one.
* Connect to the remote server
public function connect($host, $port = 80, $secure = false)
// If the URI should be accessed via SSL, prepend the Hostname with ssl://
$host = ($secure ? $this->config['ssltransport'] : 'tcp') . '://' . $host;
// If we are connected to the wrong host, disconnect first
// Now, if we are not connected, connect
if ($this->config['sslcert'] !== null) {
require_once 'Microsoft/Http/Client/Adapter/Exception.php';
if ($this->config['sslpassphrase'] !== null) {
$this->config['sslpassphrase'])) {
require_once 'Microsoft/Http/Client/Adapter/Exception.php';
$flags = STREAM_CLIENT_CONNECT;
if ($this->config['persistent']) $flags |= STREAM_CLIENT_PERSISTENT;
(int) $this->config['timeout'],
require_once 'Microsoft/Http/Client/Adapter/Exception.php';
'Unable to Connect to ' . $host . ':' . $port . '. Error #' . $errno . ': ' . $errstr);
// Set the stream timeout
require_once 'Microsoft/Http/Client/Adapter/Exception.php';
* Send request to the remote server
* @param Microsoft_Uri_Http $uri
* @param string $http_ver
* @return string Request as string
public function write($method, $uri, $http_ver = '1.1', $headers = array(), $body = '')
// Make sure we're properly connected
require_once 'Microsoft/Http/Client/Adapter/Exception.php';
$host = (strtolower($uri->getScheme()) == 'https' ? $this->config['ssltransport'] : 'tcp') . '://' . $host;
require_once 'Microsoft/Http/Client/Adapter/Exception.php';
// Save request method for later
if ($uri->getQuery()) $path .= '?' . $uri->getQuery();
$request = "{ $method} {$path} HTTP/{$http_ver}\r\n";
foreach ($headers as $k => $v) {
$request .= "\r\n" . $body;
require_once 'Microsoft/Http/Client/Adapter/Exception.php';
require_once 'Microsoft/Http/Client/Adapter/Exception.php';
* Read response from server
// First, read headers only
$stream = !empty($this->config['stream']);
$gotStatus = $gotStatus || (strpos($line, 'HTTP') !== false);
if (rtrim($line) === '') break;
// Handle 100 and 101 responses internally by restarting the read again
if ($statusCode == 100 || $statusCode == 101) return $this->read();
// Check headers to see what kind of connection / transfer encoding we have
* Responses to HEAD requests and 204 or 304 responses are not expected
* to have a body - stop reading here
if ($statusCode == 304 || $statusCode == 204 ||
// Close the connection if requested to do so by the server
if (isset ($headers['connection']) && $headers['connection'] == 'close') {
// If we got a 'transfer-encoding: chunked' header
if (isset ($headers['transfer-encoding'])) {
if (strtolower($headers['transfer-encoding']) == 'chunked') {
// Figure out the next chunk size
$chunksize = trim($line);
require_once 'Microsoft/Http/Client/Adapter/Exception.php';
$chunksize . '" unable to read chunked body');
// Convert the hexadecimal value to plain integer
$chunksize = hexdec($chunksize);
if ($current_pos >= $read_to) break;
$line = @fread($this->socket, $read_to - $current_pos);
if ($line === false || strlen($line) === 0) {
} while ($chunksize > 0);
$headers['transfer-encoding'] . '" transfer encoding');
// We automatically decode chunked-messages when writing to a stream
// this means we have to disallow the Microsoft_Http_Response to do it again
$response = str_ireplace("Transfer-Encoding: chunked\r\n", '', $response);
// Else, if we got the content-length header, read this number of bytes
} elseif (isset ($headers['content-length'])) {
for ($read_to = $current_pos + $headers['content-length'];
$chunk = @fread($this->socket, $read_to - $current_pos);
if ($chunk === false || strlen($chunk) === 0) {
// Break if the connection ended prematurely
// Fallback: just read the response until EOF
if ($buff === false || strlen($buff) === 0) {
// Close the connection if requested to do so by the server
if (isset ($headers['connection']) && $headers['connection'] == 'close') {
* Close the connection to the server
* Check if the socket has timed out - if so close connection and throw
* @throws Microsoft_Http_Client_Adapter_Exception with READ_TIMEOUT code
$timedout = $info['timed_out'];
require_once 'Microsoft/Http/Client/Adapter/Exception.php';
"Read timed out after {$this->config['timeout']} seconds ",
* Set output stream for the response
* @param resource $stream
* @return Microsoft_Http_Client_Adapter_Socket
* Destructor: make sure the socket is disconnected
* If we are in persistent TCP mode, will not close the connection
if (! $this->config['persistent']) {
|