gianfriaur/opcua-php-client-session-manager

This package is abandoned and no longer maintained. The author suggests using the https://github.com/php-opcua/opcua-session-manager package instead.

Session manager daemon for persistent OPC UA connections in PHP — Unix socket IPC, automatic session recovery, subscription transfer

Maintainers

Package info

github.com/php-opcua/opcua-session-manager

Documentation

pkg:composer/gianfriaur/opcua-php-client-session-manager

Statistics

Installs: 83

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v4.1.0 2026-04-13 08:13 UTC

This package is auto-updated.

Last update: 2026-04-13 08:13:58 UTC


README

OPC UA Session Manager

Tests Coverage Latest Version PHP Version License

Keep OPC UA sessions alive across PHP requests. A daemon-based session manager for opcua-client that eliminates the 50–200ms connection handshake overhead on every HTTP request.

PHP's request/response model destroys all state — including network connections — at the end of every request. OPC UA requires a 5-step handshake (TCP → Hello/Ack → OpenSecureChannel → CreateSession → ActivateSession) that must be repeated every single time. This package solves the problem with a long-running ReactPHP daemon that holds sessions in memory, communicating with PHP applications via a lightweight Unix socket IPC protocol.

What you get:

  • Session persistence — OPC UA connections survive across HTTP requests. Pay the handshake cost once, reuse forever
  • Automatic session reuse — reconnecting to the same endpoint returns the existing session automatically, no manual session ID tracking needed
  • Drop-in replacementManagedClient implements the same OpcUaClientInterface as the direct Client. Swap one line, keep all your code
  • All OPC UA operations — browse, read, write, method calls, subscriptions, history, path resolution, type discovery
  • Security hardening — method whitelist, IPC authentication, credential stripping, error sanitization, connection limits
  • Auto-publish — daemon automatically publishes for sessions with active subscriptions and dispatches PSR-14 events (DataChangeReceived, AlarmActivated, etc.) — no manual publish loop needed
  • Auto-connect — daemon can auto-connect and register subscriptions at startup from pre-configured connection definitions
  • Automatic cleanup — expired sessions are disconnected after configurable inactivity timeout
  • Graceful shutdown — SIGTERM/SIGINT cleanly disconnect all active sessions

A note on versioning: We're aware of the rapid major releases in a short time frame. This library is under active, full-time development right now — the goal is to reach a production-stable state as quickly as possible. Breaking changes are being bundled and shipped deliberately to avoid dragging them out across many minor releases. Once the API surface settles, major version bumps will become rare. Thanks for your patience.

Tested against the OPC UA reference implementation

The underlying opcua-client is integration-tested against UA-.NETStandard — the reference implementation maintained by the OPC Foundation, the organization that defines the OPC UA specification. This is the same stack used by major industrial vendors to certify their products.

This session manager is additionally integration-tested via uanetstandard-test-suite, verifying that all OPC UA operations work correctly when proxied through the daemon's IPC layer.

Quick Start

composer require php-opcua/opcua-session-manager

1. Start the daemon

php bin/opcua-session-manager

2. Use ManagedClient in your PHP code

use PhpOpcua\SessionManager\Client\ManagedClient;

$client = new ManagedClient();
$client->connect('opc.tcp://localhost:4840');

$value = $client->read('i=2259');
echo $value->getValue(); // 0 = Running

$client->disconnect();

That's it. Same API as the direct Client, but the session stays alive between requests.

See It in Action

Session persistence across requests

// Request 1: open session — handshake happens once
$client = new ManagedClient();
$client->connect('opc.tcp://localhost:4840');
// Do NOT call disconnect() — session stays alive in daemon

// Request 2: same endpoint → reuses existing session automatically
$client = new ManagedClient();
$client->connect('opc.tcp://localhost:4840');
$client->wasSessionReused(); // true — no handshake needed
$value = $client->read('i=2259'); // ~5ms instead of ~155ms

// If you need a separate parallel session to the same server:
$client2 = new ManagedClient();
$client2->connectForceNew('opc.tcp://localhost:4840');
$client2->wasSessionReused(); // false — new session created

Browse and read

$refs = $client->browse('i=85');
foreach ($refs as $ref) {
    echo "{$ref->displayName} ({$ref->nodeId})\n";
}

