public static function loadBytesFromChecksummedAsciiSafeString($expected_header, $string)
{
// Headers must be a constant length to prevent one type's header from
// being a prefix of another type's header, leading to ambiguity.
if (Core::ourStrlen($expected_header) !== self::SERIALIZE_HEADER_BYTES) {
throw new Ex\EnvironmentIsBrokenException('Header must be 4 bytes.');
}
$bytes = Encoding::hexToBin($string);
/* Make sure we have enough bytes to get the version header and checksum. */
if (Core::ourStrlen($bytes) < self::SERIALIZE_HEADER_BYTES + self::CHECKSUM_BYTE_SIZE) {
throw new Ex\BadFormatException('Encoded data is shorter than expected.');
}
/* Grab the version header. */
$actual_header = Core::ourSubstr($bytes, 0, self::SERIALIZE_HEADER_BYTES);
if ($actual_header !== $expected_header) {
throw new Ex\BadFormatException('Invalid header.');
}
/* Grab the bytes that are part of the checksum. */
$checked_bytes = Core::ourSubstr($bytes, 0, Core::ourStrlen($bytes) - self::CHECKSUM_BYTE_SIZE);
/* Grab the included checksum. */
$checksum_a = Core::ourSubstr($bytes, Core::ourStrlen($bytes) - self::CHECKSUM_BYTE_SIZE, self::CHECKSUM_BYTE_SIZE);
/* Re-compute the checksum. */
$checksum_b = \hash(self::CHECKSUM_HASH_ALGO, $checked_bytes, true);
/* Check if the checksum matches. */
if (!Core::hashEquals($checksum_a, $checksum_b)) {
throw new Ex\BadFormatException("Data is corrupted, the checksum doesn't match");
}
return Core::ourSubstr($bytes, self::SERIALIZE_HEADER_BYTES, Core::ourStrlen($bytes) - self::SERIALIZE_HEADER_BYTES - self::CHECKSUM_BYTE_SIZE);
}