spomky-labs/cbor-php
RFC 8949 CBOR encoder/decoder for PHP 8+. Supports all major types, tags (extensible), streaming decode, indefinite-length items, and normalization to native PHP values. Includes common tags and tools for custom tags.
Complete documentation for the CBOR (Concise Binary Object Representation) PHP library.
CBOR (Concise Binary Object Representation) is a data format defined in RFC 8949 that provides a compact binary encoding for structured data. This PHP library provides a complete implementation for encoding and decoding CBOR data.
CBOR defines 8 major types (0-7):
| Type | Description | PHP Classes |
|---|---|---|
| 0 | Unsigned Integer | UnsignedIntegerObject |
| 1 | Negative Integer | NegativeIntegerObject |
| 2 | Byte String | ByteStringObject, IndefiniteLengthByteStringObject |
| 3 | Text String | TextStringObject, IndefiniteLengthTextStringObject |
| 4 | Array | ListObject, IndefiniteLengthListObject |
| 5 | Map | MapObject, IndefiniteLengthMapObject |
| 6 | Tag | Tag subclasses (see Tags Documentation) |
| 7 | Simple/Float | TrueObject, FalseObject, NullObject, float objects |
CBORObject (interface)
├── AbstractCBORObject (abstract)
│ ├── UnsignedIntegerObject
│ ├── NegativeIntegerObject
│ ├── ByteStringObject
│ ├── IndefiniteLengthByteStringObject
│ ├── TextStringObject
│ ├── IndefiniteLengthTextStringObject
│ ├── ListObject
│ ├── IndefiniteLengthListObject
│ ├── MapObject
│ ├── IndefiniteLengthMapObject
│ ├── Tag (abstract)
│ │ ├── DatetimeTag
│ │ ├── TimestampTag
│ │ ├── DecimalFractionTag
│ │ ├── BigFloatTag
│ │ ├── ... (see Tags Reference)
│ │ └── GenericTag
│ └── OtherObject (abstract)
│ ├── TrueObject
│ ├── FalseObject
│ ├── NullObject
│ ├── UndefinedObject
│ ├── DoublePrecisionFloatObject
│ └── ...
Many CBOR objects implement the Normalizable interface, which provides a normalize() method to convert to native PHP types:
$text = TextStringObject::create('Hello');
$text->normalize(); // string: "Hello"
$int = UnsignedIntegerObject::create(42);
$int->normalize(); // string: "42"
$map = MapObject::create()
->add(TextStringObject::create('key'), UnsignedIntegerObject::create(100));
$map->normalize(); // array: ['key' => '100']
All CBOR objects provide a static create() method:
// Integers
$uint = UnsignedIntegerObject::create(42);
$nint = NegativeIntegerObject::create(-42);
// Strings
$text = TextStringObject::create('Hello World');
$bytes = ByteStringObject::create('binary data');
// Collections
$list = ListObject::create([
UnsignedIntegerObject::create(1),
UnsignedIntegerObject::create(2),
]);
$map = MapObject::create()
->add(TextStringObject::create('name'), TextStringObject::create('Alice'))
->add(TextStringObject::create('age'), UnsignedIntegerObject::create(30));
// Tags
$timestamp = TimestampTag::create(UnsignedIntegerObject::create(time()));
All objects implement __toString():
$object = TextStringObject::create('Hello');
$encoded = (string) $object;
// or
$encoded = $object->__toString();
echo bin2hex($encoded); // "6548656c6c6f"
use CBOR\Decoder;
// Default decoder with all standard tags
$decoder = Decoder::create();
// Custom decoder with specific tags
use CBOR\Tag\TagManager;
use CBOR\OtherObject\OtherObjectManager;
$tagManager = TagManager::create()
->add(TimestampTag::class)
->add(DatetimeTag::class);
$otherObjectManager = OtherObjectManager::create()
->add(TrueObject::class)
->add(FalseObject::class)
->add(NullObject::class);
$decoder = Decoder::create($tagManager, $otherObjectManager);
use CBOR\StringStream;
$binaryData = hex2bin('6548656c6c6f');
$stream = StringStream::create($binaryData);
$object = $decoder->decode($stream);
// Check type and extract value
if ($object instanceof TextStringObject) {
echo $object->getValue(); // "Hello"
echo $object->normalize(); // "Hello"
}
$list = ListObject::create();
// Add items
$list->add(UnsignedIntegerObject::create(1));
$list->add(TextStringObject::create('two'));
// Access items
$first = $list->get(0);
$count = $list->count();
// Check existence
if ($list->has(1)) {
// ...
}
// Remove items
$list->remove(0);
// Array access
$list[0] = UnsignedIntegerObject::create(42);
$value = $list[0];
// Iteration
foreach ($list as $item) {
// ...
}
// Normalize to PHP array
$phpArray = $list->normalize();
$map = MapObject::create();
// Add key-value pairs
$map->add(
TextStringObject::create('name'),
TextStringObject::create('Alice')
);
// Access values
$name = $map->get('name');
// Check existence
if ($map->has('name')) {
// ...
}
// Remove entries
$map->remove('name');
// Count entries
$count = $map->count();
// Iteration
foreach ($map as $item) {
$key = $item->getKey();
$value = $item->getValue();
}
// Normalize to PHP array
$phpArray = $map->normalize();
See the comprehensive Tags Reference for detailed information.
// Create tagged values
$timestamp = TimestampTag::create(UnsignedIntegerObject::create(time()));
$decimal = DecimalFractionTag::createFromFloat(3.14159);
// Access wrapped value
$wrappedObject = $timestamp->getValue();
// Normalize to PHP types
$dateTime = $timestamp->normalize(); // DateTimeImmutable
$number = $decimal->normalize(); // "3.14159"
See Tags Reference for comprehensive documentation on all supported tags, including:
See Creating Custom Tags for a complete guide on implementing custom tag types for:
CBOR supports streaming with indefinite-length objects:
// Indefinite-length text string
$text = IndefiniteLengthTextStringObject::create()
->append('Hello')
->append(' ')
->append('World');
echo $text->getValue(); // "Hello World"
// Indefinite-length byte string
$bytes = IndefiniteLengthByteStringObject::create()
->append('part1')
->append('part2');
// Indefinite-length list
$list = IndefiniteLengthListObject::create()
->add(UnsignedIntegerObject::create(1))
->add(UnsignedIntegerObject::create(2));
// Indefinite-length map
$map = IndefiniteLengthMapObject::create()
->append(TextStringObject::create('key1'), UnsignedIntegerObject::create(1))
->append(TextStringObject::create('key2'), UnsignedIntegerObject::create(2));
Implement the Stream interface for custom data sources:
use CBOR\Stream;
class FileStream implements Stream
{
private $handle;
private int $position = 0;
public function __construct(string $filepath)
{
$this->handle = fopen($filepath, 'rb');
}
public function read(int $length): string
{
$data = fread($this->handle, $length);
$this->position += strlen($data);
return $data;
}
public function getPosition(): int
{
return $this->position;
}
// ... implement remaining methods
}
// Use with decoder
$stream = new FileStream('/path/to/cbor/file.cbor');
$object = $decoder->decode($stream);
$object = $decoder->decode($stream);
// Check major type
if ($object instanceof UnsignedIntegerObject) {
echo "Unsigned integer: " . $object->getValue();
}
// Check for tags
if ($object instanceof TimestampTag) {
echo "Timestamp: " . $object->normalize()->format('Y-m-d');
}
// Check for normalizable
if ($object instanceof Normalizable) {
$phpValue = $object->normalize();
}
// Pattern matching (PHP 8.0+)
$value = match (true) {
$object instanceof TextStringObject => $object->getValue(),
$object instanceof UnsignedIntegerObject => (int) $object->getValue(),
$object instanceof ListObject => $object->normalize(),
default => null,
};
CBOR is used extensively in WebAuthn for credential data:
// Decode authenticator data
$authenticatorData = $decoder->decode(StringStream::create($binaryData));
if ($authenticatorData instanceof MapObject) {
$credentialId = $authenticatorData->get('credentialId');
$publicKey = $authenticatorData->get('publicKey');
// Process WebAuthn credential
}
// Decode a COSE_Sign1 structure
$coseSign1 = $decoder->decode($stream);
if ($coseSign1 instanceof COSESign1Tag) {
$protected = $coseSign1->getProtectedHeaders();
$payload = $coseSign1->getPayload();
$signature = $coseSign1->getSignature();
// Verify signature
}
// Encode sensor readings efficiently
$sensorData = MapObject::create()
->add(
TextStringObject::create('temperature'),
DecimalFractionTag::createFromFloat(23.5)
)
->add(
TextStringObject::create('humidity'),
UnsignedIntegerObject::create(65)
)
->add(
TextStringObject::create('timestamp'),
TimestampTag::create(UnsignedIntegerObject::create(time()))
);
$encoded = (string) $sensorData;
// Send over network (much smaller than JSON)
// Convert PHP data to CBOR
function encodeToCBOR(array $data): string
{
$map = MapObject::create();
foreach ($data as $key => $value) {
$keyObj = TextStringObject::create($key);
$valueObj = match (gettype($value)) {
'string' => TextStringObject::create($value),
'integer' => UnsignedIntegerObject::create($value),
'array' => convertArrayToList($value),
default => throw new Exception('Unsupported type'),
};
$map->add($keyObj, $valueObj);
}
return (string) $map;
}
// Usage
$response = encodeToCBOR([
'status' => 'success',
'code' => 200,
'data' => ['item1', 'item2']
]);
header('Content-Type: application/cbor');
echo $response;
ext-gmp or ext-bcmath for better performanceuse InvalidArgumentException;
use RuntimeException;
try {
$decoder = Decoder::create();
$object = $decoder->decode($stream);
} catch (InvalidArgumentException $e) {
// Invalid CBOR structure or data
error_log('CBOR decoding error: ' . $e->getMessage());
} catch (RuntimeException $e) {
// Missing required extension
error_log('Runtime error: ' . $e->getMessage());
}
// Get human-readable representation
var_dump($object);
// For maps and lists
foreach ($map as $item) {
echo sprintf(
"Key: %s, Value: %s\n",
$item->getKey()->normalize(),
$item->getValue()->normalize()
);
}
// Check encoded binary
$encoded = (string) $object;
echo 'Hex: ' . bin2hex($encoded) . "\n";
echo 'Length: ' . strlen($encoded) . " bytes\n";
// Encoding
$text = TextStringObject::create('hello');
$int = UnsignedIntegerObject::create(42);
$list = ListObject::create([$text, $int]);
$map = MapObject::create()->add($text, $int);
$tagged = TimestampTag::create($int);
$encoded = (string) $map;
// Decoding
$decoder = Decoder::create();
$stream = StringStream::create($encoded);
$object = $decoder->decode($stream);
$phpValue = $object->normalize();
// Tags
$timestamp = TimestampTag::create(UnsignedIntegerObject::create(time()));
$decimal = DecimalFractionTag::createFromFloat(3.14);
$datetime = DatetimeTag::create(TextStringObject::create('2024-01-15T10:30:00Z'));
How can I help you explore Laravel packages today?