$nodeId = $client->resolveNodeId('/Objects/Server/ServerStatus');
$status = $client->read($nodeId);

Read multiple values with fluent builder

$results = $client->readMulti()
    ->node('i=2259')->value()
    ->node('ns=2;i=1001')->displayName()
    ->execute();

Write to a PLC

// Auto-detection (v4) — type inferred automatically
$client->write('ns=2;i=1001', 42);

// Explicit type (still supported)
use PhpOpcua\Client\Types\BuiltinType;
$client->write('ns=2;i=1001', 42, BuiltinType::Int32);

Subscribe to data changes

$sub = $client->createSubscription(publishingInterval: 500.0);

$client->createMonitoredItems($sub->subscriptionId, [
    ['nodeId' => 'ns=2;i=1001'],
]);

$response = $client->publish();
foreach ($response->notifications as $notif) {
    echo $notif['dataValue']->getValue() . "\n";
}

Auto-publish (no manual publish loop)

When the daemon is started with an EventDispatcherInterface and autoPublish: true, it automatically calls publish() for sessions that have subscriptions. The client's PSR-14 events are dispatched to your listeners:

use PhpOpcua\Client\Event\DataChangeReceived;
use PhpOpcua\Client\Event\AlarmActivated;
use Psr\EventDispatcher\EventDispatcherInterface;

// 1. Start daemon with auto-publish
$daemon = new SessionManagerDaemon(
    socketPath: '/tmp/opcua.sock',
    clientEventDispatcher: $yourPsr14Dispatcher,
    autoPublish: true,
);

// 2. Pre-configure connections to auto-connect on startup
$daemon->autoConnect([
    'plc-1' => [
        'endpoint' => 'opc.tcp://192.168.1.10:4840',
        'config' => [],
        'subscriptions' => [
            [
                'publishing_interval' => 500.0,
                'max_keep_alive_count' => 5,
                'monitored_items' => [
                    ['node_id' => 'ns=2;s=Temperature', 'client_handle' => 1],
                    ['node_id' => 'ns=2;s=Pressure', 'client_handle' => 2],
                ],
                'event_monitored_items' => [
                    ['node_id' => 'i=2253', 'client_handle' => 10],
                ],
            ],
        ],
    ],
]);

$daemon->run();
// DataChangeReceived, EventNotificationReceived, AlarmActivated events
// are dispatched to your PSR-14 listeners automatically.

Secure connection with authentication

use PhpOpcua\Client\Security\SecurityPolicy;
use PhpOpcua\Client\Security\SecurityMode;

$client = new ManagedClient(
    socketPath: '/var/run/opcua-session-manager.sock',
    authToken: trim(file_get_contents('/etc/opcua/daemon.token')),
);

// RSA security
$client->setSecurityPolicy(SecurityPolicy::Basic256Sha256);
$client->setSecurityMode(SecurityMode::SignAndEncrypt);
$client->setClientCertificate('/certs/client.pem', '/certs/client.key');
$client->setUserCredentials('operator', 'secret');
$client->connect('opc.tcp://192.168.1.100:4840');
// ECC security (auto-generated ECC certificate)
$client = new ManagedClient();
$client->setSecurityPolicy(SecurityPolicy::EccNistP256);
$client->setSecurityMode(SecurityMode::SignAndEncrypt);
$client->setUserCredentials('operator', 'secret');
$client->connect('opc.tcp://192.168.1.100:4840');

Tip: Skip setClientCertificate() and a self-signed cert gets auto-generated in memory (RSA for RSA policies, ECC for ECC policies) — perfect for quick tests or servers with auto-accept.

ECC disclaimer: ECC security policies (EccNistP256, EccNistP384, EccBrainpoolP256r1, EccBrainpoolP384r1) are fully implemented and tested against the OPC Foundation's UA-.NETStandard reference stack. However, no commercial OPC UA vendor supports ECC endpoints yet.

How It Works

┌──────────────┐         ┌──────────────────────────────┐         ┌──────────────┐
│  PHP Request │ ──IPC──►│  Session Manager Daemon      │ ──TCP──►│  OPC UA      │
│  (short-     │◄──IPC── │                              │◄──TCP── │  Server      │
│   lived)     │         │  ● ReactPHP event loop       │         │              │
└──────────────┘         │  ● Sessions in memory        │         └──────────────┘
                         │  ● Periodic cleanup timer    │
