定制 php-opcua/opcua-client-ext-transport-pubsub 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

php-opcua/opcua-client-ext-transport-pubsub

Composer 安装命令:

composer require php-opcua/opcua-client-ext-transport-pubsub

包简介

OPC UA PubSub Subscriber for PHP — UDP + UADP + JSON, extends opcua-client

README 文档

README

OPC UA PubSub Subscriber for PHP

Tests Coverage Latest Version PHP Version License

Linux macOS Windows

Subscribe to OPC UA PubSub streams directly from PHP — UDP unicast or multicast, UADP and JSON payloads, group-key security — without any C/C++ extensions, HTTP gateways, or middleware in between.

This package extends php-opcua/opcua-client with the OPC UA Part 14 — PubSub Subscriber role. The core client stays unchanged; installing this extension only adds the PhpOpcua\Client\ExtTransportPubSub\* namespace. Same zero-dependency philosophy, same PSR-3 / PSR-14 integration, same cross-platform support.

What you can do with it:

  • Listen to PubSub NetworkMessages over UDP unicast or multicast
  • Decode UADP binary and JSON payloads into typed DataSetMessages with named fields
  • Verify and decrypt signed and encrypted PubSub streams using pre-shared group keys or a Security Key Service
  • Configure readers by (publisherId, writerGroupId, dataSetWriterId) and let the kernel demux incoming traffic
  • React in real time via PSR-14 events or plain callbacks on every decoded field

All this with ext-sockets as the only extension beyond the core's ext-openssl, and PHP 8.2 through 8.5 supported on Linux, macOS, and Windows.

Note: PubSub is a fire-and-forget broadcast paradigm, not a session-oriented protocol. A long-running worker process (ReactPHP, Symfony Messenger, Laravel queue worker, Artisan command, systemd unit) is the natural place to run a Subscriber. Short-lived PHP requests cannot sustain a meaningful subscription window.

Ships as an extension, not as a replacement

The core php-opcua/opcua-client is a tight, zero-dependency library focused on client/server OPC UA. PubSub has a different runtime model (event loop vs request/response), a different wire protocol (UADP), and different security (pre-shared group keys vs per-session asymmetric handshake). Bundling it into the core would inflate the base install for the 95% of users who only need read/write/browse/subscribe.

This package is purely additive. Nothing in the core changes when you composer require it.

Quick Start

composer require php-opcua/opcua-client-ext-transport-pubsub
use PhpOpcua\Client\ExtTransportPubSub\SubscriberBuilder;
use PhpOpcua\Client\ExtTransportPubSub\Types\DataSetMessage;
use PhpOpcua\Client\ExtTransportPubSub\Types\DataSetMetaData;
use PhpOpcua\Client\ExtTransportPubSub\Types\DataSetReaderConfig;

$metadata = DataSetMetaData::fromJsonFile('/etc/opcua/line1.json');

$subscriber = SubscriberBuilder::create()
    ->onDataSetMessage(function (DataSetMessage $msg) {
        foreach ($msg->fields as $field) {
            echo "{$field->name} = {$field->getScalar()}\n";
        }
    })
    ->listenUdp(
        endpoint: 'opc.udp://239.0.0.1:4840',
        readers: [
            new DataSetReaderConfig(
                publisherId: 100,
                writerGroupId: 1,
                dataSetWriterId: 1,
                dataSetMetaData: $metadata,
            ),
        ],
    );

$subscriber->run();

That's it. Build, configure one reader, block on run(). Press Ctrl-C (or call stop() from a signal handler) to exit cleanly.

Tip: Prefer poll(timeoutMs: 500) over run() when you have your own event loop (ReactPHP, Amp, custom). It returns the batch of decoded DataSetMessage objects from this tick without blocking past the timeout.

See It in Action

Listen on unicast UDP

$subscriber = SubscriberBuilder::create()
    ->listenUdp(
        endpoint: 'opc.udp://192.168.1.50:4840',
        readers: [$reader],
    );

Tune the UDP socket

use PhpOpcua\Client\ExtTransportPubSub\Transport\UdpOptions;

$subscriber = SubscriberBuilder::create()
    ->listenUdp(
        endpoint: 'opc.udp://239.0.0.1:4840',
        transport: new UdpOptions(
            interface: '0.0.0.0',
            receiveBufferSize: 131072,
            ttl: 8,
            reuseAddress: true,
        ),
        readers: [$reader],
    );

Decode JSON payloads

$subscriber = SubscriberBuilder::create()
    ->useJson()
    ->listenUdp(
        endpoint: 'opc.udp://239.0.0.1:4840',
        readers: [$reader],
    );

Load metadata from JSON, XML, or a live server

use PhpOpcua\Client\ExtTransportPubSub\Types\DataSetMetaData;

// From a JSON config file
$metadata = DataSetMetaData::fromJsonFile('/etc/opcua/line1.json');

// From an OPC UA DataSetMetaDataType XML file
$metadata = DataSetMetaData::fromXmlFile('/etc/opcua/line1.xml');

