• This repository has been archived on 20/Sep/2021
  • Stars
    star
    315
  • Rank 132,490 (Top 3 %)
  • Language
    PHP
  • Created about 12 years ago
  • Updated about 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

The Hoa\Stream library.

Hoa


Build status Code coverage Packagist License

Hoa is a modular, extensible and structured set of PHP libraries.
Moreover, Hoa aims at being a bridge between industrial and research worlds.

Hoa\Stream

Help on IRC Help on Gitter Documentation Board

This library is a high-level abstraction over PHP streams. It includes:

  • Stream manipulations: Open, close, auto-close, timeout, blocking mode, buffer size, metadata etc.,
  • Stream notifications: Depending of the stream wrapper, the supported listeners are the following: authrequire, authresult, complete, connect, failure, mimetype, progress, redirect, resolve, and size,
  • Context: Allow to pass options and parameters to the stream wrappers, for instance HTTP headers,
  • Filter: A function that sits between the source and the destination of a stream, useful for instance to encrypt/decrypt a data on-the-fly, or for more advanced tricks like instrumentation,
  • Wrapper: Declare user-defined protocols that will naturally be handled by the PHP standard library (like fopen, stream_get_contents etc.),
  • Interfaces: One interface per capability a stream can offer.

This library is the foundation of several others, e.g. Hoa\File or Hoa\Socket (and so Hoa\Websocket).

Learn more.

Installation

With Composer, to include this library into your dependencies, you need to require hoa/stream:

$ composer require hoa/stream '~1.0'

For more installation procedures, please read the Source page.

Testing

Before running the test suites, the development dependencies must be installed:

$ composer install

Then, to run all the test suites:

$ vendor/bin/hoa test:run

For more information, please read the contributor guide.

Quick usage

As a quick overview, we propose to discover what Hoa\Stream provides in term of interfaces, i.e. stream capabilities. This is almost the most important part of this library. Then, how to define a stream, followed by how to use stream contexts. Events, listeners and notifications will be detailed in the next section. Finally, wrappers and filters are detailed in the last sections.

Interfaces, aka stream capabilities

This library defines several interfaces representing important stream capabilities. This is very useful when designing a function, or a library, working with streams. It ensures the stream is typed and offers certain capabilities. The interfaces are declared in the Hoa\Stream\IStream namespace:

  • In, to read from a stream, provides read, readInteger, readLine, readAll, eof etc.,
  • Out, to write onto a stream, provides write, writeArray, writeLine, truncate etc.,
  • Bufferable, for streams with at least one internal buffer, provides newBuffer, flush, getBufferLevel etc.,
  • Touchable, for “touchable” streams, provides touch, copy, move, delete, changeGroup etc.,
  • Lockable, to lock a stream, provides lock and several constants representing different kind of locks, like LOCK_SHARED, LOCK_EXCLUSIVE, LOCK_NO_BLOCK etc.,
  • Pathable, for path-based stream, provides getBasename and getDirname,
  • Pointable, to move the internal pointer of the stream if any, provides rewind, seek and tell,
  • Statable, to get statistics about a stream, provides getSize, getStatistics, getATime, getCTime, isReadable etc.,
  • Structural, for a structural stream, i.e. a stream acting like a tree, provides selectRoot, selectAnyElements, selectElements, selectAdjacentSiblingElement, querySelector etc.

Thus, if one only need to read from a stream, it will type the stream with Hoa\Stream\IStream\In. It also allows an implementer to choose what capabilities its stream will provide or not.

Finally, the highest interface is Stream, defining the getStream method, that's all. That's the most undefined stream. All capabilities must extend this interface.

Define a concrete stream

The main Hoa\Stream\Stream class is abstract. Two method implementations are left to the user: _open and : _close, respectively to open a particular stream, and to close this particular stream, for instance:

class BasicFile extends Hoa\Stream\Stream
{
    protected function &_open($streamName, Hoa\Stream\Context $context = null)
    {
        if (null === $context) {
            $out = fopen($streamName, 'rb');
        } else {
            $out = fopen($streamName, 'rb', false, $context->getContext());
        }

        return $out;
    }

    protected function _close()
    {
        return fclose($this->getStream());
    }
}

Then, the most common usage will be:

$file = new BasicFile('/path/to/file');

That's all. This stream has no capability yet. Let's implement the In capability:

class BasicFile extends Hoa\Stream\Stream implements Hoa\Stream\IStream\In
{
    // …

    public function read($length)
    {
        return fread($this->getStream(), max(1, $length));
    }

    // …
}

Other methods are left as an exercise to the reader. Thus, we are now able to:

$chunk = $file->read(42);

The Stream capability is already implemented by the Hoa\Stream\Stream class.

Contextual streams

A context is represented by the Hoa\Stream\Context class. It represents a set of options and parameters for the stream. See the options and parameters for the http:// stream wrapper as an example of possible ones. Thanks to context, this is possible to add HTTP headers for instance, or to specify the proxy, the maximum number of redirections etc. All these information are options/parameters of the stream.

To use them, first let's define the context:

$contextId = 'my_http_context';
$context   = Hoa\Stream\Context::getInstance($contextId);
$context->setOptions([
    // …
]);

And thus, we can ask a stream to use this context based on the chosen context ID, like this:

$basicFile = new BasicFile('/path/to/file', $contextId);

For the stream implementer, the getOptions and getParameters methods on the Hoa\Stream\Context class will be useful to respectively retrieve the options and the parameters, and acts according to them.

The concept of options and parameters are defined by PHP itself.

Events, listeners, and notifications

A stream has some events, and several listeners. So far, listeners mostly represent “stream notifications”.

2 events are registered: hoa://Event/Stream/<streamName> and hoa://Event/Stream/<streamName>:close-before. Thus, for instance, to execute a function before the /path/to/file stream closes, one will write:

Hoa\Event\Event::getEvent('hoa://Event/Stream//path/to/file:close-before')->attach(
    function (Hoa\Event\Bucket $bucket) {
        // do something!
    }
);

Remember that a stream is not necessarily a file. It can be a socket, a WebSocket, a stringbuffer, any stream you have defined… Consequently, this event can be used in very different manner for various scenario, like logging things, closing related resources, firing another event… There is no rule. The observed stream is still opened, and can theoritically still be used.

This event is fired when calling the Hoa\Stream\Stream::close method.

Now let's move on to listeners. To register a listener, we must create an instance of our stream without opening it. This action is called “deferred opening”. We can control the opening time with the third argument of the default Hoa\Stream\Stream constructor; true to defer the opening, like:

$file = new BasicFile('/path/to/file', null, true);
// do something
$file->open();

Passing null as a second argument means: No context. Note that we must manually call the open method to open the stream then. Between the stream instanciation and the stream opening, we can attach new listeners.

Depending of the stream implementation, different listeners will be fired. The term “listener” is the one used everywhere in Hoa, but PHP —in the context of stream— refers to them as notifications. Let's take an example with an HTTP stream:

$basic = new BasicFile(
    'https://hoa-project.net/', // stream name
    null,                       // context ID
    true                        // defere opening
);
$basic->on(
    'connect',
    function (Hoa\Event\Bucket $bucket) {
        echo 'Connected', "\n";
    }
);
$basic->on(
    'redirect',
    function (Hoa\Event\Bucket $bucket) {
        echo 'Redirection to ', $bucket->getData()['message'], "\n";
    }
);
$basic->on(
    'mimetype',
    function (Hoa\Event\Bucket $bucket) {
        echo 'MIME-Type is ', $bucket->getData()['message'], "\n";
    }
);
$basic->on(
    'size',
    function (Hoa\Event\Bucket $bucket) {
        echo 'Size is ', $bucket->getData()['max'], "\n";
    }
);
$basic->on(
    'progress',
    function (Hoa\Event\Bucket $bucket) {
        echo 'Progressed, ', $bucket->getData()['transferred'], ' bytes downloaded', "\n";
    }
);

// Then open.
$basic->open();

You might see something like this:

Connected
MIME-Type is text/html; charset=UTF-8
Redirection to /En/
Connected
MIME-Type is text/html; charset=UTF-8
Progressed, … bytes downloaded
Progressed, … bytes downloaded

The exhaustive list of listeners is the following:

  • authrequire, when the authentication is required,
  • authresult, when the result of the authentication is known,
  • complete, when the stream is complete (meaning can vary a lot here),
  • connect, when the stream is connected (meaning can vary a lot here),
  • failure, when something unexpected occured,
  • mimetype, when the MIME-type of the stream is known,
  • progress, when there is significant progression,
  • redirect, when the stream is redirected to another stream,
  • resolve, when the stream is resolved (meaning can vary a lot here),
  • size, when the size of the stream is known.

