• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..28-Mar-2019-

Filter/H28-Mar-2019-654208

IStream/H28-Mar-2019-1,080129

Test/H28-Mar-2019-3,3421,995

Wrapper/H28-Mar-2019-65589

Bucket.phpH A D27-Mar-20196.2 KiB26991

CHANGELOG.mdH A D27-Mar-20197.7 KiB130103

Composite.phpH A D27-Mar-20192.9 KiB11327

Context.phpH A D27-Mar-20194.1 KiB17251

Exception.phpH A D27-Mar-20191.9 KiB526

README.mdH A D27-Mar-201919.5 KiB573455

Stream.phpH A D27-Mar-201917.8 KiB700302

composer.jsonH A D27-Mar-20191.3 KiB4645

README.md

1<p align="center">
2  <img src="https://static.hoa-project.net/Image/Hoa.svg" alt="Hoa" width="250px" />
3</p>
4
5---
6
7<p align="center">
8  <a href="https://travis-ci.org/hoaproject/stream"><img src="https://img.shields.io/travis/hoaproject/stream/master.svg" alt="Build status" /></a>
9  <a href="https://coveralls.io/github/hoaproject/stream?branch=master"><img src="https://img.shields.io/coveralls/hoaproject/stream/master.svg" alt="Code coverage" /></a>
10  <a href="https://packagist.org/packages/hoa/stream"><img src="https://img.shields.io/packagist/dt/hoa/stream.svg" alt="Packagist" /></a>
11  <a href="https://hoa-project.net/LICENSE"><img src="https://img.shields.io/packagist/l/hoa/stream.svg" alt="License" /></a>
12</p>
13<p align="center">
14  Hoa is a <strong>modular</strong>, <strong>extensible</strong> and
15  <strong>structured</strong> set of PHP libraries.<br />
16  Moreover, Hoa aims at being a bridge between industrial and research worlds.
17</p>
18
19# Hoa\Stream
20
21[![Help on IRC](https://img.shields.io/badge/help-%23hoaproject-ff0066.svg)](https://webchat.freenode.net/?channels=#hoaproject)
22[![Help on Gitter](https://img.shields.io/badge/help-gitter-ff0066.svg)](https://gitter.im/hoaproject/central)
23[![Documentation](https://img.shields.io/badge/documentation-hack_book-ff0066.svg)](https://central.hoa-project.net/Documentation/Library/Stream)
24[![Board](https://img.shields.io/badge/organisation-board-ff0066.svg)](https://waffle.io/hoaproject/stream)
25
26This library is a high-level abstraction over PHP streams. It
27includes:
28
29  * Stream manipulations: Open, close, auto-close, timeout, blocking
30    mode, buffer size, metadata etc.,
31  * Stream notifications: Depending of the stream wrapper, the
32    supported listeners are the following: `authrequire`,
33    `authresult`, `complete`, `connect`, `failure`, `mimetype`,
34    `progress`, `redirect`, `resolve`, and `size`,
35  * Context: Allow to pass options and parameters to the stream
36    wrappers, for instance HTTP headers,
37  * Filter: A function that sits between the source and the
38    destination of a stream, useful for instance to encrypt/decrypt a
39    data on-the-fly, or for more advanced tricks like instrumentation,
40  * Wrapper: Declare user-defined protocols that will naturally be
41    handled by the PHP standard library (like `fopen`,
42    `stream_get_contents` etc.),
43  * Interfaces: One interface per capability a stream can offer.
44
45This library is the foundation of several others, e.g.
46[`Hoa\File`](https://central.hoa-project.net/Resource/Library/File) or
47[`Hoa\Socket`](https://central.hoa-project.net/Resource/Library/Socket)
48(and so
49[`Hoa\Websocket`](https://central.hoa-project.net/Resource/Library/Websocket)).
50
51[Learn more](https://central.hoa-project.net/Documentation/Library/Stream).
52
53## Installation
54
55With [Composer](https://getcomposer.org/), to include this library into
56your dependencies, you need to
57require [`hoa/stream`](https://packagist.org/packages/hoa/stream):
58
59```sh
60$ composer require hoa/stream '~1.0'
61```
62
63For more installation procedures, please read [the Source
64page](https://hoa-project.net/Source.html).
65
66## Testing
67
68Before running the test suites, the development dependencies must be installed:
69
70```sh
71$ composer install
72```
73
74Then, to run all the test suites:
75
76```sh
77$ vendor/bin/hoa test:run
78```
79
80For more information, please read the [contributor
81guide](https://hoa-project.net/Literature/Contributor/Guide.html).
82
83## Quick usage
84
85As a quick overview, we propose to discover what `Hoa\Stream` provides
86in term of interfaces, i.e. stream capabilities. This is almost the
87most important part of this library. Then, how to define a stream,
88followed by how to use stream contexts. Events, listeners and
89notifications will be detailed in the next section. Finally, wrappers
90and filters are detailed in the last sections.
91
92### Interfaces, aka stream capabilities
93
94This library defines several interfaces representing important stream
95capabilities. This is very useful when designing a function, or a
96library, working with streams. It ensures the stream is typed and
97offers certain capabilities. The interfaces are declared in the
98`Hoa\Stream\IStream` namespace:
99
100  * `In`, to read from a stream, provides `read`, `readInteger`,
101    `readLine`, `readAll`, `eof` etc.,
102  * `Out`, to write onto a stream, provides `write`, `writeArray`,
103    `writeLine`, `truncate` etc.,
104  * `Bufferable`, for streams with at least one internal buffer,
105    provides `newBuffer`, `flush`, `getBufferLevel` etc.,
106  * `Touchable`, for “touchable” streams, provides `touch`, `copy`,
107    `move`, `delete`, `changeGroup` etc.,
108  * `Lockable`, to lock a stream, provides `lock` and several
109    constants representing different kind of locks, like
110    `LOCK_SHARED`, `LOCK_EXCLUSIVE`, `LOCK_NO_BLOCK` etc.,
111  * `Pathable`, for path-based stream, provides `getBasename` and
112    `getDirname`,
113  * `Pointable`, to move the internal pointer of the stream if any,
114    provides `rewind`, `seek` and `tell`,
115  * `Statable`, to get statistics about a stream, provides `getSize`,
116    `getStatistics`, `getATime`, `getCTime`, `isReadable` etc.,
117  * `Structural`, for a structural stream, i.e. a stream acting like a
118    tree, provides `selectRoot`, `selectAnyElements`,
119    `selectElements`, `selectAdjacentSiblingElement`, `querySelector`
120    etc.
121
122Thus, if one only need to read from a stream, it will type the stream
123with `Hoa\Stream\IStream\In`. It also allows an implementer to choose
124what capabilities its stream will provide or not.
125
126Finally, the highest interface is `Stream`, defining the `getStream`
127method, that's all. That's the most undefined stream. All capabilities
128must extend this interface.
129
130### Define a concrete stream
131
132The main `Hoa\Stream\Stream` class is abstract. Two method
133implementations are left to the user: `_open` and : `_close`,
134respectively to open a particular stream, and to close this particular
135stream, for instance:
136
137```php
138class BasicFile extends Hoa\Stream\Stream
139{
140    protected function &_open($streamName, Hoa\Stream\Context $context = null)
141    {
142        if (null === $context) {
143            $out = fopen($streamName, 'rb');
144        } else {
145            $out = fopen($streamName, 'rb', false, $context->getContext());
146        }
147
148        return $out;
149    }
150
151    protected function _close()
152    {
153        return fclose($this->getStream());
154    }
155}
156```
157
158Then, the most common usage will be:
159
160```php
161$file = new BasicFile('/path/to/file');
162```
163
164That's all. This stream has no capability yet. Let's implement the
165`In` capability:
166
167```php
168class BasicFile extends Hoa\Stream\Stream implements Hoa\Stream\IStream\In
169{
170    // …
171
172    public function read($length)
173    {
174        return fread($this->getStream(), max(1, $length));
175    }
176
177    // …
178}
179```
180
181Other methods are left as an exercise to the reader. Thus, we are now
182able to:
183
184```php
185$chunk = $file->read(42);
186```
187
188The `Stream` capability is already implemented by the
189`Hoa\Stream\Stream` class.
190
191### Contextual streams
192
193A context is represented by the `Hoa\Stream\Context` class. It
194represents a set of options and parameters for the stream.
195[See the options and parameters for the `http://` stream wrapper](http://php.net/context.http)
196as an example of possible ones. Thanks to context, this is possible to
197add HTTP headers for instance, or to specify the proxy, the maximum
198number of redirections etc. All these information are
199options/parameters of the stream.
200
201To use them, first let's define the context:
202
203```php
204$contextId = 'my_http_context';
205$context   = Hoa\Stream\Context::getInstance($contextId);
206$context->setOptions([
207    // …
208]);
209```
210
211And thus, we can ask a stream to use this context based on the chosen
212context ID, like this:
213
214```php
215$basicFile = new BasicFile('/path/to/file', $contextId);
216```
217
218For the stream implementer, the `getOptions` and `getParameters`
219methods on the `Hoa\Stream\Context` class will be useful to
220respectively retrieve the options and the parameters, and acts
221according to them.
222
223The concept of _options_ and _parameters_ are defined by PHP itself.
224
225### Events, listeners, and notifications
226
227A stream has some events, and several listeners. So far, listeners
228mostly represent “stream notifications”.
229
2302 events are registered: `hoa://Event/Stream/<streamName>` and
231`hoa://Event/Stream/<streamName>:close-before`. Thus, for instance, to
232execute a function before the `/path/to/file` stream closes, one
233will write:
234
235```php
236Hoa\Event\Event::getEvent('hoa://Event/Stream//path/to/file:close-before')->attach(
237    function (Hoa\Event\Bucket $bucket) {
238        // do something!
239    }
240);
241```
242
243Remember that a stream is not necessarily a file. It can be a socket,
244a WebSocket, a stringbuffer, any stream you have defined…
245Consequently, this event can be used in very different manner for
246various scenario, like logging things, closing related resources,
247firing another event… There is no rule. The observed stream is still
248opened, and can theoritically still be used.
249
250This event is fired when calling the `Hoa\Stream\Stream::close`
251method.
252
253Now let's move on to listeners. To register a listener, we must create
254an instance of our stream without opening it. This action is called
255“deferred opening”. We can control the opening time with the third
256argument of the default `Hoa\Stream\Stream` constructor; `true` to
257defer the opening, like:
258
259```php
260$file = new BasicFile('/path/to/file', null, true);
261// do something
262$file->open();
263```
264
265Passing `null` as a second argument means: No context. Note that we
266must manually call the `open` method to open the stream then. Between
267the stream instanciation and the stream opening, we can attach new
268listeners.
269
270Depending of the stream implementation, different listeners will be
271fired. The term “listener” is the one used everywhere in Hoa, but PHP
272—in the context of stream— refers to them as notifications. Let's take
273an example with an HTTP stream:
274
275```php
276$basic = new BasicFile(
277    'https://hoa-project.net/', // stream name
278    null,                       // context ID
279    true                        // defere opening
280);
281$basic->on(
282    'connect',
283    function (Hoa\Event\Bucket $bucket) {
284        echo 'Connected', "\n";
285    }
286);
287$basic->on(
288    'redirect',
289    function (Hoa\Event\Bucket $bucket) {
290        echo 'Redirection to ', $bucket->getData()['message'], "\n";
291    }
292);
293$basic->on(
294    'mimetype',
295    function (Hoa\Event\Bucket $bucket) {
296        echo 'MIME-Type is ', $bucket->getData()['message'], "\n";
297    }
298);
299$basic->on(
300    'size',
301    function (Hoa\Event\Bucket $bucket) {
302        echo 'Size is ', $bucket->getData()['max'], "\n";
303    }
304);
305$basic->on(
306    'progress',
307    function (Hoa\Event\Bucket $bucket) {
308        echo 'Progressed, ', $bucket->getData()['transferred'], ' bytes downloaded', "\n";
309    }
310);
311
312// Then open.
313$basic->open();
314```
315
316You might see something like this:
317
318```
319Connected
320MIME-Type is text/html; charset=UTF-8
321Redirection to /En/
322Connected
323MIME-Type is text/html; charset=UTF-8
324Progressed, … bytes downloaded
325Progressed, … bytes downloaded
326```
327
328The exhaustive list of listeners is the following:
329
330  * `authrequire`, when the authentication is required,
331  * `authresult`, when the result of the authentication is known,
332  * `complete`, when the stream is complete (meaning can vary a lot here),
333  * `connect`, when the stream is connected (meaning can vary a lot here),
334  * `failure`, when something unexpected occured,
335  * `mimetype`, when the MIME-type of the stream is known,
336  * `progress`, when there is significant progression,
337  * `redirect`, when the stream is redirected to another stream,
338  * `resolve`, when the stream is resolved (meaning can vary a lot here),
339  * `size`, when the size of the stream is known.
340
341All listener bucket data is an array containing the following pairs:
342
343  * `code`, one of the `STREAM_NOTIFY_*` constant, which is basically
344    the listener name
345    (see [the documentation](http://php.net/stream.constants)),
346  * `severity`, one of the `STREAM_NOTIFY_SEVERITY_*` constant:
347    * `STREAM_NOTIFY_SEVERITY_INFO`, normal, non-error related,
348      notification,
349    * `STREAM_NOTIFY_SEVERITY_WARN`, non critical error condition,
350      processing may continue,
351    * `STREAM_NOTIFY_SEVERITY_ERR`, a critical error occurred,
352      processing cannot continue.
353  * `message`, a string containing most useful information,
354  * `transferred`, amount of bytes already transferred,
355  * `max`, total number of bytes to transfer.
356
357This is possible for the stream implementer to add more
358listeners. Please, take a look at
359[the `Hoa\Event` library](https://central.hoa-project.net/Resource/Library/Event). Not
360all listeners will be fired by all kind of streams.
361
362### Wrappers
363
364A stream wrapper allows to declare schemes, like `hoa://` or
365`fortune://`. You can imagine adding your favorite online storage too,
366`cloud://`. Any stream wrapper can be used with native standard PHP
367functions, like `fopen`, `file_get_contents`, `mkdir`, `touch` etc. It
368will be transparent for the user.
369
370The `Hoa\Stream\Wrapper\Wrapper` class holds all methods to
371`register`, `unregister`, and `restore` wrappers. The `isRegistered`
372and `getRegistered` methods are also helpful. A wrapper is represented by a class:
373
374```php
375Hoa\Stream\Wrapper\Wrapper::register('tmp', Tmp::class);
376```
377
378A wrapper must implement the `Hoa\Stream\Wrapper\IWrapper\IWrapper`
379interface. It is a combination of two other interfaces in the same
380namespace: `Stream` and `File`.
381
382The `Stream` interface requires to implement several methods related to a stream, such as:
383
384  * `stream_open`,
385  * `stream_close`,
386  * `stream_cast`,
387  * `stream_eof`,
388  * `stream_flush`,
389  * `stream_lock`,
390  * `stream_metadata`,
391  * `stream_read`,
392  * `stream_write`,
393  * `stream_seek`,
394  * `stream_tell`,
395  * `stream_stat`,
396  * etc.
397
398The API provides all required information.
399
400The `File` interface requires to implement other methods related to stream acting as a file, such as:
401
402  * `mkdir`,
403  * `dir_opendir`,
404  * `dir_closedir`,
405  * `dir_readdir`,
406  * `rename`,
407  * `unlink`,
408  * etc.
409
410An example of an implementation is the `hoa://` scheme in
411[the `Hoa\Protocol` library](https://central.hoa-project.net/Resource/Library/Protocol).
412It does not depend on this library to avoid dependencies, but the code
413can be helpful.
414
415### Filters
416
417A stream is like a pipe, with an input, and an output. This is
418possible to cut this pipe in two pieces, and insert a small part: A
419filter. There are three types of filter, identified by constants on
420the `Hoa\Stream\Filter\Filter` class:
421
422  1. `Filter::READ` when the filter applies for reading operations,
423  2. `Filter::WRITE` when the filter applies for writing operations,
424  3. `Filter::READ_AND_WRITE` when both.
425
426This class allows to `register` or `remove` filters. A filter takes
427the form of a class extending the `Hoa\Stream\Filter\Basic` filter,
428and an associated name. This is not mandatory but highly encouraged.
429
430Once a filter is registered, we can apply it on a stream by using its
431name, with the `append` or `prepend` methods. You might guess that
432several filters can be applied on a stream, in a specific order, like
433“decrypt”, “unzip”, “transform to…”. In such a scenario, the order
434matters.
435
436Finally, we use the stream as usual. A stream is not necessarily an
437instance of `Hoa\Stream`, it can be any PHP stream resources. Passing
438an `Hoa\Stream` instance will obviously unwraps to its underlying PHP
439stream resource.
440
441Let's implement a filter that changes the content of the stream into
442uppercase. We start by defining out filter:
443
444```php
445class ToUpper extends Hoa\Stream\Filter\Basic
446{
447    public function filter($in, $out, &$consumed, $closing)
448    {
449        $iBucket = new Hoa\Stream\Bucket($in);
450        $oBucket = new Hoa\Stream\Bucket($out);
451
452        while (false === $iBucket->eob()) {
453            $consumed += $iBucket->getLength();
454
455            $iBucket->setData(strtoupper($iBucket->getData()));
456            $oBucket->append($iBucket);
457        }
458
459        unset($iBucket);
460        unset($oBucket);
461
462        return parent::PASS_ON;
463    }
464}
465```
466
467Great. Now let's register our filter under a specific name:
468
469```php
470$filterName = 'toupper';
471Hoa\Stream\Filter::register($filterName, ToUpper::class);
472```
473
474Then, we must apply the filter on a specific stream, so let's open a
475stream, and append the filter:
476
477```php
478$file = new Hoa\File\Read(__FILE__);
479Hoa\Stream\Filter::append($file, $filterName, Hoa\Stream\Filter::READ);
480```
481
482This filter has been applied for reading operations only. So we will
483see its effect when reading on our stream, let's do it:
484
485``` php
486echo $file->readAll();
487```
488
489You will see everything in ASCII uppercase.
490
491A filter is a low-level stream API. It integrates with all kind of
492streams. And this is a very powerful tool. We mentionned some usages
493like decrypt, transform to, unzip… Actually, PHP comes with certain
494standard filters, like: `string.toupper`, `string.tolower`, `dechunk`,
495`zlib.*`, `bzip2.*`, `convert.iconv.*` etc. The
496`Hoa\Stream\Filter\Filter::getRegistered` method will provide the list
497of all registered filters.
498
499The `Hoa\Stream\Filter\LateComputed` class is a special filter. It
500calls its public `compute` method when the stream reaches its end. So
501by extending this filter, you can override the `compute` method and
502works on the `_buffer` attribute. This buffer contains the whole
503content of the stream. This is really a buffer. Why would it be
504useful? For instance if you are reading a PHP file, you can transform
505the source code on-the-fly by using a parser —for instance— and
506rewrite parts of the file. This technique is particularily useful to
507instrument codes (adding some probes).
508
509This is also possible to auto-apply a filter with… a wrapper! For
510example the `instrument://` wrapper can prepend a filter to the stream
511being opened with the `stream_open` method (from the
512`Hoa\Stream\Wrapper\IWrapper\Stream` interface).
513
514Possibilities are numerous.
515
516### Other operations
517
518There are more to cover. `Hoa\Stream` supports composite streams (with
519the `Hoa\Stream\Composite` abstract class), i.e. streams embedding
520other streams, like
521[the `Hoa\Xml` library](https://central.hoa-project.net/Resource/Library/Xml).
522An XML stream reads and writes from another inner stream (a file, a
523socket, or anything else).
524[The `Hoa\Stringbuffer` library](https://central.hoa-project.net/Resource/Library/Stringbuffer)
525allows a string to be manipulated with a stream API, so the stream
526content is written on the disk. Stream capabiilities are not the same
527than `Hoa\File` as you might guess.
528
529## Documentation
530
531The
532[hack book of `Hoa\Stream`](https://central.hoa-project.net/Documentation/Library/Stream) contains
533detailed information about how to use this library and how it works.
534
535To generate the documentation locally, execute the following commands:
536
537```sh
538$ composer require --dev hoa/devtools
539$ vendor/bin/hoa devtools:documentation --open
540```
541
542More documentation can be found on the project's website:
543[hoa-project.net](https://hoa-project.net/).
544
545## Getting help
546
547There are mainly two ways to get help:
548
549  * On the [`#hoaproject`](https://webchat.freenode.net/?channels=#hoaproject)
550    IRC channel,
551  * On the forum at [users.hoa-project.net](https://users.hoa-project.net).
552
553## Contribution
554
555Do you want to contribute? Thanks! A detailed [contributor
556guide](https://hoa-project.net/Literature/Contributor/Guide.html) explains
557everything you need to know.
558
559## License
560
561Hoa is under the New BSD License (BSD-3-Clause). Please, see
562[`LICENSE`](https://hoa-project.net/LICENSE) for details.
563
564## Related projects
565
566The following projects are using this library:
567
568  * [Marvirc](https://github.com/Hywan/Marvirc), A dead simple,
569    extremely modular and blazing fast IRC bot,
570  * [WellCommerce](http://wellcommerce.org/), Modern e-commerce engine
571    built on top of Symfony 3 full-stack framework,
572  * And of course many Hoa's libraries.
573