PHPackages                             horde/pack - 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. [Utility &amp; Helpers](/categories/utility)
4. /
5. horde/pack

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

horde/pack
==========

Data packing library

v2.0.0(1w ago)13.8k—6.3%34LGPL-2.1-onlyPHPPHP ^8.1CI failing

Since Nov 6Pushed 6d ago5 watchersCompare

[ Source](https://github.com/horde/Pack)[ Packagist](https://packagist.org/packages/horde/pack)[ Docs](https://www.horde.org/libraries/Horde_Pack)[ RSS](/packages/horde-pack/feed)WikiDiscussions FRAMEWORK\_6\_0 Synced 2d ago

READMEChangelog (3)Dependencies (8)Versions (18)Used By (4)

horde/Pack
==========

[](#hordepack)

Data packing library that picks the fastest serialization format your PHP installation supports for each value, then optionally compresses the result.

A drop-in replacement for `serialize()`/`json_encode()` for cache, session and inter-process payloads. Pack autodetects whether the input contains real PHP objects and chooses a driver that can round- trip it. Compression is on by default for payloads above a configurable size threshold.

Installation
------------

[](#installation)

```
composer require horde/pack
```

Optional extensions, in priority order (Pack works without any of them but smaller and faster ones come from native code):

- `ext-msgpack`. Highest priority for plain data (scalars, arrays).
- `ext-igbinary`. High priority for payloads containing real PHP objects.
- `ext-json`. Always available with PHP since 8.0. Second-priority for plain data.
- PHP `serialize()`. Always available. Universal fallback.

Two implementations side by side
--------------------------------

[](#two-implementations-side-by-side)

The `2.x` line ships **two parallel implementations** in one Composer package:

- **Modern PSR-4** under `Horde\Pack\` in `src/`. Use this for new code.
- **Legacy PSR-0** under `Horde_Pack` in `lib/`. Existing callers keep working unchanged.

Both implementations share one wire format: a value packed by either class unpacks under the other. See [`doc/wire-format.md`](doc/wire-format.md)for the on-disk specification. They cohabit in caches and session blobs without coordination.

The legacy classes are in maintenance mode: bug fixes land if reported, but no new features. New work should target `Horde\Pack\Packer`.

Quick start (modern API)
------------------------

[](#quick-start-modern-api)

```
use Horde\Pack\Packer;
use Horde\Pack\PackOptions;

$packer = new Packer();

// Round-trip a value.
$blob = $packer->pack(['cache_key' => 'some data']);
$value = $packer->unpack($blob);

// Disable compression for short or already-compressed inputs.
$blob = $packer->pack($payload, PackOptions::uncompressed());

// Restrict object deserialization to a class whitelist (security).
$value = $packer->unpack(
    $blob,
    (new PackOptions())->withAllowedClasses(MyDto::class),
);
```

Configuring the packer
----------------------

[](#configuring-the-packer)

Constructor parameters are typed and have sensible defaults:

```
use Horde\Pack\DefaultDriverRegistry;
use Horde\Pack\DefaultCompressor;
use Horde\Pack\Driver\Json;
use Horde\Pack\Driver\Serialize;
use Horde\Pack\Packer;

// Default: every shipped driver supported by the host, fast compressor.
$packer = new Packer();

// Restricted driver set: only Json and Serialize.
$packer = new Packer(
    new DefaultDriverRegistry(new Json(), new Serialize()),
);

// Custom compressor (must implement Horde\Pack\Compressor).
$packer = new Packer(
    new DefaultDriverRegistry(),
    $myCompressor,
);
```

Per-call options
----------------

[](#per-call-options)

`PackOptions` is an immutable value object with named constructors and `with*()` builders:

Factory / builderEffect`PackOptions::compressed($threshold = 128)`Compress payloads larger than threshold (the default).`PackOptions::uncompressed()`Never compress.`PackOptions::alwaysCompress()`Compress every payload regardless of size.`withAllowedDrivers(string ...$classes)`Restrict to listed driver classes.`withAllowedClasses(string ...$classes)`Restrict object deserialization to listed classes. Empty list disables object deserialization entirely.`withPhpObjects(bool)`Skip the autodetect scan and assert whether input contains real PHP objects.Security: `allowedClasses`
--------------------------

[](#security-allowedclasses)

`Driver\Serialize::unpack()` honours an `allowed_classes` whitelist when deserializing PHP objects. Tightening this whitelist closes a deserialization-gadget primitive that an attacker who can corrupt the cache otherwise has access to.

The library default is `null` (unrestricted) for backwards compatibility with the legacy `Horde_Pack`. Application factories that wrap `Packer`are the right layer to apply default-deny:

```
final class HardenedPackerFactory
{
    public static function create(): Packer
    {
        return new Packer();
    }

    public static function safelyUnpack(Packer $packer, string $blob): mixed
    {
        return $packer->unpack(
            $blob,
            (new PackOptions())->withAllowedClasses(MyAllowedDto::class),
        );
    }
}
```

The other shipped drivers (Json, Igbinary, Msgpack, MsgpackSerialize) do not honour `allowedClasses`. Json refuses to encode non-stdClass objects in the first place, so the whitelist is moot there. The msgpack and igbinary extensions provide no class-whitelist hook in their deserializers. The option is accepted for interface compatibility but ignored. Callers who need a hard whitelist must restrict the driver set to `Serialize` only via `withAllowedDrivers()`.

Custom drivers
--------------

[](#custom-drivers)

Implement `Horde\Pack\Driver` and register your driver against an unused wire-format slot. The canonical drivers occupy slots 1, 2, 4, 8 and 16. Slot 32 is reserved for third-party drivers in the canonical registry layout.

```
use Horde\Pack\Driver;
use Horde\Pack\WireFormat;

final class CborDriver implements Driver
{
    public function id(): int { return 32; }
    public function supportsPhpObjects(): bool { return false; }
    public function supported(): bool { return extension_loaded('cbor'); }
    public function pack(mixed $data): string { /* ... */ }
    public function unpack(string $data, ?array $allowedClasses = null): mixed { /* ... */ }
}

$packer = new Packer(
    new DefaultDriverRegistry(
        new CborDriver(),
        new Driver\Serialize(),
        new Driver\Json(),
    ),
);
```

`DefaultDriverRegistry`'s variadic constructor REPLACES the canonical driver set entirely when called with arguments. Pass the canonical drivers explicitly alongside your own if you want to extend rather than replace.

See also
--------

[](#see-also)

- [`doc/wire-format.md`](doc/wire-format.md) - on-disk format specification.
- [`doc/UPGRADING.md`](doc/UPGRADING.md) - migrating from the legacy `Horde_Pack` API to the modern `Horde\Pack\Packer`.

License
-------

[](#license)

LGPL 2.1. See `LICENSE`.

###  Health Score

61

—

FairBetter than 98% of packages

Maintenance99

Actively maintained with recent releases

Popularity27

Limited adoption so far

Community29

Small or concentrated contributor base

Maturity80

Battle-tested with a long release history

 Bus Factor1

Top contributor holds 50.5% 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 ~355 days

Recently: every ~483 days

Total

14

Last Release

7d ago

Major Versions

1.0.7 → 2.0.0alpha12021-02-24

PHP version history (6 changes)1.0.0PHP &gt;=5.3.0

1.0.2PHP &gt;=5.3.0,&lt;=6.0.0alpha1

1.0.6PHP &gt;=5.3.0,&lt;=8.0.0alpha1

2.0.0alpha1PHP ^7

v2.0.0alpha4PHP ^7.4 || ^8

v2.0.0RC1PHP ^8.1

### Community

Maintainers

![](https://www.gravatar.com/avatar/c943a083635c28520599075eaea7ede2d743b7697b76e84d6bdc37e52cc8249b?d=identicon)[yunosh](/maintainers/yunosh)

![](https://www.gravatar.com/avatar/c931cd02664859360478593450d6c473a05bb12b209dfacfc534cd13257cc7ef?d=identicon)[ralflang](/maintainers/ralflang)

![](https://www.gravatar.com/avatar/e4f6c6771993db2ed500959b42353f6cf6a2ca0406d9617f7ae680f4504faa4a?d=identicon)[horde](/maintainers/horde)

![](https://www.gravatar.com/avatar/a7767adb66b45f2f05bcd44d49bc4e67efacd9ce05b161ce2d481d5dd6af025c?d=identicon)[mrubinsk](/maintainers/mrubinsk)

![](https://www.gravatar.com/avatar/816e2b926f25f8cd2939054c7a7173011b4303d690e25ab61bf33cf8c7cf71ae?d=identicon)[tdannhauer](/maintainers/tdannhauer)

---

Top Contributors

[![yunosh](https://avatars.githubusercontent.com/u/379318?v=4)](https://github.com/yunosh "yunosh (51 commits)")[![ralflang](https://avatars.githubusercontent.com/u/646976?v=4)](https://github.com/ralflang "ralflang (23 commits)")[![slusarz](https://avatars.githubusercontent.com/u/381003?v=4)](https://github.com/slusarz "slusarz (23 commits)")[![mrubinsk](https://avatars.githubusercontent.com/u/66822?v=4)](https://github.com/mrubinsk "mrubinsk (4 commits)")

---

Tags

serializationfast\_compression

### Embed Badge

![Health badge](/badges/horde-pack/health.svg)

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

###  Alternatives

[horde/horde

Horde base application

583.0k70](/packages/horde-horde)[horde/kronolith

Calendar and scheduling application

101.5k4](/packages/horde-kronolith)

PHPackages © 2026

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