Skip to content

Commit d0006e2

Browse files
committed
Initial commit
0 parents  commit d0006e2

46 files changed

Lines changed: 2393 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
concurrency:
10+
group: ${{ github.workflow }}-${{ github.ref }}
11+
cancel-in-progress: true
12+
13+
permissions:
14+
contents: read
15+
16+
jobs:
17+
test:
18+
name: PHP ${{ matrix.php-version }}
19+
runs-on: ubuntu-latest
20+
strategy:
21+
fail-fast: false
22+
matrix:
23+
php-version: ["8.2", "8.3", "8.4"]
24+
25+
steps:
26+
- uses: actions/checkout@v6
27+
28+
- name: Set up PHP ${{ matrix.php-version }}
29+
uses: shivammathur/setup-php@v2
30+
with:
31+
php-version: ${{ matrix.php-version }}
32+
coverage: xdebug
33+
34+
- name: Install dependencies
35+
run: composer install --no-interaction --prefer-dist
36+
37+
- name: Lint
38+
run: ./vendor/bin/pint --test
39+
40+
- name: Static analysis
41+
run: ./vendor/bin/phpstan analyse
42+
43+
- name: Run tests
44+
run: ./vendor/bin/pest

.github/workflows/release.yml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*"
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
test:
13+
name: Test (PHP ${{ matrix.php-version }})
14+
runs-on: ubuntu-latest
15+
strategy:
16+
fail-fast: true
17+
matrix:
18+
php-version: ["8.2", "8.4"]
19+
20+
steps:
21+
- uses: actions/checkout@v6
22+
23+
- name: Set up PHP ${{ matrix.php-version }}
24+
uses: shivammathur/setup-php@v2
25+
with:
26+
php-version: ${{ matrix.php-version }}
27+
28+
- name: Install dependencies
29+
run: composer install --no-interaction --prefer-dist
30+
31+
- name: Lint
32+
run: ./vendor/bin/pint --test
33+
34+
- name: Static analysis
35+
run: ./vendor/bin/phpstan analyse
36+
37+
- name: Run tests
38+
run: ./vendor/bin/pest
39+
40+
release:
41+
name: Release
42+
needs: test
43+
runs-on: ubuntu-latest
44+
45+
steps:
46+
- uses: actions/checkout@v6
47+
48+
- name: Create GitHub Release
49+
uses: softprops/action-gh-release@v2
50+
with:
51+
generate_release_notes: true

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/vendor/
2+
composer.lock
3+
.phpstan-cache/
4+
.php-cs-fixer.cache
5+
.phpunit.result.cache
6+
/coverage/
7+
.DS_Store
8+
.idea/
9+
.vscode/

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 rdapapi.io
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

Makefile

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
.PHONY: test test-coverage lint format analyse clean
2+
3+
test:
4+
./vendor/bin/pest
5+
6+
test-coverage:
7+
./vendor/bin/pest --coverage
8+
9+
lint:
10+
./vendor/bin/pint --test
11+
12+
format:
13+
./vendor/bin/pint
14+
15+
analyse:
16+
./vendor/bin/phpstan analyse
17+
18+
clean:
19+
rm -rf vendor .phpstan-cache coverage

