HEX
Server: Apache
System: Linux www 6.18.6-i1-amd #905 SMP Mon Jan 19 08:49:07 CET 2026 x86_64
User: sws1073755998 (1073755998)
PHP: 8.1.33
Disabled: NONE
Upload Files
File: //usr/share/php/CM4all/Passage.php
<?php

class PassageMessage {
    public string $command;
    public array $args = array();
    public array $headers = array();
    public ?string $body = null;

    public function __construct(string $command) {
        $this->command = $command;
    }

    public function serialize(): string {
        $s = $this->command;
        if (!empty($this->args)) {
            $s .= ' ';
            // TODO quote?
            $s .= implode(' ', $this->args);
        }

        if (!empty($this->headers)) {
            foreach ($this->headers as $name => $value) {
                // TODO quote?
                $s .= "\n$name:$value";
            }
        }

        if (!is_null($this->body)) {
            $s .= "\0";
            $s .= $this->body;
        }

        return $s;
    }
}

function cm4all_passage(string|PassageMessage $message): PassageMessage {

    if (extension_loaded('sockets') === false)
        throw new ErrorException("The 'sockets' extension is required but missing");

    $socket = socket_create(AF_UNIX, SOCK_SEQPACKET, 0);
    if ($socket === false)
        throw new RuntimeException("Failed to create socket: " . socket_strerror(socket_last_error()));

    $socketPath = '/run/cm4all/passage/socket';
    $result = socket_connect($socket, $socketPath);
    if ($result === false) {
        $error = socket_last_error($socket);
        socket_close($socket);
        throw new RuntimeException("Failed to connect to the socket: " . socket_strerror($error));
    }

    if ($message instanceof PassageMessage)
        $message = $message->serialize();

    $bytesSent = socket_send($socket, $message, strlen($message), 0);
    if ($bytesSent === false) {
        $error = socket_last_error($socket);
        socket_close($socket);
        throw new RuntimeException("Failed to send data: " . socket_strerror($error));
    }

    $response = '';
    $bytesReceived = socket_recv($socket, $response, 65536, MSG_WAITALL);
    if ($bytesReceived === false) {
        $error = socket_last_error($socket);
        socket_close($socket);
        throw new RuntimeException("Failed to receive data: " . socket_strerror($error));
    }

    socket_close($socket);

    // extract the body (after the null byte)
    $response = explode("\0", $response, 2);
    $body = @$response[1];
    $response = $response[0];

    // extract the first line
    $response = explode("\n", $response, 2);
    $line = explode(' ', $response[0], 2);
    $response = @$response[1];

    // extract the command from the first line
    $msg = new PassageMessage($line[0]);
    $msg->body = $body;

    // extract the args from the first line
    if (@$line[1])
        // TDDO allow quoted strings
        $msg->args = explode(' ', $line[1]);

    // extract headers from the remaining lines
    foreach (explode("\n", $response) as $line) {
        $line = explode(':', $line, 2);
        if (strlen($line[0]) && isset($line[1]))
            // TDDO allow quoted strings
            $msg->headers[$line[0]] = $line[1];
    }

    return $msg;
}