BIP32 specifies the serialization format used by extended keys as:
Serialization format Extended public and private keys are serialized
- 4 byte: version bytes (mainnet: 0x0488B21E public, 0x0488ADE4 private;
testnet: 0x043587CF public, 0x04358394 private)
- 1 byte: depth: 0x00 for master nodes, 0x01 for level-1 derived keys,
- 4 bytes: the fingerprint of the parent's key (0x00000000 if master key)
- 4 bytes: child number. This is ser32(i) for i in xi = xpar/i, with xi the key being serialized. (0x00000000 if master key)
- 32 bytes: the chain code
- 33 bytes: the public key or private key data (serP(K) for public keys,
0x00 || ser256(k) for private keys)
This 78 byte structure can be
encoded like other Bitcoin data in Base58, by first adding 32 checksum
bits (derived from the double SHA-256 checksum), and then converting
to the Base58 representation. This results in a Base58-encoded string
of up to 112 characters. Because of the choice of the version bytes,
the Base58 representation will start with "xprv" or "xpub" on mainnet,
"tprv" or "tpub" on testnet.
Note that the fingerprint of the parent
only serves as a fast way to detect parent and child nodes in
software, and software must be willing to deal with collisions.
Internally, the full 160-bit identifier could be used.
When importing a serialized extended public key, implementations must
verify whether the X coordinate in the public key data corresponds to
a point on the curve. If not, the extended public key is invalid.
Your PHP code must first run the b58check algorithm to verify the xpub is encoded correctly, and then decode it into the above values. Lastly, you must check that the pubkey found by decoding the xpub is a value point on the secp256k1 curve.