PHP & Laravel

Binary Tools (PHP)

A PHP library for binary data manipulation and encoding/decoding operations. This library provides safe, efficient tools for working with binary data, including UTF-8 validation and secure string comparisons.

Installation

composer require kduma/binary-tools

Requirements

  • PHP 8.4+
  • ext-mbstring - For UTF-8 validation
  • ext-hash - For secure string comparisons

Features

  • Safe binary data manipulation with bounds checking
  • UTF-8 string validation for text data
  • Multiple encoding formats (hex, base64)
  • Secure string comparison using hash_equals()
  • Big-endian integer support for network protocols
  • Position tracking for streaming operations

Core Classes

BinaryString

Immutable wrapper for binary data with conversion and comparison methods.

BinaryWriter

Stream-like writer for building binary data structures.

BinaryReader

Stream-like reader for parsing binary data with position tracking.

Usage Examples

BinaryString

use KDuma\BinaryTools\BinaryString;

// Create from different sources
$binary = BinaryString::fromString("\x48\x65\x6c\x6c\x6f");
$fromString = BinaryString::fromString("Hello");
$fromHex = BinaryString::fromHex("48656c6c6f");
$fromBase64 = BinaryString::fromBase64("SGVsbG8=");

// All represent "Hello"
echo $binary->toString(); // "Hello"

// Convert to different formats
echo $binary->toHex();    // "48656c6c6f"
echo $binary->toBase64(); // "SGVsbG8="
echo $binary->size();     // 5

// Secure comparison
$other = BinaryString::fromString("Hello");
if ($binary->equals($other)) {
    echo "Strings are equal";
}

BinaryWriter

use KDuma\BinaryTools\BinaryWriter;
use KDuma\BinaryTools\BinaryString;

$writer = new BinaryWriter();

// Write different data types
$writer->writeByte(0x42)                          // Single byte
       ->writeUint16BE(1234)                      // 16-bit big-endian integer
       ->writeBytes(BinaryString::fromHex("abcd")) // Raw bytes
       ->writeString(BinaryString::fromString("Hello")); // UTF-8 string

// Write strings with length prefixes
$text = BinaryString::fromString("Hello World");
$writer->writeStringWithLength($text);        // 8-bit length + string
$writer->writeStringWithLength($text, true);  // 16-bit length + string

// Get the result
$result = $writer->getBuffer();
echo $result->toHex(); // Complete binary data as hex

BinaryReader

use KDuma\BinaryTools\BinaryReader;
use KDuma\BinaryTools\BinaryString;

$data = BinaryString::fromHex("4204d2abcd48656c6c6f0548656c6c6f20576f726c64000b48656c6c6f20576f726c64");
$reader = new BinaryReader($data);

// Read different data types
$byte = $reader->readByte();        // 0x42
$uint16 = $reader->readUint16BE();  // 1234
$bytes = $reader->readBytes(2);     // Raw bytes
$string = $reader->readBytes(5);    // "Hello"

// Read strings with length prefixes
$stringWithLength = $reader->readStringWithLength();      // 8-bit length
$stringWithLength16 = $reader->readStringWithLength(true); // 16-bit length

// Position management
echo $reader->position;        // Current position
echo $reader->remaining_bytes; // Bytes left
echo $reader->has_more_data;   // Boolean

// Peek without advancing
$nextByte = $reader->peekByte();
$next3Bytes = $reader->peekBytes(3);

// Seek to specific position
$reader->seek(0);  // Go to start
$reader->skip(5);  // Skip 5 bytes

Common Use Cases

Protocol Implementation

// Writing a simple protocol message
$writer = new BinaryWriter();
$message = BinaryString::fromString("Hello, Protocol!");

$writer->writeByte(0x01)                    // Message type
       ->writeUint16BE(time() & 0xFFFF)     // Timestamp (16-bit)
       ->writeStringWithLength($message);    // Payload

$packet = $writer->getBuffer();

// Reading the protocol message
$reader = new BinaryReader($packet);
$messageType = $reader->readByte();
$timestamp = $reader->readUint16BE();
$payload = $reader->readStringWithLength();

echo "Type: {$messageType}, Time: {$timestamp}, Message: {$payload->toString()}";

File Header Parsing

// Parse a file with magic bytes and metadata
$fileData = BinaryString::fromHex("4d5a90000300000004000000ffff0000");
$reader = new BinaryReader($fileData);

$magic = $reader->readBytes(2)->toString();  // "MZ"
if ($magic === "MZ") {
    $bytesOnLastPage = $reader->readUint16BE();
    $pagesInFile = $reader->readUint16BE();
    // ... continue parsing
}

Data Serialization

// Serialize complex data
$writer = new BinaryWriter();

$users = [
    ['id' => 1, 'name' => 'Alice'],
    ['id' => 2, 'name' => 'Bob'],
];

$writer->writeByte(count($users)); // User count

foreach ($users as $user) {
    $writer->writeUint16BE($user['id']);
    $writer->writeStringWithLength(BinaryString::fromString($user['name']));
}

$serialized = $writer->getBuffer();

// Deserialize
$reader = new BinaryReader($serialized);
$userCount = $reader->readByte();

for ($i = 0; $i < $userCount; $i++) {
    $userId = $reader->readUint16BE();
    $userName = $reader->readStringWithLength()->toString();
    echo "User {$userId}: {$userName}\n";
}

API Reference

BinaryString

MethodDescription
toString(): stringGet raw binary data
toHex(): stringConvert to hexadecimal string
toBase64(): stringConvert to base64 string
size(): intGet byte length
equals(BinaryString $other): boolSecure comparison
fromString(string $value): staticCreate from string
fromHex(string $hex): staticCreate from hex string
fromBase64(string $base64): staticCreate from base64

BinaryWriter

MethodDescription
getBuffer(): BinaryStringGet written data
getLength(): intGet buffer length
reset(): voidClear buffer
writeByte(int $byte): selfWrite single byte (0-255)
writeBytes(BinaryString $bytes): selfWrite binary data
writeUint16BE(int $value): selfWrite 16-bit big-endian integer
writeString(BinaryString $string): selfWrite UTF-8 string
writeStringWithLength(BinaryString $string, bool $use16BitLength = false): selfWrite string with length prefix
writeBytesWithLength(BinaryString $bytes, bool $use16BitLength = false): selfWrite bytes with length prefix

BinaryReader

Property/MethodDescription
$positionCurrent read position
$lengthTotal data length
$remaining_bytesBytes remaining
$has_more_dataWhether more data available
$dataGet original data as BinaryString
$remaining_dataGet remaining data
readByte(): intRead single byte
readBytes(int $count): BinaryStringRead N bytes
readUint16BE(): intRead 16-bit big-endian integer
readString(int $length): BinaryStringRead UTF-8 string of specific length
readStringWithLength(bool $use16BitLength = false): BinaryStringRead string with length prefix
readBytesWithLength(bool $use16BitLength = false): BinaryStringRead bytes with length prefix
peekByte(): intPeek next byte without advancing
peekBytes(int $count): BinaryStringPeek N bytes without advancing
seek(int $position): voidSeek to position
skip(int $count): voidSkip N bytes

Error Handling

The library throws appropriate exceptions for error conditions:

  • InvalidArgumentException - Invalid parameters (e.g., byte values > 255)
  • RuntimeException - Runtime errors (e.g., reading past end of data, invalid UTF-8)
try {
    $reader = new BinaryReader(BinaryString::fromHex("41"));
    $reader->readBytes(5); // Trying to read more than available
} catch (RuntimeException $e) {
    echo "Error: " . $e->getMessage();
}