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 17 2005-10-03 20:25:31Z roundcube $
23 require_once 'PEAR.php';
26 * Generalized Socket class. More docs to be written.
29 * @author Stig Bakken <ssb@php.net>
30 * @author Chuck Hagenbuch <chuck@horde.org>
32 class Net_Socket extends PEAR {
35 /** Socket file pointer. */
38 /** Whether the socket is blocking. */
41 /** Whether the socket is persistent. */
42 var $persistent = false;
44 /** The IP address to connect to. */
47 /** The port number to connect to. */
50 /** Number of seconds to wait on socket connections before
51 assuming there's no more data. */
54 /** Number of bytes to read at a time in readLine() and
56 var $lineLength = 2048;
61 * Constructs a new Net_Socket object.
73 * Connect to the specified port. If called when the socket is
74 * already connected, it disconnects and connects again.
76 * @param $addr string IP address or host name
77 * @param $port int TCP port number
78 * @param $persistent bool (optional) whether the connection is
79 * persistent (kept open between requests by the web server)
80 * @param $timeout int (optional) how long to wait for data
81 * @param $options array see options for stream_context_create
83 * @return mixed true on success or error object
85 function connect($addr, $port, $persistent = null, $timeout = null, $options = null)
87 if (is_resource($this->fp)) {
92 if (strspn($addr, '.0123456789') == strlen($addr)) {
95 $this->addr = gethostbyname($addr);
97 $this->port = $port % 65536;
98 if ($persistent !== null) {
99 $this->persistent = $persistent;
101 if ($timeout !== null) {
102 $this->timeout = $timeout;
104 $openfunc = $this->persistent ? 'pfsockopen' : 'fsockopen';
107 if ($options && function_exists('stream_context_create')) {
108 if ($this->timeout) {
109 $timeout = $this->timeout;
113 $context = stream_context_create($options);
114 $fp = $openfunc($this->addr, $this->port, $errno, $errstr, $timeout, $context);
116 if ($this->timeout) {
117 $fp = @$openfunc($this->addr, $this->port, $errno, $errstr, $this->timeout);
119 $fp = @$openfunc($this->addr, $this->port, $errno, $errstr);
124 return $this->raiseError($errstr, $errno);
129 return $this->setBlocking($this->blocking);
135 * Disconnects from the peer, closes the socket.
138 * @return mixed true on success or an error object otherwise
140 function disconnect()
142 if (is_resource($this->fp)) {
147 return $this->raiseError("not connected");
153 * Find out if the socket is in blocking mode.
156 * @return bool the current blocking mode.
158 function isBlocking()
160 return $this->blocking;
166 * Sets whether the socket connection should be blocking or
167 * not. A read call to a non-blocking socket will return immediately
168 * if there is no data available, whereas it will block until there
169 * is data for blocking sockets.
171 * @param $mode bool true for blocking sockets, false for nonblocking
173 * @return mixed true on success or an error object otherwise
175 function setBlocking($mode)
177 if (is_resource($this->fp)) {
178 $this->blocking = $mode;
179 socket_set_blocking($this->fp, $this->blocking);
182 return $this->raiseError("not connected");
188 * Sets the timeout value on socket descriptor,
189 * expressed in the sum of seconds and microseconds
191 * @param $seconds int seconds
192 * @param $microseconds int microseconds
194 * @return mixed true on success or an error object otherwise
196 function setTimeout($seconds, $microseconds)
198 if (is_resource($this->fp)) {
199 socket_set_timeout($this->fp, $seconds, $microseconds);
202 return $this->raiseError("not connected");
208 * Returns information about an existing socket resource.
209 * Currently returns four entries in the result array:
212 * timed_out (bool) - The socket timed out waiting for data<br>
213 * blocked (bool) - The socket was blocked<br>
214 * eof (bool) - Indicates EOF event<br>
215 * unread_bytes (int) - Number of bytes left in the socket buffer<br>
219 * @return mixed Array containing information about existing socket resource or an error object otherwise
223 if (is_resource($this->fp)) {
224 return socket_get_status($this->fp);
226 return $this->raiseError("not connected");
232 * Get a specified line of data
235 * @return $size bytes of data from the socket, or a PEAR_Error if
240 if (is_resource($this->fp)) {
241 return fgets($this->fp, $size);
243 return $this->raiseError("not connected");
249 * Read a specified amount of data. This is guaranteed to return,
250 * and has the added benefit of getting everything in one fread()
251 * chunk; if you know the size of the data you're getting
252 * beforehand, this is definitely the way to go.
254 * @param $size The number of bytes to read from the socket.
256 * @return $size bytes of data from the socket, or a PEAR_Error if
261 if (is_resource($this->fp)) {
262 return fread($this->fp, $size);
264 return $this->raiseError("not connected");
270 * Write a specified amount of data.
273 * @return mixed true on success or an error object otherwise
275 function write($data)
277 if (is_resource($this->fp)) {
278 return fwrite($this->fp, $data);
280 return $this->raiseError("not connected");
286 * Write a line of data to the socket, followed by a trailing "\r\n".
289 * @return mixed fputs result, or an error
291 function writeLine ($data)
293 if (is_resource($this->fp)) {
294 return $this->write($data . "\r\n");
296 return $this->raiseError("not connected");
302 * Tests for end-of-file on a socket descriptor
309 return (is_resource($this->fp) && feof($this->fp));
315 * Reads a byte of data
318 * @return 1 byte of data from the socket, or a PEAR_Error if
323 if (is_resource($this->fp)) {
324 return ord($this->read(1));
326 return $this->raiseError("not connected");
332 * Reads a word of data
335 * @return 1 word of data from the socket, or a PEAR_Error if
340 if (is_resource($this->fp)) {
341 $buf = $this->read(2);
342 return (ord($buf[0]) + (ord($buf[1]) << 8));
344 return $this->raiseError("not connected");
350 * Reads an int of data
353 * @return 1 int of data from the socket, or a PEAR_Error if
358 if (is_resource($this->fp)) {
359 $buf = $this->read(4);
360 return (ord($buf[0]) + (ord($buf[1]) << 8) +
361 (ord($buf[2]) << 16) + (ord($buf[3]) << 24));
363 return $this->raiseError("not connected");
369 * Reads a zeroterminated string of data
372 * @return string, or a PEAR_Error if
375 function readString()
377 if (is_resource($this->fp)) {
379 while (($char = $this->read(1)) != "\x00") {
384 return $this->raiseError("not connected");
388 // {{{ readIPAddress()
390 * Reads an IP Address and returns it in a dot formated string
393 * @return Dot formated string, or a PEAR_Error if
396 function readIPAddress()
398 if (is_resource($this->fp)) {
399 $buf = $this->read(4);
400 return sprintf("%s.%s.%s.%s", ord($buf[0]), ord($buf[1]),
401 ord($buf[2]), ord($buf[3]));
403 return $this->raiseError("not connected");
409 * Read until either the end of the socket or a newline, whichever
410 * comes first. Strips the trailing newline from the returned data.
413 * @return All available data up to a newline, without that
414 * newline, or until the end of the socket, or a PEAR_Error if
419 if (is_resource($this->fp)) {
421 $timeout = time() + $this->timeout;
422 while (!$this->eof() && (!$this->timeout || time() < $timeout)) {
423 $line .= $this->gets($this->lineLength);
424 if (substr($line, -2) == "\r\n" ||
425 substr($line, -1) == "\n") {
426 return rtrim($line, "\r\n");
431 return $this->raiseError("not connected");
437 * Read until the socket closes. THIS FUNCTION WILL NOT EXIT if the
438 * socket is in blocking mode until the socket closes.
441 * @return All data until the socket closes, or a PEAR_Error if
446 if (is_resource($this->fp)) {
448 while (!$this->eof())
449 $data .= $this->read($this->lineLength);
452 return $this->raiseError("not connected");