3 // +----------------------------------------------------------------------+
5 // +----------------------------------------------------------------------+
6 // | Copyright (c) 1997-2003 The PHP Group |
7 // +----------------------------------------------------------------------+
8 // | This source file is subject to version 2.0 of the PHP license, |
9 // | that is bundled with this package in the file LICENSE, and is |
10 // | available at through the world-wide-web at |
11 // | http://www.php.net/license/2_02.txt. |
12 // | If you did not receive a copy of the PHP license and are unable to |
13 // | obtain it through the world-wide-web, please send a note to |
14 // | license@php.net so we can mail you a copy immediately. |
15 // +----------------------------------------------------------------------+
16 // | Authors: Stig Bakken <ssb@php.net> |
17 // | Chuck Hagenbuch <chuck@horde.org> |
18 // +----------------------------------------------------------------------+
20 // $Id: Socket.php,v 1.38 2008/02/15 18:24:17 chagenbu Exp $
22 require_once 'PEAR.php';
24 define('NET_SOCKET_READ', 1);
25 define('NET_SOCKET_WRITE', 2);
26 define('NET_SOCKET_ERROR', 4);
29 * Generalized Socket class.
32 * @author Stig Bakken <ssb@php.net>
33 * @author Chuck Hagenbuch <chuck@horde.org>
35 class Net_Socket extends PEAR {
38 * Socket file pointer.
44 * Whether the socket is blocking. Defaults to true.
45 * @var boolean $blocking
50 * Whether the socket is persistent. Defaults to false.
51 * @var boolean $persistent
53 var $persistent = false;
56 * The IP address to connect to.
62 * The port number to connect to.
68 * Number of seconds to wait on socket connections before assuming
69 * there's no more data. Defaults to no timeout.
70 * @var integer $timeout
75 * Number of bytes to read at a time in readLine() and
76 * readAll(). Defaults to 2048.
77 * @var integer $lineLength
79 var $lineLength = 2048;
82 * Connect to the specified port. If called when the socket is
83 * already connected, it disconnects and connects again.
85 * @param string $addr IP address or host name.
86 * @param integer $port TCP port number.
87 * @param boolean $persistent (optional) Whether the connection is
88 * persistent (kept open between requests
90 * @param integer $timeout (optional) How long to wait for data.
91 * @param array $options See options for stream_context_create.
95 * @return boolean | PEAR_Error True on success or a PEAR_Error on failure.
97 function connect($addr, $port = 0, $persistent = null, $timeout = null, $options = null)
99 if (is_resource($this->fp)) {
105 return $this->raiseError('$addr cannot be empty');
106 } elseif (strspn($addr, '.0123456789') == strlen($addr) ||
107 strstr($addr, '/') !== false) {
110 $this->addr = @gethostbyname($addr);
113 $this->port = $port % 65536;
115 if ($persistent !== null) {
116 $this->persistent = $persistent;
119 if ($timeout !== null) {
120 $this->timeout = $timeout;
123 $openfunc = $this->persistent ? 'pfsockopen' : 'fsockopen';
126 $old_track_errors = @ini_set('track_errors', 1);
127 if ($options && function_exists('stream_context_create')) {
128 if ($this->timeout) {
129 $timeout = $this->timeout;
133 $context = stream_context_create($options);
135 // Since PHP 5 fsockopen doesn't allow context specification
136 if (function_exists('stream_socket_client')) {
137 $flags = $this->persistent ? STREAM_CLIENT_PERSISTENT : STREAM_CLIENT_CONNECT;
138 $addr = $this->addr . ':' . $this->port;
139 $fp = stream_socket_client($addr, $errno, $errstr, $timeout, $flags, $context);
141 $fp = @$openfunc($this->addr, $this->port, $errno, $errstr, $timeout, $context);
144 if ($this->timeout) {
145 $fp = @$openfunc($this->addr, $this->port, $errno, $errstr, $this->timeout);
147 $fp = @$openfunc($this->addr, $this->port, $errno, $errstr);
152 if ($errno == 0 && isset($php_errormsg)) {
153 $errstr = $php_errormsg;
155 @ini_set('track_errors', $old_track_errors);
156 return $this->raiseError($errstr, $errno);
159 @ini_set('track_errors', $old_track_errors);
162 return $this->setBlocking($this->blocking);
166 * Disconnects from the peer, closes the socket.
169 * @return mixed true on success or a PEAR_Error instance otherwise
171 function disconnect()
173 if (!is_resource($this->fp)) {
174 return $this->raiseError('not connected');
183 * Find out if the socket is in blocking mode.
186 * @return boolean The current blocking mode.
188 function isBlocking()
190 return $this->blocking;
194 * Sets whether the socket connection should be blocking or
195 * not. A read call to a non-blocking socket will return immediately
196 * if there is no data available, whereas it will block until there
197 * is data for blocking sockets.
199 * @param boolean $mode True for blocking sockets, false for nonblocking.
201 * @return mixed true on success or a PEAR_Error instance otherwise
203 function setBlocking($mode)
205 if (!is_resource($this->fp)) {
206 return $this->raiseError('not connected');
209 $this->blocking = $mode;
210 socket_set_blocking($this->fp, $this->blocking);
215 * Sets the timeout value on socket descriptor,
216 * expressed in the sum of seconds and microseconds
218 * @param integer $seconds Seconds.
219 * @param integer $microseconds Microseconds.
221 * @return mixed true on success or a PEAR_Error instance otherwise
223 function setTimeout($seconds, $microseconds)
225 if (!is_resource($this->fp)) {
226 return $this->raiseError('not connected');
229 return socket_set_timeout($this->fp, $seconds, $microseconds);
233 * Sets the file buffering size on the stream.
234 * See php's stream_set_write_buffer for more information.
236 * @param integer $size Write buffer size.
238 * @return mixed on success or an PEAR_Error object otherwise
240 function setWriteBuffer($size)
242 if (!is_resource($this->fp)) {
243 return $this->raiseError('not connected');
246 $returned = stream_set_write_buffer($this->fp, $size);
247 if ($returned == 0) {
250 return $this->raiseError('Cannot set write buffer.');
254 * Returns information about an existing socket resource.
255 * Currently returns four entries in the result array:
258 * timed_out (bool) - The socket timed out waiting for data<br>
259 * blocked (bool) - The socket was blocked<br>
260 * eof (bool) - Indicates EOF event<br>
261 * unread_bytes (int) - Number of bytes left in the socket buffer<br>
265 * @return mixed Array containing information about existing socket resource or a PEAR_Error instance otherwise
269 if (!is_resource($this->fp)) {
270 return $this->raiseError('not connected');
273 return socket_get_status($this->fp);
277 * Get a specified line of data
280 * @return $size bytes of data from the socket, or a PEAR_Error if
285 if (!is_resource($this->fp)) {
286 return $this->raiseError('not connected');
289 return @fgets($this->fp, $size);
293 * Read a specified amount of data. This is guaranteed to return,
294 * and has the added benefit of getting everything in one fread()
295 * chunk; if you know the size of the data you're getting
296 * beforehand, this is definitely the way to go.
298 * @param integer $size The number of bytes to read from the socket.
300 * @return $size bytes of data from the socket, or a PEAR_Error if
305 if (!is_resource($this->fp)) {
306 return $this->raiseError('not connected');
309 return @fread($this->fp, $size);
313 * Write a specified amount of data.
315 * @param string $data Data to write.
316 * @param integer $blocksize Amount of data to write at once.
317 * NULL means all at once.
320 * @return mixed If the socket is not connected, returns an instance of PEAR_Error
321 * If the write succeeds, returns the number of bytes written
322 * If the write fails, returns false.
324 function write($data, $blocksize = null)
326 if (!is_resource($this->fp)) {
327 return $this->raiseError('not connected');
330 if (is_null($blocksize) && !OS_WINDOWS) {
331 return @fwrite($this->fp, $data);
333 if (is_null($blocksize)) {
338 $size = strlen($data);
339 while ($pos < $size) {
340 $written = @fwrite($this->fp, substr($data, $pos, $blocksize));
341 if ($written === false) {
352 * Write a line of data to the socket, followed by a trailing "\r\n".
355 * @return mixed fputs result, or an error
357 function writeLine($data)
359 if (!is_resource($this->fp)) {
360 return $this->raiseError('not connected');
363 return fwrite($this->fp, $data . "\r\n");
367 * Tests for end-of-file on a socket descriptor.
369 * Also returns true if the socket is disconnected.
376 return (!is_resource($this->fp) || feof($this->fp));
380 * Reads a byte of data
383 * @return 1 byte of data from the socket, or a PEAR_Error if
388 if (!is_resource($this->fp)) {
389 return $this->raiseError('not connected');
392 return ord(@fread($this->fp, 1));
396 * Reads a word of data
399 * @return 1 word of data from the socket, or a PEAR_Error if
404 if (!is_resource($this->fp)) {
405 return $this->raiseError('not connected');
408 $buf = @fread($this->fp, 2);
409 return (ord($buf[0]) + (ord($buf[1]) << 8));
413 * Reads an int of data
416 * @return integer 1 int of data from the socket, or a PEAR_Error if
421 if (!is_resource($this->fp)) {
422 return $this->raiseError('not connected');
425 $buf = @fread($this->fp, 4);
426 return (ord($buf[0]) + (ord($buf[1]) << 8) +
427 (ord($buf[2]) << 16) + (ord($buf[3]) << 24));
431 * Reads a zero-terminated string of data
434 * @return string, or a PEAR_Error if
437 function readString()
439 if (!is_resource($this->fp)) {
440 return $this->raiseError('not connected');
444 while (($char = @fread($this->fp, 1)) != "\x00") {
451 * Reads an IP Address and returns it in a dot formatted string
454 * @return Dot formatted string, or a PEAR_Error if
457 function readIPAddress()
459 if (!is_resource($this->fp)) {
460 return $this->raiseError('not connected');
463 $buf = @fread($this->fp, 4);
464 return sprintf('%d.%d.%d.%d', ord($buf[0]), ord($buf[1]),
465 ord($buf[2]), ord($buf[3]));
469 * Read until either the end of the socket or a newline, whichever
470 * comes first. Strips the trailing newline from the returned data.
473 * @return All available data up to a newline, without that
474 * newline, or until the end of the socket, or a PEAR_Error if
479 if (!is_resource($this->fp)) {
480 return $this->raiseError('not connected');
484 $timeout = time() + $this->timeout;
485 while (!feof($this->fp) && (!$this->timeout || time() < $timeout)) {
486 $line .= @fgets($this->fp, $this->lineLength);
487 if (substr($line, -1) == "\n") {
488 return rtrim($line, "\r\n");
495 * Read until the socket closes, or until there is no more data in
496 * the inner PHP buffer. If the inner buffer is empty, in blocking
497 * mode we wait for at least 1 byte of data. Therefore, in
498 * blocking mode, if there is no data at all to be read, this
499 * function will never exit (unless the socket is closed on the
504 * @return string All data until the socket closes, or a PEAR_Error if
509 if (!is_resource($this->fp)) {
510 return $this->raiseError('not connected');
514 while (!feof($this->fp)) {
515 $data .= @fread($this->fp, $this->lineLength);
521 * Runs the equivalent of the select() system call on the socket
522 * with a timeout specified by tv_sec and tv_usec.
524 * @param integer $state Which of read/write/error to check for.
525 * @param integer $tv_sec Number of seconds for timeout.
526 * @param integer $tv_usec Number of microseconds for timeout.
529 * @return False if select fails, integer describing which of read/write/error
530 * are ready, or PEAR_Error if not connected.
532 function select($state, $tv_sec, $tv_usec = 0)
534 if (!is_resource($this->fp)) {
535 return $this->raiseError('not connected');
541 if ($state & NET_SOCKET_READ) {
544 if ($state & NET_SOCKET_WRITE) {
545 $write[] = $this->fp;
547 if ($state & NET_SOCKET_ERROR) {
548 $except[] = $this->fp;
550 if (false === ($sr = stream_select($read, $write, $except, $tv_sec, $tv_usec))) {
556 $result |= NET_SOCKET_READ;
559 $result |= NET_SOCKET_WRITE;
561 if (count($except)) {
562 $result |= NET_SOCKET_ERROR;
568 * Turns encryption on/off on a connected socket.
570 * @param bool $enabled Set this parameter to true to enable encryption
571 * and false to disable encryption.
572 * @param integer $type Type of encryption. See
573 * http://se.php.net/manual/en/function.stream-socket-enable-crypto.php for values.
576 * @return false on error, true on success and 0 if there isn't enough data and the
577 * user should try again (non-blocking sockets only). A PEAR_Error object
578 * is returned if the socket is not connected
580 function enableCrypto($enabled, $type)
582 if (version_compare(phpversion(), "5.1.0", ">=")) {
583 if (!is_resource($this->fp)) {
584 return $this->raiseError('not connected');
586 return @stream_socket_enable_crypto($this->fp, $enabled, $type);
588 return $this->raiseError('Net_Socket::enableCrypto() requires php version >= 5.1.0');