PHPackages                             centralnic-reseller/php-sdk - 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. [API Development](/categories/api)
4. /
5. centralnic-reseller/php-sdk

ActiveLibrary[API Development](/categories/api)

centralnic-reseller/php-sdk
===========================

API connector library for the insanely fast Team Internet Backend APIs (CentralNic Reseller, Internet.bs, Moniker)

v27.0.0(2w ago)544.6k↓13.6%2[1 PRs](https://github.com/centralnicgroup-opensource/rtldev-middleware-php-sdk/pulls)1MITPHPPHP &gt;=8.3.0CI passing

Since Dec 9Pushed 5d ago3 watchersCompare

[ Source](https://github.com/centralnicgroup-opensource/rtldev-middleware-php-sdk)[ Packagist](https://packagist.org/packages/centralnic-reseller/php-sdk)[ Docs](https://centralnicgroup-opensource.github.io/rtldev-middleware-php-sdk/)[ RSS](/packages/centralnic-reseller-php-sdk/feed)WikiDiscussions master Synced 2w ago

READMEChangelog (10)Dependencies (59)Versions (126)Used By (1)

php-sdk
=======

[](#php-sdk)

[![semantic-release](https://camo.githubusercontent.com/5f3b57745af83409bc673dec57e3eb360e1ec53b37ac29f81a319e347fa351c6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2532302532302546302539462539332541362546302539462539412538302d73656d616e7469632d2d72656c656173652d6531303037392e737667)](https://github.com/semantic-release/semantic-release)[![Build Status](https://github.com/centralnicgroup-opensource/rtldev-middleware-php-sdk/workflows/Release/badge.svg?branch=master)](https://github.com/centralnicgroup-opensource/rtldev-middleware-php-sdk/workflows/Release/badge.svg?branch=master)[![Packagist](https://camo.githubusercontent.com/474ab1dd423746e8c911400a06bc7bc47f16f66449e099c712b590815acbac4b/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f63656e7472616c6e69632d726573656c6c65722f7068702d73646b2e737667)](https://packagist.org/packages/centralnic-reseller/php-sdk)[![PHP from Packagist](https://camo.githubusercontent.com/df757a24f1f28f1379d4768fd02447d07b79a4b6b2b1a7dcb7d70b649b4f8599/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f63656e7472616c6e69632d726573656c6c65722f7068702d73646b2e737667)](https://packagist.org/packages/centralnic-reseller/php-sdk)[![License: MIT](https://camo.githubusercontent.com/08cef40a9105b6526ca22088bc514fbfdbc9aac1ddbf8d4e6c750e3a88a44dca/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d626c75652e737667)](https://opensource.org/licenses/MIT)[![PRs welcome](https://camo.githubusercontent.com/dd0b24c1e6776719edb2c273548a510d6490d8d25269a043dfabbd38419905da/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5052732d77656c636f6d652d627269676874677265656e2e737667)](https://github.com/centralnicgroup-opensource/rtldev-middleware-php-sdk/blob/master/CONTRIBUTING.md)[![codecov](https://camo.githubusercontent.com/2093351e2829a7b95fda45fd6d0f99ef0ae730668bcebf05c14b6d5c81935846/68747470733a2f2f636f6465636f762e696f2f67682f63656e7472616c6e696367726f75702d6f70656e736f757263652f72746c6465762d6d6964646c65776172652d7068702d73646b2f67726170682f62616467652e737667)](https://codecov.io/gh/centralnicgroup-opensource/rtldev-middleware-php-sdk)

This module is a connector library for the insanely fast CNIC Backend APIs (CentralNic Reseller, internet.bs, moniker). Do not hesitate to contact us in case of questions.

Resources
---------

[](#resources)

- Documentation Links (PHP-SDK internal registrar id available in round brackets):
    - [CentralNic Reseller (CNR)](https://support.centralnicreseller.com/hc/en-gb/articles/13513253776285-Self-Development-Kit-for-PHP)
    - [Internet.bs (IBS)](https://faq.internetbs.net/hc/en-gb/articles/24953916500381-Self-Development-Kit-for-PHP)
    - [Moniker (MONIKER)](https://support.moniker.com/hc/en-gb/articles/24954146333981-Self-Development-Kit-for-PHP)
- [Release Notes](https://github.com/centralnicgroup-opensource/rtldev-middleware-php-sdk/releases)
- [Migration Guide](https://github.com/centralnicgroup-opensource/rtldev-middleware-php-sdk/blob/master/MIGRATION.md) — how to upgrade across major versions

Usage
-----

[](#usage)

```
composer require centralnic-reseller/php-sdk
```

Idiomatic code for the **current** major, whatever that is when you read this — this section is kept up to date rather than pinned to the version that introduced the factory:

```
use CNIC\ClientFactory;

// --- CNR (CentralNic Reseller, fka RRPproxy) ---
$cl = ClientFactory::cnr();                // returns a fully-typed CNR\SessionClient
$cl->useOTESystem()                        // omit for LIVE (the default)
   ->setCredentials($user, $password);     // or ->setRoleCredentials($acct, $role, $pw)
// CNR has one fixed script path, so request() defaults it — pass a command only.
$r = $cl->request(["COMMAND" => "StatusAccount"]);
if ($r->isSuccess()) {
    print_r($r->getHash());
}
$cl->close();                              // release the cached cURL handle

// --- IBS / Moniker (JSON API) ---
$cl = ClientFactory::ibs();                // or ClientFactory::moniker()
$cl->useOTESystem()->setCredentials($user, $password);
// This platform exposes many endpoints under one host and the *path* selects the
// operation, so pass it as the second argument — there is no default that works.
$r = $cl->request(["domain" => "example.com"], "Domain/Check");
if ($r->isSuccess()) {
    print_r($r->getHash());
}
$cl->close();
```

Two brand differences the snippet is deliberately explicit about:

- **The `$path` argument.** `request(array $cmd = [], string $path = "")` is symmetric across all brands, but only CNR has a meaningful default (`api/call.cgi`). On IBS/Moniker the path *is* the operation, so omitting it sends the request to the bare host.
- **Sessions and role logins are CNR-only, by type.** `login()`, `logout()`, `saveSession()`, `getSession()`/`setSession()` and `setRoleCredentials()` exist on the CNR client and **do not exist** on `IBS\Client`/`MONIKER\Client` — calling one is a static-analysis error at the call site, not a runtime surprise. See [Migration Guide → v22.0.0](https://github.com/centralnicgroup-opensource/rtldev-middleware-php-sdk/blob/master/MIGRATION.md#-v2200).

**Type against the interfaces, not the concrete classes.** Depending on `CNIC\ResponseInterface`, `CNIC\ColumnInterface`, `CNIC\RecordInterface` and `CNIC\LoggerInterface` is what keeps future majors from breaking you; code that reaches for `CNIC\CNR\Response` or uses `method_exists()` fallbacks is what does not survive them.

### Reading the rows of a list response

[](#reading-the-rows-of-a-list-response)

A response is fully assembled by the time you hold one, and read-only from then on. Walk its records with `foreach` — the response is iterable — or address them by index:

```
$r = $cl->request(["COMMAND" => "QueryDomainList", "LIMIT" => "100"]);

foreach ($r as $index => $rec) {
    echo $index, ": ", $rec->getStringByKey("DOMAIN"), "\n";
}

$r->getRecord(0);           // ?RecordInterface — by index, or null if out of range
$r->getRecords();           // RecordInterface[] — the whole list
$r->getColumn("DOMAIN");    // ?ColumnInterface — column-wise instead of row-wise
$r->getPagination();        // COUNT / FIRST / LAST / LIMIT / TOTAL / PAGES / …
```

**Ask for the type you want.** `getDataByKey()`/`getDataByIndex()` return `mixed`, because an IBS/Moniker cell may legitimately carry a nested array or object. When you expect a plain value, the typed accessors save you the check — each returns `null` for a missing key, an out-of-range index, or a value of the wrong type, so there is nothing to narrow by hand and no annotation to write:

```
$name   = $rec->getStringByKey("DOMAIN");             // ?string
$expiry = $rec->getDateTimeByKey("expirationdate");   // ?ApiDateTime

$name   = $r->getColumn("DOMAIN")?->getStringByIndex(0);   // same, by column
```

`foreach` keeps its position in the loop rather than on the response, so iterating is repeatable, needs no rewind step, and two places iterating the same response cannot interfere. If you are coming from a version with `getNextRecord()`/`rewindRecordList()`, see [Migration Guide → v31.0.0](https://github.com/centralnicgroup-opensource/rtldev-middleware-php-sdk/blob/master/MIGRATION.md#-v3100).

### Debug output

[](#debug-output)

`enableDebugMode()` writes one record per request to standard output. Two seams let you take it somewhere else, and they are independent:

```
use CNIC\LogSinkInterface;

// 1. Keep the brand's format, change the destination.
final class FileSink implements LogSinkInterface
{
    public function __construct(private readonly string $path) {}

    public function write(string $message): void
    {
        file_put_contents($this->path, $message . PHP_EOL, FILE_APPEND);
    }
}

$cl->enableDebugMode()->setLogSink(new FileSink("/var/log/cnic.log"));

// 2. Change the format too: extend CNIC\AbstractLogger and implement one
//    method — the sink wiring comes with it.
final class MyLogger extends \CNIC\AbstractLogger
{
    #[\Override]
    public function format(string $post, \CNIC\ResponseInterface $response, ?string $error = null): string
    {
        return sprintf("[%d] %s\n", $response->getCode(), $post);
    }
}

$cl->setCustomLogger(new MyLogger(new FileSink("/var/log/cnic.log")));
```

Order matters between the two: `setLogSink()` rebuilds the **brand** logger around your sink, so call it before `setCustomLogger()`, not after.

`LoggerInterface::format()` **returns** the record rather than printing it, so you can route SDK debug output into your own logging without reimplementing a brand's format — and assert on it in your own tests without output buffering. Sensitive command values (`PASSWORD`, `AUTH`, `transferAuthInfo`) are already masked before they reach the formatter.

### Testing your integration offline

[](#testing-your-integration-offline)

Nothing in the request lifecycle needs a network. `setTransport()` swaps the cURL layer for anything implementing `CNIC\TransportInterface`, so you can hand the client a canned API response and still exercise the real command building, parsing and logging:

```
use CNIC\TransportInterface;

final class CannedTransport implements TransportInterface
{
    public function __construct(private readonly string $raw) {}

    /**
     * @param array $options
     * @return array{0: string, 1: string|null}
     */
    public function post(string $url, string $data, int $timeoutSeconds, string $userAgent, array $options = []): array
    {
        return [$this->raw, null]; // element [1] is the transport error; non-null means [0] is unusable
    }

    public function close(): void {}
}

$cl->setTransport(new CannedTransport("[RESPONSE]\r\nCODE=200\r\nDESCRIPTION=Command completed successfully\r\nEOF\r\n"));
$r = $cl->request(["COMMAND" => "StatusAccount"]); // no network touched
```

Each of the client's three collaborators has a matching reader, so your own tests can assert the wiring took effect rather than reaching into the client: `getTransport()`, `getLogger()` and `getSocketConfig()`. That is how you confirm a custom logger survived the `setLogSink()`/`setCustomLogger()` ordering rule above, or that the transport double is the one in place:

```
$transport = new CannedTransport($raw);
assert($cl->setTransport($transport)->getTransport() === $transport);
assert($cl->setCustomLogger($myLogger)->getLogger() === $myLogger);
```

For working, runnable examples per brand — including the CNR session flow (`saveSession()`/`reuseSession()` across two stateless requests) — see [`examples/app_CNR.php`](https://github.com/centralnicgroup-opensource/rtldev-middleware-php-sdk/blob/master/examples/app_CNR.php), [`examples/app_IBS.php`](https://github.com/centralnicgroup-opensource/rtldev-middleware-php-sdk/blob/master/examples/app_IBS.php) and [`examples/app_MONIKER.php`](https://github.com/centralnicgroup-opensource/rtldev-middleware-php-sdk/blob/master/examples/app_MONIKER.php). Those are not part of the Composer package — clone the repository to run them, as described under [Running the Demo Application](#running-the-demo-application).

Date &amp; time values
----------------------

[](#date--time-values)

The APIs declare their date columns in **UTC** and emit two shapes: a full timestamp (`2026-07-25 07:46:34`, optionally with a fractional-second part, as CNR sends) and a bare calendar date (`2030/07/17`, as internet.bs/Moniker send). `CNIC\ApiDateTime` parses both into one flat, immutable struct, and accepts **either** `-` or `/` as the date separator — consistently within one value, so `2026-02/20` is refused. `$date`/`$dateTime` always come back with `-`, regardless of which one the source used:

```
use CNIC\ApiDateTime;

$dt = ApiDateTime::from("2026-07-25 07:46:34");
$dt->ts;             // 1784965594
$dt->date;           // "2026-07-25"
$dt->dateTime;       // "2026-07-25 07:46:34"
$dt->tz;             // "UTC"
$dt->raw;            // "2026-07-25 07:46:34" — the input, verbatim
$dt->isDateOnly();   // false
$dt->toArray();      // ready for json_encode()
```

FieldTypeCNR `2026-07-25 07:46:34`internet.bs / Moniker `2030/07/17``ts``int|null``1784965594`**`null`** — exact instant unknown`date``string``2026-07-25``2030-07-17` — always `-`, even here`dateTime``string|null``2026-07-25 07:46:34`**`null`**`tz``string``UTC``UTC``raw``string``2026-07-25 07:46:34``2030/07/17` — verbatim inputA bare calendar date names no instant, so `ts` and `dateTime` are **both null** for one — deliberately, rather than defaulting to midnight, which would be a fabricated instant indistinguishable from a real one. `date` is always populated, so there is unconditionally something to print; `$dt->ts === null` (or `isDateOnly()`) is the unambiguous test.

`raw` keeps whatever the source sent, including a fractional-second part `dateTime` discards. It is for display, logging and round-trip fidelity only — **compare and sort on `ts` or `date`, never on `raw`**, since `"2026/02/20"` sorts wrong against `"2026-03-01"` as plain strings.

Parsing is strict. Values PHP's own date handling would silently roll over into a *different* instant — `2026-02-30` becoming `2026-03-02`, `2026-13-45` becoming `2027-02-14`, `0000-00-00` becoming `-0001-11-30` — are refused with a `CNIC\Exception\InvalidDateTimeException`, as are offset-bearing values (never silently relabelled UTC). Use `ApiDateTime::tryFrom()` when a `null` is preferable to an exception:

```
ApiDateTime::tryFrom(null);          // null
ApiDateTime::tryFrom("2026-02-30");  // null — refused, not coerced
```

Note

This is a **parser, not a formatter**. Responses are not rewritten: `getPlain()`, `getHash()` and `getListHash()` keep returning the raw API strings verbatim — internet.bs/Moniker dates keep their `/` separator — and this type is opt-in at the point where a value is actually used. There is no locale formatting and no `ext-intl` dependency — presenting a value in the viewer's timezone is a display concern for the consuming application:

```
(new \DateTimeImmutable("@{$dt->ts}"))->setTimezone(new \DateTimeZone("Europe/Berlin"));
```

`CNIC\Record::getDateTimeByKey()` and `CNIC\Column::getDateTimeByIndex()` do that narrowing for you, right where you already read a value — no `null` check on a non-string, missing, or unparsable value needed beyond the returned `?ApiDateTime` itself:

```
$rec = $response->getRecord(0);
$expiry = $rec?->getDateTimeByKey("expirationdate"); // ?ApiDateTime — works for "-" or "/" input
$expiry?->date;       // "2030-07-17"
$expiry?->isDateOnly(); // true

$col = $response->getColumn("expirationdate");
$col?->getDateTimeByIndex(0); // same parsing, by column index instead of record key
```

Run `composer demo:datetime` for a runnable tour — it needs no credentials and makes no API calls.

Dev Container
-------------

[](#dev-container)

If you want to contribute, we recommend using Visual Studio Code and to follow the below setup instructions:

- Add an entry in your hosts file: `127.0.0.1         devsdk.centralnicreseller.net`

PHP SDK Data can be accessed via apache server at this url: `http://devsdk.centralnicreseller.net`

### Environment variables (`env.sh`)

[](#environment-variables-envsh)

The devcontainer looks for an `env.sh` file in the workspace root and **automatically sources it** in two places:

1. **Every new integrated-terminal session** — the file is sourced via `~/.zshenv` so credentials are available as soon as you open a terminal, without a manual `source env.sh`.
2. **PHPUnit runs triggered from the VSCode UI** — the PHPUnit wrapper script sources `env.sh` before invoking PHP, so IDE-triggered tests see the same variables as `composer test` does from the terminal.

`env.sh` is listed in `.gitignore` and will never be committed. Create it once in the workspace root with the variables you need — copy [`env.example.sh`](https://github.com/centralnicgroup-opensource/rtldev-middleware-php-sdk/blob/master/env.example.sh) as a starting point.

Note

The auto-loading takes effect for **new** terminal sessions. If your terminal was already open when you created or updated `env.sh`, run `source env.sh` once in that session or open a new terminal.

Running the Demo Application
----------------------------

[](#running-the-demo-application)

To run the demo application, follow these steps:

1. **Set your credentials** — create an `env.sh` in the workspace root (see [Environment variables (`env.sh`)](#environment-variables-envsh)), or replace the placeholders inside the demo file directly.
2. **Run the demo** for the brand you want:

    ```
    composer demo:cnr        # CentralNic Reseller  → examples/app_CNR.php
    composer demo:ibs        # internet.bs          → examples/app_IBS.php
    composer demo:moniker    # Moniker              → examples/app_MONIKER.php
    composer demo:datetime   # ApiDateTime parser   → examples/datetime.php (no credentials, no network)
    ```

    These are thin wrappers around plain PHP — edit the file listed on the right to change a demo, or run it directly without any tooling (`php -f examples/app_CNR.php`).

CI / Testing
------------

[](#ci--testing)

CI is powered by [reusable GitHub Actions workflows](https://github.com/centralnicgroup-opensource/rtldev-middleware-shareable-workflows). The test matrix covers:

PHP VersionStatus8.3✓8.4✓8.5✓The matrix is configured via the repository variable `RTLDEV_MW_CI_PHP_MATRIX` and tracks the **actively-maintained** PHP versions — new versions are added as they enter active support and dropped once they reach end-of-life.

Note

`composer.json` requires `php: >=8.3.0`, which sets the **minimum** only — the SDK runs on every version in the matrix above. Note that the source code itself is deliberately held to **PHP 8.3 language features** (Rector is pinned to 8.3) because the SDK also ships inside ionCube-encoded WHMCS integrations that cannot execute newer syntax. In short: runs on 8.3–8.5, but only *uses* 8.3-level language features. Full rationale: [PHP Version Policy](https://github.com/centralnicgroup-opensource/rtldev-middleware-php-sdk/blob/master/docs/agents/project-policies.md#php-version-policy).

Maintainers
-----------

[](#maintainers)

- **Kai Schwarz** - [KaiSchwarz-cnic](https://github.com/kaischwarz-cnic)
- **Asif Nawaz** - [AsifNawaz-cnic](https://github.com/AsifNawaz-cnic)

License
-------

[](#license)

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

###  Health Score

63

—

FairBetter than 99% of packages

Maintenance98

Actively maintained with recent releases

Popularity36

Limited adoption so far

Community21

Small or concentrated contributor base

Maturity83

Battle-tested with a long release history

 Bus Factor1

Top contributor holds 61.7% 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 ~17 days

Recently: every ~0 days

Total

101

Last Release

19d ago

Major Versions

v22.0.0 → v23.0.02026-07-28

v23.0.0 → v24.0.02026-07-29

v24.0.0 → v25.0.02026-07-29

v25.0.0 → v26.0.02026-07-29

v26.0.0 → v27.0.02026-07-30

PHP version history (4 changes)v7.0.0PHP &gt;=7.4.0

v7.1.8PHP &gt;=7.3.0

v7.1.9PHP ^7.3.0

v14.0.0PHP &gt;=8.3.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/49be2d560d7510481b53ee05f688295c79bf052b76da7a8c48c3a96c26999559?d=identicon)[centralnic-reseller](/maintainers/centralnic-reseller)

---

Top Contributors

[![KaiSchwarz-cnic](https://avatars.githubusercontent.com/u/229425?v=4)](https://github.com/KaiSchwarz-cnic "KaiSchwarz-cnic (429 commits)")[![semantic-release-bot](https://avatars.githubusercontent.com/u/32174276?v=4)](https://github.com/semantic-release-bot "semantic-release-bot (107 commits)")[![AsifNawaz-cnic](https://avatars.githubusercontent.com/u/107853964?v=4)](https://github.com/AsifNawaz-cnic "AsifNawaz-cnic (84 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (73 commits)")[![h9k](https://avatars.githubusercontent.com/u/1579124?v=4)](https://github.com/h9k "h9k (2 commits)")

---

Tags

apisdkdnssslconnectorapplicationregistrationdomainispresellercertpremiumbackorderpreregistrationcniccentralniccnrinternet.bsmoniker

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan, Psalm, Rector

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/centralnic-reseller-php-sdk/health.svg)

```
[![Health](https://phpackages.com/badges/centralnic-reseller-php-sdk/health.svg)](https://phpackages.com/packages/centralnic-reseller-php-sdk)
```

###  Alternatives

[corbanb/freebird-php

Twitter API v1.1 Application only authoization library

158.6k](/packages/corbanb-freebird-php)

PHPackages © 2026

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