Pure PHP implementation of the OPC UA protocol stack.
Connect your PHP applications to PLCs, SCADA systems, sensors, historians, and IoT devices — no C/C++ extensions, no HTTP gateways, no middleware.
Packages • Quick Start • Integrations • Transport • AI-Ready • Why php-opcua
OPC UA (Open Platform Communications Unified Architecture) is the industry standard protocol for secure, reliable communication in industrial automation and IoT. It's used worldwide to connect PLCs, SCADA systems, sensors, robots, CNC machines, building automation, and more.
php-opcua brings this protocol to the PHP ecosystem with a complete, native binary implementation.
| Package | Description |
|---|---|
| opcua-client | The core OPC UA client library. Pure PHP binary protocol implementation with support for browse, read, write, method calls, subscriptions, history read, events, alarms, and type discovery. 10 security policies (6 RSA + 4 ECC), 3 authentication modes, auto-retry, fluent builders, modular service architecture (add/replace built-in modules, ship your own), wire-serialization pipeline for safe cross-process IPC, PSR-3/PSR-14/PSR-16 integration. |
| opcua-session-manager | ReactPHP daemon that keeps OPC UA sessions alive across PHP requests via cross-platform local IPC — Unix-domain socket on Linux/macOS, TCP loopback on Windows (auto-selected). Eliminates the per-request connection overhead (~150ms → ~5ms). Third-party service modules are reachable transparently through ManagedClient::__call(). |
| opcua-client-nodeset |
| Package | Description |
|---|---|
| opcua-cli | |
| opcua-client-gui | Graphical OPC UA client built with NativePHP. Browse, read, write, and monitor OPC UA servers through a native desktop interface. In development. |
| Package | Description |
|---|---|
| laravel-opcua | Laravel integration with Facade, .env-based configuration, named connections (like config/database.php), Artisan command for the session manager daemon, and automatic PSR-3/PSR-14/PSR-16 injection. Transparent session persistence — daemon running → ManagedClient; not running → direct Client. Zero code changes between modes. |
| symfony-opcua | Symfony bundle with autowirable services, YAML-based semantic configuration, named connections (like Doctrine), console command for the session manager daemon, and automatic PSR-3/PSR-14/PSR-16 injection. Transparent session persistence — daemon running → ManagedClient; not running → direct Client. Zero code changes between modes. Auto-publish and auto-connect for declarative subscription management. |
| Package | Description |
|---|---|
| opcua-client-ext-reverse-connect | Client-side listener for OPC UA Reverse Connect (Part 6 §7.1.2.3). The server dials back into the PHP listener; once a ReverseHello arrives the listener whitelist-validates the announced ServerUri and hands the live socket to TcpTransport::fromConnectedSocket() — no second TCP handshake. Targets edge-to-cloud topologies where the OPC UA server sits behind a NAT or firewall that forbids inbound connections. |
| opcua-client-ext-transport-https | opc.https:// wire transport for opcua-client — OPC UA Part 6 §7.4 HTTPS mappings. Each service request is a single HTTPS POST; TLS is the secure channel. Ships Binary (§7.4.4, production-ready) and the JSON (§7.4.5) foundation (5 base-type codecs byte-exact with UA-.NETStandard 1.5 reversible mode + per-service codec registry). XML SOAP and legacy SOAP/HTTP with WS-SecureConversation are roadmap (community-driven). Use it when the network forbids inbound opc.tcp but allows outbound https. |
| opcua-client-ext-transport-pubsub | OPC UA Pub/Sub Subscriber for opcua-client — OPC UA Part 14. Listens to PubSub NetworkMessages over UDP (unicast or multicast), decoding both UADP binary and JSON payloads into typed DataSetMessages with named fields. Verifies and decrypts Sign / SignAndEncrypt streams from pre-shared group keys or a Security Key Service (Part 14 SKS). Readers demux by (publisherId, writerGroupId, dataSetWriterId) and every decoded field surfaces through PSR-14 events or plain callbacks. ext-sockets is the only dependency beyond the core's ext-openssl. Use it for broadcast, many-to-many telemetry from PLCs and field devices with no client-server session. |
| opcua-client-ext-mqtt | MQTT transport extension for OPC UA Pub/Sub. Enables broker-based many-to-many communication over MQTT. In development. |
| Package | Description |
|---|---|
| uanetstandard-test-suite | Docker-based OPC UA test infrastructure built on the OPC Foundation's UA-.NETStandard reference implementation. 12 pre-configured servers covering all security policies (RSA + ECC NIST + ECC Brainpool), authentication methods, the Security Key Service (Part 14), HTTPS Binary (Part 6 §7.4.4), a PubSub UDP+UADP publisher, and ~270 test nodes per server. Includes a GitHub Action for CI integration. |
| extra-test-suite | Companion suite to uanetstandard-test-suite: Docker-based open62541 servers for service sets and scenarios the UA-.NETStandard reference implementation does not cover. NodeManagement (AddNodes / DeleteNodes / AddReferences / DeleteReferences) on :24840 and a permissive all-security mirror (every RSA security policy + Anonymous/Username/Password) on :24841. Ports sit clear of 4840-4849. Includes a GitHub Action for CI integration. |
|
All packages are integration-tested against UA-.NETStandard — the reference implementation maintained by the OPC Foundation, the organization that defines the OPC UA specification. 2900+ tests across the ecosystem run via uanetstandard-test-suite against 12 server instances covering every security policy (RSA + ECC), authentication method, data type, method call, subscription, event, alarm, historical read, the Security Key Service (Part 14), HTTPS Binary (Part 6 §7.4.4), and a PubSub UDP+UADP publisher. Unit tests run cross-OS (Linux, macOS, Windows) × PHP 8.2–8.5 on every push; integration tests run Linux-only (Docker-hosted OPC UA servers). |
composer require php-opcua/opcua-clientRequirements: PHP 8.2+ and ext-openssl. No other extensions required.
use PhpOpcua\Client\ClientBuilder;
$client = ClientBuilder::create()
->connect('opc.tcp://localhost:4840');
// Read server status
$status = $client->read('i=2259');
echo $status->getValue(); // 0 = Running
$client->disconnect();$refs = $client->browse('i=85'); // Objects folder
foreach ($refs as $ref) {
echo "{$ref->displayName} ({$ref->nodeId})\n";
}$results = $client->readMulti()
->node('i=2259')->value()
->node('ns=2;i=1001')->displayName()
->node('ns=2;s=Temperature')->value()
->execute();use PhpOpcua\Client\Types\BuiltinType;
$client->write('ns=2;i=1001', 42); // auto-detect type
$client->write('ns=2;i=1001', 42, BuiltinType::Int32); // explicit type$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";
}use PhpOpcua\Client\Security\SecurityPolicy;
use PhpOpcua\Client\Security\SecurityMode;
$client = ClientBuilder::create()
->setSecurityPolicy(SecurityPolicy::Basic256Sha256)
->setSecurityMode(SecurityMode::SignAndEncrypt)
->setClientCertificate('/certs/client.pem', '/certs/client.key', '/certs/ca.pem')
->setUserCredentials('operator', 'secret')
->connect('opc.tcp://192.168.1.100:4840');$values = $client->historyReadRaw(
'ns=2;i=1001',
startTime: new DateTimeImmutable('-1 hour'),
endTime: new DateTimeImmutable(),
);
foreach ($values as $dv) {
echo "[{$dv->sourceTimestamp->format('H:i:s')}] {$dv->getValue()}\n";
}Install the CLI globally or per-project:
composer require php-opcua/opcua-cli# Browse a server
opcua-cli browse opc.tcp://localhost:4840 /Objects --recursive
# Read a value
opcua-cli read opc.tcp://localhost:4840 ns=2;i=1001
# Watch values in real-time
opcua-cli watch opc.tcp://localhost:4840 ns=2;i=1001
# Write a value
opcua-cli write opc.tcp://localhost:4840 ns=2;i=1001 42 --type=Int32
# Discover endpoints and security policies
opcua-cli endpoints opc.tcp://localhost:4840
# Export address space to NodeSet2.xml
opcua-cli dump:nodeset opc.tcp://localhost:4840 --output=MyPLC.NodeSet2.xml
# Generate PHP types from NodeSet2.xml
opcua-cli generate:nodeset MyPLC.NodeSet2.xml --output=src/Generated --namespace=App\\OpcUa
# Manage server certificate trust
opcua-cli trust opc.tcp://localhost:4840
opcua-cli trust:list
opcua-cli trust:remove ab:cd:12:34:...All commands support --json output, full security configuration (-s, -m, --cert, --key), and debug logging (--debug, --debug-stderr, --debug-file).
composer require php-opcua/opcua-client-nodeset51 OPC Foundation companion specifications, ready to use as typed PHP classes:
use PhpOpcua\Client\ClientBuilder;
use PhpOpcua\Nodeset\Robotics\RoboticsRegistrar;
use PhpOpcua\Nodeset\Robotics\Enums\OperationalModeEnumeration;
$client = ClientBuilder::create()
->loadGeneratedTypes(new RoboticsRegistrar()) // auto-loads dependencies
->connect('opc.tcp://192.168.1.100:4840');
$mode = $client->read('ns=2;s=OperationalMode')->getValue();
// Returns: OperationalModeEnumeration::MANUAL_HIGH_SPEED (PHP enum, not raw int)Supported specifications include: DI (Device Integration), Robotics, MachineTool, BACnet, MTConnect, AutoID, ISA-95, PackML, MachineVision, PROFINET, I4AAS, LADS, CNC, Safety, Scales, Woodworking, and 35 more.
A Docker-based test infrastructure built on the OPC Foundation's UA-.NETStandard reference implementation, with 12 OPC UA servers for integration testing:
| Server | Port | Purpose |
|---|---|---|
| No Security | 4840 | Basic connectivity, anonymous access |
| Username/Password | 4841 | Credential authentication |
| Certificate | 4842 | X.509 certificate authentication |
| All Security | 4843 | All policies, modes, and auth methods |
| Discovery | 4844 | OPC UA Discovery Server |
| Auto-Accept | 4845 | Auto-trust any client certificate |
| Sign Only | 4846 | Message signing without encryption |
| Legacy Security | 4847 | Deprecated policies (Basic128Rsa15, Basic256) |
| ECC NIST | 4848 | ECC NIST P-256 / P-384 curves |
| ECC Brainpool | 4849 | ECC Brainpool P-256r1 / P-384r1 curves |
| Security Key Service | 4851 | OPC UA Part 14 SKS (GetSecurityKeys) |
| HTTPS Binary | 4852 | OPC UA Part 6 §7.4.4 HTTPS Binary transport |
| PubSub UDP+UADP publisher | (internal) | OPC UA Part 14 PubSub deterministic publisher |
Each server exposes ~270 nodes: scalars, arrays, matrices, methods, dynamic variables, events, alarms, historical data, structured objects, and access-controlled variables.
docker compose up -d- uses: php-opcua/uanetstandard-test-suite@v1.0.0
- uses: php-opcua/extra-test-suite@v1.1.0composer require php-opcua/laravel-opcuaOPCUA_ENDPOINT=opc.tcp://192.168.1.100:4840use PhpOpcua\LaravelOpcua\Facades\Opcua;
$client = Opcua::connect();
$value = $client->read('i=2259');
echo $value->getValue(); // 0 = Running
$client->disconnect();- Named connections in
config/opcua.php(likeconfig/database.php) - Automatic PSR-3 logging, PSR-14 events, and PSR-16 caching via Laravel's services
- Artisan command to start the session manager daemon:
php artisan opcua:session - Transparent session persistence — daemon running →
ManagedClient; not running → directClient. Zero code changes - Trust store — certificate trust management with configurable policies and auto-accept
- Write auto-detection — omit the type parameter and let the client detect it automatically
- 47 PSR-14 events for full observability of OPC UA operations
composer require php-opcua/symfony-opcua# config/packages/php_opcua_symfony_opcua.yaml
php_opcua_symfony_opcua:
connections:
default:
endpoint: '%env(OPCUA_ENDPOINT)%'use PhpOpcua\SymfonyOpcua\OpcuaManager;
class PlcController
{
public function __construct(private readonly OpcuaManager $opcua) {}
public function index(): Response
{
$client = $this->opcua->connect();
$value = $client->read('i=2259');
echo $value->getValue(); // 0 = Running
$client->disconnect();
}
}- Autowiring — inject
OpcuaManagerorOpcUaClientInterface(default connection) anywhere - Named connections in YAML config (like Doctrine connections)
- Automatic PSR-3 logging, PSR-14 events, and PSR-16 caching via Symfony's services
- Console command to start the session manager daemon:
php bin/console opcua:session - Transparent session persistence — daemon running →
ManagedClient; not running → directClient. Zero code changes - Auto-publish — daemon monitors subscriptions automatically and dispatches PSR-14 events to Symfony listeners
- Auto-connect — define subscriptions in YAML config per connection, daemon sets them up at startup
- Trust store — certificate trust management with configurable policies and auto-accept
- Write auto-detection — omit the type parameter and let the client detect it automatically
- 47 PSR-14 events for full observability of OPC UA operations
opcua-client ships TCP out of the box. Extensions add three additional wire transports for the network topologies the default does not handle. Pick on what the network between your PHP app and the OPC UA server allows:
| Your situation | Use | Package |
|---|---|---|
Default — outbound opc.tcp:// is allowed end-to-end |
TCP (built-in) | opcua-client |
| Server sits behind NAT / firewall that forbids inbound connections — server must dial out to you | Reverse Connect (Part 6 §7.1.2.3) | opcua-client-ext-reverse-connect |
Network only allows outbound https:// (corporate proxy, cloud egress filter) |
HTTPS Binary (Part 6 §7.4.4) | opcua-client-ext-transport-https |
| Broadcast / many-to-many data distribution from PLCs to consumers, no client-server session | PubSub (Part 14) | opcua-client-ext-transport-pubsub |
| Broker-based many-to-many distribution where consumers subscribe through an MQTT broker | PubSub over MQTT (Part 14) | opcua-client-ext-mqtt (in development) |
The ClientTransportInterface contract added in opcua-client v4.4 means every transport plugs in via ClientBuilder::setTransport(...). The application code (read, write, browse, subscribe) stays identical regardless of the underlying wire.
Every package ships machine-readable documentation alongside the human-readable docs — designed for AI coding assistants (Claude, Cursor, GitHub Copilot, ChatGPT, Continue, etc.) so they generate correct OPC UA code on the first try:
llms.txt— short index per llmstxt.org conventionsllms-full.txt— full-text concatenation of the package's docsllms-skills.md— task-oriented skill primers (when applicable)
Feed the relevant file to your AI assistant when starting an OPC UA task. The ecosystem-wide convention means your assistant gets accurate, version-matched context for any package you bring into the project.
- Pure PHP — Native binary protocol. No C extensions, no FFI, no HTTP gateways, no sidecars.
- Zero runtime dependencies — Only
ext-openssl. PSR-3, PSR-14, and PSR-16 are optional. - Full protocol support — Browse, read, write, method calls, subscriptions, events, alarms, history read, type discovery, path resolution.
- Industrial-grade security — 10 security policies (6 RSA + 4 ECC: NIST P-256/P-384, Brainpool P-256/P-384), 3 authentication modes, certificate trust management with TOFU support.
- Modular architecture — Every OPC UA service set is a self-contained
ServiceModule. Add your own withClientBuilder::addModule(), replace built-ins withreplaceModule(). Third-party module methods are reachable transparently over IPC viaManagedClient::__call(). - Safe cross-process IPC — A JSON-based wire-serialization pipeline (
WireSerializable+WireTypeRegistry) with an explicit__ttype allowlist — nounserialize()on the wire path, zero PHP gadget-chain surface by construction. - Developer experience — Fluent builders, auto-batching, auto-retry,
readonlyDTOs, typed enums, MockClient for testing. - Cross-platform — Linux, macOS, Windows. PHP 8.2 through 8.5. The session-manager IPC auto-selects Unix-domain socket on Linux/macOS and TCP loopback on Windows; zero application-side changes.
- Session persistence — Optional ReactPHP daemon keeps connections alive across PHP requests (~150ms → ~5ms).
- 51 companion specs — Pre-generated types for DI, Robotics, MachineTool, BACnet, and more.
- Tested — 2900+ tests across all packages, integration-tested against the OPC Foundation's UA-.NETStandard reference implementation, CI across PHP 8.2–8.5 × Linux / macOS / Windows for unit tests, Linux for integration tests.
- AI-Ready — Every package ships with
llms.txt,llms-full.txt, andllms-skills.md— machine-readable documentation designed for AI coding assistants (Claude, Cursor, Copilot, ChatGPT). Feed them to your AI so it generates correct OPC UA code out of the box.
All packages in the php-opcua ecosystem follow the same version numbering as opcua-client. Each release is aligned with the corresponding client library release to ensure full compatibility across the ecosystem.
Industrial automation lives or dies by trust. If you find a vulnerability in any php-opcua package, please disclose responsibly — open a private GitHub security advisory on the affected repository rather than a public issue. Each repo ships a SECURITY.md with the disclosure protocol and the supported version range.
For general questions on the security model (10 RSA + ECC policies, certificate trust store with TOFU, OPC UA application certificate vs TLS client certificate, message-level sign-and-encrypt, etc.), see the security/ section of opcua-client docs.
Each package is released under its own license. See the individual repository for details.