Files
LittleBeast/src/Std/Lib/Openprovider.php
2026-04-27 23:00:14 +09:00

564 lines
19 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace Std\Lib;
use Std\Lib\Curl;
class Openprovider {
protected string $dataDir = ROOT."/data/cache/";
protected int $tokenDuration = 172800; // 48時間
protected int $dataDuration = 1800; // 30分
private string $user = '';
private string $pass = '';
private string $token = '';
private string $ip = '';
private int $resellerId = 0;
private int $lastAuth = 0;
private string $BASEURL = DEBUG_MODE ? 'http://api.sandbox.openprovider.nl:8480/v1beta'
: 'https://api.openprovider.eu/v1beta';
public function __construct() {
if (!OPENPROVIDER_ENABLED) return;
$this->user = OPENPROVIDER['username'];
$this->pass = OPENPROVIDER['password'];
$this->ip = OPENPROVIDER['ip'];
}
/***
* トークンの受け取り。
* このライブリリーを使ったら、一回「login()」を実行する事が必須となります。
*
* @return Result 結果
*/
public function login(): \Result {
if (!OPENPROVIDER_ENABLED) return \Result::error('エラーOpenProviderは無効です。');
$cache = $this->getCache('login');
if (time() < ($this->lastAuth + $this->tokenDuration)) {
$this->token = $cache['data']['token'];
$this->lastAuth = $cache['last_auth'];
return \Result::Success('', $cache);
}
$curl = new Curl("{$this->BASEURL}/auth/login");
$payload = [
'username' => $this->user,
'password' => $this->pass,
'ip' => $this->ip ?: '0.0.0.0',
];
$curl->setMethod("POST");
$curl->setPostRaw(json_encode($payload));
$curl->addHeader("Content-Type", "application/json");
$curl->addHeader("Accept", "application/json");
$res = $curl->execute();
if (!$res->isSuccess) {
$err = "CURLの実行に失敗 ".$curl->message;
assert_unless_success($res, $err);
return \Result::Error($err);
}
$body = $curl->getResponseBody();
if ($curl->getResponseCode() != 200) {
$err = json_decode($body, true);
assert_not_null($err, "エラーの受け取りに失敗。");
assert($curl->getResponseCode() == 200, $err['desc']);
return \Result::Error();
}
assert_not_null($body, "返事ボディーは空です。");
$res = json_decode($body, true);
if (isset($res['data']['token'])) {
$this->token = $res['data']['token'];
$this->lastAuth = time();
$res['last_auth'] = $this->lastAuth;
$this->setCache('login', $res);
return \Result::Success('', $res);
}
return \Result::Error('ログインに失敗。');
}
// カスタマー
// ドメイン
//// ドメイン
/***
* ドメイン一覧。
*
* @return Result 結果。
*/
public function listDomains(array $query = []): \Result {
if (!OPENPROVIDER_ENABLED) return \Result::error('エラーOpenProviderは無効です。');
$cache = $this->getCache('listdomains');
if ($this->isValidLifespan($cache, $query)) return \Result::Success('', $cache);
$curl = $this->setupCurl('/domains');
$res = $this->curlResult($curl);
if (isset($res['data']['results'])) {
$this->setCache('listdomains', $res->data);
return \Result::Success('', $res['data']['results']);
}
return \Result::Error('ドメインの確認に失敗。');
}
/**
* ドメイン名の登録。
*
* @param string $name 登録したいドメイン名(例:"076studio.jp"
* @param array $info カスタマー情報等
* @param int $period 年間(デフォルト=1年)
* @return Result 結果。配列の場合:'activation_date'(リアルタイムで成功したのみ), 'auth_code'TLDが対応している場合のみ, 'expiration_date', 'id', 'renewal_date', 'status'ACT又はREQ
*/
public function createDomain(string $name, array $info, int $period = 1): \Result {
if (!OPENPROVIDER_ENABLED) return \Result::error('エラーOpenProviderは無効です。');
if (!isset($info['owner_handle']) || $info['owner_handle'] === '') $info['owner_handle'] = OPENPROVIDER['owner_handle'];
if (!isset($info['admin_handle']) || $info['admin_handle'] === '') $info['admin_handle'] = OPENPROVIDER['owner_handle'];
if (!isset($info['tech_handle']) || $info['tech_handle'] === '') $info['tech_handle'] = OPENPROVIDER['owner_handle'];
if (!isset($info['billing_handle']) || $info['billing_handle'] === '') $info['billing_handle'] = OPENPROVIDER['owner_handle'];
if (!isset($info['reseller_handle']) || $info['reseller_handle'] === '') $info['reseller_handle'] = OPENPROVIDER['owner_handle'];
if (!isset($info['name_servers']) || empty($info['name_servers'])) $info['name_servers'] = ['ns1.openprovider.nl', 'ns2.openprovider.be', 'ns3.openprovider.eu'];
if (!isset($info['autorenew']) || $info['autorenew'] === '') $info['autorenew'] = 'default';
// 新しい顧客の場合
$parts = explode('.', $name, 2);
assert_exists($parts[0]);
assert_exists($parts[1]);
$domain = [
'name' => $parts[0],
'extension' => $parts[1],
];
$ns = [];
foreach ($info['name_servers'] as $n) {
$ns[] = ['name' => $n];
}
$payload = [
'name' => $domain,
'period' => $period,
'owner_handle' => $owner_handle,
'admin_handle' => $admin_handle,
'tech_handle' => $tech_handle,
'billing_handle' => $billing_handle,
'reseller_handle' => $reseller_handle,
'name_servers' => $ns,
'autorenew' => $autorenew,
];
$curl = $this->setupCurl('/domains/', 'POST', $payload);
kys('TODO');
$res = $this->curlResult($curl);
if (isset($res['data'])) return \Result::Success('', $res);
return \Result::Error('ドメインの確認に失敗。');
}
/***
* ドメインを登録可能かどうかの確認。
*
* @param array $domains ドメイン名リスト。例:['076.moe', '076.co.jp', '076.com']
* @param bool $with_price 値段を表示するかどうか。デフォルトは「false」
* @return Result 結果。配列の場合:'domain'と'status'はいつでもあり、'reason', 'premium', 'is_premium'が多分あり、そして'price'が「with_price」が「true」の場合のみ。
*/
public function checkDomainAvailable(array $domains, bool $with_price = false): \Result {
if (!OPENPROVIDER_ENABLED) return \Result::error('エラーOpenProviderは無効です。');
$domainList = [];
foreach ($domains as $d) {
$domain = explode('.', $d);
assert_exists($domain[0]);
assert_exists($domain[1]);
if (count($domain) !== 2) {
return \Result::Error("不正なドメイン形: {$d}");
}
$domainList[] = [
'name' => $domain[0],
'extension' => $domain[1],
];
}
$payload = [
'domains' => $domainList,
'with_price' => $with_price,
];
$curl = $this->setupCurl('/domains/check', 'POST', $payload);
$res = $this->curlResult($curl);
if (isset($res->data['data']['results'])) return \Result::Success('', $res->data['data']['results']);
return \Result::Error('ドメインの確認に失敗。');
}
//// 追加データ
//// 顧客様の追加データ
/**
* 顧客様の一覧
*
* @param array $query 検索クエリー
* @return Result
*/
public function listCustomers(array $query = []): \Result {
if (!OPENPROVIDER_ENABLED) return \Result::error('エラーOpenProviderは無効です。');
$cache = $this->getCache('listcustomers');
if ($this->isValidLifespan($cache, $query)) return \Result::Success('', $cache);
foreach ($query as $k => $v) { if (is_bool($v)) $query[$k] = $v ? '1' : '0'; }
$uri = '/customers?'.http_build_query($query, '', '&', PHP_QUERY_RFC3986);
$curl = $this->setupCurl($uri);
$res = $this->curlResult($curl);
if (isset($res->data['data'])) {
$res->data['query'] = $query;
$this->setCache('listcustomers', $res->data);
return \Result::Success('', $res->data);
}
return \Result::Error('顧客様一覧の受け取りに失敗。');
}
/**
* 顧客様の表示
*
* @param string $handle ハンドル
* @param bool $withAdditionalData 詳細データ含むか?
* @return Result
*/
public function getCustomer(string $handle, bool $withAdditionalData = false): \Result {
if (!OPENPROVIDER_ENABLED) return \Result::error('エラーOpenProviderは無効です。');
$cacheName = "getcustomer-{$handle}";
$cache = $this->getCache($cacheName);
if ($this->isValidLifespan($cache, $handle, 'handle')) return \Result::Success('', $cache);
$query = [ 'with_additional_data' => $withAdditionalData ? 'true' : 'false' ];
$uri = "/customers/{$handle}?".http_build_query($query, '', '&', PHP_QUERY_RFC3986);
// kys($uri);
$curl = $this->setupCurl($uri);
$res = $this->curlResult($curl);
if (isset($res->data['data'])) {
$res->data['handle'] = $handle;
$this->setCache($cacheName, $res->data);
return \Result::Success('', $res->data);
}
return \Result::Error('顧客様の受け取りに失敗。');
}
//// ドメイン値段
/**
* ドメイン値段一覧
*
* @param array $query 検索クエリー
* @return Result
*/
public function getDomainPrices(array $query): \Result {
if (!OPENPROVIDER_ENABLED) return \Result::error('エラーOpenProviderは無効です。');
$name = '';
$ext = '';
if (isset($query['domain.name'])) $name = $query['domain.name'];
if (isset($query['domain.extension'])) $ext = $query['domain.extension'];
$cacheName = $name && $ext ? "domainprices-{$name}.{$ext}" : 'domainprices';
$cache = $this->getCache($cacheName);
if ($this->isValidLifespan($cache)) return \Result::Success('', $cache);
$uri = "/domains/prices?".http_build_query($query, '', '&', PHP_QUERY_RFC3986);
$curl = $this->setupCurl($uri);
$res = $this->curlResult($curl);
if (isset($res->data['data'])) {
$this->setCache($cacheName, $res->data);
return \Result::Success('', $res->data);
}
return \Result::Error('TLD一覧の受け取りに失敗。');
}
//// 認証コード
//// TLD
/**
* TLD一覧
*
* @param array $query 検索クエリー
* @return Result
*/
public function listTlds(array $query = []): \Result {
if (!OPENPROVIDER_ENABLED) return \Result::error('エラーOpenProviderは無効です。');
$cache = $this->getCache('listtlds');
if ($this->isValidLifespan($cache)) return \Result::Success('', $cache);
if (empty($query)) $query = [ 'limit' => 10, 'offset' => 0, 'order' => 'ASC' ];
foreach ($query as $k => $v) if (is_bool($v)) $query[$k] = $v ? '1' : '0';
$uri = '/tlds?'.http_build_query($query, '', '&', PHP_QUERY_RFC3986);
$curl = $this->setupCurl($uri);
$res = $this->curlResult($curl);
if (isset($res->data['data'])) {
$this->setCache('listtlds', $res->data);
return \Result::Success('', $res->data);
}
return \Result::Error('TLD一覧の受け取りに失敗。');
}
/**
* TLDの表示
*
* @param string $tld TLD
* @param array $query 検索クエリー
* @return Result
*/
public function getTld(string $tld, array $query = []): \Result {
if (!OPENPROVIDER_ENABLED) return \Result::error('エラーOpenProviderは無効です。');
$cache = $this->getCache("gettld-{$tld}");
if ($this->isValidLifespan($cache)) return \Result::Success('', $cache);
if (empty($query)) $query = [ 'limit' => 10, 'offset' => 0 ];
foreach ($query as $k => $v) if (is_bool($v)) $query[$k] = $v ? '1' : '0';
$uri = "/tlds/{$tld}?".http_build_query($query, '', '&', PHP_QUERY_RFC3986);
$curl = $this->setupCurl($uri);
$res = $this->curlResult($curl);
if (isset($res->data['data'])) {
$this->setCache("gettld-{$tld}", $res->data);
return \Result::Success('', $res->data);
}
return \Result::Error('TLD一覧の受け取りに失敗。');
}
/**
* TLDの受け取り
*/
// 請求
//// 請求書
//// 支払
//// トランザクション
// DNS
//// DomainToken
//// ネームサーバー
//// NSグループ
//// テンプレート
//// ゾーン
/**
* DNSゾーン一覧
*
* @param array $query
* @return Result
*/
public function listDnsZones(array $query = []): \Result {
if (!OPENPROVIDER_ENABLED) return \Result::error('エラーOpenProviderは無効です。');
$cache = $this->getCache('listdnszones');
if ($this->isValidLifespan($cache, $query)) return \Result::Success('', $cache);
if (empty($query)) $query = [ 'limit' => 25, 'offset' => 0, 'order_by.name' => 'asc' ];
foreach ($query as $k => $v) if (is_bool($v)) $query[$k] = $v ? '1' : '0';
$uri = "/dns/zones?".http_build_query($query, '', '&', PHP_QUERY_RFC3986);
$curl = $this->setupCurl($uri);
$res = $this->curlResult($curl);
if (isset($res->data['data'])) {
$this->setCache('listdnszones', $res->data);
return \Result::Success('', $res->data);
}
return \Result::Error('TLD一覧の受け取りに失敗。');
}
/**
* DNSゾーン一覧
*
* @param string $domain ドメイン名
* @param array $query 検索クエリー
* @return Result
*/
public function getDnsZone(string $domain, array $query = []): \Result {
if (!OPENPROVIDER_ENABLED) return \Result::error('エラーOpenProviderは無効です。');
$cache = $this->getCache("getdnszone-{$domain}");
if ($this->isValidLifespan($cache)) return \Result::Success('', $cache);
if (empty($query)) $query = [ 'limit' => 100, 'offset' => 0, 'order_by.name' => 'asc' ];
foreach ($query as $k => $v) if (is_bool($v)) $query[$k] = $v ? '1' : '0';
$uri = "/dns/zones/{$domain}?".http_build_query($query, '', '&', PHP_QUERY_RFC3986);
$curl = $this->setupCurl($uri);
$res = $this->curlResult($curl);
if (isset($res->data['data'])) {
$this->setCache("getdnszone-{$domain}", $res->data);
return \Result::Success('', $res->data);
}
return \Result::Error('TLD一覧の受け取りに失敗。');
}
//// ゾーンレコード
/**
* DNSレコード一覧
*
* @param string $domain
* @return Result
*/
public function listZoneRecords(string $domain): \Result {
if (!OPENPROVIDER_ENABLED) return \Result::error('エラーOpenProviderは無効です。');
$cache = $this->getCache("getzonerecords-{$domain}");
if ($this->isValidLifespan($cache)) return \Result::Success('', $cache);
$curl = $this->setupCurl("/dns/zones/{$domain}/records");
$res = $this->curlResult($curl);
if (isset($res->data['data'])) {
$this->setCache("getzonerecords-{$domain}", $res->data);
return \Result::Success('', $res->data);
}
return \Result::Error('TLD一覧の受け取りに失敗。');
}
// Easydmarc
// ライセンス
// リセラー・顧客様
// SpamExpert
// SSL証明書
////////
/**
* トークンの受け取り。
*
* @return string トークン
*/
public function getToken(): string {
if (!OPENPROVIDER_ENABLED) return '';
return $this->token;
}
/**
* リセラーIDの受け取り。
*
* @return int リセラーID
*/
public function getResellerId(): int {
if (!OPENPROVIDER_ENABLED) return 0;
return $this->resellerId;
}
//////////
private function setupCurl(string $uri, string $resType = 'GET', array $payload = []): Curl {
$curl = new Curl("{$this->BASEURL}{$uri}");
$curl->setMethod($resType);
if (!empty($payload)) $curl->setPostRaw(json_encode($payload));
$curl->setBearerAuth($this->token);
$curl->addHeader('Content-Type', 'application/json');
$curl->addHeader('Accept', 'application/json');
return $curl;
}
private function curlResult(Curl &$curl): \Result {
$res = $curl->execute();
if (!$res->isSuccess) {
$err = "CURL実行に失敗 {$curl->message}";
assert_unless_success($res, $err);
return \Result::Error($err);
}
$body = $curl->getResponseBody();
if ($curl->getResponseCode() != 200) {
$err = json_decode($body, true);
assert_not_null($err, "エラーの受け取りに失敗。");
assert($curl->getResponseCode() == 200, $err['desc']);
return \Result::Error($err['desc']);
}
assert_not_null($body, "返事ボディーは空です。");
return \Result::Success('', json_decode($body, true));
}
/**
* キャッシュの作成
*
* @param string $type キャッシュ類login、domainlist等
* @param array $data 保存するデータ
* @return Result
*/
private function setCache(string $type, array $data): \Result {
if (!file_exists($this->dataDir)) {
if (!mkdir($this->dataDir, 0755))
return \Result::Error('エラー:ユーザーのアイコンディレクトリの作成に失敗。');
}
$data['lifespan'] = time();
$json = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
if (file_put_contents("{$this->dataDir}{$type}.json", $json) === false) return \Result::Error('エラー:ユーザーデータの保存に失敗。');
return \Result::Success();
}
/**
* キャッシュから受け取り
*
* @param string $type キャッシュ類login、domainlist等
* @return array
*/
private function getCache(string $type): array {
if (!file_exists("{$this->dataDir}{$type}.json")) return [];
$content = file_get_contents("{$this->dataDir}{$type}.json");
if ($content === false) return [];
$data = json_decode($content, true);
if (json_last_error() !== JSON_ERROR_NONE || !is_array($data)) return [];
if ($type === 'login') {
$this->token = $data['data']['token'];
$this->lastAuth = $data['last_auth'];
}
return $data;
}
/**
* キャッシュを破壊する
*
* @param string $name キャッシュのファイル名
* @return Result
*/
private function murderCache(string $name): \Result {
if (!file_exists("{$this->dataDir}{$name}.json")) return \Result::Error('キャッシュファイルが存在しない。');
if (!unlink("{$this->dataDir}{$name}.json")) return \Result::Error('キャッシュファイルの削除に失敗。');
return \Result::Success();
}
/**
* キャッシュ有効期限の確認
*
* @param array $cache
* @param mixed $data デフォルトnull
* @param string $dataPoint デフォルトquery
* @return bool
*/
private function isValidLifespan(array $cache, mixed $data = null, string $dataPoint = 'query'): bool {
if (NULL === $data) return (!empty($cache) && (isset($cache['lifespan']) && time() < ($cache['lifespan'] + $this->dataDuration)));
else return (!empty($cache)
&& (isset($cache[$dataPoint])
&& $cache[$dataPoint] === $data)
&& (isset($cache['lifespan']) && time() < ($cache['lifespan'] + $this->dataDuration)));
}
}