co-stack/reversible

提供可移植的可逆函数和队列。例如,可用于传输编码或复杂值处理。

v1.7.0 2023-12-22 13:38 UTC

This package is auto-updated.

Last update: 2024-09-22 15:31:24 UTC


README

pipeline status coverage report

什么是可逆函数

可逆函数是可以正向执行和反向回退(撤销)的函数。它们无副作用(幂等)且无状态。

这些函数对于传输编码、持久化映射、加密等许多其他用例特别有用。

注意

某些编码并非完全幂等,例如 Base64Encodingbase64_encode 函数不保留数据类型(int、float、bool)。可能不是完全幂等的 Reversible 实现实现了 Lossy 接口。

摘要

此包的真正优势在于 ReversiblePipe。下面更简单的示例只是为了说明。

$mySecret = 'correcthorsebatterystaple';

$myValue = [
    'foo-bar-baz',
    'boo-beng-fump'
];

$pipe = new \CoStack\Reversible\Applicable\ReversiblePipe();
$pipe->enqueue(new \CoStack\Reversible\Operation\Encoding\JsonEncoding())
     ->enqueue(new \CoStack\Reversible\Operation\Security\HmacAssertion($mySecret))
     ->enqueue(new \CoStack\Reversible\Operation\Encoding\Base64Encoding());

// The pipe will json encode the array, add the HMAC to the encoded array and base64 encode it
$transportSafeAndHmacProtected = $pipe->execute($myValue);

// Transport over wire
// ------->------->------->

// The pipe will base64 decode it and validate the HMAC. If the HMAC is valid the string will be json decoded and the array returned
$myValue = $pipe->reverse($transportSafeAndHmacProtected);

示例

我为您准备了一些有用的示例,展示了此包的通用性。

通过空中发送的标量值

在系统 A 上


// System A
$input = random_bytes(256);
$encoding = new \CoStack\Reversible\Operation\Encoding\Base64Encoding();
$output = $encoding->execute($input);

// System B
$encoding = new \CoStack\Reversible\Operation\Encoding\Base64Encoding();
$restoredInput = $encoding->reverse($output);
// $restoredInput is exactly $input what was generated on System A

通过字符串传输关联数组,无需序列化

 // Shared Library
 function getPipe(): \CoStack\Reversible\Applicable\ReversiblePipe {
    $pipe = new \CoStack\Reversible\Applicable\ReversiblePipe();
    $pipe->enqueue(new \CoStack\Reversible\Operation\Mapping\ArrayKeyMapping(['key1', 'key2', 'payload']));
    $pipe->enqueue(new \CoStack\Reversible\Applicable\ApplyOnArrayValueRecursively(new \CoStack\Reversible\Operation\Encoding\Base64Encoding()));
    $pipe->enqueue(new \CoStack\Reversible\Operation\Transform\ImplodeTransform());
    return $pipe;
}

// System A
$array = [
    'key1' => 1,
    'key2' => 'value',
    'payload' => uniqid(),
];
$pipe = getPipe();
$safeEncodedObject = $pipe->execute($array);

// The string will contain base64 encoded values, imploded with "|". There are no associative keys in the string because they have been replaced by the ArrayKeyMapping

// System B
$pipe = getPipe();
$array = $pipe->reverse($safeEncodedObject);

请注意,ImplodeTransform 是有损的,因为 explode(',', implode(',', [2])) === ['2'](整数将变成字符串)。

通过问题媒介(例如,查询参数)传输对象

// Shared Library
function getPipe(): \CoStack\Reversible\Applicable\ReversiblePipe {
    $pipe = new \CoStack\Reversible\Applicable\ReversiblePipe();
    $pipe->enqueue(new \CoStack\Reversible\Operation\Encoding\SerializationEncoding());
    $pipe->enqueue(new \CoStack\Reversible\Operation\Encoding\UrlEncode());
    return $pipe;
}

// System A
$object = new SplFileInfo('file.txt');
$pipe = getPipe();
$safeEncodedObject = $pipe->execute($object);

// System B
$pipe = getPipe();
$object = $pipe->reverse($safeEncodedObject);

UUIDv4 到二进制和回(例如,在数据库中持久化二进制格式的 uuid)


$uuid = gen_uuid();

$uuidToBinary = new \CoStack\Reversible\Applicable\ReversiblePipe();
$uuidToBinary->enqueue(new \CoStack\Reversible\Operation\Fixed\FixedStringStripping('-', [8, 4, 4, 4]));
$uuidToBinary->enqueue(new \CoStack\Reversible\Operation\Encoding\HexToBinEncoding());

$binary = $uuidToBinary->execute($uuid);
// Persist binary uuid in DB

// Select binary uuid from DB and convert to readable string again
$uuidAgain = $uuidToBinary->reverse($binary);

安全性

在数据转换和编码的最后添加 \CoStack\Reversible\Operation\Security\HmacAssertion,以生成 HMAC,反转时将自动验证。

$mySecretKey = 'Tr0ub4dor&3';

$protectMeFromChanges = uniqid();

$pipe = new \CoStack\Reversible\Applicable\ReversiblePipe();
$pipe->enqueue(new \CoStack\Reversible\Operation\Encoding\Base64Encoding());
$pipe->enqueue(new \CoStack\Reversible\Operation\Security\HmacAssertion($mySecretKey));

$stringWithHmac = $pipe->execute($protectMeFromChanges);

$stringWithHmac .= 'EvilChanges';

try {
    $pipe->reverse($stringWithHmac);
} catch (\CoStack\Reversible\Exception\HmacAssertionFailedException $exception) {
    echo 'Someone fiddled with the string!';
    exit(1);
}