PHPackages                             hostmaster/ua - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. hostmaster/ua

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

hostmaster/ua
=============

Modern PHP 8.2+ EPP client library for the .UA registry (epp.hostmaster.ua).

1.0.1(4w ago)020MITPHPPHP ^8.2

Since Apr 29Pushed 4w agoCompare

[ Source](https://github.com/hostmaster-direct/ua)[ Packagist](https://packagist.org/packages/hostmaster/ua)[ Docs](https://github.com/hostmaster-direct/ua)[ RSS](/packages/hostmaster-ua/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (2)Dependencies (4)Versions (3)Used By (0)

hostmaster/ua
=============

[](#hostmasterua)

Modern PHP 8.2+ EPP client library for the Ukrainian (.UA) domain registry, [epp.hostmaster.ua](https://epp.hostmaster.ua/).

- **Strict types**, readonly DTOs, typed enums, full PSR-4 / Composer
- Native [RFC 5730](https://www.rfc-editor.org/rfc/rfc5730)/[5734](https://www.rfc-editor.org/rfc/rfc5734)EPP-over-TLS transport (4-byte length-prefixed frames)
- Hostmaster.ua dialect: `contact-1.1`, `domain-1.1`, `host-1.1`, `uaepp-1.1` (license, force-host-delete), `rgp-1.1`, `balance-1.0`
- Per-result-code exception hierarchy — handle `ObjectExistsException`, `BillingException`, `AuthorizationException`, etc. directly
- PSR-3 logging hook for wire-level debugging

Install
-------

[](#install)

```
composer require hostmaster/ua
```

Requires PHP 8.2+ with `ext-dom`, `ext-libxml`, `ext-openssl`, `ext-mbstring`.

Quick start
-----------

[](#quick-start)

```
use Hostmaster\Ua\Client;
use Hostmaster\Ua\Config;
use Hostmaster\Ua\Enum\ContactType;
use Hostmaster\Ua\Enum\PostalType;
use Hostmaster\Ua\Model\Address;
use Hostmaster\Ua\Model\AuthInfo;
use Hostmaster\Ua\Model\ContactCreate;
use Hostmaster\Ua\Model\DomainContact;
use Hostmaster\Ua\Model\DomainCreate;
use Hostmaster\Ua\Model\Nameserver;
use Hostmaster\Ua\Model\Period;
use Hostmaster\Ua\Model\PostalInfo;

$client = new Client(new Config(
    username: 'MYREG',
    password: 'super-secret',
    // host: 'epp-test.hostmaster.ua', // OT&E
    // localCert: '/etc/ssl/registrar.pem',
    // localPk:   '/etc/ssl/registrar.key',
));

$client->login();

$results = $client->domain->check(['example.ua', 'example2.ua']);
foreach ($results as $r) {
    printf("%s -> %s%s\n", $r->name, $r->available ? 'free' : 'taken',
        $r->reason ? " ({$r->reason})" : '');
}

$client->contact->create(new ContactCreate(
    id: 'CT-EXAMPLE',
    postalInfo: [
        new PostalInfo(
            type: PostalType::International,
            name: 'John Doe',
            address: new Address(
                street: ['10 Khreshchatyk St'],
                city: 'Kyiv',
                countryCode: 'UA',
                postalCode: '01001',
            ),
        ),
    ],
    email: 'john@example.com',
    authInfo: new AuthInfo('contact-secret'),
));

$client->domain->create(new DomainCreate(
    name: 'example.ua',
    registrant: 'CT-EXAMPLE',
    period: new Period(1),
    nameservers: [
        Nameserver::reference('ns1.example.com'),
        Nameserver::reference('ns2.example.com'),
    ],
    contacts: [
        new DomainContact('CT-EXAMPLE', ContactType::Admin),
        new DomainContact('CT-EXAMPLE', ContactType::Tech),
    ],
    authInfo: new AuthInfo('domain-secret'),
    license: 'A0000000', // optional uaepp:license extension
));

$client->logout();
```

Architecture
------------

[](#architecture)

```
Hostmaster\Ua
├── Client                  Facade — connects services with a Session
├── Config                  Readonly connection / login config
├── Session                 Owns a Connection; runs login/logout/dispatch
├── Connection
│   ├── Connection          Transport interface
│   └── SocketConnection    TLS stream socket, length-prefixed frames
├── Protocol
│   ├── Namespaces          XML namespace constants
│   ├── XmlBuilder          Build EPP request frames (DOM-based)
│   ├── XmlParser           Parse server  envelopes
│   ├── EppResponse         Successful response with raw DOM + xpath
│   ├── ResultCode          enum: every EPP 1xxx/2xxx code
│   ├── Hydrator            DOM → DTO conversion
│   └── TridGenerator       clTRID strategy (default = random)
├── Service
│   ├── DomainService       check/info/create/update/delete/renew/transfer + RGP restore
│   ├── ContactService     check/info/create/update/delete/transfer*
│   ├── HostService         check/info/create/update/delete (+ uaepp force delete)
│   ├── PollService         poll request/ack
│   └── BalanceService      balance:info
├── Notification
│   └── EmailNotificationParser  Parses notify@epp.hostmaster.ua emails
├── Logging
│   ├── Redactor            Stateless secret stripping for any string
│   └── RedactingLogger     PSR-3 decorator that redacts on the way through
├── Model                   Readonly DTOs (DomainInfo, ContactInfo, EmailNotification, …)
├── Enum                    PostalType, ContactType, IpVersion, TransferOp, EmailTemplate, …
└── Exception               Hierarchy keyed on EPP result codes

```

Exception handling
------------------

[](#exception-handling)

Every 2xxx response is thrown as a typed exception. Catch the specific class you care about, fall back to `EppException` for everything else, and `HostmasterException` for any failure originating in this library:

```
use Hostmaster\Ua\Exception\AuthenticationException;
use Hostmaster\Ua\Exception\BillingException;
use Hostmaster\Ua\Exception\ObjectExistsException;
use Hostmaster\Ua\Exception\ObjectNotFoundException;
use Hostmaster\Ua\Exception\EppException;
use Hostmaster\Ua\Exception\ConnectionException;

try {
    $client->login();
    $client->domain->create($req);
} catch (AuthenticationException $e) {
    // 2200/2501 — bad credentials
} catch (ObjectExistsException $e) {
    // 2302 — domain already registered
} catch (BillingException $e) {
    // 2104 — registrar balance is negative
} catch (EppException $e) {
    // any other 2xxx — inspect $e->resultCode, $e->reasons, $e->svTRID
} catch (ConnectionException $e) {
    // network/TLS failure
}
```

The exception classes correspond to result-code groups defined in [`src/Protocol/ResultCode.php`](src/Protocol/ResultCode.php) and mapped in [`src/Exception/EppException.php`](src/Exception/EppException.php).

Logging &amp; secret redaction
------------------------------

[](#logging--secret-redaction)

Pass any PSR-3 `LoggerInterface` as the second argument to `new Client(...)`. Wire frames are logged at `debug` level. Sensitive fields (``, ``, ``, ``, ``, ``) are **redacted by default** before they ever reach the logger — your handler sees `*****`, while your application code still receives the real password as a string when you build a request or read a response.

```
$client = new Client($config, new \Monolog\Logger('epp'));
```

### Standalone redaction (no logger needed)

[](#standalone-redaction-no-logger-needed)

`Redactor` is framework-agnostic — call it from anywhere you want to store or display EPP XML safely (DB columns, support tickets, audit trails):

```
use Hostmaster\Ua\Logging\Redactor;

$db->insert('epp_audit', [
    'trid' => $svTRID,
    'request' => Redactor::redact($requestXml),
    'response' => Redactor::redact($responseXml),
]);
```

Add custom rules for your own extension fields:

```
$customPatterns = array_merge(Redactor::defaultPatterns(), [
    '/()([^info('paying invoice', ['xml' => $rawXml]); // 'xml' value is sanitised on its way out
```

The wrapper redacts the message string and every string-valued context field, recursively. Non-string context values pass through untouched.

Polling messages
----------------

[](#polling-messages)

```
while (($msg = $client->poll->request()) !== null) {
    echo "[{$msg->id}] {$msg->message}\n";
    // $msg->response gives access to  /  for typed parsing
    $client->poll->acknowledge($msg->id);
}
```

Email notifications
-------------------

[](#email-notifications)

The registry mirrors poll messages over email (`From: notify@epp.hostmaster.ua`, `X-Notifier: UAEPP-NOTIFY`, `X-Template: …`). `EmailNotificationParser` converts a raw RFC 5322 message — or already-split headers + body — into an `EmailNotification` value object with the operation, object type, name, and ROID extracted from the subject:

```
use Hostmaster\Ua\Notification\EmailNotificationParser;
use Hostmaster\Ua\Enum\EmailTemplate;

$notification = EmailNotificationParser::parseRaw($rawEmail);

if ($notification->template === EmailTemplate::ObjectNew
    && $notification->objectType === 'DOMAIN') {
    $repo->markCreated($notification->objectName, $notification->roid);
}

// Or when your MTA already gave you an array of headers (e.g. from a webhook):
$n = EmailNotificationParser::fromHeaders($headersArray, $body);

// Sanity check before parsing:
if (EmailNotificationParser::isRegistryNotification($headersArray)) {
    // … process …
}
```

`EmailTemplate` covers every documented `X-Template` value (object created/changed/deleted, transfer requested/completed/cancelled/rejected, RGP, pending delete, host unlinked, contract events, balance reports, DNSSEC checks, etc.). Unknown values fall back to `EmailTemplate::Unknown`so the parser stays forward-compatible.

Hostmaster.ua extensions
------------------------

[](#hostmasterua-extensions)

- `uaepp:license` — passed via `DomainCreate::$license` / `DomainUpdate::$license`
- `uaepp:deleteNS confirm="yes"` — `HostService::delete($name, force: true)`
- `rgp:restore op="request"` — `DomainService::restoreRequest($name)`

Examples
--------

[](#examples)

The [`examples/`](examples/) directory contains a runnable script for every EPP command, mirroring the structure of the official Hostmaster.ua documentation. See [`examples/README.md`](examples/README.md) for a one-to-one mapping of registry doc pages to library calls.

```
export UAEPP_USER=my-registrar
export UAEPP_PASS=secret
php examples/session.php
php examples/domain.php
php examples/contact.php
php examples/host.php
php examples/poll.php
php examples/balance.php
php examples/notifications-email.php
php examples/logging-redaction.php
php examples/error-handling.php
php examples/end-to-end.php
```

Development
-----------

[](#development)

```
composer install
composer test
composer phpstan
composer cs-fix
```

License
-------

[](#license)

MIT — see [LICENSE](LICENSE).

###  Health Score

41

—

FairBetter than 87% of packages

Maintenance94

Actively maintained with recent releases

Popularity8

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity47

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~12 days

Total

2

Last Release

29d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/38e80478ca807c2854ddd993b28db35cdac7d57fb4887dc9f571f545d46ae62c?d=identicon)[hostmaster](/maintainers/hostmaster)

---

Top Contributors

[![hostmaster-direct](https://avatars.githubusercontent.com/u/280488825?v=4)](https://github.com/hostmaster-direct "hostmaster-direct (2 commits)")

---

Tags

domainregistryuaregistrarepphostmaster

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/hostmaster-ua/health.svg)

```
[![Health](https://phpackages.com/badges/hostmaster-ua/health.svg)](https://phpackages.com/packages/hostmaster-ua)
```

###  Alternatives

[ecotone/ecotone

Enterprise architecture layer for Laravel and Symfony — CQRS, Event Sourcing, Durable Workflows (Sagas, Orchestrators), Projections, and Outbox messaging via PHP attributes.

562565.8k41](/packages/ecotone-ecotone)[civicrm/civicrm-core

Open source constituent relationship management for non-profits, NGOs and advocacy organizations.

744284.3k34](/packages/civicrm-civicrm-core)[struzik-vladislav/epp-client

PHP library for communicating with EPP(Extensible Provisioning Protocol) servers

1915.2k12](/packages/struzik-vladislav-epp-client)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
