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