Stellar PHP SDK API Documentation

XdrJsonHelper
in package

FinalYes

Primitive SEP-51 (XDR-JSON) helper methods.

This class provides low-level encoding and decoding utilities for the SEP-0051 standard mapping between Stellar XDR structures and their JSON representations. Higher-level toJson/fromJson methods on individual XDR classes delegate to these primitives for the byte-level and numeric operations defined in the spec.

All methods are stateless and operate only on their arguments.

Tags
see
https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0051.md

Table of Contents

Methods

bytesToHex()  : string
SEP-51 Opaque type: encode raw bytes as a lowercase hex string.
canonicalJson()  : string
Canonical JSON normalisation for structural JSON comparison.
escapeString()  : string
SEP-51 String type: escape bytes per the SEP-51 String escape ladder.
hexToBytes()  : string
Inverse of bytesToHex: decode a lowercase hex string back to raw bytes.
int128PartsToString()  : string
Assemble a signed 128-bit integer from hi/lo limbs and return as a base-10 string.
int256PartsToString()  : string
Assemble a signed 256-bit integer from four limbs and return as a base-10 string.
int64ToString()  : string
64-bit signed integer to base-10 string (SEP-51 Hyper Integer encoding).
ksortRecursive()  : mixed
Recursively sort object property names for canonical JSON normalisation.
safePreview()  : string
Return a safe, bounded preview of user-supplied input for use in exception messages.
stringToInt128Parts()  : array{hi: string, lo: string}
Decompose a signed 128-bit integer string into hi/lo limbs.
stringToInt256Parts()  : array{hiHi: string, hiLo: string, loHi: string, loLo: string}
Decompose a signed 256-bit integer string into four limbs.
stringToInt64()  : int
Parse a base-10 integer string (or a PHP int) to a 64-bit signed int.
stringToUint128Parts()  : array{hi: string, lo: string}
Decompose an unsigned 128-bit integer string into hi/lo uint64 parts.
stringToUint256Parts()  : array{hiHi: string, hiLo: string, loHi: string, loLo: string}
Decompose an unsigned 256-bit integer string into four uint64 limbs.
stringToUint64()  : int
Parse a base-10 unsigned-integer string (or a PHP int) to a uint64 value.
uint128PartsToString()  : string
Assemble an unsigned 128-bit integer from hi/lo uint64 parts and return as a base-10 string.
uint256PartsToString()  : string
Assemble an unsigned 256-bit integer from four uint64 limbs and return as a base-10 string.
uint64ToString()  : string
64-bit unsigned integer to base-10 string (SEP-51 Unsigned Hyper Integer encoding).
unescapeString()  : string
Inverse of escapeString: decode a SEP-51 escaped-ASCII string back to raw bytes.
wrapUnsignedToSignedInt()  : int
Wrap an unsigned uint64 base-10 string into the matching PHP signed-int representation used by the Parts struct fields.

Methods

bytesToHex()

SEP-51 Opaque type: encode raw bytes as a lowercase hex string.

public static bytesToHex(string $bytes) : string

Per SEP-0051 the Opaque types (both fixed-length and variable-length) are represented as hexadecimal strings. An empty byte sequence encodes as an empty string "" (not "0" and not "00").

Parameters
$bytes : string

Raw binary input (any length, including zero).

Return values
string

Lowercase hex string (even length; two hex chars per byte).

canonicalJson()

Canonical JSON normalisation for structural JSON comparison.

public static canonicalJson(string $json) : string

The algorithm:

  1. Decode with assoc=false (stdClass mode) so the empty-object / empty-array distinction is preserved: json_decode('}') -> stdClass, json_decode('[]') -> [].
  2. Recurse via ksortRecursive: sort object property names lexicographically; preserve list order for indexed arrays.
  3. Re-encode with JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE so that forward slashes and non-ASCII codepoints are not double-escaped.

