GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( fa3955...215ebf )
by Navarr
03:01
created

Socket::read()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
ccs 0
cts 5
cp 0
cc 2
eloc 5
nc 2
nop 2
crap 6
1
<?php
2
3
namespace Navarr\Socket;
4
5
use Navarr\Socket\Exception\SocketException;
6
7
/**
8
 * Class Socket.
9
 *
10
 * <p>A simple wrapper for PHP's socket functions.</p>
11
 */
12
class Socket
13
{
14
    /**
15
     * @var resource Will store a reference to the php socket object.
16
     */
17
    protected $resource = null;
18
    /**
19
     * @var int Should be set to one of the php predefined constants for Sockets - AF_UNIX, AF_INET, or AF_INET6
20
     */
21
    protected $domain = null;
22
    /**
23
     * @var int Should be set to one of the php predefined constants for Sockets - SOCK_STREAM, SOCK_DGRAM,
24
     *          SOCK_SEQPACKET, SOCK_RAW, SOCK_RDM
25
     */
26
    protected $type = null;
27
    /**
28
     * @var int Should be set to the protocol number to be used. Can use getprotobyname to get the value.
29
     *          Alternatively, there are two predefined constants for Sockets that could be used - SOL_TCP, SOL_UDP
30
     */
31
    protected $protocol = null;
32
    /**
33
     * @var array An internal storage of php socket resources and their associated Socket object.
34
     */
35
    protected static $map = [];
36
37
    /**
38
     * Sets up the Socket Resource and stores it in the local map.
39
     *
40
     * <p>This class uses the <a href="https://en.wikipedia.org/wiki/Factory_(object-oriented_programming)">
41
     * Factory pattern</a> to create instances. Please use the <code>create</code> method to create new instances
42
     * of this class.
43
     *
44
     * @see Socket::create()
45
     *
46
     * @param resource $resource The php socket resource. This is just a reference to the socket object created using
47
     *                           the <code>socket_create</code> method.
48
     */
49 3
    protected function __construct($resource)
50
    {
51 3
        $this->resource = $resource;
52 3
        self::$map[(string) $resource] = $this;
53 3
    }
54
55
    /**
56
     * Cleans up the Socket and dereferences the internal resource.
57
     */
58
    public function __destruct()
59
    {
60
        $this->close();
61
        $this->resource = null;
62
    }
63
64
    /**
65
     * Return the php socket resource name.
66
     *
67
     * <p>Resources are always converted to strings with the structure "Resource id#1", where 1 is the resource number
68
     * assigned to the resource by PHP at runtime. While the exact structure of this string should not be relied on and
69
     * is subject to change, it will always be unique for a given resource within the lifetime of the script execution
70
     * and won't be reused.</p>
71
     *
72
     * <p>If the resource object has been dereferrenced (set to <code>null</code>), this will return an empty
73
     * string.</p>
74
     *
75
     * @return string The string representation of the resource or an empty string if the resource was null.
76
     */
77
    public function __toString()
78
    {
79
        return (string) $this->resource;
80
    }
81
82
    /**
83
     * Accept a connection.
84
     *
85
     * <p>After the socket socket has been created using <code>create()</code>, bound to a name with
86
     * <code>bind()</code>, and told to listen for connections with <code>listen()</code>, this function will accept
87
     * incoming connections on that socket. Once a successful connection is made, a new Socket resource is returned,
88
     * which may be used for communication. If there are multiple connections queued on the socket, the first will be
89
     * used. If there are no pending connections, this will block until a connection becomes present. If socket has
90
     * been made non-blocking using <code>setBlocking()</code>, a <code>SocketException</code> will be thrown.</p>
91
     *
92
     * <p>The Socket returned by this method may not be used to accept new connections. The original listening Socket,
93
     * however, remains open and may be reused.</p>
94
     *
95
     * @throws Exception\SocketException If the Socket is set as non-blocking and there are no pending connections.
96
     *
97
     * @see Socket::create()
98
     * @see Socket::bind()
99
     * @see Socket::listen()
100
     * @see Socket::setBlocking()
101
     *
102
     * @return Socket A new Socket representation of the accepted socket.
103
     */
104
    public function accept()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
105
    {
106
        $return = @socket_accept($this->resource);
107
108
        if ($return === false) {
109
            throw new SocketException($this->resource);
110
        }
111
112
        return new self($return);
113
    }
114
115
    /**
116
     * Binds a name to a socket.
117
     *
118
     * <p>Binds the name given in address to the php socket resource currently in use. This has to be done before a
119
     * connection is established using <code>connect()</code> or <code>listen()</code>.</p>
120
     *
121
     * @param string $address <p>If the socket is of the AF_INET family, the address is an IP in dotted-quad
122
     *                        notation (e.g. <code>127.0.0.1</code>).</p> <p>If the socket is of the AF_UNIX family, the address is the path
123
     *                        of the Unix-domain socket (e.g. <code>/tmp/my.sock</code>).</p>
124
     * @param int    $port    <p>(Optional) The port parameter is only used when binding an AF_INET socket, and designates the port
125
     *                        on which to listen for connections.</p>
126
     *
127
     * @throws Exception\SocketException If the bind was unsuccessful.
128
     *
129
     * @return bool <p>Returns <code>true</code> if the bind was successful.</p>
130
     */
131 1
    public function bind($address, $port = 0)
132
    {
133 1
        $return = @socket_bind($this->resource, $address, $port);
134
135 1
        if ($return === false) {
136
            throw new SocketException($this->resource);
137
        }
138
139 1
        return true;
140
    }
141
142
    /**
143
     * Close the socket.
144
     *
145
     * <p>Closes the php socket resource currently in use and removes the reference to it in the internal map.</p>
146
     *
147
     * @return void
148
     */
149
    public function close()
150
    {
151
        unset(self::$map[(string) $this->resource]);
152
        @socket_close($this->resource);
153
    }
154
155
    /**
156
     * Connect to a socket.
157
     *
158
     * <p>Initiate a connection to the address given using the current php socket resource, which must be a valid
159
     * socket resource created with <code>create()</code>.
160
     *
161
     * @param string $address <p>The address parameter is either an IPv4 address in dotted-quad notation (e.g.
162
     *                        <code>127.0.0.1</code>) if the socket is AF_INET, a valid IPv6 address (e.g. <code>::1</code>) if IPv6 support
163
     *                        is enabled and the socket is AF_INET6, or the pathname of a Unix domain socket, if the socket family is AF_UNIX.
164
     *                        </p>
165
     * @param int    $port    <p>(Optional) The port parameter is only used and is mandatory when connecting to an AF_INET or
166
     *                        an AF_INET6 socket, and designates the port on the remote host to which a connection should be made.</p>
167
     *
168
     * @throws Exception\SocketException If the connect was unsuccessful or if the socket is non-blocking.
169
     *
170
     * @see Socket::bind()
171
     * @see Socket::listen()
172
     * @see Socket::create()
173
     *
174
     * @return bool <p>Returns <code>true</code> if the connect was successful.
175
     */
176
    public function connect($address, $port = 0)
177
    {
178
        $return = @socket_connect($this->resource, $address, $port);
179
180
        if ($return === false) {
181
            throw new SocketException($this->resource);
182
        }
183
184
        return true;
185
    }
186
187
    /**
188
     * Build Socket objects based on an array of php socket resources.
189
     *
190
     * @param array $resources The resources parameter is a list of php socket resource objects.
191
     *
192
     * @return Socket[] <p>Returns an array of Socket objects built from the given php socket resources.</p>
193
     */
194
    protected static function constructFromResources(array $resources)
195
    {
196
        $sockets = [];
197
198
        foreach ($resources as $resource) {
199
            $sockets[] = new self($resource);
200
        }
201
202
        return $sockets;
203
    }
204
205
    /**
206
     * Create a socket.
207
     *
208
     * <p>Creates and returns a Socket. A typical network connection is made up of two sockets, one performing the role
209
     * of the client, and another performing the role of the server.</p>
210
     *
211
     * @param int $domain   <p>The domain parameter specifies the protocol family to be used by the socket.</p><p>
212
     *                      <code>AF_INET</code> - IPv4 Internet based protocols. TCP and UDP are common protocols of this protocol family.
213
     *                      </p><p><code>AF_INET6</code> - IPv6 Internet based protocols. TCP and UDP are common protocols of this protocol
214
     *                      family.</p><p><code>AF_UNIX</code> - Local communication protocol family. High efficiency and low overhead make
215
     *                      it a great form of IPC (Interprocess Communication).</p>
216
     * @param int $type     <p>The type parameter selects the type of communication to be used by the socket.</p><p>
217
     *                      <code>SOCK_STREAM</code> - Provides sequenced, reliable, full-duplex, connection-based byte streams. An
218
     *                      out-of-band data transmission mechanism may be supported. The TCP protocol is based on this socket type.</p><p>
219
     *                      <code>SOCK_DGRAM</code> - Supports datagrams (connectionless, unreliable messages of a fixed maximum length).
220
     *                      The UDP protocol is based on this socket type.</p><p><code>SOCK_SEQPACKET</code> - Provides a sequenced,
221
     *                      reliable, two-way connection-based data transmission path for datagrams of fixed maximum length; a consumer is
222
     *                      required to read an entire packet with each read call.</p><p><code>SOCK_RAW</code> - Provides raw network
223
     *                      protocol access. This special type of socket can be used to manually construct any type of protocol. A common
224
     *                      use for this socket type is to perform ICMP requests (like ping).</p><p><code>SOCK_RDM</code> - Provides a
225
     *                      reliable datagram layer that does not guarantee ordering. This is most likely not implemented on your operating
226
     *                      system.</p>
227
     * @param int $protocol <p>The protocol parameter sets the specific protocol within the specified domain to be used
228
     *                      when communicating on the returned socket. The proper value can be retrieved by name by using
229
     *                      <code>getprotobyname()</code>. If the desired protocol is TCP, or UDP the corresponding constants
230
     *                      <code>SOL_TCP</code>, and <code>SOL_UDP</code> can also be used.<p><p>Some of the common protocol types</p><p>
231
     *                      icmp - The Internet Control Message Protocol is used primarily by gateways and hosts to report errors in
232
     *                      datagram communication. The "ping" command (present in most modern operating systems) is an example application
233
     *                      of ICMP.</p><p>udp - The User Datagram Protocol is a connectionless, unreliable, protocol with fixed record
234
     *                      lengths. Due to these aspects, UDP requires a minimum amount of protocol overhead.</p><p>tcp - The Transmission
235
     *                      Control Protocol is a reliable, connection based, stream oriented, full duplex protocol. TCP guarantees that all
236
     *                      data packets will be received in the order in which they were sent. If any packet is somehow lost during
237
     *                      communication, TCP will automatically retransmit the packet until the destination host acknowledges that packet.
238
     *                      For reliability and performance reasons, the TCP implementation itself decides the appropriate octet boundaries
239
     *                      of the underlying datagram communication layer. Therefore, TCP applications must allow for the possibility of
240
     *                      partial record transmission.</p>
241
     *
242
     * @throws Exception\SocketException If there is an error creating the php socket.
243
     *
244
     * @return Socket Returns a Socket object based on the successful creation of the php socket.
245
     */
246 4
    public static function create($domain, $type, $protocol)
247
    {
248 4
        $return = @socket_create($domain, $type, $protocol);
249
250 4
        if ($return === false) {
251 1
            throw new SocketException();
252
        }
253
254 3
        $socket = new self($return);
255 3
        $socket->domain = $domain;
256 3
        $socket->type = $type;
257 3
        $socket->protocol = $protocol;
258
259 3
        return $socket;
260
    }
261
262
    /**
263
     * Opens a socket on port to accept connections.
264
     *
265
     * <p>Creates a new socket resource of type <code>AF_INET</code> listening on all local interfaces on the given
266
     * port waiting for new connections.</p>
267
     *
268
     * @param int $port    The port on which to listen on all interfaces.
269
     * @param int $backlog <p>The backlog parameter defines the maximum length the queue of pending connections may
270
     *                     grow to. <code>SOMAXCONN</code> may be passed as the backlog parameter.</p>
271
     *
272
     * @throws Exception\SocketException If the socket is not successfully created.
273
     *
274
     * @see Socket::create()
275
     * @see Socket::bind()
276
     * @see Socket::listen()
277
     *
278
     * @return Socket Returns a Socket object based on the successful creation of the php socket.
279
     */
280
    public static function createListen($port, $backlog = 128)
281
    {
282
        $return = @socket_create_listen($port, $backlog);
283
284
        if ($return === false) {
285
            throw new SocketException();
286
        }
287
288
        $socket = new self($return);
289
        $socket->domain = AF_INET;
290
291
        return $socket;
292
    }
293
294
    /**
295
     * Creates a pair of indistinguishable sockets and stores them in an array.
296
     *
297
     * <p>Creates two connected and indistinguishable sockets. This function is commonly used in IPC (InterProcess
298
     * Communication).</p>
299
     *
300
     * @param int $domain   <p>The domain parameter specifies the protocol family to be used by the socket. See
301
     *                      <code>create()</code> for the full list.</p>
302
     * @param int $type     <p>The type parameter selects the type of communication to be used by the socket. See
303
     *                      <code>create()</code> for the full list.</p>
304
     * @param int $protocol <p>The protocol parameter sets the specific protocol within the specified domain to be used
305
     *                      when communicating on the returned socket. The proper value can be retrieved by name by using
306
     *                      <code>getprotobyname()</code>. If the desired protocol is TCP, or UDP the corresponding constants
307
     *                      <code>SOL_TCP</code>, and <code>SOL_UDP</code> can also be used. See <code>create()</code> for the full list of
308
     *                      supported protocols.
309
     *
310
     * @throws Exception\SocketException If the creation of the php sockets is not successful.
311
     *
312
     * @see Socket::create()
313
     *
314
     * @return Socket[] An array of Socket objects containing identical sockets.
315
     */
316
    public static function createPair($domain, $type, $protocol)
317
    {
318
        $array = [];
319
        $return = @socket_create_pair($domain, $type, $protocol, $array);
320
321
        if ($return === false) {
322
            throw new SocketException();
323
        }
324
325
        $sockets = self::constructFromResources($array);
326
327
        foreach ($sockets as $socket) {
328
            $socket->domain = $domain;
329
            $socket->type = $type;
330
            $socket->protocol = $protocol;
331
        }
332
333
        return $sockets;
334
    }
335
336
    /**
337
     * Gets socket options.
338
     *
339
     * <p>Retrieves the value for the option specified by the optname parameter for the current socket.</p>
340
     *
341
     * @param int $level   <p>The level parameter specifies the protocol level at which the option resides. For example,
342
     *                     to retrieve options at the socket level, a level parameter of <code>SOL_SOCKET</code> would be used. Other
343
     *                     levels, such as <code>TCP</code>, can be used by specifying the protocol number of that level. Protocol numbers
344
     *                     can be found by using the <code>getprotobyname()</code> function.
345
     * @param int $optname <p><b>Available Socket Options</b></p><p><code>SO_DEBUG</code> - Reports whether debugging
346
     *                     information is being recorded. Returns int.</p><p><code>SO_BROADCAST</code> - Reports whether transmission of
347
     *                     broadcast messages is supported. Returns int.</p><p><code>SO_REUSERADDR</code> - Reports whether local addresses
348
     *                     can be reused. Returns int.</p><p><code>SO_KEEPALIVE</code> - Reports whether connections are kept active with
349
     *                     periodic transmission of messages. If the connected socket fails to respond to these messages, the connection is
350
     *                     broken and processes writing to that socket are notified with a SIGPIPE signal. Returns int.</p><p>
351
     *                     <code>SO_LINGER</code> - Reports whether the socket lingers on <code>close()</code> if data is present. By
352
     *                     default, when the socket is closed, it attempts to send all unsent data. In the case of a connection-oriented
353
     *                     socket, <code>close()</code> will wait for its peer to acknowledge the data. If <code>l_onoff</code> is non-zero
354
     *                     and <code>l_linger</code> is zero, all the unsent data will be discarded and RST (reset) is sent to the peer in
355
     *                     the case of a connection-oriented socket. On the other hand, if <code>l_onoff</code> is non-zero and
356
     *                     <code>l_linger</code> is non-zero, <code>close()</code> will block until all the data is sent or the time
357
     *                     specified in <code>l_linger</code> elapses. If the socket is non-blocking, <code>close()</code> will fail and
358
     *                     return an error. Returns an array with two keps: <code>l_onoff</code> and <code>l_linger</code>.</p><p>
359
     *                     <code>SO_OOBINLINE</code> - Reports whether the socket leaves out-of-band data inline. Returns int.</p><p>
360
     *                     <code>SO_SNDBUF</code> - Reports the size of the send buffer. Returns int.</p><p><code>SO_RCVBUF</code> -
361
     *                     Reports the size of the receive buffer. Returns int.</p><p><code>SO_ERROR</code> - Reports information about
362
     *                     error status and clears it. Returns int.</p><p><code>SO_TYPE</code> - Reports the socket type (e.g.
363
     *                     <code>SOCK_STREAM</code>). Returns int.</p><p><code>SO_DONTROUTE</code> - Reports whether outgoing messages
364
     *                     bypass the standard routing facilities. Returns int.</p><p><code>SO_RCVLOWAT</code> - Reports the minimum number
365
     *                     of bytes to process for socket input operations. Returns int.</p><p><code>SO_RCVTIMEO</code> - Reports the
366
     *                     timeout value for input operations. Returns an array with two keys: <code>sec</code> which is the seconds part
367
     *                     on the timeout value and <code>usec</code> which is the microsecond part of the timeout value.</p><p>
368
     *                     <code>SO_SNDTIMEO</code> - Reports the timeout value specifying the amount of time that an output function
369
     *                     blocks because flow control prevents data from being sent. Returns an array with two keys: <code>sec</code>
370
     *                     which is the seconds part on the timeout value and <code>usec</code> which is the microsecond part of the
371
     *                     timeout value.</p><p><code>SO_SNDLOWAT</code> - Reports the minimum number of bytes to process for socket output
372
     *                     operations. Returns int.</p><p><code>TCP_NODELAY</code> - Reports whether the Nagle TCP algorithm is disabled.
373
     *                     Returns int.</p><p><code>IP_MULTICAST_IF</code> - The outgoing interface for IPv4 multicast packets. Returns the
374
     *                     index of the interface (int).</p><p><code>IPV6_MULTICAST_IF</code> - The outgoing interface for IPv6 multicast
375
     *                     packets. Returns the same thing as <code>IP_MULTICAST_IF</code>.</p><p><code>IP_MULTICAST_LOOP</code> - The
376
     *                     multicast loopback policy for IPv4 packets, which determines whether multicast packets sent by this socket also
377
     *                     reach receivers in the same host that have joined the same multicast group on the outgoing interface used by
378
     *                     this socket. This is the case by default. Returns int.</p><p><code>IPV6_MULTICAST_LOOP</code> - Analogous to
379
     *                     <code>IP_MULTICAST_LOOP</code>, but for IPv6. Returns int.</p><p><code>IP_MULTICAST_TTL</code> - The
380
     *                     time-to-live of outgoing IPv4 multicast packets. This should be a value between 0 (don't leave the interface)
381
     *                     and 255. The default value is 1 (only the local network is reached). Returns int.</p><p>
382
     *                     <code>IPV6_MULTICAST_HOPS</code> - Analogous to <code>IP_MULTICAST_TTL</code>, but for IPv6 packets. The value
383
     *                     -1 is also accepted, meaning the route default should be used. Returns int.</p>
384
     *
385
     * @throws Exception\SocketException If there was an error retrieving the option.
386
     *
387
     * @return mixed See the descriptions based on the option being requested above.
388
     */
389
    public function getOption($level, $optname)
390
    {
391
        $return = @socket_get_option($this->resource, $level, $optname);
392
393
        if ($return === false) {
394
            throw new SocketException($this->resource);
395
        }
396
397
        return $return;
398
    }
399
400
    /**
401
     * Queries the remote side of the given socket which may either result in host/port or in a Unix filesystem
402
     * path, dependent on its type.
403
     *
404
     * @param string $address <p>If the given socket is of type <code>AF_INET</code> or <code>AF_INET6</code>,
405
     *                        <code>getPeerName()</code> will return the peers (remote) IP address in appropriate notation (e.g.
406
     *                        <code>127.0.0.1</code> or <code>fe80::1</code>) in the address parameter and, if the optional port parameter is
407
     *                        present, also the associated port.</p><p>If the given socket is of type <code>AF_UNIX</code>,
408
     *                        <code>getPeerName()</code> will return the Unix filesystem path (e.g. <code>/var/run/daemon.sock</cod>) in the
409
     *                        address parameter.</p>
410
     * @param int    $port    (Optional) If given, this will hold the port associated to the address.
411
     *
412
     * @throws Exception\SocketException <p>If the retrieval of the peer name fails or if the socket type is not
413
     *                                   <code>AF_INET</code>, <code>AF_INET6</code>, or <code>AF_UNIX</code>.</p>
414
     *
415
     * @return bool <p>Returns <code>true</code> if the retrieval of the peer name was successful.</p>
416
     */
417
    public function getPeerName(&$address, &$port)
418
    {
419
        $return = @socket_getpeername($this->resource, $address, $port);
420
421
        if ($return === false) {
422
            throw new SocketException($this->resource);
423
        }
424
425
        return $return;
426
    }
427
428
    /**
429
     * Queries the local side of the given socket which may either result in host/port or in a Unix filesystem path,
430
     * dependent on its type.
431
     *
432
     * <p><b>Note:</b> <code>getSockName()</code> should not be used with <code>AF_UNIX</code> sockets created with
433
     * <code>connect()</code>. Only sockets created with <code>accept()</code> or a primary server socket following a
434
     * call to <code>bind()</code> will return meaningful values.</p>
435
     *
436
     * @param string $address <p>If the given socket is of type <code>AF_INET</code> or <code>AF_INET6</code>,
437
     *                        <code>getSockName()</code> will return the local IP address in appropriate notation (e.g.
438
     *                        <code>127.0.0.1</code> or <code>fe80::1</code>) in the address parameter and, if the optional port parameter is
439
     *                        present, also the associated port.</p><p>If the given socket is of type <code>AF_UNIX</code>,
440
     *                        <code>getSockName()</code> will return the Unix filesystem path (e.g. <code>/var/run/daemon.sock</cod>) in the
441
     *                        address parameter.</p>
442
     * @param int    $port    If provided, this will hold the associated port.
443
     *
444
     * @throws Exception\SocketException <p>If the retrieval of the socket name fails or if the socket type is not
445
     *                                   <code>AF_INET</code>, <code>AF_INET6</code>, or <code>AF_UNIX</code>.</p>
446
     *
447
     * @return bool <p>Returns <code>true</code> if the retrieval of the socket name was successful.</p>
448
     */
449 1
    public function getSockName(&$address, &$port)
450
    {
451 1
        if (!in_array($this->domain, [AF_UNIX, AF_INET, AF_INET6])) {
452
            return false;
453
        }
454
455 1
        $return = @socket_getsockname($this->resource, $address, $port);
456
457 1
        if ($return === false) {
458
            throw new SocketException($this->resource);
459
        }
460
461 1
        return $return;
462
    }
463
464
    /**
465
     * Imports a stream.
466
     *
467
     * <p>Imports a stream that encapsulates a socket into a socket extension resource.</p>
468
     *
469
     * @param $stream The stream resource to import.
470
     *
471
     * @throws Exception\SocketException If the import of the stream is not successful.
472
     *
473
     * @return Socket Returns a Socket object based on the stream.
474
     */
475
    public static function importStream($stream)
476
    {
477
        $return = @socket_import_stream($stream);
478
479
        if ($return === false) {
480
            throw new SocketException($stream);
481
        }
482
483
        return new self($return);
484
    }
485
486
    /**
487
     * Listens for a connection on a socket.
488
     *
489
     * <p>After the socket has been created using <code>create()</code> and bound to a name with <code>bind()</code>,
490
     * it may be told to listen for incoming connections on socket.</p>
491
     *
492
     * @param int $backlog <p>A maximum of backlog incoming connections will be queued for processing. If a connection
493
     *                     request arrives with the queue full the client may receive an error with an indication of ECONNREFUSED, or, if
494
     *                     the underlying protocol supports retransmission, the request may be ignored so that retries may succeed.</p><p>
495
     *                     <b>Note:</b> The maximum number passed to the backlog parameter highly depends on the underlying platform. On
496
     *                     Linux, it is silently truncated to <code>SOMAXCONN</code>. On win32, if passed <code>SOMAXCONN</code>, the
497
     *                     underlying service provider responsible for the socket will set the backlog to a maximum reasonable value. There
498
     *                     is no standard provision to find out the actual backlog value on this platform.</p>
499
     *
500
     * @throws Exception\SocketException If the listen fails.
501
     *
502
     * @return bool <p>Returns <code>true</code> on success.
503
     */
504 1
    public function listen($backlog = 0)
505
    {
506 1
        $return = socket_listen($this->resource, $backlog);
507
508 1
        if ($return === false) {
509
            throw new SocketException($this->resource);
510
        }
511
512 1
        return true;
513
    }
514
515
    /**
516
     * reads a maximum of length bytes from a socket.
517
     *
518
     * <p>Reads from the socket created by the <code>create()</code> or <code>accept()</code> functions.</p>
519
     *
520
     * @param int $length <p>The maximum number of bytes read is specified by the length parameter. Otherwise you can
521
     *                    use <code>\r</code>, <code>\n</code>, or <code>\0</code> to end reading (depending on the type parameter, see
522
     *                    below).</p>
523
     * @param int $type   <p>(Optional) type parameter is a named constant:<ul><li><code>PHP_BINARY_READ</code> (Default)
524
     *                    - use the system <code>recv()</code> function. Safe for reading binary data.</li><li>
525
     *                    <code>PHP_NORMAL_READ</code> - reading stops at <code>\n</code> or <code>\r</code>.</li></ul></p>
526
     *
527
     * @throws Exception\SocketException If there was an error reading or if the host closed the connection.
528
     *
529
     * @see Socket::create()
530
     * @see Socket::accept()
531
     *
532
     * @return string Returns the data as a string. Returns a zero length string ("") when there is no more data to
533
     *                read.
534
     */
535
    public function read($length, $type = PHP_BINARY_READ)
536
    {
537
        $return = @socket_read($this->resource, $length, $type);
538
539
        if ($return === false) {
540
            throw new SocketException($this->resource);
541
        }
542
543
        return $return;
544
    }
545
546
    /**
547
     * Receives data from a connected socket.
548
     *
549
     * <p>Receives length bytes of data in buffer from the socket. <code>receive()</code> can be used to gather data
550
     * from connected sockets. Additionally, one or more flags can be specified to modify the behaviour of the
551
     * function.</p><p>buffer is passed by reference, so it must be specified as a variable in the argument list. Data
552
     * read from socket by <code>receive()</code> will be returned in buffer.</p>
553
     *
554
     * @param string $buffer <p>The data received will be fetched to the variable specified with buffer. If an error
555
     *                       occurs, if the connection is reset, or if no data is available, buffer will be set to <code>NULL</code>.</p>
556
     * @param int    $length Up to length bytes will be fetched from remote host.
557
     * @param int    $flags  <p>The value of flags can be any combination of the following flags, joined with the binary OR
558
     *                       (<code>|</code>) operator.<ul><li><code>MSG_OOB</code> - Process out-of-band data.</li><li><code>MSG_PEEK</code>
559
     *                       - Receive data from the beginning of the receive queue without removing it from the queue.</li><li>
560
     *                       <code>MSG_WAITALL</code> - Block until at least length are received. However, if a signal is caught or the
561
     *                       remote host disconnects, the function may return less data.</li><li><code>MSG_DONTWAIT</code> - With this flag
562
     *                       set, the function returns even if it would normally have blocked.</li></ul></p>
563
     *
564
     * @throws Exception\SocketException If there was an error receiving data.
565
     *
566
     * @return int Returns the number of bytes received.
567
     */
568
    public function receive(&$buffer, $length, $flags)
569
    {
570
        $return = @socket_recv($this->resource, $buffer, $length, $flags);
571
572
        if ($return === false) {
573
            throw new SocketException($this->resource);
574
        }
575
576
        return $return;
577
    }
578
579
    /**
580
     * Runs the select() system call on the given arrays of sockets with a specified timeout.
581
     *
582
     * <p>accepts arrays of sockets and waits for them to change status. Those coming with BSD sockets background will
583
     * recognize that those socket resource arrays are in fact the so-called file descriptor sets. Three independent
584
     * arrays of socket resources are watched.</p><p><b>WARNING:</b> On exit, the arrays are modified to indicate which
585
     * socket resource actually changed status.</p><p>ou do not need to pass every array to <code>select()</code>. You
586
     * can leave it out and use an empty array or <code>NULL</code> instead. Also do not forget that those arrays are
587
     * passed by reference and will be modified after <code>select()</code> returns.
588
     *
589
     * @param Socket[] &$read               <p>The sockets listed in the read array will be watched to see if characters become
590
     *                                      available for reading (more precisely, to see if a read will not block - in particular, a socket resource is also
591
     *                                      ready on end-of-file, in which case a <code>read()</code> will return a zero length string).</p>
592
     * @param Socket[] &$write              The sockets listed in the write array will be watched to see if a write will not block.
593
     * @param Socket[] &$except             he sockets listed in the except array will be watched for exceptions.
594
     * @param int      $timeoutSeconds      The seconds portion of the timeout parameters (in conjunction with
595
     *                                      timeoutMilliseconds). The timeout is an upper bound on the amount of time elapsed before <code>select()</code>
596
     *                                      returns. timeoutSeconds may be zero, causing the <code>select()</code> to return immediately. This is useful for
597
     *                                      polling. If timeoutSeconds is <code>NULL</code> (no timeout), the <code>select()</code> can block
598
     *                                      indefinitely.</p>
599
     * @param int      $timeoutMilliseconds See the description for timeoutSeconds.
600
     *
601
     * @throws SocketException If there was an error.
602
     *
603
     * @return int Returns the number of socket resources contained in the modified arrays, which may be zero if the
604
     *             timeout expires before anything interesting happens.
605
     */
606
    public static function select(
607
        &$read,
608
        &$write,
609
        &$except,
610
        $timeoutSeconds,
611
        $timeoutMilliseconds = 0
612
    ) {
613
        $readSockets = null;
614
        $writeSockets = null;
615
        $exceptSockets = null;
616
617
        if (!is_null($read)) {
618
            $readSockets = self::mapClassToRawSocket($read);
619
        }
620
        if (!is_null($write)) {
621
            $writeSockets = self::mapClassToRawSocket($write);
622
        }
623
        if (!is_null($except)) {
624
            $exceptSockets = self::mapClassToRawSocket($except);
625
        }
626
627
        $return = @socket_select(
628
            $readSockets,
629
            $writeSockets,
630
            $exceptSockets,
631
            $timeoutSeconds,
632
            $timeoutMilliseconds
633
        );
634
635
        if ($return === false) {
636
            throw new SocketException();
637
        }
638
639
        $read = [];
640
        $write = [];
641
        $except = [];
642
643
        if ($readSockets) {
644
            $read = static::mapRawSocketToClass($readSockets);
645
        }
646
        if ($writeSockets) {
647
            $write = static::mapRawSocketToClass($writeSockets);
648
        }
649
        if ($exceptSockets) {
650
            $except = static::mapRawSocketToClass($exceptSockets);
651
        }
652
653
        return $return;
654
    }
655
656
    /**
657
     * Maps an array of Sockets to an array of socket resources.
658
     *
659
     * @param Socket[] $sockets An array of sockets to map.
660
     *
661
     * @return resource[] Returns the corresponding array of resources.
662
     */
663
    protected static function mapClassToRawSocket($sockets)
664
    {
665
        return array_map(function (Socket $socket) {
666
            return $socket->resource;
667
        }, $sockets);
668
    }
669
670
    /**
671
     * Maps an array of socket resources to an array of Sockets.
672
     *
673
     * @param resource[] $sockets An array of socket resources to map.
674
     *
675
     * @return Socket[] Returns the corresponding array of Socket objects.
676
     */
677
    protected static function mapRawSocketToClass($sockets)
678
    {
679
        return array_map(function ($rawSocket) {
680
            return self::$map[(string) $rawSocket];
681
        }, $sockets);
682
    }
683
684
    /**
685
     * Write to a socket.
686
     *
687
     * <p>The function <code>write()</code> writes to the socket from the given buffer.</p>
688
     *
689
     * @param string $buffer The buffer to be written.
690
     * @param int    $length The optional parameter length can specify an alternate length of bytes written to the socket.
691
     *                       If this length is greater than the buffer length, it is silently truncated to the length of the buffer.
692
     *
693
     * @throws Exception\SocketException If there was a failure.
694
     *
695
     * @return int Returns the number of bytes successfully written to the socket.
696
     */
697 1 View Code Duplication
    public function write($buffer, $length = null)
698
    {
699 1
        if (null === $length) {
700
            $length = strlen($buffer);
701
        }
702
703
        // make sure everything is written
704
        do {
705 1
            $return = @socket_write($this->resource, $buffer, $length);
706
707 1
            if (false !== $return && $return < $length) {
708
                $buffer = substr($buffer, $return);
709
                $length -= $return;
710
            } else {
711 1
                break;
712
            }
713
        } while (true);
714
715 1
        if ($return === false) {
716 1
            throw new SocketException($this->resource);
717
        }
718
719
        return $return;
720
    }
721
722
    /**
723
     * Sends data to a connected socket.
724
     *
725
     * <p>Sends length bytes to the socket from buffer.</p>
726
     *
727
     * @param string $buffer A buffer containing the data that will be sent to the remote host.
728
     * @param int    $flags  <p>The value of flags can be any combination of the following flags, joined with the binary OR
729
     *                       (<code>|</code>) operator.<ul><li><code>MSG_OOB</code> - Send OOB (out-of-band) data.</li><li>
730
     *                       <code>MSG_EOR</code> - Indicate a record mark. The sent data completes the record.</li><li><code>MSG_EOF</code> -
731
     *                       Close the sender side of the socket and include an appropriate notification of this at the end of the sent data.
732
     *                       The sent data completes the transaction.</li><li><code>MSG_DONTROUTE</code> - Bypass routing, use direct
733
     *                       interface.</li></ul></p>
734
     * @param int    $length The number of bytes that will be sent to the remote host from buffer.
735
     *
736
     * @throws Exception\SocketException If there was a failure.
737
     *
738
     * @return int Returns the number of bytes sent.
739
     */
740 View Code Duplication
    public function send($buffer, $flags = 0, $length = null)
741
    {
742
        if (null === $length) {
743
            $length = strlen($buffer);
744
        }
745
746
        // make sure everything is written
747
        do {
748
            $return = @socket_send($this->resource, $buffer, $length, $flags);
749
750
            if (false !== $return && $return < $length) {
751
                $buffer = substr($buffer, $return);
752
                $length -= $return;
753
            } else {
754
                break;
755
            }
756
        } while (true);
757
758
        if ($return === false) {
759
            throw new SocketException($this->resource);
760
        }
761
762
        return $return;
763
    }
764
765
    /**
766
     * Set the socket to blocking / non blocking.
767
     *
768
     * <p>Removes (blocking) or set (non blocking) the <code>O_NONBLOCK</code> flag on the socket.</p><p>When an
769
     * operation is performed on a blocking socket, the script will pause its execution until it receives a signal or it
770
     * can perform the operation.</p><p>When an operation is performed on a non-blocking socket, the script will not
771
     * pause its execution until it receives a signal or it can perform the operation. Rather, if the operation would
772
     * result in a block, the called function will fail.</p>
773
     *
774
     * @param bool $bool Flag to indicate if the Socket should block (<code>true</code>) or not block
775
     *                   (<code>false</code>).
776
     *
777
     * @return void
778
     */
779
    public function setBlocking($bool)
780
    {
781
        if ($bool) {
782
            @socket_set_block($this->resource);
783
        } else {
784
            @socket_set_nonblock($this->resource);
785
        }
786
    }
787
}
788