Aleksander Machniak
2013-01-07 3e3767138e2ea62aea549917c13040849036fbf3
commit | author | age
627330 1 <?php
58b5dd 2 /**
A 3  * Net_Socket
4  *
5  * PHP Version 4
6  *
7  * Copyright (c) 1997-2003 The PHP Group
8  *
9  * This source file is subject to version 2.0 of the PHP license,
10  * that is bundled with this package in the file LICENSE, and is
11  * available at through the world-wide-web at
12  * http://www.php.net/license/2_02.txt.
13  * If you did not receive a copy of the PHP license and are unable to
14  * obtain it through the world-wide-web, please send a note to
15  * license@php.net so we can mail you a copy immediately.
16  *
17  * Authors: Stig Bakken <ssb@php.net>
18  *          Chuck Hagenbuch <chuck@horde.org>
19  *
20  * @category  Net
21  * @package   Net_Socket
22  * @author    Stig Bakken <ssb@php.net>
23  * @author    Chuck Hagenbuch <chuck@horde.org>
24  * @copyright 1997-2003 The PHP Group
25  * @license   http://www.php.net/license/2_02.txt PHP 2.02
26  * @version   CVS: $Id$
27  * @link      http://pear.php.net/packages/Net_Socket
28  */
627330 29
T 30 require_once 'PEAR.php';
31
58b5dd 32 define('NET_SOCKET_READ', 1);
a5b598 33 define('NET_SOCKET_WRITE', 2);
T 34 define('NET_SOCKET_ERROR', 4);
35
627330 36 /**
a5b598 37  * Generalized Socket class.
627330 38  *
58b5dd 39  * @category  Net
A 40  * @package   Net_Socket
41  * @author    Stig Bakken <ssb@php.net>
42  * @author    Chuck Hagenbuch <chuck@horde.org>
43  * @copyright 1997-2003 The PHP Group
44  * @license   http://www.php.net/license/2_02.txt PHP 2.02
45  * @link      http://pear.php.net/packages/Net_Socket
627330 46  */
58b5dd 47 class Net_Socket extends PEAR
A 48 {
a5b598 49     /**
T 50      * Socket file pointer.
51      * @var resource $fp
52      */
627330 53     var $fp = null;
T 54
a5b598 55     /**
T 56      * Whether the socket is blocking. Defaults to true.
57      * @var boolean $blocking
58      */
627330 59     var $blocking = true;
T 60
a5b598 61     /**
T 62      * Whether the socket is persistent. Defaults to false.
63      * @var boolean $persistent
64      */
627330 65     var $persistent = false;
T 66
a5b598 67     /**
T 68      * The IP address to connect to.
69      * @var string $addr
70      */
627330 71     var $addr = '';
T 72
a5b598 73     /**
T 74      * The port number to connect to.
75      * @var integer $port
76      */
627330 77     var $port = 0;
T 78
a5b598 79     /**
T 80      * Number of seconds to wait on socket connections before assuming
81      * there's no more data. Defaults to no timeout.
82      * @var integer $timeout
83      */
627330 84     var $timeout = false;
T 85
86     /**
a5b598 87      * Number of bytes to read at a time in readLine() and
T 88      * readAll(). Defaults to 2048.
89      * @var integer $lineLength
627330 90      */
a5b598 91     var $lineLength = 2048;
627330 92
T 93     /**
58b5dd 94      * The string to use as a newline terminator. Usually "\r\n" or "\n".
A 95      * @var string $newline
96      */
97     var $newline = "\r\n";
98
99     /**
627330 100      * Connect to the specified port. If called when the socket is
T 101      * already connected, it disconnects and connects again.
102      *
58b5dd 103      * @param string  $addr       IP address or host name.
A 104      * @param integer $port       TCP port number.
105      * @param boolean $persistent (optional) Whether the connection is
106      *                            persistent (kept open between requests
107      *                            by the web server).
108      * @param integer $timeout    (optional) How long to wait for data.
109      * @param array   $options    See options for stream_context_create.
a5b598 110      *
627330 111      * @access public
a5b598 112      *
T 113      * @return boolean | PEAR_Error  True on success or a PEAR_Error on failure.
627330 114      */
58b5dd 115     function connect($addr, $port = 0, $persistent = null,
A 116                      $timeout = null, $options = null)
627330 117     {
T 118         if (is_resource($this->fp)) {
119             @fclose($this->fp);
120             $this->fp = null;
121         }
122
a5b598 123         if (!$addr) {
T 124             return $this->raiseError('$addr cannot be empty');
125         } elseif (strspn($addr, '.0123456789') == strlen($addr) ||
126                   strstr($addr, '/') !== false) {
627330 127             $this->addr = $addr;
T 128         } else {
a5b598 129             $this->addr = @gethostbyname($addr);
627330 130         }
a5b598 131
627330 132         $this->port = $port % 65536;
a5b598 133
627330 134         if ($persistent !== null) {
T 135             $this->persistent = $persistent;
136         }
a5b598 137
627330 138         if ($timeout !== null) {
T 139             $this->timeout = $timeout;
140         }
a5b598 141
627330 142         $openfunc = $this->persistent ? 'pfsockopen' : 'fsockopen';
58b5dd 143         $errno    = 0;
A 144         $errstr   = '';
145
e275ce 146         $old_track_errors = @ini_set('track_errors', 1);
58b5dd 147
627330 148         if ($options && function_exists('stream_context_create')) {
T 149             if ($this->timeout) {
150                 $timeout = $this->timeout;
151             } else {
152                 $timeout = 0;
153             }
154             $context = stream_context_create($options);
e275ce 155
A 156             // Since PHP 5 fsockopen doesn't allow context specification
157             if (function_exists('stream_socket_client')) {
58b5dd 158                 $flags = STREAM_CLIENT_CONNECT;
A 159
160                 if ($this->persistent) {
161                     $flags = STREAM_CLIENT_PERSISTENT;
162                 }
163
e275ce 164                 $addr = $this->addr . ':' . $this->port;
58b5dd 165                 $fp   = stream_socket_client($addr, $errno, $errstr,
A 166                                              $timeout, $flags, $context);
e275ce 167             } else {
58b5dd 168                 $fp = @$openfunc($this->addr, $this->port, $errno,
A 169                                  $errstr, $timeout, $context);
e275ce 170             }
627330 171         } else {
T 172             if ($this->timeout) {
58b5dd 173                 $fp = @$openfunc($this->addr, $this->port, $errno,
A 174                                  $errstr, $this->timeout);
627330 175             } else {
T 176                 $fp = @$openfunc($this->addr, $this->port, $errno, $errstr);
177             }
178         }
179
180         if (!$fp) {
58b5dd 181             if ($errno == 0 && !strlen($errstr) && isset($php_errormsg)) {
e275ce 182                 $errstr = $php_errormsg;
A 183             }
184             @ini_set('track_errors', $old_track_errors);
627330 185             return $this->raiseError($errstr, $errno);
T 186         }
187
e275ce 188         @ini_set('track_errors', $old_track_errors);
627330 189         $this->fp = $fp;
T 190
191         return $this->setBlocking($this->blocking);
192     }
193
194     /**
195      * Disconnects from the peer, closes the socket.
196      *
197      * @access public
e275ce 198      * @return mixed true on success or a PEAR_Error instance otherwise
627330 199      */
T 200     function disconnect()
201     {
a5b598 202         if (!is_resource($this->fp)) {
T 203             return $this->raiseError('not connected');
627330 204         }
T 205
a5b598 206         @fclose($this->fp);
T 207         $this->fp = null;
208         return true;
209     }
210
627330 211     /**
58b5dd 212      * Set the newline character/sequence to use.
A 213      *
214      * @param string $newline  Newline character(s)
215      * @return boolean True
216      */
217     function setNewline($newline)
218     {
219         $this->newline = $newline;
220         return true;
221     }
222
223     /**
627330 224      * Find out if the socket is in blocking mode.
T 225      *
226      * @access public
a5b598 227      * @return boolean  The current blocking mode.
627330 228      */
T 229     function isBlocking()
230     {
231         return $this->blocking;
232     }
233
234     /**
235      * Sets whether the socket connection should be blocking or
236      * not. A read call to a non-blocking socket will return immediately
237      * if there is no data available, whereas it will block until there
238      * is data for blocking sockets.
239      *
58b5dd 240      * @param boolean $mode True for blocking sockets, false for nonblocking.
A 241      *
627330 242      * @access public
e275ce 243      * @return mixed true on success or a PEAR_Error instance otherwise
627330 244      */
T 245     function setBlocking($mode)
246     {
a5b598 247         if (!is_resource($this->fp)) {
T 248             return $this->raiseError('not connected');
627330 249         }
T 250
a5b598 251         $this->blocking = $mode;
58b5dd 252         stream_set_blocking($this->fp, (int)$this->blocking);
a5b598 253         return true;
T 254     }
255
627330 256     /**
T 257      * Sets the timeout value on socket descriptor,
258      * expressed in the sum of seconds and microseconds
259      *
58b5dd 260      * @param integer $seconds      Seconds.
A 261      * @param integer $microseconds Microseconds.
262      *
627330 263      * @access public
e275ce 264      * @return mixed true on success or a PEAR_Error instance otherwise
627330 265      */
T 266     function setTimeout($seconds, $microseconds)
267     {
a5b598 268         if (!is_resource($this->fp)) {
T 269             return $this->raiseError('not connected');
270         }
271
272         return socket_set_timeout($this->fp, $seconds, $microseconds);
273     }
274
275     /**
276      * Sets the file buffering size on the stream.
277      * See php's stream_set_write_buffer for more information.
278      *
58b5dd 279      * @param integer $size Write buffer size.
A 280      *
a5b598 281      * @access public
T 282      * @return mixed on success or an PEAR_Error object otherwise
283      */
284     function setWriteBuffer($size)
285     {
286         if (!is_resource($this->fp)) {
287             return $this->raiseError('not connected');
288         }
289
e275ce 290         $returned = stream_set_write_buffer($this->fp, $size);
a5b598 291         if ($returned == 0) {
627330 292             return true;
T 293         }
a5b598 294         return $this->raiseError('Cannot set write buffer.');
627330 295     }
T 296
297     /**
298      * Returns information about an existing socket resource.
299      * Currently returns four entries in the result array:
300      *
301      * <p>
302      * timed_out (bool) - The socket timed out waiting for data<br>
303      * blocked (bool) - The socket was blocked<br>
304      * eof (bool) - Indicates EOF event<br>
305      * unread_bytes (int) - Number of bytes left in the socket buffer<br>
306      * </p>
307      *
308      * @access public
58b5dd 309      * @return mixed Array containing information about existing socket
A 310      *               resource or a PEAR_Error instance otherwise
627330 311      */
T 312     function getStatus()
313     {
a5b598 314         if (!is_resource($this->fp)) {
T 315             return $this->raiseError('not connected');
627330 316         }
T 317
a5b598 318         return socket_get_status($this->fp);
T 319     }
320
627330 321     /**
T 322      * Get a specified line of data
323      *
58b5dd 324      * @param int $size ??
A 325      *
627330 326      * @access public
T 327      * @return $size bytes of data from the socket, or a PEAR_Error if
328      *         not connected.
329      */
58b5dd 330     function gets($size = null)
627330 331     {
a5b598 332         if (!is_resource($this->fp)) {
T 333             return $this->raiseError('not connected');
627330 334         }
T 335
58b5dd 336         if (is_null($size)) {
A 337             return @fgets($this->fp);
338         } else {
339             return @fgets($this->fp, $size);
340         }
a5b598 341     }
T 342
627330 343     /**
T 344      * Read a specified amount of data. This is guaranteed to return,
345      * and has the added benefit of getting everything in one fread()
346      * chunk; if you know the size of the data you're getting
347      * beforehand, this is definitely the way to go.
348      *
58b5dd 349      * @param integer $size The number of bytes to read from the socket.
A 350      *
627330 351      * @access public
T 352      * @return $size bytes of data from the socket, or a PEAR_Error if
353      *         not connected.
354      */
355     function read($size)
356     {
a5b598 357         if (!is_resource($this->fp)) {
T 358             return $this->raiseError('not connected');
627330 359         }
T 360
a5b598 361         return @fread($this->fp, $size);
T 362     }
363
627330 364     /**
T 365      * Write a specified amount of data.
a5b598 366      *
58b5dd 367      * @param string  $data      Data to write.
A 368      * @param integer $blocksize Amount of data to write at once.
369      *                           NULL means all at once.
627330 370      *
T 371      * @access public
58b5dd 372      * @return mixed If the socket is not connected, returns an instance of
A 373      *               PEAR_Error
e275ce 374      *               If the write succeeds, returns the number of bytes written
A 375      *               If the write fails, returns false.
627330 376      */
a5b598 377     function write($data, $blocksize = null)
627330 378     {
a5b598 379         if (!is_resource($this->fp)) {
T 380             return $this->raiseError('not connected');
627330 381         }
T 382
a5b598 383         if (is_null($blocksize) && !OS_WINDOWS) {
e275ce 384             return @fwrite($this->fp, $data);
a5b598 385         } else {
T 386             if (is_null($blocksize)) {
387                 $blocksize = 1024;
388             }
389
58b5dd 390             $pos  = 0;
a5b598 391             $size = strlen($data);
T 392             while ($pos < $size) {
393                 $written = @fwrite($this->fp, substr($data, $pos, $blocksize));
58b5dd 394                 if (!$written) {
A 395                     return $written;
a5b598 396                 }
T 397                 $pos += $written;
398             }
399
400             return $pos;
401         }
402     }
403
627330 404     /**
58b5dd 405      * Write a line of data to the socket, followed by a trailing newline.
A 406      *
407      * @param string $data Data to write
627330 408      *
T 409      * @access public
410      * @return mixed fputs result, or an error
411      */
a5b598 412     function writeLine($data)
627330 413     {
a5b598 414         if (!is_resource($this->fp)) {
T 415             return $this->raiseError('not connected');
627330 416         }
T 417
58b5dd 418         return fwrite($this->fp, $data . $this->newline);
a5b598 419     }
T 420
627330 421     /**
a5b598 422      * Tests for end-of-file on a socket descriptor.
T 423      *
424      * Also returns true if the socket is disconnected.
627330 425      *
T 426      * @access public
427      * @return bool
428      */
429     function eof()
430     {
a5b598 431         return (!is_resource($this->fp) || feof($this->fp));
627330 432     }
T 433
434     /**
435      * Reads a byte of data
436      *
437      * @access public
438      * @return 1 byte of data from the socket, or a PEAR_Error if
439      *         not connected.
440      */
441     function readByte()
442     {
a5b598 443         if (!is_resource($this->fp)) {
T 444             return $this->raiseError('not connected');
627330 445         }
T 446
a5b598 447         return ord(@fread($this->fp, 1));
T 448     }
449
627330 450     /**
T 451      * Reads a word of data
452      *
453      * @access public
454      * @return 1 word of data from the socket, or a PEAR_Error if
455      *         not connected.
456      */
457     function readWord()
458     {
a5b598 459         if (!is_resource($this->fp)) {
T 460             return $this->raiseError('not connected');
627330 461         }
T 462
a5b598 463         $buf = @fread($this->fp, 2);
T 464         return (ord($buf[0]) + (ord($buf[1]) << 8));
465     }
466
627330 467     /**
T 468      * Reads an int of data
469      *
470      * @access public
a5b598 471      * @return integer  1 int of data from the socket, or a PEAR_Error if
T 472      *                  not connected.
627330 473      */
T 474     function readInt()
475     {
a5b598 476         if (!is_resource($this->fp)) {
T 477             return $this->raiseError('not connected');
627330 478         }
T 479
a5b598 480         $buf = @fread($this->fp, 4);
T 481         return (ord($buf[0]) + (ord($buf[1]) << 8) +
482                 (ord($buf[2]) << 16) + (ord($buf[3]) << 24));
483     }
484
627330 485     /**
a5b598 486      * Reads a zero-terminated string of data
627330 487      *
T 488      * @access public
489      * @return string, or a PEAR_Error if
490      *         not connected.
491      */
492     function readString()
493     {
a5b598 494         if (!is_resource($this->fp)) {
T 495             return $this->raiseError('not connected');
627330 496         }
T 497
a5b598 498         $string = '';
58b5dd 499         while (($char = @fread($this->fp, 1)) != "\x00") {
a5b598 500             $string .= $char;
T 501         }
502         return $string;
503     }
504
627330 505     /**
e275ce 506      * Reads an IP Address and returns it in a dot formatted string
627330 507      *
T 508      * @access public
e275ce 509      * @return Dot formatted string, or a PEAR_Error if
627330 510      *         not connected.
T 511      */
512     function readIPAddress()
513     {
a5b598 514         if (!is_resource($this->fp)) {
T 515             return $this->raiseError('not connected');
627330 516         }
T 517
a5b598 518         $buf = @fread($this->fp, 4);
e275ce 519         return sprintf('%d.%d.%d.%d', ord($buf[0]), ord($buf[1]),
a5b598 520                        ord($buf[2]), ord($buf[3]));
T 521     }
522
627330 523     /**
T 524      * Read until either the end of the socket or a newline, whichever
525      * comes first. Strips the trailing newline from the returned data.
526      *
527      * @access public
528      * @return All available data up to a newline, without that
529      *         newline, or until the end of the socket, or a PEAR_Error if
530      *         not connected.
531      */
532     function readLine()
533     {
a5b598 534         if (!is_resource($this->fp)) {
T 535             return $this->raiseError('not connected');
627330 536         }
T 537
a5b598 538         $line = '';
58b5dd 539
a5b598 540         $timeout = time() + $this->timeout;
58b5dd 541
a5b598 542         while (!feof($this->fp) && (!$this->timeout || time() < $timeout)) {
T 543             $line .= @fgets($this->fp, $this->lineLength);
544             if (substr($line, -1) == "\n") {
58b5dd 545                 return rtrim($line, $this->newline);
a5b598 546             }
T 547         }
548         return $line;
549     }
550
627330 551     /**
a5b598 552      * Read until the socket closes, or until there is no more data in
T 553      * the inner PHP buffer. If the inner buffer is empty, in blocking
554      * mode we wait for at least 1 byte of data. Therefore, in
555      * blocking mode, if there is no data at all to be read, this
556      * function will never exit (unless the socket is closed on the
557      * remote end).
627330 558      *
T 559      * @access public
a5b598 560      *
T 561      * @return string  All data until the socket closes, or a PEAR_Error if
562      *                 not connected.
627330 563      */
T 564     function readAll()
565     {
a5b598 566         if (!is_resource($this->fp)) {
T 567             return $this->raiseError('not connected');
627330 568         }
a5b598 569
T 570         $data = '';
571         while (!feof($this->fp)) {
572             $data .= @fread($this->fp, $this->lineLength);
573         }
574         return $data;
627330 575     }
a5b598 576
T 577     /**
578      * Runs the equivalent of the select() system call on the socket
579      * with a timeout specified by tv_sec and tv_usec.
580      *
58b5dd 581      * @param integer $state   Which of read/write/error to check for.
A 582      * @param integer $tv_sec  Number of seconds for timeout.
583      * @param integer $tv_usec Number of microseconds for timeout.
a5b598 584      *
T 585      * @access public
586      * @return False if select fails, integer describing which of read/write/error
587      *         are ready, or PEAR_Error if not connected.
588      */
589     function select($state, $tv_sec, $tv_usec = 0)
590     {
591         if (!is_resource($this->fp)) {
592             return $this->raiseError('not connected');
593         }
594
58b5dd 595         $read   = null;
A 596         $write  = null;
a5b598 597         $except = null;
T 598         if ($state & NET_SOCKET_READ) {
599             $read[] = $this->fp;
600         }
601         if ($state & NET_SOCKET_WRITE) {
602             $write[] = $this->fp;
603         }
604         if ($state & NET_SOCKET_ERROR) {
605             $except[] = $this->fp;
606         }
58b5dd 607         if (false === ($sr = stream_select($read, $write, $except,
A 608                                           $tv_sec, $tv_usec))) {
a5b598 609             return false;
T 610         }
611
612         $result = 0;
613         if (count($read)) {
614             $result |= NET_SOCKET_READ;
615         }
616         if (count($write)) {
617             $result |= NET_SOCKET_WRITE;
618         }
619         if (count($except)) {
620             $result |= NET_SOCKET_ERROR;
621         }
622         return $result;
623     }
624
625     /**
626      * Turns encryption on/off on a connected socket.
627      *
58b5dd 628      * @param bool    $enabled Set this parameter to true to enable encryption
A 629      *                         and false to disable encryption.
630      * @param integer $type    Type of encryption. See stream_socket_enable_crypto()
631      *                         for values.
a5b598 632      *
58b5dd 633      * @see    http://se.php.net/manual/en/function.stream-socket-enable-crypto.php
a5b598 634      * @access public
58b5dd 635      * @return false on error, true on success and 0 if there isn't enough data
A 636      *         and the user should try again (non-blocking sockets only).
637      *         A PEAR_Error object is returned if the socket is not
638      *         connected
a5b598 639      */
T 640     function enableCrypto($enabled, $type)
641     {
642         if (version_compare(phpversion(), "5.1.0", ">=")) {
643             if (!is_resource($this->fp)) {
644                 return $this->raiseError('not connected');
645             }
646             return @stream_socket_enable_crypto($this->fp, $enabled, $type);
647         } else {
58b5dd 648             $msg = 'Net_Socket::enableCrypto() requires php version >= 5.1.0';
A 649             return $this->raiseError($msg);
a5b598 650         }
T 651     }
627330 652
T 653 }