PHPackages                             eloquent/confetti - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Search &amp; Filtering](/categories/search)
4. /
5. eloquent/confetti

AbandonedArchivedLibrary[Search &amp; Filtering](/categories/search)

eloquent/confetti
=================

Streaming data transformation system for PHP.

0.3.1(11y ago)158.8k1MITPHPPHP &gt;=5.3

Since Apr 7Pushed 6y ago1 watchersCompare

[ Source](https://github.com/eloquent/confetti)[ Packagist](https://packagist.org/packages/eloquent/confetti)[ Docs](https://github.com/eloquent/confetti)[ RSS](/packages/eloquent-confetti/feed)WikiDiscussions develop Synced 2d ago

READMEChangelog (4)Dependencies (3)Versions (6)Used By (1)

Confetti
========

[](#confetti)

*Streaming data transformation system for PHP.*

[![The most recent stable version is 0.3.1](https://camo.githubusercontent.com/4fbbaf74b16906525576816ca42043fc469a25b7088becff47b7dd215d314399/687474703a2f2f696d672e736869656c64732e696f2f3a73656d7665722d302e332e312d79656c6c6f772e737667 "This project uses semantic versioning")](http://semver.org/)[![Current build status image](https://camo.githubusercontent.com/32b0d7f07a655c703567972db6b0afcc4a5690a1ac2632715365b129af704a9d/687474703a2f2f696d672e736869656c64732e696f2f7472617669732f656c6f7175656e742f636f6e66657474692f646576656c6f702e737667 "Current build status for the develop branch")](https://travis-ci.org/eloquent/confetti)[![Current coverage status image](https://camo.githubusercontent.com/5b81d41bce73b0e70193599a1cf0ab1269c39f70df358c30cfa72f8b3a90f5fb/687474703a2f2f696d672e736869656c64732e696f2f636f766572616c6c732f656c6f7175656e742f636f6e66657474692f646576656c6f702e737667 "Current test coverage for the develop branch")](https://coveralls.io/r/eloquent/confetti)

Installation and documentation
------------------------------

[](#installation-and-documentation)

- Available as [Composer](http://getcomposer.org/) package [eloquent/confetti](https://packagist.org/packages/eloquent/confetti).
- [API documentation](http://lqnt.co/confetti/artifacts/documentation/api/) available.

What is *Confetti*?
-------------------

[](#what-is-confetti)

*Confetti* is a system for implementing streaming data transformation. It allows a single transform implementation to be used for strings, [React streams](https://github.com/reactphp/react/tree/0.4/src/Stream), and [native PHP stream filters](http://php.net/stream.filters). *Confetti* transforms are simple to implement, and can facilitate a wide range of stream manipulations, such as encoding, encryption, and incremental hashing.

This library contains no transform implementations. For real-world examples of data transform usage, see [Endec](https://github.com/eloquent/endec), and [Lockbox](https://github.com/eloquent/lockbox-php).

Transform streams
-----------------

[](#transform-streams)

The [TransformStream](http://lqnt.co/confetti/artifacts/documentation/api/Eloquent/Confetti/TransformStream.html) class provides a simple way to create a [React stream](https://github.com/reactphp/react/tree/0.4/src/Stream)wrapper around a transform. It implements both [ReadableStreamInterface](https://github.com/reactphp/react/blob/0.4/src/Stream/ReadableStreamInterface.php) and [WritableStreamInterface](https://github.com/reactphp/react/blob/0.4/src/Stream/WritableStreamInterface.php). Its usage is as follows:

```
use Eloquent\Confetti\TransformStream;

$stream = new TransformStream(new Base64DecodeTransform);
$stream->on(
    'data',
    function ($data, $stream) {
        echo $data;
    }
);
$stream->on(
    'error',
    function ($error, $stream) {
        throw $error;
    }
);

try {
    $stream->write('Zm9v'); // outputs 'foo'
    $stream->end('YmFy');   // outputs 'bar'
} catch (Exception $e) {
    // unable to decode
}
```

### The `success` event

[](#the-success-event)

In addition to the events used by [React streams](https://github.com/reactphp/react/tree/0.4/src/Stream) (`data`, `end`, `close`, `error`), The [TransformStream](http://lqnt.co/confetti/artifacts/documentation/api/Eloquent/Confetti/TransformStream.html) class will emit a `success` event upon closing if there have been no errors. The `success` callback will be passed the stream, and can access the inner transform by calling `$stream->transform()`:

```
$stream->on(
    'success',
    function ($stream) {
        echo get_class($stream->transform());
    }
);
```

### Combining transforms

[](#combining-transforms)

Any number of transforms can be combined into a single transform instance by using the [CompoundTransform](http://lqnt.co/confetti/artifacts/documentation/api/Eloquent/Confetti/CompoundTransform.html) class. This is useful for creating streams that apply multiple transforms in sequence:

```
use Eloquent\Confetti\CompoundTransform;
use Eloquent\Confetti\TransformStream;

$stream = new TransformStream(
    new CompoundTransform(array(new Rot13Transform, new Base64DecodeTransform))
);
$stream->on(
    'data',
    function ($data, $stream) {
        echo $data;
    }
);

$stream->write('Mz9i'); // outputs 'foo'
$stream->end('LzSl');   // outputs 'bar'
```

Implementing a transform
------------------------

[](#implementing-a-transform)

At the heart of *Confetti* lies the [TransformInterface](http://lqnt.co/confetti/artifacts/documentation/api/Eloquent/Confetti/TransformInterface.html) interface. A correctly implemented transform can be used for both string-based, and streaming transformations.

A simple transform might look like the following:

```
use Eloquent\Confetti\TransformInterface;

class Rot13Transform implements TransformInterface
{
    public function transform($data, &$context, $isEnd = false)
    {
        return array(str_rot13($data), strlen($data), null);
    }
}
```

The transform receives an arbitrary amount of data as a string, and returns an tuple (array) where the first element is the transformed data, the second element is the amount of data consumed in bytes (in this example, the data is always completely consumed), and the third element is any error that occurred.

This transform can now be utilized in several ways. To apply the transform to a string, simply call `transform()` with a boolean true for the `$isEnd` argument:

```
$transform = new Rot13Transform;

list($data) = $transform->transform('foobar', $context, true);
echo $data; // outputs 'sbbone'
```

To use the transform as a [React stream](https://github.com/reactphp/react/tree/0.4/src/Stream), create a new [TransformStream](http://lqnt.co/confetti/artifacts/documentation/api/Eloquent/Confetti/TransformStream.html) and inject the transform.

```
use Eloquent\Confetti\TransformStream;

$stream = new TransformStream(new Rot13Transform);
$stream->on(
    'data',
    function ($data, $stream) {
        echo $data;
    }
);

$stream->end('foobar'); // outputs 'sbbone'
```

Native stream filters
---------------------

[](#native-stream-filters)

Transforms can also be used to implement [native PHP stream filters](http://php.net/stream.filters), but PHP's stream filter system requires that each filter is implemented as an individual class. *Confetti* includes an abstract class that greatly simplifies implementing stream filters.

To create a stream filter simply extend from `AbstractNativeStreamFilter`, and implement the `createTransform()` method:

```
use Eloquent\Confetti\AbstractNativeStreamFilter;

class Rot13NativeStreamFilter extends AbstractNativeStreamFilter
{
    protected function createTransform()
    {
        return new Rot13Transform;
    }
}
```

Once the filter is registered, it can be used like any other stream filter:

```
stream_filter_register('confetti.rot13', 'Rot13NativeStreamFilter');

$path = '/path/to/file';
$stream = fopen($path, 'wb');
stream_filter_append($stream, 'confetti.rot13');
fwrite($stream, 'foobar');
fclose($stream);
echo file_get_contents($path); // outputs 'sbbone'
```

Note that the only way to detect a native stream filter failure is to check the length of data written. If the length is 0, it indicates an error:

```
stream_filter_register(
    'confetti.base64decode',
    'Base64DecodeNativeStreamFilter'
);

$path = '/path/to/file';
$stream = fopen($path, 'wb');
stream_filter_append($stream, 'confetti.base64decode');
if (!fwrite($stream, '!!!!')) {
    echo 'Decoding failed.';
}
fclose($stream);
```

Complex transforms
------------------

[](#complex-transforms)

More complex transforms may not be able to consume data byte-by-byte. As an example, attempting to base64 decode each byte as it is received would result in invalid output. The correct data cannot be known until a full block of 4 base64 bytes is received. There's also the possibility of receiving bytes that are invalid for the base64 encoding scheme.

A base64 decode transform might be implemented like so:

```
use Eloquent\Confetti\AbstractTransform;
use Eloquent\Confetti\BufferedTransformInterface;

class Base64DecodeTransform extends AbstractTransform implements
    BufferedTransformInterface
{
    public function transform($data, &$context, $isEnd = false)
    {
        $consume = $this->blocksSize(strlen($data), 4, $isEnd);
        if (!$consume) {
            return array('', 0, null);
        }

        $consumedData = substr($data, 0, $consume);
        if (1 === strlen(rtrim($consumedData, '=')) % 4) {
            return array('', 0, new Exception('Base64 decode failed.'));
        }

        $outputBuffer = base64_decode($consumedData, true);
        if (false === $outputBuffer) {
            return array('', 0, new Exception('Base64 decode failed.'));
        }

        return array($outputBuffer, $consume, null);
    }

    public function bufferSize()
    {
        return 4;
    }
}
```

This transform will now decode blocks of base64 data and append the result to the output buffer. The `bufferSize()` method suggests an appropriate buffer size for classes that consume this transform (in this case, 4 bytes - the size of a base64 block), and the call to `AbstractTransform::blocksSize()` ensures that data is only consumed in blocks of 4 bytes at a time. If an invalid byte is passed, or the data stream ends at an invalid number of bytes, an exception is returned as the third tuple element to indicate the error.

The context parameter
---------------------

[](#the-context-parameter)

Transforms also have the ability to utilize the `$context` parameter. This parameter can be assigned any value, and is used as an arbitrary data store that is guaranteed to persist across the lifetime of the stream transformation. When the first call to `transform()` is made, the `$context` argument will be `null`. On subsequent calls, `$context` will contain whatever was previously assigned to the variable. This allows for advanced behavior, such as buffering.

As an example of the context's usage, consider a transform that produces an MD5 hash of the incoming data:

```
use Eloquent\Confetti\TransformInterface;

class Md5Transform implements TransformInterface
{
    public function transform($data, &$context, $isEnd = false)
    {
        if (null === $context) {
            $context = hash_init('md5');
        }

        hash_update($context, $data);

        if ($isEnd) {
            $output = hash_final($context);
        } else {
            $output = '';
        }

        return array($output, strlen($data), null);
    }
}
```

In this case, the `$context` parameter is used to store the hash context. The transform now functions as follows:

```
use Eloquent\Confetti\TransformStream;

$stream = new TransformStream(new Md5Transform);
$stream->on(
    'data',
    function ($data, $stream) {
        echo $data;
    }
);

$stream->write('foo');
$stream->end('bar'); // outputs '3858f62230ac3c915f300c664312c63f'
```

###  Health Score

30

—

LowBetter than 64% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity26

Limited adoption so far

Community11

Small or concentrated contributor base

Maturity52

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 93.9% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~14 days

Total

4

Last Release

4376d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/100152?v=4)[Erin](/maintainers/ezzatron)[@ezzatron](https://github.com/ezzatron)

---

Top Contributors

[![ezzatron](https://avatars.githubusercontent.com/u/100152?v=4)](https://github.com/ezzatron "ezzatron (31 commits)")[![jmalloc](https://avatars.githubusercontent.com/u/761536?v=4)](https://github.com/jmalloc "jmalloc (2 commits)")

---

Tags

streamdatareactphpstreamingfiltertransformtransformationreact

### Embed Badge

![Health badge](/badges/eloquent-confetti/health.svg)

```
[![Health](https://phpackages.com/badges/eloquent-confetti/health.svg)](https://phpackages.com/packages/eloquent-confetti)
```

###  Alternatives

[clue/stream-filter

A simple and modern approach to stream filtering in PHP

1.7k261.7M7](/packages/clue-stream-filter)[react/socket

Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP

1.3k116.9M402](/packages/react-socket)[react/http

Event-driven, streaming HTTP client and server implementation for ReactPHP

78126.4M414](/packages/react-http)[flow-php/parquet

PHP ETL - library for reading and writing Parquet files

56143.1k8](/packages/flow-php-parquet)[flow-php/snappy

PHP ETL - Google Snappy compression algorithm implementation

10190.4k2](/packages/flow-php-snappy)[event4u/data-helpers

Framework-agnostic PHP library for data mapping, DTOs and utilities. Includes DataMapper, SimpleDto/LiteDto, DataAccessor/Mutator/Filter and helper classes (MathHelper, EnvHelper, etc.). Works with Laravel, Symfony/Doctrine or standalone PHP.

1421.5k](/packages/event4u-data-helpers)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