The result is a deterministic, whitespace-free JSON string. Two JSON values that are semantically equal (same structure, same key order after sorting, same values) will produce byte-identical canonical forms.

Note: this method does not impose an input-size limit. Callers are responsible for bounding $json length before invoking this method; an HTTP layer or file reader should apply a size limit appropriate to its threat model.

Parameters
$json : string

Any valid JSON string.

Tags
throws
JsonException

On malformed input JSON.

Return values
string

Canonical (sorted-keys, compact) JSON string.

escapeString()

SEP-51 String type: escape bytes per the SEP-51 String escape ladder.

public static escapeString(string $bytes) : string

Escaping rules (applied byte-by-byte on the raw binary input):

  • 0x00 (NUL) -> \0
  • 0x09 (TAB) -> \t
  • 0x0A (LF) -> \n
  • 0x0D (CR) -> \r
  • 0x5C (BS) -> \
  • 0x20..0x7E (printable ASCII, excluding backslash) -> verbatim
  • all other bytes (0x01..0x08, 0x0B, 0x0C, 0x0E..0x1F, 0x7F, 0x80..0xFF) -> \xNN (lowercase hex, exactly two digits)

The input is treated as a raw byte string (not UTF-8); strlen() and ord() are used throughout — never mb_strlen() or mb_substr().

When this output is subsequently stored inside a JSON string literal the JSON encoder will escape each backslash a second time, producing the double-escaped form the spec specifies (e.g. "\xc3" in JSON text).

Parameters
$bytes : string

Raw binary input (any byte sequence).

Return values
string

Escaped ASCII output (only printable ASCII bytes).

hexToBytes()

Inverse of bytesToHex: decode a lowercase hex string back to raw bytes.

public static hexToBytes(string $hex) : string

Strict mode is enforced: only lowercase hexadecimal characters [0-9a-f] are accepted. Uppercase hex is rejected; SEP-0051 §Opaque specifies lowercase hex output, and the decoder mirrors that constraint so that round-trips remain canonical.

Parameters
$hex : string

Lowercase hex string (even length; zero length allowed).

Tags
throws
InvalidArgumentException

On odd-length input, uppercase characters, or non-hex characters.

Return values
string

Raw binary bytes.

int128PartsToString()

Assemble a signed 128-bit integer from hi/lo limbs and return as a base-10 string.

public static int128PartsToString(string $hi, string $lo) : string

Per XDR Int128Parts (verified against XdrInt128Parts.php encode path): hi is signed int64; lo is unsigned uint64.

result = hi_signed * 2^64 + lo_unsigned

lo_unsigned is obtained by treating the PHP int stored in $lo as an unsigned 64-bit value (i.e. adding 2^64 if negative). GMP is used throughout to handle the full range.

Parameters
$hi : string

Signed int64 as base-10 string (range [-2^63, 2^63-1]).

$lo : string