┌──────────────┐         │  ● Signal handlers           │
│  PHP Request │ ──IPC──►│                              │
│  (reuses     │◄──IPC── │  Sessions:                   │
│   session)   │         │   [sess-a1b2] → Client (TCP) │
└──────────────┘         │   [sess-c3d4] → Client (TCP) │
                         └──────────────────────────────┘

Without the session manager:

Request 1:  [connect 150ms] [read 5ms] [disconnect]  → total ~155ms
Request 2:  [connect 150ms] [read 5ms] [disconnect]  → total ~155ms

With the session manager:

Request 1:  [open session 150ms] [read 5ms]           → total ~155ms  (first time only)
Request 2:                       [read 5ms]           → total ~5ms
Request N:                       [read 5ms]           → total ~5ms

Features

Feature What it does
Drop-in Replacement ManagedClient implements the same OpcUaClientInterface as the direct Client
Session Persistence OPC UA sessions survive across PHP requests via the daemon
Automatic Session Reuse Reconnecting to the same endpoint returns the existing session instead of creating a new one
All OPC UA Operations Browse, read, write, method calls, subscriptions, history, path resolution
String NodeIds All methods accept 'i=2259' or 'ns=2;s=MyNode' in addition to NodeId objects
Fluent Builder API readMulti(), writeMulti(), createMonitoredItems(), translateBrowsePaths() support chainable builders
Typed Returns All service responses return public readonly DTOs — SubscriptionResult, CallResult, BrowseResultSet, etc.
Type Discovery discoverDataTypes() auto-detects custom server structures
Transfer & Recovery transferSubscriptions() and republish() for session migration
PSR-3 Logging Optional structured logging via any PSR-3 logger
PSR-16 Cache Cache management forwarded to daemon — invalidateCache(), flushCache()
Security 10 policies (RSA + ECC), 3 auth modes, IPC authentication, method whitelist
Auto-Retry Automatic reconnect on connection failures
Auto-Batching Transparent batching for readMulti()/writeMulti()
Auto-Publish Daemon automatically calls publish() for sessions with subscriptions and dispatches PSR-14 events
Auto-Connect Daemon connects and registers subscriptions at startup from pre-configured definitions
Automatic Cleanup Expired sessions closed after inactivity timeout
Graceful Shutdown SIGTERM/SIGINT disconnect all sessions cleanly

Daemon Options

php bin/opcua-session-manager [options]
Option Default Description
--socket <path> /tmp/opcua-session-manager.sock Unix socket path
--timeout <sec> 600 Session inactivity timeout
--cleanup-interval <sec> 30 Expired session cleanup interval
--auth-token <token> (none) Shared secret for IPC authentication
--auth-token-file <path> (none) Read auth token from file (recommended)
--max-sessions <n> 100 Maximum concurrent sessions
--socket-mode <octal> 0600 Socket file permissions
--allowed-cert-dirs <dirs> (none) Comma-separated allowed certificate directories

Auth token priority: OPCUA_AUTH_TOKEN env var > --auth-token-file > --auth-token.

Security

The daemon implements multiple layers of security hardening:

  • IPC authentication — shared-secret token validated with timing-safe hash_equals()
  • Socket permissions0600 by default (owner-only)
  • Method whitelist — only 45 documented OPC UA operations allowed via query
  • Credential protection — passwords and private key paths stripped immediately after connection
  • Session limits — configurable maximum to prevent resource exhaustion
  • Certificate path restrictions--allowed-cert-dirs constrains certificate directories
  • Input size limit — IPC requests capped at 1MB
  • Connection protection — 30s per-connection timeout, max 50 concurrent IPC connections
  • Error sanitization — messages truncated, file paths stripped
  • PID file lock — prevents multiple daemon instances

Recommended production setup

openssl rand -hex 32 > /etc/opcua/daemon.token
chmod 600 /etc/opcua/daemon.token

OPCUA_AUTH_TOKEN=$(cat /etc/opcua/daemon.token) php bin/opcua-session-manager \
    --socket /var/run/opcua-session-manager.sock \
    --socket-mode 0660 \
    --max-sessions 50 \
    --allowed-cert-dirs /etc/opcua/certs

Comparison