README.md

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
# rdapapi-php
2+
3+
Official PHP SDK for the [RDAP API](https://rdapapi.io) — look up domains, IP addresses, ASNs, nameservers, and entities via the RDAP protocol.
4+
5+
[![Packagist Version](https://img.shields.io/packagist/v/rdapapi/rdapapi-php.svg)](https://packagist.org/packages/rdapapi/rdapapi-php)
6+
[![PHP Version](https://img.shields.io/packagist/php-v/rdapapi/rdapapi-php.svg)](https://packagist.org/packages/rdapapi/rdapapi-php)
7+
[![CI](https://github.com/rdapapi/rdapapi-php/actions/workflows/ci.yml/badge.svg)](https://github.com/rdapapi/rdapapi-php/actions/workflows/ci.yml)
8+
9+
## Installation
10+
11+
```bash
12+
composer require rdapapi/rdapapi-php
13+
```
14+
15+
Requires PHP 8.2 or later.
16+
17+
## Quick Start
18+
19+
```php
20+
<?php
21+
22+
use RdapApi\RdapApi;
23+
24+
$api = new RdapApi('your-api-key');
25+
26+
$domain = $api->domain('google.com');
27+
28+
echo $domain->registrar->name; // "MarkMonitor Inc."
29+
echo $domain->dates->registered; // "1997-09-15T04:00:00Z"
30+
echo $domain->dates->expires; // "2028-09-14T04:00:00Z"
31+
print_r($domain->nameservers); // ["ns1.google.com", ...]
32+
```
33+
34+
## Usage
35+
36+
### Configuration
37+
38+
```php
39+
use RdapApi\RdapApi;
40+
41+
// Default configuration
42+
$api = new RdapApi('your-api-key');
43+
44+
// Custom timeout (in seconds)
45+
$api = new RdapApi('your-api-key', ['timeout' => 10]);
46+
47+
// Custom base URL
48+
$api = new RdapApi('your-api-key', ['base_url' => 'https://custom.api.com/v1']);
49+
```
50+
51+
### Domain Lookup
52+
53+
```php
54+
$domain = $api->domain('example.com');
55+
echo $domain->domain; // "example.com"
56+
echo $domain->registrar->name; // Registrar name
57+
echo $domain->registrar->iana_id; // IANA registrar ID
58+
echo $domain->dnssec; // true/false
59+
60+
// With registrar follow-through (for thin registries)
61+
$domain = $api->domain('example.com', ['follow' => true]);
62+
echo $domain->meta->followed; // true
63+
```
64+
65+
### IP Address Lookup
66+
67+
```php
68+
$ip = $api->ip('8.8.8.8');
69+
echo $ip->name; // "LVLT-GOGL-8-8-8"
70+
echo $ip->country; // "US"
71+
print_r($ip->cidr); // ["8.8.8.0/24"]
72+
echo $ip->start_address; // "8.8.8.0"
73+
echo $ip->end_address; // "8.8.8.255"
74+
```
75+
76+
### ASN Lookup
77+
78+
```php
79+
$asn = $api->asn(15169); // integer
80+
$asn = $api->asn('AS15169'); // string with prefix (stripped automatically)
81+
82+
echo $asn->name; // "GOOGLE"
83+
echo $asn->start_autnum; // 15169
84+
```
85+
86+
### Nameserver Lookup
87+
88+
```php
89+
$ns = $api->nameserver('ns1.google.com');
90+
echo $ns->ldh_name; // "ns1.google.com"
91+
print_r($ns->ip_addresses->v4); // ["216.239.32.10"]
92+
print_r($ns->ip_addresses->v6); // ["2001:4860:4802:32::a"]
93+
```
94+
95+
### Entity Lookup
96+
97+
```php
98+
$entity = $api->entity('GOGL');
99+
echo $entity->name; // "Google LLC"
100+
echo $entity->organization; // "Google LLC"
101+
echo $entity->autnums[0]->handle; // "AS15169"
102+
echo $entity->networks[0]->cidr[0]; // "8.8.8.0/24"
103+
```
104+
105+
### Bulk Domain Lookup
106+
107+
Requires a Pro or Business plan. Up to 10 domains per call.
108+
109+
```php
110+
$resp = $api->bulkDomains(
111+
['google.com', 'github.com', 'example.com'],
112+
['follow' => true],
113+
);
114+
115+
echo $resp->summary->total; // 3
116+
echo $resp->summary->successful; // 3
117+
118+
foreach ($resp->results as $result) {
119+
if ($result->status === 'success') {
120+
echo "{$result->domain} — {$result->data->registrar->name}\n";
121+
} else {
122+
echo "{$result->domain} — error: {$result->message}\n";
123+
}
124+
}
125+
```
126+
127+
## Error Handling
128+
129+
All API errors are thrown as typed exceptions that extend `RdapApiException`:
130+
131+
```php
132+
use RdapApi\Exceptions\AuthenticationException;
133+
use RdapApi\Exceptions\NotFoundException;
134+
use RdapApi\Exceptions\RateLimitException;
135+
use RdapApi\Exceptions\SubscriptionRequiredException;
136+
137+
try {
138+
$domain = $api->domain('example.com');
139+
} catch (NotFoundException $e) {
140+
echo "Not found: {$e->getMessage()}";
141+
} catch (RateLimitException $e) {
142+
echo "Rate limited, retry after {$e->retryAfter} seconds";
143+
} catch (AuthenticationException $e) {
144+
echo "Invalid API key";
145+
} catch (SubscriptionRequiredException $e) {
146+
echo "Subscription required";
147+
}
148+
```
149+
150+
| Exception | HTTP Status | Description |
151+
|---|---|---|
152+
| `ValidationException` | 400 | Invalid input |
153+
| `AuthenticationException` | 401 | Invalid or missing API key |
154+
| `SubscriptionRequiredException` | 403 | No active subscription |
155+
| `NotFoundException` | 404 | No RDAP data found |
156+
| `RateLimitException` | 429 | Rate limit or quota exceeded |
157+
| `UpstreamException` | 502 | Upstream RDAP server failure |
158+
159+
All exceptions expose `statusCode`, `errorCode`, and `getMessage()`. `RateLimitException` also has `retryAfter` (int or null).
160+
161+
## Nullable Fields
162+
163+
Fields that may be absent in API responses use nullable types (`?string`, `?int`). Check for null before using:
164+
165+
```php
166+
if ($domain->dates->expires !== null) {
167+
echo "Expires: {$domain->dates->expires}";
168+
}
169+
170+
// Or use PHP 8's nullsafe operator
171+
echo $domain->entities->registrant?->name;
172+
```
173+
174+
## License
175+
176+
MIT — see [LICENSE](LICENSE).

composer.json

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
{
2+
"name": "rdapapi/rdapapi-php",
3+
"description": "Official PHP SDK for the RDAP API — look up domains, IPs, ASNs, nameservers, and entities via RDAP.",
4+
"type": "library",
5+
"license": "MIT",
6+
"keywords": ["rdap", "whois", "domain", "ip", "asn", "dns", "api", "nameserver", "entity"],
7+
"authors": [
8+
{
9+
"name": "RDAP API",
10+
"email": "support@rdapapi.io",
11+
"homepage": "https://rdapapi.io"
12+
}
13+
],
14+
"homepage": "https://rdapapi.io",
15+
"require": {
16+
"php": "^8.2",
17+
"guzzlehttp/guzzle": "^7.0"
18+
},
19+
"require-dev": {
20+
"laravel/pint": "^1.0",
21+
"pestphp/pest": "^3.0",
22+
"phpstan/phpstan": "^2.0"
23+
},
24+
"autoload": {
25+
"psr-4": {
26+
"RdapApi\\": "src/"
27+
}
28+
},
29+
"autoload-dev": {
30+
"psr-4": {
31+
"RdapApi\\Tests\\": "tests/"
32+
}
33+
},
34+
"scripts": {
35+
"test": "pest",
36+
"test:coverage": "pest --coverage",
37+
"lint": "pint --test",
38+
"format": "pint",
39+
"analyse": "phpstan analyse"
40+
},
41+
"config": {
42+
"sort-packages": true,
43+
"allow-plugins": {
44+
"pestphp/pest-plugin": true
45+
}
46+
},
47+
"minimum-stability": "stable",
48+
"prefer-stable": true
49+
}

0 commit comments

Comments
 (0)