Unsigned uint64 as base-10 string. May be a negative base-10 string when the uint64 value exceeds PHP_INT_MAX and is stored as a signed PHP int (the negative form is reinterpreted as the unsigned bit pattern via two's-complement).

Tags
throws
InvalidArgumentException

If hi or lo are not valid integer strings.

Return values
string

Base-10 decimal string of the assembled 128-bit signed integer.

int256PartsToString()

Assemble a signed 256-bit integer from four limbs and return as a base-10 string.

public static int256PartsToString(string $hiHi, string $hiLo, string $loHi, string $loLo) : string

Per XDR Int256Parts (verified against XdrInt256Parts.php encode path):

  • hiHi: signed int64 (most significant)
  • hiLo: unsigned uint64
  • loHi: unsigned uint64
  • loLo: unsigned uint64 (least significant)

All limb strings may be supplied in either unsigned form ("18446744073709551615") or in PHP's signed two's-complement wrap form ("-1") — the internal uint64HalfToGmp helper handles both representations for lossless assembly.

Parameters
$hiHi : string

Signed int64 as base-10 string (range [-2^63, 2^63-1]).

$hiLo : string

Unsigned uint64 as base-10 string. May be a negative base-10 string when the uint64 value exceeds PHP_INT_MAX and is stored as a signed PHP int (the negative form is reinterpreted as the unsigned bit pattern via two's-complement).

$loHi : string

Unsigned uint64 as base-10 string (same note as hiLo).

$loLo : string

Unsigned uint64 as base-10 string (same note as hiLo).

Tags
throws
InvalidArgumentException

If any limb string is invalid.

Return values
string

Base-10 decimal string of the assembled 256-bit signed integer.

int64ToString()

64-bit signed integer to base-10 string (SEP-51 Hyper Integer encoding).

public static int64ToString(int $value) : string
Parameters
$value : int

A PHP int (64-bit signed on 64-bit systems).

Return values
string

Base-10 decimal string representation.

ksortRecursive()

Recursively sort object property names for canonical JSON normalisation.

public static ksortRecursive(mixed $value[, int $depth = 512 ]) : mixed

Walk rules:

  • stdClass (object): cast to array, ksort by string key, recurse into values, cast back to object. This preserves the } vs [] distinction in re-encoding.
  • Indexed array (list-shape): preserve element order; recurse into elements.
  • Associative array: ksort and recurse (defensive; should not occur in stdClass-mode decode but covered for callers using this method directly on mixed structures).
  • Scalar / null: return as-is.

The $depth parameter bounds recursion depth, matching json_decode's own default of 512. Callers constructing deeply-nested PHP arrays by hand and passing them directly here (rather than via canonicalJson) should pass an appropriate depth bound. canonicalJson starts the recursion at depth=512 which aligns with json_decode's own limit.

Parameters
$value : mixed

Any decoded JSON value.

$depth : int = 512

Remaining recursion depth. Throws when it reaches zero.

Tags
throws
InvalidArgumentException

When $depth is exhausted (nesting too deep).

Return values
mixed

The same structure with all object property keys sorted recursively.

safePreview()

Return a safe, bounded preview of user-supplied input for use in exception messages.

public static safePreview(string $s[, int $max = 80 ]) : string

Embedding unbounded user input in exception messages can cause log-amplification denial-of-service when the message is logged. This helper caps the preview at $max bytes and appends "..." when the string is truncated, keeping messages informative without being exploitable.

Parameters
$s : string

The user-supplied string.

$max : int = 80

Maximum characters before truncation (must be > 3).

Return values
string

A safe, bounded preview.

stringToInt128Parts()

Decompose a signed 128-bit integer string into hi/lo limbs.

public static stringToInt128Parts(string $value) : array{hi: string, lo: string}

Per XDR Int128Parts (verified against XdrInt128Parts.php decode path): hi is signed int64; lo is unsigned uint64.

Returns an associative array with:

  • 'hi': signed int64 base-10 string (range [-2^63, 2^63-1])
  • 'lo': unsigned uint64 base-10 string (range [0, 2^64-1])
Parameters
$value : string

Base-10 decimal string of a signed 128-bit integer.

Tags
throws
InvalidArgumentException

If $value is not a valid int128 string.

Return values
array{hi: string, lo: string}

stringToInt256Parts()

Decompose a signed 256-bit integer string into four limbs.

public static stringToInt256Parts(string $value) : array{hiHi: string, hiLo: string, loHi: string, loLo: string}

Per XDR Int256Parts (verified against XdrInt256Parts.php decode path): only hiHi is signed int64; hiLo, loHi, loLo are unsigned uint64. Returns an associative array with:

  • 'hiHi': signed int64 base-10 string (range [-2^63, 2^63-1])
  • 'hiLo': unsigned uint64 base-10 string (range [0, 2^64-1])
  • 'loHi': unsigned uint64 base-10 string (range [0, 2^64-1])
  • 'loLo': unsigned uint64 base-10 string (range [0, 2^64-1])
Parameters
$value : string

Base-10 decimal string of a signed 256-bit integer.

Tags
throws
InvalidArgumentException

If $value is not a valid int256 string.

Return values
array{hiHi: string, hiLo: string, loHi: string, loLo: string}

stringToInt64()

Parse a base-10 integer string (or a PHP int) to a 64-bit signed int.

public static stringToInt64(int|string $value) : int

Accepts int|string for compatibility with JSON producers that emit numbers for 64-bit integers in addition to the spec-required strings.

Strict validation rules:

  • Empty string is rejected.
  • Leading/trailing whitespace is rejected.
  • Scientific notation ("1e10") is rejected.
  • Decimal points ("1.0") are rejected.
  • Hex notation ("0x10") is rejected.
  • Leading "+" is rejected.
  • Only an optional leading "-" followed by one or more decimal digits is accepted.
  • Leading zeros are accepted (SEP-0051 does not forbid them in 64-bit string-encoded integers).
  • The resulting value must be in [-2^63, 2^63-1].
  • intval() is explicitly NOT used because intval("abc") silently returns 0.
Parameters
$value : int|string

The value to parse.

Tags
throws
InvalidArgumentException

On any validation failure.

Return values
int

The parsed 64-bit signed integer.

stringToUint128Parts()

Decompose an unsigned 128-bit integer string into hi/lo uint64 parts.

public static stringToUint128Parts(string $value) : array{hi: string, lo: string}

Returns an associative array with keys 'hi' and 'lo', both as base-10 strings representing unsigned uint64 values in [0, 2^64-1].

Parameters
$value : string

Base-10 decimal string of an unsigned 128-bit integer.

Tags
throws
InvalidArgumentException

If $value is not a valid uint128 string.

Return values
array{hi: string, lo: string}

stringToUint256Parts()

Decompose an unsigned 256-bit integer string into four uint64 limbs.

public static stringToUint256Parts(string $value) : array{hiHi: string, hiLo: string, loHi: string, loLo: string}

Returns an associative array with keys 'hiHi', 'hiLo', 'loHi', 'loLo', all as base-10 strings representing unsigned uint64 values in [0, 2^64-1].

Parameters
$value : string

Base-10 decimal string of an unsigned 256-bit integer.

Tags
throws
InvalidArgumentException

If $value is not a valid uint256 string.

Return values
array{hiHi: string, hiLo: string, loHi: string, loLo: string}

stringToUint64()

Parse a base-10 unsigned-integer string (or a PHP int) to a uint64 value.

public static stringToUint64(int|string $value) : int

Accepts int|string for compatibility with JSON producers that emit numbers for 64-bit integers in addition to the spec-required strings.

For uint64 values above PHP_INT_MAX (i.e. 9223372036854775808..18446744073709551615) a string must be provided; those values cannot be expressed as a PHP native int. The method uses GMP for range validation against [0, 2^64-1] and returns the value as a PHP int, reinterpreting the upper-half as a negative signed int (two's complement) — this matches how the XDR parts structs store uint64 limbs.

Strict validation: same rules as stringToInt64 except no leading minus is allowed.

Parameters
$value : int|string

The value to parse.

Tags
throws
InvalidArgumentException

On any validation failure including values < 0 or > 2^64-1.

Return values
int

The uint64 value stored as a PHP int (may be negative for values > PHP_INT_MAX).

uint128PartsToString()

Assemble an unsigned 128-bit integer from hi/lo uint64 parts and return as a base-10 string.

public static uint128PartsToString(string $hi, string $lo) : string

For unsigned 128-bit (UInt128Parts) both the hi and lo limbs are unsigned uint64 values stored as PHP signed ints (two's-complement). GMP is used to reconstruct the full value.

Parameters
$hi : string

Unsigned uint64 as base-10 string. May be a negative base-10 string when the uint64 value exceeds PHP_INT_MAX and is stored as a signed PHP int (the negative form is reinterpreted as the unsigned bit pattern via two's-complement).

$lo : string

Unsigned uint64 as base-10 string. May be a negative base-10 string when the uint64 value exceeds PHP_INT_MAX and is stored as a signed PHP int (the negative form is reinterpreted as the unsigned bit pattern via two's-complement).

Tags
throws
InvalidArgumentException

If hi or lo are not valid int64-fitting strings.

Return values
string

Base-10 decimal string of the assembled 128-bit unsigned integer.

uint256PartsToString()

Assemble an unsigned 256-bit integer from four uint64 limbs and return as a base-10 string.

public static uint256PartsToString(string $hiHi, string $hiLo, string $loHi, string $loLo) : string

Per XDR UInt256Parts all four limbs are unsigned uint64 values.

Parameters
$hiHi : string

Unsigned uint64 as base-10 string (most significant limb). May be a negative base-10 string when the uint64 value exceeds PHP_INT_MAX and is stored as a signed PHP int (the negative form is reinterpreted as the unsigned bit pattern via two's-complement).

$hiLo : string

Unsigned uint64 as base-10 string (same note as hiHi).

$loHi : string

Unsigned uint64 as base-10 string (same note as hiHi).

$loLo : string

Unsigned uint64 as base-10 string (least significant limb; same note as hiHi).

Tags
throws
InvalidArgumentException

If any limb string is invalid.

Return values
string

Base-10 decimal string of the assembled 256-bit unsigned integer.

uint64ToString()

64-bit unsigned integer to base-10 string (SEP-51 Unsigned Hyper Integer encoding).

public static uint64ToString(int $value) : string

PHP's int is a 64-bit signed integer on 64-bit systems, so the valid range for the $value parameter is [0, PHP_INT_MAX] (i.e. [0, 2^63-1]). Values in the upper uint64 range (2^63..2^64-1) cannot be represented as a PHP int without overflow; callers holding such values must use stringToUint64() with a string argument instead of this method.

Parameters
$value : int

A PHP int in [0, PHP_INT_MAX].

Tags
throws
InvalidArgumentException

If $value is negative.

Return values
string

Base-10 decimal string.

unescapeString()

Inverse of escapeString: decode a SEP-51 escaped-ASCII string back to raw bytes.

public static unescapeString(string $escaped) : string

Recognised escape sequences:

  • \0 -> 0x00
  • \t -> 0x09
  • \n -> 0x0A
  • \r -> 0x0D
  • \ -> 0x5C
  • \xNN (exactly two lowercase hex digits) -> byte 0xNN

Any other character following a backslash is rejected. Unescaped printable ASCII characters (0x20..0x7E) are returned as their byte value. The input is validated strictly so that malformed sequences do not silently produce wrong output.

Parameters
$escaped : string

The escaped-ASCII string (output of escapeString).

Tags
throws
InvalidArgumentException

On unrecognised escape sequence, truncated \x, or invalid hex digits.

Return values
string

Raw binary bytes.

wrapUnsignedToSignedInt()

Wrap an unsigned uint64 base-10 string into the matching PHP signed-int representation used by the Parts struct fields.

public static wrapUnsignedToSignedInt(string $decimal) : int

The 128-bit / 256-bit Parts wrappers store every limb as a PHP signed int (XDR's hyper / unsigned hyper map onto the same 64-bit native slot on 64-bit systems). Values in [2^63, 2^64-1] therefore land in PHP as negative integers via two's-complement subtraction. This helper performs that conversion once, with full input validation, so the generated parts-decoder bodies do not each carry their own inline closure.

Accepted input: a non-empty string of decimal digits representing an unsigned integer in [0, 2^64-1]. Out-of-range values, leading signs, empty strings, and non-digit characters are rejected.

Parameters
$decimal : string

Unsigned base-10 string in [0, 2^64-1].

Tags
throws
InvalidArgumentException

On any validation failure.

Return values
int

PHP signed int (may be negative for values above PHP_INT_MAX).

On this page

Search results