Direct Client ManagedClient
Connection Direct TCP Via daemon (Unix socket)
Session lifetime Dies with PHP process Persists across requests
Per-operation overhead ~1–5ms ~5–15ms
Connection overhead ~50–200ms every request ~50–200ms first time only
Subscriptions Lost between requests Maintained by daemon
Certificate paths Relative or absolute Absolute only

Documentation

# Document Covers
01 Introduction Overview, requirements, quick start
02 Overview & Architecture Problem, solution, components
03 Installation Requirements, Composer setup, project structure
04 Daemon CLI options, security, systemd/Supervisor, internals
05 ManagedClient API Full API reference, configuration, session persistence
06 IPC Protocol Transport, commands, authentication, wire format
07 Type Serialization JSON conversion for all OPC UA types and DTOs
08 Testing Test infrastructure, helper class, running tests
09 Examples Complete code examples for all features

Testing

./vendor/bin/pest                                          # everything
./vendor/bin/pest tests/Unit/                              # unit only
./vendor/bin/pest tests/Integration/ --group=integration   # integration only

456+ tests (unit + integration). Integration tests run against uanetstandard-test-suite — a Docker-based OPC UA environment built on the OPC Foundation's UA-.NETStandard reference implementation — covering browse, read/write, subscriptions, method calls, path resolution, connection state, security, type serialization, session persistence, session recovery, and all v4.0.0 DTOs.

Note on coverage: SessionManagerDaemon is excluded from coverage reports because it runs as a separate long-lived process (ReactPHP event loop). PHP coverage tools (pcov, xdebug) only instrument the test runner process — they cannot track code executing inside a subprocess started via proc_open(). The daemon is fully tested by the integration suite, which starts a real daemon, sends IPC commands, and verifies responses. This is a known limitation shared by other daemon-based PHP packages (Laravel Horizon, Symfony Messenger, RoadRunner workers).

Ecosystem

Package Description
opcua-client Pure PHP OPC UA client
opcua-cli CLI tool — browse, read, write, watch, discover endpoints, manage certificates, generate code from NodeSet2.xml
opcua-session-manager Daemon-based session persistence across PHP requests (this package)
opcua-client-nodeset Pre-generated PHP types from 51 OPC Foundation companion specifications (DI, Robotics, Machinery, MachineTool, ISA-95, CNC, MTConnect, and more). 807 PHP files — NodeId constants, enums, typed DTOs, codecs, registrars with automatic dependency resolution. Just composer require and loadGeneratedTypes().
laravel-opcua Laravel integration — service provider, facade, config
uanetstandard-test-suite Docker-based OPC UA test servers (UA-.NETStandard) for integration testing

AI-Ready

This package ships with machine-readable documentation designed for AI coding assistants (Claude, Cursor, Copilot, ChatGPT, and others). Feed these files to your AI so it knows how to use the library correctly:

File Purpose
llms.txt Compact project summary — architecture, key classes, API signatures, and configuration. Optimized for LLM context windows with minimal token usage.
llms-full.txt Comprehensive technical reference — every class, method, DTO, serialization format, IPC protocol, and daemon internal. For deep dives and complex questions.
llms-skills.md Task-oriented recipes — step-by-step instructions for common tasks (install, configure, deploy, persist sessions, subscriptions, security, monitoring). Written so an AI can generate correct, production-ready code from a user's intent.

How to use: copy the files you need into your project's AI configuration directory. The files are located in vendor/php-opcua/opcua-session-manager/ after composer install.

  • Claude Code: reference per-session with --add-file vendor/php-opcua/opcua-session-manager/llms-skills.md
  • Cursor: copy into your project's rules directory — cp vendor/php-opcua/opcua-session-manager/llms-skills.md .cursor/rules/opcua-session-manager.md
  • GitHub Copilot: copy or append the content into your project's .github/copilot-instructions.md file (create the file and directory if they don't exist). Copilot reads this file automatically for project-specific context
  • Other tools: paste the content into your system prompt, project knowledge base, or context configuration

Roadmap

See ROADMAP.md for what's coming next.

Contributing

Contributions welcome — see CONTRIBUTING.md.

Versioning

This package follows the same version numbering as php-opcua/opcua-client. Each release of opcua-session-manager is aligned with the corresponding release of the client library to ensure full compatibility.

Changelog

See CHANGELOG.md.

License

MIT