php-opcua / opcua-cli
CLI tool for OPC UA — browse, read, write, watch, discover endpoints, manage certificates, and generate code from NodeSet2.xml
Requires
- php: ^8.2
- php-opcua/opcua-client: ^4.3.0
- php-tui/php-tui: ^0.2.1
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.0
- pestphp/pest: ^3.0
README
Command-line tool for OPC UA servers. Browse, read, write, watch, interactively explore, discover endpoints, manage certificates, and generate PHP code from NodeSet2.xml -- all from the terminal.
Built on top of php-opcua/opcua-client, the pure PHP OPC UA client.
Installation
Standalone binary (no PHP required)
Pre-built, self-contained executables are published on every tag release. No PHP installation, no composer, no php.ini, no extensions — one file.
# Linux x86_64 curl -LO https://github.com/php-opcua/opcua-cli/releases/latest/download/opcua-cli-linux-x86_64 chmod +x opcua-cli-linux-x86_64 ./opcua-cli-linux-x86_64 --version # Linux aarch64 (ARM: Raspberry Pi, AWS Graviton, industrial edge gateways) curl -LO https://github.com/php-opcua/opcua-cli/releases/latest/download/opcua-cli-linux-aarch64 chmod +x opcua-cli-linux-aarch64 # macOS arm64 (Apple Silicon — M1/M2/M3/M4) curl -LO https://github.com/php-opcua/opcua-cli/releases/latest/download/opcua-cli-macos-arm64 chmod +x opcua-cli-macos-arm64 xattr -cr opcua-cli-macos-arm64 # clear Gatekeeper quarantine — see note below # Windows x86_64 (experimental in v4.3.0 — may be missing from some releases, see note below) curl.exe -LO https://github.com/php-opcua/opcua-cli/releases/latest/download/opcua-cli-windows-x86_64.exe opcua-cli-windows-x86_64.exe --version
Each release also ships SHA256SUMS.txt; verify with sha256sum --check SHA256SUMS.txt (Linux/macOS) or Get-FileHash -Algorithm SHA256 (PowerShell).
The binaries bundle PHP 8.4, the statically linked OpenSSL (with full ECC curve support including brainpoolP256r1/P384r1), and the compiled opcua-cli — built via static-php-cli + Box.
macOS note — unsigned binaries. The macOS artefact for v4.3.0 is not code-signed or notarized. On first launch Gatekeeper will refuse to run it ("cannot be opened because the developer cannot be verified"). Strip the quarantine flag with
xattr -cr <binary>as shown above, or open the binary once via System Settings → Privacy & Security → Open Anyway. Code-signing + notarization is tracked for v4.4.0.
Intel Mac (
macos-x86_64) not shipped. GitHub retired the freemacos-13runner pool during 2025, so a native Intel build is no longer producible on CI without a paid runner. Intel Mac users should install via Composer (composer global require php-opcua/opcua-cli) or build from source — seedoc/04-build-from-source.md. Note that the Apple Silicon binary (macos-arm64) will not run on Intel Macs: Rosetta 2 translates x86_64 → arm64, not the reverse.
Windows note — experimental. The
windows-x86_64.exeleg of the release workflow runs withcontinue-on-error: true, so a release is published even if the Windows build fails. If the.exeis not listed on a given release page, the Windows build did not complete successfully that cycle — usedoc/04-build-from-source.mdto produce it locally, or wait for the next release. Windows promotion to first-class support is tracked for v4.4.0.
Need a binary for a platform not in the list above (Alpine/musl, a different PHP or extension set)? See doc/04-build-from-source.md — step-by-step instructions for reproducing the build locally.
Via Composer
composer require php-opcua/opcua-cli
The binary is installed at vendor/bin/opcua-cli.
For global installation:
composer global require php-opcua/opcua-cli
Quick Start
# Discover what's available opcua-cli endpoints opc.tcp://localhost:4840 # Browse the address space opcua-cli browse opc.tcp://localhost:4840 # Read a value opcua-cli read opc.tcp://localhost:4840 "i=2259" # Write a value opcua-cli write opc.tcp://localhost:4840 "ns=2;i=1001" 42 --type=Int32 # Watch a value in real time opcua-cli watch opc.tcp://localhost:4840 "ns=2;i=1001"
Commands
browse -- Browse the address space
opcua-cli browse opc.tcp://localhost:4840
opcua-cli browse opc.tcp://localhost:4840 /Objects/MyPLC
opcua-cli browse opc.tcp://localhost:4840 "ns=2;i=1000"
opcua-cli browse opc.tcp://localhost:4840 /Objects --recursive --depth=3
opcua-cli browse opc.tcp://localhost:4840 /Objects --json
├── Server (i=2253) [Object]
├── MyPLC (ns=2;i=1000) [Object]
│ ├── Temperature (ns=2;i=1001) [Variable]
│ └── Pressure (ns=2;i=1002) [Variable]
└── DeviceSet (ns=3;i=5001) [Object]
| Option | Description |
|---|---|
--recursive |
Browse recursively (tree view) |
--depth=N |
Maximum depth for recursive browse (default: 3) |
read -- Read a node value
opcua-cli read opc.tcp://localhost:4840 "i=2259" opcua-cli read opc.tcp://localhost:4840 "ns=2;i=1001" --attribute=DisplayName opcua-cli read opc.tcp://localhost:4840 "ns=2;i=1001" --json
NodeId: ns=2;i=1001
Attribute: Value
Value: 23.5
Type: Double
Status: Good (0x00000000)
Source: 2026-03-24T15:30:00+00:00
Server: 2026-03-24T15:30:00+00:00
| Option | Description |
|---|---|
--attribute=NAME |
Attribute to read: Value (default), DisplayName, BrowseName, DataType, NodeClass, Description, AccessLevel, NodeId |
write -- Write a value to a node
opcua-cli write opc.tcp://localhost:4840 "ns=2;i=1001" 42 opcua-cli write opc.tcp://localhost:4840 "ns=2;i=1001" 42 --type=Int32 opcua-cli write opc.tcp://localhost:4840 "ns=2;i=2000" true --type=Boolean
| Option | Description |
|---|---|
--type=TYPE |
Explicit OPC UA type: Boolean, SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Float, Double, String |
endpoints -- Discover server endpoints
opcua-cli endpoints opc.tcp://localhost:4840
Endpoint: opc.tcp://localhost:4840
Security: None (mode: None)
Auth: Anonymous, UserName
Endpoint: opc.tcp://localhost:4840
Security: Basic256Sha256 (mode: SignAndEncrypt)
Auth: Anonymous, UserName, Certificate
Endpoint: opc.tcp://localhost:4840
Security: ECC_nistP256 (mode: SignAndEncrypt)
Auth: Anonymous, UserName
watch -- Watch a value in real time
# Subscription mode (default) -- server pushes changes opcua-cli watch opc.tcp://localhost:4840 "ns=2;i=1001" # Polling mode -- read every 250ms opcua-cli watch opc.tcp://localhost:4840 "ns=2;i=1001" --interval=250
[15:30:00.123] 23.5
[15:30:00.625] 23.6
[15:30:01.127] 23.4
^C
explore -- Interactive TUI browser
Full-screen terminal UI to walk the address space without typing commands. Tree on the left, details pane on the right (with live Value / Status / Source timestamp for Variables), log pane at the bottom.
opcua-cli explore opc.tcp://localhost:4840 opcua-cli explore opc.tcp://localhost:4840 -u operator -p operator123
| Key | Action |
|---|---|
↑ / ↓ |
Move selection |
→ / Enter |
Expand node (browse children) |
← |
Collapse or jump to parent |
r |
Refresh the Value of the selected Variable |
q / Esc |
Quit |
Platform support. explore currently runs on Linux and macOS. Windows support is coming soon.
Flags. --json and --debug are rejected (they would corrupt the interactive screen). Use --debug-stderr or --debug-file=<path> if you need logs while explore is running.
generate:nodeset -- Generate PHP classes from NodeSet2.xml
opcua-cli generate:nodeset path/to/Opc.Ua.Di.NodeSet2.xml \ --output=src/Generated/Di/ --namespace=App\\OpcUa\\Di
Generates:
- NodeId constants -- one class with all node IDs as string constants
- PHP enums --
BackedEnumfor each OPC UA enumeration type - DTOs -- readonly classes with typed properties for structured DataTypes
- Codecs --
ExtensionObjectCodecimplementations for binary encoding/decoding - Registrar -- batch-registers all codecs with the client
| Option | Description |
|---|---|
--output=PATH |
Output directory (default: ./generated/) |
--namespace=NS |
PHP namespace (default: Generated\\OpcUa) |
No server connection required -- reads the XML file locally.
dump:nodeset -- Export server address space to NodeSet2.xml
opcua-cli dump:nodeset opc.tcp://192.168.1.100:4840 --output=MyPLC.NodeSet2.xml opcua-cli dump:nodeset opc.tcp://192.168.1.100:4840 --output=MyPLC.NodeSet2.xml --namespace=2
| Option | Description |
|---|---|
--output=FILE |
Output XML file path (required) |
--namespace=N |
Export only this namespace index (default: all non-zero) |
The exported file can be fed directly to generate:nodeset.
trust -- Trust a server certificate
opcua-cli trust opc.tcp://server:4840 --trust-store=~/.opcua
trust:list -- List trusted certificates
opcua-cli trust:list --trust-store=~/.opcua
trust:remove -- Remove a trusted certificate
opcua-cli trust:remove ab:cd:12:34:... --trust-store=~/.opcua
| Option | Description |
|---|---|
--trust-store=<path> |
Custom trust store path |
--trust-policy=<policy> |
Validation policy (fingerprint, fingerprint+expiry, full) |
--no-trust-policy |
Disable trust validation for this command |
Security Options
All commands support full security configuration — 10 policies (6 RSA + 4 ECC), 3 modes, 3 auth methods:
# Username/password authentication opcua-cli read opc.tcp://server:4840 "i=2259" -u admin -p secret # Full security with RSA certificates opcua-cli read opc.tcp://server:4840 "i=2259" \ --security-policy=Basic256Sha256 \ --security-mode=SignAndEncrypt \ --cert=/path/to/client.pem \ --key=/path/to/client.key \ --ca=/path/to/ca.pem \ -u operator -p secret # ECC security (auto-generated ECC certificate) opcua-cli read opc.tcp://server:4840 "i=2259" \ --security-policy=ECC_nistP256 \ --security-mode=SignAndEncrypt \ -u operator -p secret
| Option | Short | Description |
|---|---|---|
--security-policy=<policy> |
-s |
None, Basic128Rsa15, Basic256, Basic256Sha256, Aes128Sha256RsaOaep, Aes256Sha256RsaPss, ECC_nistP256, ECC_nistP384, ECC_brainpoolP256r1, ECC_brainpoolP384r1 |
--security-mode=<mode> |
-m |
None, Sign, SignAndEncrypt |
--cert=<path> |
Client certificate path | |
--key=<path> |
Client private key path | |
--ca=<path> |
CA certificate path | |
--username=<user> |
-u |
Username |
--password=<pass> |
-p |
Password |
--timeout=<seconds> |
-t |
Connection timeout (default: 5) |
ECC disclaimer: ECC security policies (
ECC_nistP256,ECC_nistP384,ECC_brainpoolP256r1,ECC_brainpoolP384r1) are fully implemented and tested against the OPC Foundation's UA-.NETStandard reference stack. However, no commercial OPC UA vendor supports ECC endpoints yet. When using ECC, client certificates are auto-generated if--cert/--keyare omitted, and username/password authentication uses theEccEncryptedSecretprotocol automatically.
Output Options
JSON
Add --json (or -j) to any command for machine-readable output:
opcua-cli browse opc.tcp://localhost:4840 --json | jq '.[].name' opcua-cli read opc.tcp://localhost:4840 "i=2259" --json | jq '.Value'
Debug Logging
# Log to stdout (incompatible with --json) opcua-cli read opc.tcp://localhost:4840 "i=2259" --debug # Log to stderr (compatible with --json) opcua-cli read opc.tcp://localhost:4840 "i=2259" --debug-stderr --json # Log to file opcua-cli read opc.tcp://localhost:4840 "i=2259" --debug-file=/tmp/opcua.log --json
Global Options
| Option | Short | Description |
|---|---|---|
--json |
-j |
Output in JSON format |
--debug |
-d |
Debug logging on stdout |
--debug-stderr |
Debug logging on stderr | |
--debug-file=<path> |
Debug logging to file | |
--help |
-h |
Show help |
--version |
-v |
Show version |
Ecosystem
| Package | Description |
|---|---|
| opcua-client | Pure PHP OPC UA client |
| opcua-cli | CLI tool — browse, read, write, watch, interactively explore, discover endpoints, manage certificates, generate code from NodeSet2.xml (this package) |
| opcua-session-manager | Daemon-based session persistence across PHP requests. Keeps OPC UA connections alive between short-lived PHP processes via a ReactPHP daemon and Unix sockets. Separate package by design — see ROADMAP.md for rationale. |
| 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 |
Testing
Tested against the OPC UA reference implementationThe 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 CLI tool is additionally integration-tested via uanetstandard-test-suite, verifying that every command works correctly against real-world OPC UA servers. Like opcua-client, the CLI unit tests run on Linux, macOS, and Windows across PHP 8.2–8.5 in CI on every push. |
288 tests (258 unit + 30 integration) with 99.9% code coverage. Unit tests run cross-OS (Linux, macOS, Windows) × PHP 8.2–8.5 = 12 combinations; integration tests run on Linux × PHP 8.2–8.5 = 4 combinations against uanetstandard-test-suite — a Docker-based OPC UA environment built on the OPC Foundation's UA-.NETStandard reference implementation.
./vendor/bin/pest # everything ./vendor/bin/pest tests/Unit/ # unit only ./vendor/bin/pest tests/Integration/ --group=integration # integration only
CI runs on PHP 8.2, 8.3, 8.4, and 8.5 via GitHub Actions.
Requirements
- PHP >= 8.2
php-opcua/opcua-client
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 CLI tool correctly:
| File | Purpose |
|---|---|
llms.txt |
Compact project summary — commands, options, architecture. Optimized for LLM context windows with minimal token usage. |
llms-full.txt |
Comprehensive technical reference — every command, option, class, code generator, output system. For deep dives and complex questions. |
llms-skills.md |
Task-oriented recipes — step-by-step instructions for common tasks (browse, read, write, watch, security, trust, code generation, scripting). Written so an AI can generate correct commands 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-cli/ after composer install.
- Claude Code: reference per-session with
--add-file vendor/php-opcua/opcua-cli/llms-skills.md - Cursor: copy into your project's rules directory —
cp vendor/php-opcua/opcua-cli/llms-skills.md .cursor/rules/opcua-cli.md - GitHub Copilot: copy or append the content into your project's
.github/copilot-instructions.mdfile (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
Versioning
This package follows the same version numbering as php-opcua/opcua-client. Each release of opcua-cli is aligned with the corresponding release of the client library to ensure full compatibility.
License
MIT. See LICENSE.
