source: branches/version-2_13_0/data/module/Net/Socket.php @ 23143

Revision 23143, 18.4 KB checked in by m_uehara, 7 years ago (diff)

#2348 r23140 をマージ

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-httpd-php; charset=UTF-8
Line 
1<?php
2/**
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 */
29
30require_once 'PEAR.php';
31
32define('NET_SOCKET_READ', 1);
33define('NET_SOCKET_WRITE', 2);
34define('NET_SOCKET_ERROR', 4);
35
36/**
37 * Generalized Socket class.
38 *
39 * @category  Net
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
46 */
47class Net_Socket extends PEAR
48{
49    /**
50     * Socket file pointer.
51     * @var resource $fp
52     */
53    var $fp = null;
54
55    /**
56     * Whether the socket is blocking. Defaults to true.
57     * @var boolean $blocking
58     */
59    var $blocking = true;
60
61    /**
62     * Whether the socket is persistent. Defaults to false.
63     * @var boolean $persistent
64     */
65    var $persistent = false;
66
67    /**
68     * The IP address to connect to.
69     * @var string $addr
70     */
71    var $addr = '';
72
73    /**
74     * The port number to connect to.
75     * @var integer $port
76     */
77    var $port = 0;
78
79    /**
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     */
84    var $timeout = false;
85
86    /**
87     * Number of bytes to read at a time in readLine() and
88     * readAll(). Defaults to 2048.
89     * @var integer $lineLength
90     */
91    var $lineLength = 2048;
92
93    /**
94     * The string to use as a newline terminator. Usually "\r\n" or "\n".
95     * @var string $newline
96     */
97    var $newline = "\r\n";
98
99    /**
100     * Connect to the specified port. If called when the socket is
101     * already connected, it disconnects and connects again.
102     *
103     * @param string  $addr       IP address or host name.
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.
110     *
111     * @access public
112     *
113     * @return boolean | PEAR_Error  True on success or a PEAR_Error on failure.
114     */
115    function connect($addr, $port = 0, $persistent = null,
116                     $timeout = null, $options = null)
117    {
118        if (is_resource($this->fp)) {
119            @fclose($this->fp);
120            $this->fp = null;
121        }
122
123        if (!$addr) {
124            return $this->raiseError('$addr cannot be empty');
125        } elseif (strspn($addr, '.0123456789') == strlen($addr) ||
126                  strstr($addr, '/') !== false) {
127            $this->addr = $addr;
128        } else {
129            $this->addr = @gethostbyname($addr);
130        }
131
132        $this->port = $port % 65536;
133
134        if ($persistent !== null) {
135            $this->persistent = $persistent;
136        }
137
138        if ($timeout !== null) {
139            $this->timeout = $timeout;
140        }
141
142        $openfunc = $this->persistent ? 'pfsockopen' : 'fsockopen';
143        $errno    = 0;
144        $errstr   = '';
145
146        $old_track_errors = @ini_set('track_errors', 1);
147
148        if ($options && function_exists('stream_context_create')) {
149            if ($this->timeout) {
150                $timeout = $this->timeout;
151            } else {
152                $timeout = 0;
153            }
154            $context = stream_context_create($options);
155
156            // Since PHP 5 fsockopen doesn't allow context specification
157            if (function_exists('stream_socket_client')) {
158                $flags = STREAM_CLIENT_CONNECT;
159
160                if ($this->persistent) {
161                    $flags = STREAM_CLIENT_PERSISTENT;
162                }
163
164                $addr = $this->addr . ':' . $this->port;
165                $fp   = stream_socket_client($addr, $errno, $errstr,
166                                             $timeout, $flags, $context);
167            } else {
168                $fp = @$openfunc($this->addr, $this->port, $errno,
169                                 $errstr, $timeout, $context);
170            }
171        } else {
172            if ($this->timeout) {
173                $fp = @$openfunc($this->addr, $this->port, $errno,
174                                 $errstr, $this->timeout);
175            } else {
176                $fp = @$openfunc($this->addr, $this->port, $errno, $errstr);
177            }
178        }
179
180        if (!$fp) {
181            if ($errno == 0 && !strlen($errstr) && isset($php_errormsg)) {
182                $errstr = $php_errormsg;
183            }
184            @ini_set('track_errors', $old_track_errors);
185            return $this->raiseError($errstr, $errno);
186        }
187
188        @ini_set('track_errors', $old_track_errors);
189        $this->fp = $fp;
190
191        return $this->setBlocking($this->blocking);
192    }
193
194    /**
195     * Disconnects from the peer, closes the socket.
196     *
197     * @access public
198     * @return mixed true on success or a PEAR_Error instance otherwise
199     */
200    function disconnect()
201    {
202        if (!is_resource($this->fp)) {
203            return $this->raiseError('not connected');
204        }
205
206        @fclose($this->fp);
207        $this->fp = null;
208        return true;
209    }
210
211    /**
212     * Set the newline character/sequence to use.
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    /**
224     * Find out if the socket is in blocking mode.
225     *
226     * @access public
227     * @return boolean  The current blocking mode.
228     */
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     *
240     * @param boolean $mode True for blocking sockets, false for nonblocking.
241     *
242     * @access public
243     * @return mixed true on success or a PEAR_Error instance otherwise
244     */
245    function setBlocking($mode)
246    {
247        if (!is_resource($this->fp)) {
248            return $this->raiseError('not connected');
249        }
250
251        $this->blocking = $mode;
252        stream_set_blocking($this->fp, (int)$this->blocking);
253        return true;
254    }
255
256    /**
257     * Sets the timeout value on socket descriptor,
258     * expressed in the sum of seconds and microseconds
259     *
260     * @param integer $seconds      Seconds.
261     * @param integer $microseconds Microseconds.
262     *
263     * @access public
264     * @return mixed true on success or a PEAR_Error instance otherwise
265     */
266    function setTimeout($seconds, $microseconds)
267    {
268        if (!is_resource($this->fp)) {
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     *
279     * @param integer $size Write buffer size.
280     *
281     * @access public
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
290        $returned = stream_set_write_buffer($this->fp, $size);
291        if ($returned == 0) {
292            return true;
293        }
294        return $this->raiseError('Cannot set write buffer.');
295    }
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
309     * @return mixed Array containing information about existing socket
310     *               resource or a PEAR_Error instance otherwise
311     */
312    function getStatus()
313    {
314        if (!is_resource($this->fp)) {
315            return $this->raiseError('not connected');
316        }
317
318        return socket_get_status($this->fp);
319    }
320
321    /**
322     * Get a specified line of data
323     *
324     * @param int $size ??
325     *
326     * @access public
327     * @return $size bytes of data from the socket, or a PEAR_Error if
328     *         not connected.
329     */
330    function gets($size = null)
331    {
332        if (!is_resource($this->fp)) {
333            return $this->raiseError('not connected');
334        }
335
336        if (is_null($size)) {
337            return @fgets($this->fp);
338        } else {
339            return @fgets($this->fp, $size);
340        }
341    }
342
343    /**
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     *
349     * @param integer $size The number of bytes to read from the socket.
350     *
351     * @access public
352     * @return $size bytes of data from the socket, or a PEAR_Error if
353     *         not connected.
354     */
355    function read($size)
356    {
357        if (!is_resource($this->fp)) {
358            return $this->raiseError('not connected');
359        }
360
361        return @fread($this->fp, $size);
362    }
363
364    /**
365     * Write a specified amount of data.
366     *
367     * @param string  $data      Data to write.
368     * @param integer $blocksize Amount of data to write at once.
369     *                           NULL means all at once.
370     *
371     * @access public
372     * @return mixed If the socket is not connected, returns an instance of
373     *               PEAR_Error
374     *               If the write succeeds, returns the number of bytes written
375     *               If the write fails, returns false.
376     */
377    function write($data, $blocksize = null)
378    {
379        if (!is_resource($this->fp)) {
380            return $this->raiseError('not connected');
381        }
382
383        if (is_null($blocksize) && !OS_WINDOWS) {
384            return @fwrite($this->fp, $data);
385        } else {
386            if (is_null($blocksize)) {
387                $blocksize = 1024;
388            }
389
390            $pos  = 0;
391            $size = strlen($data);
392            while ($pos < $size) {
393                $written = @fwrite($this->fp, substr($data, $pos, $blocksize));
394                if (!$written) {
395                    return $written;
396                }
397                $pos += $written;
398            }
399
400            return $pos;
401        }
402    }
403
404    /**
405     * Write a line of data to the socket, followed by a trailing newline.
406     *
407     * @param string $data Data to write
408     *
409     * @access public
410     * @return mixed fputs result, or an error
411     */
412    function writeLine($data)
413    {
414        if (!is_resource($this->fp)) {
415            return $this->raiseError('not connected');
416        }
417
418        return fwrite($this->fp, $data . $this->newline);
419    }
420
421    /**
422     * Tests for end-of-file on a socket descriptor.
423     *
424     * Also returns true if the socket is disconnected.
425     *
426     * @access public
427     * @return bool
428     */
429    function eof()
430    {
431        return (!is_resource($this->fp) || feof($this->fp));
432    }
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    {
443        if (!is_resource($this->fp)) {
444            return $this->raiseError('not connected');
445        }
446
447        return ord(@fread($this->fp, 1));
448    }
449
450    /**
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    {
459        if (!is_resource($this->fp)) {
460            return $this->raiseError('not connected');
461        }
462
463        $buf = @fread($this->fp, 2);
464        return (ord($buf[0]) + (ord($buf[1]) << 8));
465    }
466
467    /**
468     * Reads an int of data
469     *
470     * @access public
471     * @return integer  1 int of data from the socket, or a PEAR_Error if
472     *                  not connected.
473     */
474    function readInt()
475    {
476        if (!is_resource($this->fp)) {
477            return $this->raiseError('not connected');
478        }
479
480        $buf = @fread($this->fp, 4);
481        return (ord($buf[0]) + (ord($buf[1]) << 8) +
482                (ord($buf[2]) << 16) + (ord($buf[3]) << 24));
483    }
484
485    /**
486     * Reads a zero-terminated string of data
487     *
488     * @access public
489     * @return string, or a PEAR_Error if
490     *         not connected.
491     */
492    function readString()
493    {
494        if (!is_resource($this->fp)) {
495            return $this->raiseError('not connected');
496        }
497
498        $string = '';
499        while (($char = @fread($this->fp, 1)) != "\x00") {
500            $string .= $char;
501        }
502        return $string;
503    }
504
505    /**
506     * Reads an IP Address and returns it in a dot formatted string
507     *
508     * @access public
509     * @return Dot formatted string, or a PEAR_Error if
510     *         not connected.
511     */
512    function readIPAddress()
513    {
514        if (!is_resource($this->fp)) {
515            return $this->raiseError('not connected');
516        }
517
518        $buf = @fread($this->fp, 4);
519        return sprintf('%d.%d.%d.%d', ord($buf[0]), ord($buf[1]),
520                       ord($buf[2]), ord($buf[3]));
521    }
522
523    /**
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    {
534        if (!is_resource($this->fp)) {
535            return $this->raiseError('not connected');
536        }
537
538        $line = '';
539
540        $timeout = time() + $this->timeout;
541
542        while (!feof($this->fp) && (!$this->timeout || time() < $timeout)) {
543            $line .= @fgets($this->fp, $this->lineLength);
544            if (substr($line, -1) == "\n") {
545                return rtrim($line, $this->newline);
546            }
547        }
548        return $line;
549    }
550
551    /**
552     * Read until the socket closes, or until there is no more data in
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).
558     *
559     * @access public
560     *
561     * @return string  All data until the socket closes, or a PEAR_Error if
562     *                 not connected.
563     */
564    function readAll()
565    {
566        if (!is_resource($this->fp)) {
567            return $this->raiseError('not connected');
568        }
569
570        $data = '';
571        while (!feof($this->fp)) {
572            $data .= @fread($this->fp, $this->lineLength);
573        }
574        return $data;
575    }
576
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     *
581     * @param integer $state   Which of read/write/error to check for.
582     * @param integer $tv_sec  Number of seconds for timeout.
583     * @param integer $tv_usec Number of microseconds for timeout.
584     *
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
595        $read   = null;
596        $write  = null;
597        $except = null;
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        }
607        if (false === ($sr = stream_select($read, $write, $except,
608                                          $tv_sec, $tv_usec))) {
609            return false;
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     *
628     * @param bool    $enabled Set this parameter to true to enable encryption
629     *                         and false to disable encryption.
630     * @param integer $type    Type of encryption. See stream_socket_enable_crypto()
631     *                         for values.
632     *
633     * @see    http://se.php.net/manual/en/function.stream-socket-enable-crypto.php
634     * @access public
635     * @return false on error, true on success and 0 if there isn't enough data
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
639     */
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 {
648            $msg = 'Net_Socket::enableCrypto() requires php version >= 5.1.0';
649            return $this->raiseError($msg);
650        }
651    }
652
653}
Note: See TracBrowser for help on using the repository browser.