// From a running server via the classic opcua-client
$metadata = DataSetMetaData::fetchFromServer($client, 'ns=2;s=PDS/Line1/Metadata');

Secure the stream with pre-shared keys

use PhpOpcua\Client\ExtTransportPubSub\Security\PubSubSecurityMode;
use PhpOpcua\Client\ExtTransportPubSub\Security\PubSubSecurityOptions;
use PhpOpcua\Client\ExtTransportPubSub\Security\StaticGroupKeyProvider;

$subscriber = SubscriberBuilder::create()
    ->listenUdp(
        endpoint: 'opc.udp://239.0.0.1:4840',
        security: new PubSubSecurityOptions(
            mode: PubSubSecurityMode::SignAndEncrypt,
            keyProvider: new StaticGroupKeyProvider(
                signingKey: hex2bin($_ENV['PUBSUB_SIGN']),
                encryptingKey: hex2bin($_ENV['PUBSUB_ENC']),
                keyNonce: hex2bin($_ENV['PUBSUB_NONCE']),
            ),
        ),
        readers: [$reader],
    );

Rotate keys from a Security Key Service

use PhpOpcua\Client\ClientBuilder;
use PhpOpcua\Client\ExtTransportPubSub\Security\SksGroupKeyProvider;

$client = ClientBuilder::create()->connect('opc.tcp://sks.example.com:4840');

$provider = new SksGroupKeyProvider($client, securityGroupId: 'line1-ops');
$provider->refresh();

$subscriber = SubscriberBuilder::create()
    ->listenUdp(
        endpoint: 'opc.udp://239.0.0.1:4840',
        security: new PubSubSecurityOptions(PubSubSecurityMode::SignAndEncrypt, $provider),
        readers: [$reader],
    );

Poll instead of run

while (! $shouldStop) {
    foreach ($subscriber->poll(timeoutMs: 250) as $msg) {
        handle($msg);
    }
    doOtherWork();
}

Graceful shutdown from a signal handler

pcntl_async_signals(true);
pcntl_signal(SIGTERM, fn () => $subscriber->stop());
pcntl_signal(SIGINT, fn () => $subscriber->stop());

$subscriber->run();

Receive PSR-14 events for every step

use PhpOpcua\Client\ExtTransportPubSub\Event\DataSetFieldReceived;
use PhpOpcua\Client\ExtTransportPubSub\Event\MessageDecodeError;
use PhpOpcua\Client\ExtTransportPubSub\Event\SecurityValidationFailed;

$subscriber = SubscriberBuilder::create()
    ->setEventDispatcher($yourDispatcher)
    ->listenUdp(/* ... */);

Listeners fire for NetworkMessageReceived, DataSetMessageReceived, DataSetFieldReceived, MessageDecodeError, SecurityValidationFailed, TransportOpened, TransportClosed, and TransportError. Zero overhead when no dispatcher is configured.

Add structured logging

use Monolog\Logger;
use Monolog\Handler\StreamHandler;

$logger = new Logger('pubsub');
$logger->pushHandler(new StreamHandler('php://stderr', Logger::DEBUG));

$subscriber = SubscriberBuilder::create()
    ->setLogger($logger)
    ->listenUdp(/* ... */);

Any PSR-3 logger works. Without one, logging is silently disabled.

Plug in your own transport

use PhpOpcua\Client\ExtTransportPubSub\Transport\PubSubTransportInterface;

class MyKafkaTransport implements PubSubTransportInterface { /* ... */ }

$subscriber = SubscriberBuilder::create()
    ->listenOn(
        transports: [new MyKafkaTransport(/* ... */)],
        readers: [$reader],
    );

The PubSubTransportInterface contract is the extension point that keeps the subscriber agnostic to the underlying transport. External packages like php-opcua/opcua-client-ext-mqtt plug in by implementing this interface.

Why This Package?

  • Zero runtime dependencies beyond the coreext-sockets plus the core's ext-openssl. Optional PSR-3 logging and PSR-14 events via any compatible implementation.
  • PHP 8.2+ — runs on any modern PHP.
  • Native UADP binary — speaks the OPC UA binary PubSub encoding directly over UDP. No translation layer.
  • UDP unicast and multicast — IGMP group join with MCAST_JOIN_GROUP plus legacy IP_ADD_MEMBERSHIP fallback. TTL, buffer size, and SO_REUSEADDR exposed as first-class options.
  • JSON codec included — the reversible form from Part 14 §7.2, round-trippable without external metadata.
  • Group-key security — HMAC-SHA256 signing and AES-256-CBC encryption handled in pure PHP via ext-openssl. Pre-shared keys or live rotation from a Security Key Service.
  • Metadata any way you like — PHP arrays, JSON files, DataSetMetaDataType XML exports, or a live read from the publishing server.
  • Typed everywhere — every DTO uses public readonly properties. No arrays, no magic.
  • Cross-platform — tested on Linux, macOS, and Windows across PHP 8.2–8.5. No FFI, no COM, no platform-specific APIs beyond ext-sockets.
  • Does not modify the coreClientBuilder, Client, ClientKernel, OpcUaClientInterface are untouched.

