summaryrefslogtreecommitdiffstats
path: root/vendor/clue/socket-raw/README.md
blob: 7ea79b3c8ed135f3cfde64c0b8139f6b47305578 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
# clue/socket-raw

[![CI status](https://github.com/clue/socket-raw/actions/workflows/ci.yml/badge.svg)](https://github.com/clue/socket-raw/actions)
[![installs on Packagist](https://img.shields.io/packagist/dt/clue/socket-raw?color=blue&label=installs%20on%20Packagist)](https://packagist.org/packages/clue/socket-raw)

Simple and lightweight OOP wrapper for PHP's low-level sockets extension (ext-sockets).

PHP offers two networking APIs, the newer [streams API](https://www.php.net/manual/en/book.stream.php) and the older [socket API](https://www.php.net/manual/en/ref.sockets.php).
While the former has been a huge step forward in generalizing various streaming resources,
it lacks some of the advanced features of the original and much more low-level socket API.
This lightweight library exposes this socket API in a modern way by providing a thin wrapper around the underlying API.

* **Full socket API** -
  It exposes the whole [socket API](https://www.php.net/manual/en/ref.sockets.php) through a *sane* object-oriented interface.
  Provides convenience methods for common operations as well as exposing all underlying methods and options.
* **Fluent interface** -
  Uses a fluent interface so you can easily chain method calls.
  Error conditions will be signalled using `Exception`s instead of relying on cumbersome return codes.
* **Lightweight, SOLID design** -
  Provides a thin abstraction that is [*just good enough*](https://en.wikipedia.org/wiki/Principle_of_good_enough)
  and does not get in your way.
  This library is merely a very thin wrapper and has no other external dependencies.
* **Good test coverage** -
  Comes with an automated test suite and is regularly tested in the *real world*.

**Table of contents**

* [Support us](#support-us)
* [Quickstart example](#quickstart-example)
* [Usage](#usage)
  * [Factory](#factory)
    * [createClient()](#createclient)
    * [createServer()](#createserver)
    * [create*()](#create)
  * [Socket](#socket)
    * [Methods](#methods)
      * [Data I/O](#data-io)
      * [Unconnected I/O](#unconnected-io)
      * [Non-blocking (async) I/O](#non-blocking-async-io)
      * [Connection handling](#connection-handling)
* [Install](#install)
* [Tests](#tests)
* [License](#license)

## Support us

We invest a lot of time developing, maintaining and updating our awesome
open-source projects. You can help us sustain this high-quality of our work by
[becoming a sponsor on GitHub](https://github.com/sponsors/clue). Sponsors get
numerous benefits in return, see our [sponsoring page](https://github.com/sponsors/clue)
for details.

Let's take these projects to the next level together! 🚀

## Quickstart example

Once [installed](#install), you can use the following example to send and receive HTTP messages:

```php
$factory = new \Socket\Raw\Factory();

$socket = $factory->createClient('www.google.com:80');
echo 'Connected to ' . $socket->getPeerName() . PHP_EOL;

// send simple HTTP request to remote side
$socket->write("GET / HTTP/1.1\r\n\Host: www.google.com\r\n\r\n");

// receive and dump HTTP response
var_dump($socket->read(8192));

$socket->close();
```

See also the [examples](examples).

## Usage

### Factory

As shown in the [quickstart example](#quickstart-example), this library uses a `Factory` pattern
as a simple API to [`socket_create()`](https://www.php.net/manual/en/function.socket-create.php).
It provides simple access to creating TCP, UDP, UNIX, UDG and ICMP protocol sockets and supports both IPv4 and IPv6 addressing.

```php
$factory = new \Socket\Raw\Factory();
```

#### createClient()

The `createClient(string $address, null|float $timeout): Socket` method is
the most convenient method for creating connected client sockets
(similar to how [`fsockopen()`](https://www.php.net/manual/en/function.fsockopen.php) or
[`stream_socket_client()`](https://www.php.net/manual/en/function.stream-socket-client.php) work).

```php
// establish a TCP/IP stream connection socket to www.google.com on port 80
$socket = $factory->createClient('tcp://www.google.com:80');

// same as above, as scheme defaults to TCP
$socket = $factory->createClient('www.google.com:80');

// same as above, but wait no longer than 2.5s for connection
$socket = $factory->createClient('www.google.com:80', 2.5);

// create connectionless UDP/IP datagram socket connected to google's DNS
$socket = $factory->createClient('udp://8.8.8.8:53');

// establish TCP/IPv6 stream connection socket to localhost on port 1337
$socket = $factory->createClient('tcp://[::1]:1337');

// connect to local Unix stream socket path
$socket = $factory->createClient('unix:///tmp/daemon.sock');

// create Unix datagram socket
$socket = $factory->createClient('udg:///tmp/udg.socket');

// create a raw low-level ICMP socket (requires root!)
$socket = $factory->createClient('icmp://192.168.0.1');
```

#### createServer()

The `createServer($address)` method can be used to create a server side (listening) socket bound to specific address/path
(similar to how [`stream_socket_server()`](https://www.php.net/manual/en/function.stream-socket-server.php) works).
It accepts the same addressing scheme as the [`createClient()`](#createclient) method.

```php
// create a TCP/IP stream connection socket server on port 1337
$socket = $factory->createServer('tcp://localhost:1337');

// create a UDP/IPv6 datagram socket server on port 1337
$socket = $factory->createServer('udp://[::1]:1337');
```

#### create*()

Less commonly used, the `Factory` provides access to creating (unconnected) sockets for various socket types:

```php
$socket = $factory->createTcp4();
$socket = $factory->createTcp6();

$socket = $factory->createUdp4();
$socket = $factory->createUdp6();

$socket = $factory->createUnix();
$socket = $factory->createUdg();

$socket = $factory->createIcmp4();
$socket = $factory->createIcmp6();
```

You can also create arbitrary socket protocol types through the underlying mechanism:

```php
$factory->create($family, $type, $protocol);
```

### Socket

As discussed above, the `Socket` class is merely an object-oriented wrapper around a socket resource. As such, it helps if you're familar with socket programming in general.

The recommended way to create a `Socket` instance is via the above [`Factory`](#factory).

#### Methods

All low-level socket operations are available as methods on the `Socket` class.

You can refer to PHP's fairly good [socket API documentation](https://www.php.net/manual/en/ref.sockets.php) or the docblock comments in the [`Socket` class](src/Socket.php) to get you started.

##### Data I/O:

```
$socket->write('data');
$data = $socket->read(8192);
```

##### Unconnected I/O:

```
$socket->sendTo('data', $flags, $remote);
$data = $socket->rcvFrom(8192, $flags, $remote);
```

##### Non-blocking (async) I/O:

```
$socket->setBlocking(false);
$socket->selectRead();
$socket->selectWrite();
```

##### Connection handling:

```php
$client = $socket->accept();
$socket->bind($address);
$socket->connect($address);
$socket->shutdown();
$socket->close();
```

## Install

The recommended way to install this library is [through Composer](https://getcomposer.org/).
[New to Composer?](https://getcomposer.org/doc/00-intro.md)

This project follows [SemVer](https://semver.org/).
This will install the latest supported version:

```bash
$ composer require clue/socket-raw:^1.6
```

See also the [CHANGELOG](CHANGELOG.md) for details about version upgrades.

This project aims to run on any platform and thus does not require any PHP
extensions besides `ext-sockets` and supports running on legacy PHP 5.3 through
current PHP 8+.
It's *highly recommended to use the latest supported PHP version* for this project.

## Tests

To run the test suite, you first need to clone this repo and then install all
dependencies [through Composer](https://getcomposer.org/):

```bash
$ composer install
```

To run the test suite, go to the project root and run:

```bash
$ vendor/bin/phpunit
```

Note that the test suite contains tests for ICMP sockets which require root
access on Unix/Linux systems. Therefor some tests will be skipped unless you run
the following command to execute the full test suite:

```bash
$ sudo vendor/bin/phpunit
```

The test suite also contains a number of functional integration tests that rely
on a stable internet connection.
If you do not want to run these, they can simply be skipped like this:

```bash
$ vendor/bin/phpunit --exclude-group internet
```

## License

This project is released under the permissive [MIT license](LICENSE).

> Did you know that I offer custom development services and issuing invoices for
  sponsorships of releases and for contributions? Contact me (@clue) for details.