All listener bucket data is an array containing the following pairs:

  • code, one of the STREAM_NOTIFY_* constant, which is basically the listener name (see the documentation),
  • severity, one of the STREAM_NOTIFY_SEVERITY_* constant:
    • STREAM_NOTIFY_SEVERITY_INFO, normal, non-error related, notification,
    • STREAM_NOTIFY_SEVERITY_WARN, non critical error condition, processing may continue,
    • STREAM_NOTIFY_SEVERITY_ERR, a critical error occurred, processing cannot continue.
  • message, a string containing most useful information,
  • transferred, amount of bytes already transferred,
  • max, total number of bytes to transfer.

This is possible for the stream implementer to add more listeners. Please, take a look at the Hoa\Event library. Not all listeners will be fired by all kind of streams.

Wrappers

A stream wrapper allows to declare schemes, like hoa:// or fortune://. You can imagine adding your favorite online storage too, cloud://. Any stream wrapper can be used with native standard PHP functions, like fopen, file_get_contents, mkdir, touch etc. It will be transparent for the user.

The Hoa\Stream\Wrapper\Wrapper class holds all methods to register, unregister, and restore wrappers. The isRegistered and getRegistered methods are also helpful. A wrapper is represented by a class:

Hoa\Stream\Wrapper\Wrapper::register('tmp', Tmp::class);

A wrapper must implement the Hoa\Stream\Wrapper\IWrapper\IWrapper interface. It is a combination of two other interfaces in the same namespace: Stream and File.

The Stream interface requires to implement several methods related to a stream, such as:

  • stream_open,
  • stream_close,
  • stream_cast,
  • stream_eof,
  • stream_flush,
  • stream_lock,
  • stream_metadata,
  • stream_read,
  • stream_write,
  • stream_seek,
  • stream_tell,
  • stream_stat,
  • etc.

The API provides all required information.

The File interface requires to implement other methods related to stream acting as a file, such as:

  • mkdir,
  • dir_opendir,
  • dir_closedir,
  • dir_readdir,
  • rename,
  • unlink,
  • etc.

An example of an implementation is the hoa:// scheme in the Hoa\Protocol library. It does not depend on this library to avoid dependencies, but the code can be helpful.

Filters

A stream is like a pipe, with an input, and an output. This is possible to cut this pipe in two pieces, and insert a small part: A filter. There are three types of filter, identified by constants on the Hoa\Stream\Filter\Filter class:

  1. Filter::READ when the filter applies for reading operations,
  2. Filter::WRITE when the filter applies for writing operations,
  3. Filter::READ_AND_WRITE when both.

This class allows to register or remove filters. A filter takes the form of a class extending the Hoa\Stream\Filter\Basic filter, and an associated name. This is not mandatory but highly encouraged.

Once a filter is registered, we can apply it on a stream by using its name, with the append or prepend methods. You might guess that several filters can be applied on a stream, in a specific order, like “decrypt”, “unzip”, “transform to…”. In such a scenario, the order matters.

Finally, we use the stream as usual. A stream is not necessarily an instance of Hoa\Stream, it can be any PHP stream resources. Passing an Hoa\Stream instance will obviously unwraps to its underlying PHP stream resource.

Let's implement a filter that changes the content of the stream into uppercase. We start by defining out filter:

class ToUpper extends Hoa\Stream\Filter\Basic
{
    public function filter($in, $out, &$consumed, $closing)
    {
        $iBucket = new Hoa\Stream\Bucket($in);
        $oBucket = new Hoa\Stream\Bucket($out);

        while (false === $iBucket->eob()) {
            $consumed += $iBucket->getLength();

            $iBucket->setData(strtoupper($iBucket->getData()));
            $oBucket->append($iBucket);
        }

        unset($iBucket);
        unset($oBucket);

        return parent::PASS_ON;
    }
}

Great. Now let's register our filter under a specific name:

$filterName = 'toupper';
Hoa\Stream\Filter::register($filterName, ToUpper::class);

Then, we must apply the filter on a specific stream, so let's open a stream, and append the filter:

$file = new Hoa\File\Read(__FILE__);
Hoa\Stream\Filter::append($file, $filterName, Hoa\Stream\Filter::READ);

