XpressEngine Core  1.11.2
 All Classes Namespaces Files Functions Variables Pages
SocketWrapper.php
Go to the documentation of this file.
1 <?php
22 require_once 'HTTP/Request2/Exception.php';
23 
40 {
45  protected $connectionWarnings = array();
46 
51  protected $socket;
52 
57  protected $deadline;
58 
63  protected $timeout;
64 
76  public function __construct($address, $timeout, array $contextOptions = array())
77  {
78  if (!empty($contextOptions)
79  && !isset($contextOptions['socket']) && !isset($contextOptions['ssl'])
80  ) {
81  // Backwards compatibility with 2.1.0 and 2.1.1 releases
82  $contextOptions = array('ssl' => $contextOptions);
83  }
84  $context = stream_context_create();
85  foreach ($contextOptions as $wrapper => $options) {
86  foreach ($options as $name => $value) {
87  if (!stream_context_set_option($context, $wrapper, $name, $value)) {
89  "Error setting '{$wrapper}' wrapper context option '{$name}'"
90  );
91  }
92  }
93  }
94  set_error_handler(array($this, 'connectionWarningsHandler'));
95  $this->socket = stream_socket_client(
96  $address, $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $context
97  );
98  restore_error_handler();
99  // if we fail to bind to a specified local address (see request #19515),
100  // connection still succeeds, albeit with a warning. Throw an Exception
101  // with the warning text in this case as that connection is unlikely
102  // to be what user wants and as Curl throws an error in similar case.
103  if ($this->connectionWarnings) {
104  if ($this->socket) {
105  fclose($this->socket);
106  }
107  $error = $errstr ? $errstr : implode("\n", $this->connectionWarnings);
109  "Unable to connect to {$address}. Error: {$error}", 0, $errno
110  );
111  }
112  }
113 
117  public function __destruct()
118  {
119  fclose($this->socket);
120  }
121 
130  public function read($length)
131  {
132  if ($this->deadline) {
133  stream_set_timeout($this->socket, max($this->deadline - time(), 1));
134  }
135  $data = fread($this->socket, $length);
136  $this->checkTimeout();
137  return $data;
138  }
139 
153  public function readLine($bufferSize, $localTimeout = null)
154  {
155  $line = '';
156  while (!feof($this->socket)) {
157  if (null !== $localTimeout) {
158  stream_set_timeout($this->socket, $localTimeout);
159  } elseif ($this->deadline) {
160  stream_set_timeout($this->socket, max($this->deadline - time(), 1));
161  }
162 
163  $line .= @fgets($this->socket, $bufferSize);
164 
165  if (null === $localTimeout) {
166  $this->checkTimeout();
167 
168  } else {
169  $info = stream_get_meta_data($this->socket);
170  // reset socket timeout if we don't have request timeout specified,
171  // prevents further calls failing with a bogus Exception
172  if (!$this->deadline) {
173  $default = (int)@ini_get('default_socket_timeout');
174  stream_set_timeout($this->socket, $default > 0 ? $default : PHP_INT_MAX);
175  }
176  if ($info['timed_out']) {
178  "readLine() call timed out", HTTP_Request2_Exception::TIMEOUT
179  );
180  }
181  }
182  if (substr($line, -1) == "\n") {
183  return rtrim($line, "\r\n");
184  }
185  }
186  return $line;
187  }
188 
197  public function write($data)
198  {
199  if ($this->deadline) {
200  stream_set_timeout($this->socket, max($this->deadline - time(), 1));
201  }
202  $written = fwrite($this->socket, $data);
203  $this->checkTimeout();
204  // http://www.php.net/manual/en/function.fwrite.php#96951
205  if ($written < strlen($data)) {
206  throw new HTTP_Request2_MessageException('Error writing request');
207  }
208  return $written;
209  }
210 
216  public function eof()
217  {
218  return feof($this->socket);
219  }
220 
229  public function setDeadline($deadline, $timeout)
230  {
231  $this->deadline = $deadline;
232  $this->timeout = $timeout;
233  }
234 
240  public function enableCrypto()
241  {
242  $modes = array(
243  STREAM_CRYPTO_METHOD_TLS_CLIENT,
244  STREAM_CRYPTO_METHOD_SSLv3_CLIENT,
245  STREAM_CRYPTO_METHOD_SSLv23_CLIENT,
246  STREAM_CRYPTO_METHOD_SSLv2_CLIENT
247  );
248 
249  foreach ($modes as $mode) {
250  if (stream_socket_enable_crypto($this->socket, true, $mode)) {
251  return;
252  }
253  }
255  'Failed to enable secure connection when connecting through proxy'
256  );
257  }
258 
264  protected function checkTimeout()
265  {
266  $info = stream_get_meta_data($this->socket);
267  if ($info['timed_out'] || $this->deadline && time() > $this->deadline) {
268  $reason = $this->deadline
269  ? "after {$this->timeout} second(s)"
270  : 'due to default_socket_timeout php.ini setting';
272  "Request timed out {$reason}", HTTP_Request2_Exception::TIMEOUT
273  );
274  }
275  }
276 
289  protected function connectionWarningsHandler($errno, $errstr)
290  {
291  if ($errno & E_WARNING) {
292  array_unshift($this->connectionWarnings, $errstr);
293  }
294  return true;
295  }
296 }
297 ?>
connectionWarningsHandler($errno, $errstr)
readLine($bufferSize, $localTimeout=null)
setDeadline($deadline, $timeout)
__construct($address, $timeout, array $contextOptions=array())