Features

Feature What it does
UDP Transport Unicast and IPv4 multicast with MCAST_JOIN_GROUP (legacy fallback), SO_REUSEADDR, non-blocking sockets, socket_select timeout
UADP Codec Binary PubSub encoding — PublisherId (Byte/UInt16/UInt32/UInt64/String), GroupHeader, PayloadHeader with multiple DataSetMessages, Variant / RawData / DataValue field encodings
JSON Codec Reversible JSON encoding from Part 14 §7.2 (encode + decode, no external metadata required)
Subscriber Runtime Event loop over N transports, demux by (publisherId, writerGroupId, dataSetWriterId), blocking run() and non-blocking poll()
Security Sign (HMAC-SHA256) and SignAndEncrypt (AES-256-CBC) with pre-shared keys via StaticGroupKeyProvider or SKS-backed rotation via SksGroupKeyProvider
Metadata Loaders DataSetMetaData::fromArray(), fromJsonFile(), fromXmlFile(), fromXmlString(), fromBinary(), fetchFromServer()
PSR-14 Events NetworkMessageReceived, DataSetMessageReceived, DataSetFieldReceived, MessageDecodeError, SecurityValidationFailed, TransportOpened, TransportClosed, TransportError
PSR-3 Logging Any PSR-3 logger plugs in. NullLogger by default.
Pluggable Transports PubSubTransportInterface is the stable hook point for third-party transports (e.g. MQTT)
Module System PubSubModule base class lets you extend the kernel with custom behaviour (telemetry, alarm forwarding, ...)
Typed DTOs public readonly properties everywhere — NetworkMessage, DataSetMessage, DataSetField, FieldMetaData, DataSetMetaData, DataSetReaderConfig, UdpOptions, ReceivedPayload, PubSubSecurityOptions

Documentation

Full docs live under docs/ (published at https://www.php-opcua.com/documentation/opcua-client-ext-transport-pubsub).

Document Covers
Overview What it is, when to use it, what ships
Quick start Reader + callback + listen, in three steps
How it works The transport → codec → security → kernel pipeline
Encodings UADP and JSON, field encodings
Subscriber & builder Builder, run() / poll() / stop(), lifecycle
Transports UDP configuration, multicast, custom transports
Readers & metadata DataSetReaderConfig, loading DataSetMetaData
Modules / Events Custom kernel hooks; the 8 PSR-14 events
Group-key security Sign, SignAndEncrypt, static keys, SKS rotation
Testing · Exceptions Fake transport + dispatcher; error reference

Testing

Run ./vendor/bin/pest after composer install. Unit tests cover codec round-trips, UDP loopback send/receive, kernel demux, security unwrap, metadata loaders, and SKS key fetching. CI runs on PHP 8.2, 8.3, 8.4, and 8.5 across Linux, macOS, and Windows via GitHub Actions.

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

Ecosystem

Package Description
opcua-client Pure PHP OPC UA client (required)
opcua-client-ext-transport-pubsub OPC UA PubSub Subscriber (this package)
opcua-client-nodeset Pre-generated PHP types from OPC Foundation companion specifications
opcua-session-manager Daemon-based session persistence for the classic client
laravel-opcua Laravel integration for the classic client
opcua-cli CLI tool — browse, read, write, watch, manage certificates

Community

Have questions, ideas, or want to share what you've built? Join the GitHub Discussions.

Connected a PubSub-capable device? We're collecting a community-driven list of tested publishers. Share your experience — even a one-liner like "open62541 1.4, UDP multicast, works fine" helps other users know what to expect.

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
llms-full.txt Comprehensive technical reference — every class, DTO, encoding detail
llms-skills.md Task-oriented recipes — step-by-step instructions for common tasks

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

  • Claude Code: reference per-session with --add-file vendor/php-opcua/opcua-client-ext-transport-pubsub/llms-skills.md
  • Cursor: copy into your project's rules directory — cp vendor/php-opcua/opcua-client-ext-transport-pubsub/llms-skills.md .cursor/rules/opcua-pubsub.md
  • GitHub Copilot: copy or append into .github/copilot-instructions.md
  • Other tools: paste the content into your system prompt or project knowledge base

Roadmap

See ROADMAP.md for what's coming next.

Contributing

Contributions welcome — see CONTRIBUTING.md.

Changelog

See CHANGELOG.md.

License

MIT

php-opcua/opcua-client-ext-transport-pubsub 适用场景与选型建议

php-opcua/opcua-client-ext-transport-pubsub 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 0 次下载、GitHub Stars 达 0, 最近一次更新时间为 2026 年 06 月 09 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「udp」 「subscriber」 「pubsub」 「publish-subscribe」 「multicast」 「IIoT」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 php-opcua/opcua-client-ext-transport-pubsub 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 php-opcua/opcua-client-ext-transport-pubsub 我们能提供哪些服务?
定制开发 / 二次开发

基于 php-opcua/opcua-client-ext-transport-pubsub 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 42
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-06-09