This filter has been applied for reading operations only. So we will see its effect when reading on our stream, let's do it:

echo $file->readAll();

You will see everything in ASCII uppercase.

A filter is a low-level stream API. It integrates with all kind of streams. And this is a very powerful tool. We mentionned some usages like decrypt, transform to, unzip… Actually, PHP comes with certain standard filters, like: string.toupper, string.tolower, dechunk, zlib.*, bzip2.*, convert.iconv.* etc. The Hoa\Stream\Filter\Filter::getRegistered method will provide the list of all registered filters.

The Hoa\Stream\Filter\LateComputed class is a special filter. It calls its public compute method when the stream reaches its end. So by extending this filter, you can override the compute method and works on the _buffer attribute. This buffer contains the whole content of the stream. This is really a buffer. Why would it be useful? For instance if you are reading a PHP file, you can transform the source code on-the-fly by using a parser —for instance— and rewrite parts of the file. This technique is particularily useful to instrument codes (adding some probes).

This is also possible to auto-apply a filter with… a wrapper! For example the instrument:// wrapper can prepend a filter to the stream being opened with the stream_open method (from the Hoa\Stream\Wrapper\IWrapper\Stream interface).

Possibilities are numerous.

Other operations

There are more to cover. Hoa\Stream supports composite streams (with the Hoa\Stream\Composite abstract class), i.e. streams embedding other streams, like the Hoa\Xml library. An XML stream reads and writes from another inner stream (a file, a socket, or anything else). The Hoa\Stringbuffer library allows a string to be manipulated with a stream API, so the stream content is written on the disk. Stream capabiilities are not the same than Hoa\File as you might guess.

Documentation

The hack book of Hoa\Stream contains detailed information about how to use this library and how it works.

To generate the documentation locally, execute the following commands:

$ composer require --dev hoa/devtools
$ vendor/bin/hoa devtools:documentation --open

More documentation can be found on the project's website: hoa-project.net.

Getting help

There are mainly two ways to get help:

Contribution

Do you want to contribute? Thanks! A detailed contributor guide explains everything you need to know.

License

Hoa is under the New BSD License (BSD-3-Clause). Please, see LICENSE for details.

Related projects

The following projects are using this library:

  • Marvirc, A dead simple, extremely modular and blazing fast IRC bot,
  • WellCommerce, Modern e-commerce engine built on top of Symfony 3 full-stack framework,
  • And of course many Hoa's libraries.

More Repositories

1

Ruler

The Hoa\Ruler library.
PHP
625
star
2

Compiler

The Hoa\Compiler library.
PHP
453
star
3

Websocket

The Hoa\Websocket library.
PHP
422
star
4

Ustring

The Hoa\Ustring library.
PHP
402
star
5

Console

The Hoa\Console library.
PHP
366
star
6

Math

The Hoa\Math library.
PHP
366
star
7

Iterator

The Hoa\Iterator library.
PHP
333
star
8

File

The Hoa\File library.
PHP
323
star
9

Event

The Hoa\Event library
PHP
323
star
10

Consistency

The Hoa\Consistency library.
PHP
319
star
11

Exception

The Hoa\Exception library.
PHP
316
star
12

Regex

The Hoa\Regex library.
PHP
310
star
13

Protocol

The Hoa\Protocol library.
PHP
308
star
14

Visitor

The Hoa\Visitor library.
PHP
263
star
15

Zformat

The Hoa\Zformat library.
PHP
259
star
16

Eventsource

The Hoa\Eventsource library.
PHP
110
star
17

Central

Hoa is a modular, extensible, and structured set of PHP libraries.
PHP
105
star
18

Mime

The Hoa\Mime library.
PHP
101
star
19

Kitab

Kitab is the ideal companion for Documentation-Driven Quality: Render and Test your documentation.
PHP
79
star
20

Socket

The Hoa\Socket library.
PHP
64
star
21

Fastcgi

The Hoa\Fastcgi library.
PHP
60
star
22

Bench

The Hoa\Bench library.
PHP
56
star
23

Praspel

The Hoa\Praspel library.
PHP
40
star
24

Core

The Hoa\Core library.
PHP
35
star
25

Acl

The Hoa\Acl library.
PHP
28
star
26

Router

