Name |
Date |
Size |
#Lines |
LOC |
||
---|---|---|---|---|---|---|
.. | 28-Mar-2019 | - | ||||
Filter/ | H | 28-Mar-2019 | - | 654 | 208 | |
IStream/ | H | 28-Mar-2019 | - | 1,080 | 129 | |
Test/ | H | 28-Mar-2019 | - | 3,342 | 1,995 | |
Wrapper/ | H | 28-Mar-2019 | - | 655 | 89 | |
Bucket.php | H A D | 27-Mar-2019 | 6.2 KiB | 269 | 91 | |
CHANGELOG.md | H A D | 27-Mar-2019 | 7.7 KiB | 130 | 103 | |
Composite.php | H A D | 27-Mar-2019 | 2.9 KiB | 113 | 27 | |
Context.php | H A D | 27-Mar-2019 | 4.1 KiB | 172 | 51 | |
Exception.php | H A D | 27-Mar-2019 | 1.9 KiB | 52 | 6 | |
README.md | H A D | 27-Mar-2019 | 19.5 KiB | 573 | 455 | |
Stream.php | H A D | 27-Mar-2019 | 17.8 KiB | 700 | 302 | |
composer.json | H A D | 27-Mar-2019 | 1.3 KiB | 46 | 45 |
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[](https://webchat.freenode.net/?channels=#hoaproject) 22[](https://gitter.im/hoaproject/central) 23[](https://central.hoa-project.net/Documentation/Library/Stream) 24[](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