PHP 8.5.10 Released!

The Yar Protocol

Yar does not rely on a schema or IDL file: everything is exchanged on the wire as plain bytes. Any language that can read and write bytes can speak to a Yar service, without installing any framework at all — build one fixed-size binary header and a serialized request body, send them to the service URI, and parse the reply.

A message consists of a fixed-size header of 82 bytes followed by a body. The header is laid out exactly like the following C structure, packed with no padding, and is written to the wire field after field in declaration order:

typedef struct _yar_header {
    uint32_t       id;            /* transaction id */
    uint16_t       version;       /* protocol version, currently always 0 */
    uint32_t       magic_num;     /* must be 0x80DFEC60 */
    uint32_t       reserved;
    unsigned char  provider[32];  /* request from whom (authentication) */
    unsigned char  token[32];     /* request token (authentication) */
    uint32_t       body_len;      /* length of the whole body, including
                                     the packager identifier */
} __attribute__ ((packed)) yar_header_t;

The id, magic_num, reserved and body_len fields are stored in network byte order (big-endian); the remaining fields are raw bytes.

The body starts with an 8-byte packager identifier — PHP, JSON or MSGPACK, zero-padded — telling the receiver how the remainder was encoded, followed by the serialized content itself.

  • The request body decodes to an array with the keys i (the transaction id), m (the method being called) and p (the list of parameters).

  • The response body decodes to an array with the keys i (the transaction id), s (the status, one of the YAR_ERR_* codes), r (the return value), o (any output the service method produced) and e (the error or exception, when the call failed).

Over HTTP the message is sent as the body of a POST request, with the response arriving as the body of the reply; over TCP or Unix sockets it is written directly on the stream.

Приклад #1 Calling a Yar service without the extension

The following self-contained script builds a valid Yar request for the php packager with nothing but standard sockets, sends it to a service URI, and prints the decoded response. Running it against the Operator service from the examples prints int(3).

<?php

$uri = "http://api.example.com/operator.php";

/* 1. the body: packager identifier + serialized request */
$serialized = serialize(array("i" => 1, "m" => "add", "p" => array(1, 2)));
$body = str_pad("PHP", 8, "\0") . $serialized;

/* 2. the header: 82 bytes, multi-byte integers in network byte order */
$header = pack("N", 1)                    /* id */
        . pack("v", 0)                    /* version */
        . pack("N", 0x80DFEC60)           /* magic number */
        . pack("N", 0)                    /* reserved */
        . str_pad("", 32, "\0")           /* provider */
        . str_pad("", 32, "\0")           /* token */
        . pack("N", strlen($body));       /* body length */

/* 3. send it as the body of a POST request */
$stream = stream_context_create(array("http" => array(
    "method"  => "POST",
    "header"  => "Content-Type: application/octet-stream\r\n",
    "content" => $header . $body,
)));
$reply = file_get_contents($uri, false, $stream);

/* 4. parse the reply: 82-byte header, then the response body */
$response = unserialize(substr($reply, 82 + 8));
var_dump($response["r"]);
?>

A more complete client implementation in plain PHP, which also decodes the response header and supports concurrent calls, lives in the tools/ directory of the » Yar source repository.

add a note

User Contributed Notes

There are no user contributed notes for this page.
To Top