The Hoa\Router library.
PHP
28
star
27

Zombie

The Hoa\Zombie library.
PHP
28
star
28

Worker

The Hoa\Worker library.
PHP
26
star
29

Irc

The Hoa\Irc library.
PHP
25
star
30

Mail

The Hoa\Mail library.
PHP
24
star
31

Dns

The Hoa\Dns library.
PHP
23
star
32

Contributions-Symfony-ConsoleBridge

Hoa\Console to Symfony bundle bridge.
PHP
20
star
33

Contributions-Symfony-RulerBundle

The Hoa\Ruler Symfony2 bundle.
PHP
15
star
34

Graph

The Hoa\Graph library.
PHP
15
star
35

Database

The Hoa\Database library.
PHP
15
star
36

Locale

The Hoa\Locale library.
PHP
13
star
37

Json

The Hoa\Json library.
PHP
13
star
38

Dispatcher

The Hoa\Dispatcher library.
PHP
12
star
39

Registry

The Hoa\Registry library.
PHP
12
star
40

Cli

The Hoa\Cli library.
PHP
12
star
41

Test

The Hoa\Test library.
PHP
11
star
42

Http

The Hoa\Http library.
PHP
10
star
43

Session

The Hoa\Session library.
PHP
9
star
44

View

The Hoa\View library.
PHP
9
star
45

Option

The Hoa\Option library.
PHP
9
star
46

Cache

The Hoa\Cache library.
PHP
8
star
47

Memory

The Hoa\Memory library.
PHP
7
star
48

String

The Hoa\String library (deprecated by Hoa\Ustring).
PHP
7
star
49

-

The Hoa\  library.
PHP
7
star
50

Tree

The Hoa\Tree library.
PHP
7
star
51

Xml

The Hoa\Xml library.
PHP
7
star
52

Realdom

The Hoa\Realdom library.
PHP
7
star
53

Xyl

The Hoa\Xyl library.
PHP
7
star
54

Devtools

The Hoa\Devtools library.
PHP
6
star
55

Heap

The Hoa\Heap library.
PHP
5
star
56

Promise

The Hoa\Promise library.
PHP
5
star
57

Serialize

The Hoa\Serialize library.
PHP
5
star
58

Notification

The Hoa\Notification library.
PHP
4
star
59

Stringbuffer

The Hoa\Stringbuffer library.
PHP
4
star
60

Contributions-Atoum-PraspelExtension

Include Praspel inside atoum.
PHP
4
star
61

Translate

The Hoa\Translate library.
PHP
4
star
62

Embryo

The embryo repository helps to bootstrap an application, it is a skeleton.
PHP
4
star
63

Infrastructure

Everything related to the infrastructure of Hoa.
Shell
4
star
64

Log

The Hoa\Log library.
PHP
4
star
65

Xmlrpc

The Hoa\XmlRpc library.
PHP
4
star
66

W3

The W3 repository contains the website of Hoa.
PHP
4
star
67

Sandbox

Sandbox contains real examples.
PHP
3
star
68

Contributions-Symfony-ConsoleBundle

The Hoa\Console Symfony2 bundle.
PHP
3
star
69

Blog

Blog of the Hoa project
CSS
3
star
70

Model

The Hoa\Model library.
PHP
3
star
71

Prototype

The Hoa\Prototype library.
PHP
3
star
72

Contributions-Atom-Pp

PP —the grammar description language from Hoa\Compiler— support in Atom.
CoffeeScript
3
star
73

Literature

The literature repository contains all documentations, manuals & co.
Python
2
star
74

Keynote

Keynotes: presentations, conferences, notes, etc.
HTML
2
star
75

ActionBoard

Roadmap, actions, milestones… everything related to the schedule of Hoa is here
2
star
76

Contributions-Symfony-BenchBundle

The Hoa\Bench Symfony2 bundle.
PHP
2
star
77

Contributions-Provisioning

Provisioning scripts related to Hoa
2
star
78

Shop

Hoa's project shop
HTML
1
star
79

Contributions-Zsh-Hoa

Hoa\Cli support (autocompletion & co.) in Zsh.
1
star
80

Contributions-Vim-Pp

PP —the grammar description language from Hoa\Compiler— support in Vim.
Vim Script
1
star
81

Contributions-Atoum-Option-Extension

Add option asserter for atoum
PHP
1
star