]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - extlib/Net/Socket.php
Added new 'Scroller' plugin from @buttle which aims to replace the out-dated
[quix0rs-gnu-social.git] / extlib / Net / Socket.php
1 <?php
2 //
3 // +----------------------------------------------------------------------+
4 // | PHP Version 4                                                        |
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 // +----------------------------------------------------------------------+
19 //
20 // $Id: Socket.php,v 1.38 2008/02/15 18:24:17 chagenbu Exp $
21
22 require_once 'PEAR.php';
23
24 define('NET_SOCKET_READ',  1);
25 define('NET_SOCKET_WRITE', 2);
26 define('NET_SOCKET_ERROR', 4);
27
28 /**
29  * Generalized Socket class.
30  *
31  * @version 1.1
32  * @author Stig Bakken <ssb@php.net>
33  * @author Chuck Hagenbuch <chuck@horde.org>
34  */
35 class Net_Socket extends PEAR {
36
37     /**
38      * Socket file pointer.
39      * @var resource $fp
40      */
41     var $fp = null;
42
43     /**
44      * Whether the socket is blocking. Defaults to true.
45      * @var boolean $blocking
46      */
47     var $blocking = true;
48
49     /**
50      * Whether the socket is persistent. Defaults to false.
51      * @var boolean $persistent
52      */
53     var $persistent = false;
54
55     /**
56      * The IP address to connect to.
57      * @var string $addr
58      */
59     var $addr = '';
60
61     /**
62      * The port number to connect to.
63      * @var integer $port
64      */
65     var $port = 0;
66
67     /**
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
71      */
72     var $timeout = false;
73
74     /**
75      * Number of bytes to read at a time in readLine() and
76      * readAll(). Defaults to 2048.
77      * @var integer $lineLength
78      */
79     var $lineLength = 2048;
80
81     /**
82      * Connect to the specified port. If called when the socket is
83      * already connected, it disconnects and connects again.
84      *
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
89      *                             by the web server).
90      * @param integer $timeout     (optional) How long to wait for data.
91      * @param array   $options     See options for stream_context_create.
92      *
93      * @access public
94      *
95      * @return boolean | PEAR_Error  True on success or a PEAR_Error on failure.
96      */
97     function connect($addr, $port = 0, $persistent = null, $timeout = null, $options = null)
98     {
99         if (is_resource($this->fp)) {
100             @fclose($this->fp);
101             $this->fp = null;
102         }
103
104         if (!$addr) {
105             return $this->raiseError('$addr cannot be empty');
106         } elseif (strspn($addr, '.0123456789') == strlen($addr) ||
107                   strstr($addr, '/') !== false) {
108             $this->addr = $addr;
109         } else {
110             $this->addr = @gethostbyname($addr);
111         }
112
113         $this->port = $port % 65536;
114
115         if ($persistent !== null) {
116             $this->persistent = $persistent;
117         }
118
119         if ($timeout !== null) {
120             $this->timeout = $timeout;
121         }
122
123         $openfunc = $this->persistent ? 'pfsockopen' : 'fsockopen';
124         $errno = 0;
125         $errstr = '';
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;
130             } else {
131                 $timeout = 0;
132             }
133             $context = stream_context_create($options);
134
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);
140             } else {
141                 $fp = @$openfunc($this->addr, $this->port, $errno, $errstr, $timeout, $context);
142             }
143         } else {
144             if ($this->timeout) {
145                 $fp = @$openfunc($this->addr, $this->port, $errno, $errstr, $this->timeout);
146             } else {
147                 $fp = @$openfunc($this->addr, $this->port, $errno, $errstr);
148             }
149         }
150
151         if (!$fp) {
152             if ($errno == 0 && isset($php_errormsg)) {
153                 $errstr = $php_errormsg;
154             }
155             @ini_set('track_errors', $old_track_errors);
156             return $this->raiseError($errstr, $errno);
157         }
158
159         @ini_set('track_errors', $old_track_errors);
160         $this->fp = $fp;
161
162         return $this->setBlocking($this->blocking);
163     }
164
165     /**
166      * Disconnects from the peer, closes the socket.
167      *
168      * @access public
169      * @return mixed true on success or a PEAR_Error instance otherwise
170      */
171     function disconnect()
172     {
173         if (!is_resource($this->fp)) {
174             return $this->raiseError('not connected');
175         }
176
177         @fclose($this->fp);
178         $this->fp = null;
179         return true;
180     }
181
182     /**
183      * Find out if the socket is in blocking mode.
184      *
185      * @access public
186      * @return boolean  The current blocking mode.
187      */
188     function isBlocking()
189     {
190         return $this->blocking;
191     }
192
193     /**
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.
198      *
199      * @param boolean $mode  True for blocking sockets, false for nonblocking.
200      * @access public
201      * @return mixed true on success or a PEAR_Error instance otherwise
202      */
203     function setBlocking($mode)
204     {
205         if (!is_resource($this->fp)) {
206             return $this->raiseError('not connected');
207         }
208
209         $this->blocking = $mode;
210         socket_set_blocking($this->fp, $this->blocking);
211         return true;
212     }
213
214     /**
215      * Sets the timeout value on socket descriptor,
216      * expressed in the sum of seconds and microseconds
217      *
218      * @param integer $seconds  Seconds.
219      * @param integer $microseconds  Microseconds.
220      * @access public
221      * @return mixed true on success or a PEAR_Error instance otherwise
222      */
223     function setTimeout($seconds, $microseconds)
224     {
225         if (!is_resource($this->fp)) {
226             return $this->raiseError('not connected');
227         }
228
229         return socket_set_timeout($this->fp, $seconds, $microseconds);
230     }
231
232     /**
233      * Sets the file buffering size on the stream.
234      * See php's stream_set_write_buffer for more information.
235      *
236      * @param integer $size     Write buffer size.
237      * @access public
238      * @return mixed on success or an PEAR_Error object otherwise
239      */
240     function setWriteBuffer($size)
241     {
242         if (!is_resource($this->fp)) {
243             return $this->raiseError('not connected');
244         }
245
246         $returned = stream_set_write_buffer($this->fp, $size);
247         if ($returned == 0) {
248             return true;
249         }
250         return $this->raiseError('Cannot set write buffer.');
251     }
252
253     /**
254      * Returns information about an existing socket resource.
255      * Currently returns four entries in the result array:
256      *
257      * <p>
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>
262      * </p>
263      *
264      * @access public
265      * @return mixed Array containing information about existing socket resource or a PEAR_Error instance otherwise
266      */
267     function getStatus()
268     {
269         if (!is_resource($this->fp)) {
270             return $this->raiseError('not connected');
271         }
272
273         return socket_get_status($this->fp);
274     }
275
276     /**
277      * Get a specified line of data
278      *
279      * @access public
280      * @return $size bytes of data from the socket, or a PEAR_Error if
281      *         not connected.
282      */
283     function gets($size)
284     {
285         if (!is_resource($this->fp)) {
286             return $this->raiseError('not connected');
287         }
288
289         return @fgets($this->fp, $size);
290     }
291
292     /**
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.
297      *
298      * @param integer $size  The number of bytes to read from the socket.
299      * @access public
300      * @return $size bytes of data from the socket, or a PEAR_Error if
301      *         not connected.
302      */
303     function read($size)
304     {
305         if (!is_resource($this->fp)) {
306             return $this->raiseError('not connected');
307         }
308
309         return @fread($this->fp, $size);
310     }
311
312     /**
313      * Write a specified amount of data.
314      *
315      * @param string  $data       Data to write.
316      * @param integer $blocksize  Amount of data to write at once.
317      *                            NULL means all at once.
318      *
319      * @access public
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.
323      */
324     function write($data, $blocksize = null)
325     {
326         if (!is_resource($this->fp)) {
327             return $this->raiseError('not connected');
328         }
329
330         if (is_null($blocksize) && !OS_WINDOWS) {
331             return @fwrite($this->fp, $data);
332         } else {
333             if (is_null($blocksize)) {
334                 $blocksize = 1024;
335             }
336
337             $pos = 0;
338             $size = strlen($data);
339             while ($pos < $size) {
340                 $written = @fwrite($this->fp, substr($data, $pos, $blocksize));
341                 if ($written === false) {
342                     return false;
343                 }
344                 $pos += $written;
345             }
346
347             return $pos;
348         }
349     }
350
351     /**
352      * Write a line of data to the socket, followed by a trailing "\r\n".
353      *
354      * @access public
355      * @return mixed fputs result, or an error
356      */
357     function writeLine($data)
358     {
359         if (!is_resource($this->fp)) {
360             return $this->raiseError('not connected');
361         }
362
363         return fwrite($this->fp, $data . "\r\n");
364     }
365
366     /**
367      * Tests for end-of-file on a socket descriptor.
368      *
369      * Also returns true if the socket is disconnected.
370      *
371      * @access public
372      * @return bool
373      */
374     function eof()
375     {
376         return (!is_resource($this->fp) || feof($this->fp));
377     }
378
379     /**
380      * Reads a byte of data
381      *
382      * @access public
383      * @return 1 byte of data from the socket, or a PEAR_Error if
384      *         not connected.
385      */
386     function readByte()
387     {
388         if (!is_resource($this->fp)) {
389             return $this->raiseError('not connected');
390         }
391
392         return ord(@fread($this->fp, 1));
393     }
394
395     /**
396      * Reads a word of data
397      *
398      * @access public
399      * @return 1 word of data from the socket, or a PEAR_Error if
400      *         not connected.
401      */
402     function readWord()
403     {
404         if (!is_resource($this->fp)) {
405             return $this->raiseError('not connected');
406         }
407
408         $buf = @fread($this->fp, 2);
409         return (ord($buf[0]) + (ord($buf[1]) << 8));
410     }
411
412     /**
413      * Reads an int of data
414      *
415      * @access public
416      * @return integer  1 int of data from the socket, or a PEAR_Error if
417      *                  not connected.
418      */
419     function readInt()
420     {
421         if (!is_resource($this->fp)) {
422             return $this->raiseError('not connected');
423         }
424
425         $buf = @fread($this->fp, 4);
426         return (ord($buf[0]) + (ord($buf[1]) << 8) +
427                 (ord($buf[2]) << 16) + (ord($buf[3]) << 24));
428     }
429
430     /**
431      * Reads a zero-terminated string of data
432      *
433      * @access public
434      * @return string, or a PEAR_Error if
435      *         not connected.
436      */
437     function readString()
438     {
439         if (!is_resource($this->fp)) {
440             return $this->raiseError('not connected');
441         }
442
443         $string = '';
444         while (($char = @fread($this->fp, 1)) != "\x00")  {
445             $string .= $char;
446         }
447         return $string;
448     }
449
450     /**
451      * Reads an IP Address and returns it in a dot formatted string
452      *
453      * @access public
454      * @return Dot formatted string, or a PEAR_Error if
455      *         not connected.
456      */
457     function readIPAddress()
458     {
459         if (!is_resource($this->fp)) {
460             return $this->raiseError('not connected');
461         }
462
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]));
466     }
467
468     /**
469      * Read until either the end of the socket or a newline, whichever
470      * comes first. Strips the trailing newline from the returned data.
471      *
472      * @access public
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
475      *         not connected.
476      */
477     function readLine()
478     {
479         if (!is_resource($this->fp)) {
480             return $this->raiseError('not connected');
481         }
482
483         $line = '';
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");
489             }
490         }
491         return $line;
492     }
493
494     /**
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
500      * remote end).
501      *
502      * @access public
503      *
504      * @return string  All data until the socket closes, or a PEAR_Error if
505      *                 not connected.
506      */
507     function readAll()
508     {
509         if (!is_resource($this->fp)) {
510             return $this->raiseError('not connected');
511         }
512
513         $data = '';
514         while (!feof($this->fp)) {
515             $data .= @fread($this->fp, $this->lineLength);
516         }
517         return $data;
518     }
519
520     /**
521      * Runs the equivalent of the select() system call on the socket
522      * with a timeout specified by tv_sec and tv_usec.
523      *
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.
527      *
528      * @access public
529      * @return False if select fails, integer describing which of read/write/error
530      *         are ready, or PEAR_Error if not connected.
531      */
532     function select($state, $tv_sec, $tv_usec = 0)
533     {
534         if (!is_resource($this->fp)) {
535             return $this->raiseError('not connected');
536         }
537
538         $read = null;
539         $write = null;
540         $except = null;
541         if ($state & NET_SOCKET_READ) {
542             $read[] = $this->fp;
543         }
544         if ($state & NET_SOCKET_WRITE) {
545             $write[] = $this->fp;
546         }
547         if ($state & NET_SOCKET_ERROR) {
548             $except[] = $this->fp;
549         }
550         if (false === ($sr = stream_select($read, $write, $except, $tv_sec, $tv_usec))) {
551             return false;
552         }
553
554         $result = 0;
555         if (count($read)) {
556             $result |= NET_SOCKET_READ;
557         }
558         if (count($write)) {
559             $result |= NET_SOCKET_WRITE;
560         }
561         if (count($except)) {
562             $result |= NET_SOCKET_ERROR;
563         }
564         return $result;
565     }
566
567     /**
568      * Turns encryption on/off on a connected socket.
569      *
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.
574      *
575      * @access public
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
579      */
580     function enableCrypto($enabled, $type)
581     {
582         if (version_compare(phpversion(), "5.1.0", ">=")) {
583             if (!is_resource($this->fp)) {
584                 return $this->raiseError('not connected');
585             }
586             return @stream_socket_enable_crypto($this->fp, $enabled, $type);
587         } else {
588             return $this->raiseError('Net_Socket::enableCrypto() requires php version >= 5.1.0');
589         }
590     }
591
592 }