Introduction
A pure-PHP OPC UA client. It speaks the binary protocol over TCP, manages secure channels, sessions and cryptography without relying on any C/C++ extension.
What is it?
php-opcua/opcua-client is an OPC UA client implementation written entirely
in PHP. The library covers the OPC UA binary protocol, secure channel negotiation, session
management and the cryptographic primitives required to talk to industrial servers — without
any native dependencies beyond ext-openssl.
Read & write attribute values, browse the address space, call methods, subscribe to monitored items and consume historical data — all from idiomatic PHP code.
Requirements
- PHP ≥ 8.2
ext-openssl- Optional: any PSR-3 logger implementation for diagnostic output
Installation
Install the package with Composer:
composer require php-opcua/opcua-client
Quick Start
Open a connection, read a single attribute, close — three lines of plumbing:
<?php
use PhpOpcua\Client\ClientBuilder;
use PhpOpcua\Client\Types\NodeId;
use PhpOpcua\Client\Types\StatusCode;
$client = ClientBuilder::create()
->connect('opc.tcp://localhost:4840');
$dataValue = $client->read(NodeId::numeric(0, 2259));
if ($dataValue->status->equals(StatusCode::good())) {
echo $dataValue->value;
}
$client->disconnect();
Features
- 47 granular protocol events, observable through PSR-14 dispatchers
- 10 security policies covering Sign and Sign&Encrypt at every supported strength
- Encoder/decoder for all standard OPC UA types — including extension objects
- Subscription helpers with automatic re-publish and acknowledgement bookkeeping
- Pluggable trust-store, transport and module subsystems for advanced integrations
Architecture
The library is layered: a thin Client facade composes a Session running on top of a SecureChannel, which itself rides a binary Transport. Encoding and security are isolated subsystems used at every layer.
Client
└── Session
└── SecureChannel
├── Transport (TCP)
├── Encoding (binary, XML)
└── Security (policies, signing, encryption)
The blocks below are the reusable primitives every page in this documentation will rely on. Copy & adapt them when authoring new pages.
Callouts
Five variants for inline asides. Use note for plain context,
tip to share an idiomatic shortcut, warning for
non-obvious gotchas, danger for footguns, info
for neutral cross-references.
Note
SessionClosedException.
Idiomatic
ClientBuilder::create() over instantiating
Client directly — the builder wires the default
transport, security policy and PSR-3 logger for you.
Warning
SecurityPolicy::None is selected. Restrict that policy to
local development.
Footgun
$client->disconnect() from inside a subscription
callback deadlocks the publish loop. Schedule the disconnect on the next
tick instead.
Info
php-opcua/transport-react.
Do / Don't
Pair recommended and discouraged patterns side-by-side. Useful in "best practices" sections and migration guides.
Resolve NodeId via the typed factories:
NodeId::numeric(0, 2259)
They validate the namespace index at construction time and produce a value object that survives serialization.
Don't string-format identifiers by hand:
"ns=0;i=2259"
The parser is unforgiving and silent failures will look like "no such node" at runtime.
Version notices
Inline pills for "added / changed / deprecated / removed" notes,
modeled after Symfony's versionadded directive.
Inline, they read like this:
Added in
v4.3.0
the
$timeout parameter accepts 0 to disable the
watchdog.
Method & parameters
Signature card followed by a typed parameter list. The pattern doubles as cheap API reference until we have a proper reflection-based generator.
$client->read(NodeId $node, ?int $timeout = null): DataValue
$node
NodeId::numeric(), NodeId::string() or
NodeId::guid().
$timeout
null falls back to the
session-level default; 0 disables the watchdog entirely.
Code tabs
Switch between equivalent snippets in different languages, runtimes, or package managers. Open the first tab by default; use Tab to focus, Enter to switch.
$client = ClientBuilder::create()
->withSecurity(SecurityPolicy::Basic256Sha256)
->connect('opc.tcp://plc.local:4840');
composer require php-opcua/opcua-client \
--with-all-dependencies
{
"endpoint": "opc.tcp://plc.local:4840",
"security": "Basic256Sha256",
"timeout_ms": 30000
}
Tables
Plain CommonMark tables. The body wrapper styles header rows as monospace eyebrows and uses thin white/5 dividers between body rows — no outer box, just the same engineering rhythm as the rest of the page.
| Method | Returns | Description |
|---|---|---|
read() |
DataValue |
Reads a single attribute from the address space. |
write() |
StatusCode |
Writes a value back to the target node. |
browse() |
array<Reference> |
Walks the references of a node. |
call() |
OutputArguments |
Invokes a Method node and returns its output arguments. |
Step-by-step
Numbered timeline for guided walkthroughs. Each step gets a violet badge and a short title; the body accepts paragraphs, code blocks, callouts.
-
01
Install the package
Use Composer to pull the latest stable:
composer require php-opcua/opcua-client -
02
Configure security
Pick a policy from
SecurityPolicyand a matchingMessageSecurityMode. For local PLCs without TLS,SecurityPolicy::None+Noneis acceptable. -
03
Open the channel
Call
connect()with anopc.tcp://endpoint. The builder returns a ready-to-useClient; the secure channel and session are negotiated lazily on first request. -
04
Read, write, subscribe
Issue your service calls. The library multiplexes them on the same channel until you
disconnect().
Related links
"See also" cluster — thin glass card with a short link list. Lighter than callouts; pair it with the end of a section.