OpenProviderライブラリ

諏訪子 <suwako@076.moe>、2026-04-24 23:28
コミット f0f75124ee5f7b205f3a328eec0f9b9aa994ad7e ・親 7492790 ・ファイルを見る

7個のファイル、+438 -9

@@ -21,6 +21,12 @@
2121 'pubkey' => ROOT.'/public/static/pub.pem',
2222 'privkey' => ROOT.'/data/priv.pem',
2323 ]);
24+define('OPENPROVIDER', [
25+ 'username' => '',
26+ 'password' => '',
27+ 'ip' => '0.0.0.0',
28+ 'owner_handle' => 'HK912631-JP',
29+]);
2430
2531 define('MAILER_ENABLED', false);
2632 define('LOGGING_ENABLED', true);
@@ -5,11 +5,20 @@
55 use Std\Lib\Auth;
66 use Std\Lib\Template;
77
8+
9+use Std\Lib\Openprovider;
10+
811 class Page {
912 use Mods;
1013
1114 public function about(array $params): void {
1215 try {
16+ $op = new OpenProvider();
17+ $op->login();
18+ // kys($op->getToken());
19+ // kys($op->checkDomainAvailable(['076.moe', '076.xxx', '076.nigger']));
20+ // kys($op->listTlds());
21+ kys($op->searchCustomers());
1322 $tmpl = new Template('/');
1423 $pagetit = '新ページ';
1524 $description = 'PHPフレームワークについて';
@@ -22,8 +22,13 @@
2222 private bool $verifySSL = true;
2323 private string $username = '';
2424 private string $password = '';
25+ private string $token = '';
2526 private string $referer = '';
27+ private string $authType = '';
2628
29+ // デバッグ用
30+ private string $DEBUG_REQ_HDR = '';
31+
2732 // レスポンス関連のプロパティ
2833 private array $responseHeaders = [];
2934 private string $responseBody = '';
@@ -195,13 +200,39 @@
195200 * @param string $password パスワード
196201 * @return Curl このインスタンス(メソッドチェーン用)
197202 */
198- public function setBasicAuth(string $username, string $password): Curl {
199- $this->username = $username;
200- $this->password = $password;
203+ public function setBasicAuth(string $username = '', string $password = ''): Curl {
204+ if ($username !== '') $this->username = $username;
205+ if ($password !== '') $this->password = $password;
206+ $this->authType = 'Basic';
201207 return $this;
202208 }
203209
204210 /**
211+ * トークン認証の資格情報を設定する
212+ *
213+ * @param string $token セッショントークン
214+ * @return Curl このインスタンス(メソッドチェーン用)
215+ */
216+ public function setBearerAuth(string $token = ''): Curl {
217+ if ($token !== '') $this->token = $token;
218+ $this->authType = 'Bearer';
219+ return $this;
220+ }
221+
222+ /**
223+ * 認証を取りけソ
224+ *
225+ * @return Curl このインスタンス(メソッドチェーン用)
226+ */
227+ public function unsetAuth(): Curl {
228+ $this->username = '';
229+ $this->password = '';
230+ $this->token = '';
231+ $this->authType = '';
232+ return $this;
233+ }
234+
235+ /**
205236 * リファラーURLを設定する
206237 *
207238 * @param string $referer リファラーURL
@@ -300,14 +331,16 @@
300331 $path .= '?'.$parsed['query'];
301332 }
302333
303- // Basic認証
334+ // 認証
304335 $authHeader = '';
305- if (!empty($this->username) && !empty($this->password)) {
336+ if (!empty($this->authType) && $this->authType === 'Basic') {
337+ assert_not_null($this->username);
338+ assert_not_null($this->password);
306339 $authHeader = "Authorization: Basic "
307340 .base64_encode($this->username.':'.$this->password)."\r\n";
308- } elseif (isset($parsed['user']) && isset($parsed['pass'])) {
309- $authHeader = "Authorization: Basic "
310- .base64_encode($parsed['user'].':'.$parsed['pass'])."\r\n";
341+ } else if (!empty($this->authType) && $this->authType === 'Bearer') {
342+ assert_not_null($this->token);
343+ $authHeader = "Authorization: Bearer ".$this->token."\r\n";
311344 }
312345
313346 // 送信するHTTPリクエストを構築
@@ -368,6 +401,8 @@
368401 $request .= $httpData;
369402 }
370403
404+ $this->DEBUG_REQ_HDR = $request;
405+
371406 if ($this->verbose && $this->stderr) {
372407 fwrite($this->stderr, "* リクエストヘッダー:\n{$request}\n");
373408 }
@@ -571,6 +606,15 @@
571606 */
572607 public function getInfo(): array {
573608 return $this->info;
609+ }
610+
611+ /**
612+ * リクエスト情報を取得する
613+ *
614+ * @return string 情報の配列
615+ */
616+ public function getRequestHeader(): string {
617+ return $this->DEBUG_REQ_HDR;
574618 }
575619
576620 // 機能性メソッド
@@ -0,0 +1,302 @@
1+<?php
2+namespace Std\Lib;
3+
4+use Std\Lib\Curl;
5+
6+class Openprovider {
7+ private string $user;
8+ private string $pass;
9+ private string $token;
10+ private string $ip;
11+ private int $reseller_id;
12+ private string $BASEURL = 'https://api.openprovider.eu/v1beta';
13+ // private Curl $curl;
14+
15+ public function __construct() {
16+ if (!OPENPROVIDER_ENABLED) return;
17+ $this->user = OPENPROVIDER['username'];
18+ $this->pass = OPENPROVIDER['password'];
19+ $this->ip = OPENPROVIDER['ip'];
20+ }
21+
22+ /***
23+ * トークンの受け取り。
24+ * このライブリリーを使ったら、一回「login()」を実行する事が必須となります。
25+ *
26+ * @return Result 結果
27+ */
28+ public function login(): \Result {
29+ $curl = new Curl("{$this->BASEURL}/auth/login");
30+
31+ $payload = [
32+ 'username' => $this->user,
33+ 'password' => $this->pass,
34+ 'ip' => $this->ip ?: '0.0.0.0',
35+ ];
36+
37+ $curl->setMethod("POST");
38+ $curl->setPostRaw(json_encode($payload));
39+ $curl->addHeader("Content-Type", "application/json");
40+ $curl->addHeader("Accept", "application/json");
41+
42+ $res = $curl->execute();
43+ if (!$res->isSuccess) {
44+ $err = "CURLの実行に失敗: ".$curl->message;
45+ assert_unless_success($res, $err);
46+ return \Result::Error($err);
47+ }
48+
49+ $body = $curl->getResponseBody();
50+ if ($curl->getResponseCode() != 200) {
51+ $err = json_decode($body, true);
52+ assert_not_null($err, "エラーの受け取りに失敗。");
53+ assert($curl->getResponseCode() == 200, $err['desc']);
54+ return \Result::Error();
55+ }
56+ assert_not_null($body, "返事ボディーは空です。");
57+
58+ $data = json_decode($body, true);
59+ if (isset($data['data']['token'])) {
60+ $this->token = $data['data']['token'];
61+ $this->reseller_id = $data['data']['reseller_id'];
62+ return \Result::Success();
63+ }
64+
65+ return \Result::Error("ログインに失敗。");
66+ }
67+
68+ // カスタマー
69+
70+ // ドメイン
71+
72+ //// ドメイン
73+
74+ /***
75+ * ドメインを登録可能かどうかの確認。
76+ *
77+ * @param array $domains ドメイン名リスト。例:['076.moe', '076.co.jp', '076.com']
78+ * @param bool $with_price 値段を表示するかどうか。デフォルトは「false」
79+ * @return Result|array 結果。配列の場合:'domain'と'status'はいつでもあり、'reason', 'premium', 'is_premium'が多分あり、そして'price'が「with_price」が「true」の場合のみ。
80+ */
81+ public function checkDomainAvailable(array $domains, bool $with_price = false): \Result|array {
82+ $domainList = [];
83+ foreach ($domains as $d) {
84+ $domain = explode('.', $d);
85+ assert_exists($domain[0]);
86+ assert_exists($domain[1]);
87+ if (count($domain) !== 2) {
88+ return \Result::Error("不正なドメイン形: {$d}");
89+ }
90+
91+ $domainList[] = [
92+ 'name' => $domain[0],
93+ 'extension' => $domain[1],
94+ ];
95+ }
96+
97+ $payload = [
98+ 'domains' => $domainList,
99+ 'with_price' => $with_price,
100+ ];
101+
102+ $curl = $this->setupCurl('/domains/check', 'POST', $payload);
103+ $data = $this->curlResult($curl);
104+ if (isset($data['data']['results'])) return $data['data']['results'];
105+
106+ return \Result::Error("ドメインの確認に失敗。");
107+ }
108+
109+ /**
110+ * ドメイン名の登録。
111+ *
112+ * @param string $name 登録したいドメイン名(例:"076studio.jp")
113+ * @param int $period 年間(デフォルト=1年)
114+ * @param string $owner_handle
115+ * @param string $admin_handle
116+ * @param string $tech_handle
117+ * @param string $billing_handle
118+ * @param string $reseller_handle
119+ * @param array $name_servers ネームサーバー(4つまで、デフォルトはOpenProviderさんのネームサーバー)
120+ * @param string $autorenew 自動的に更新するかどうか(可能な値:on|off|default、デフォルト=default)
121+ * @return Result|array 結果。配列の場合:'activation_date'(リアルタイムで成功したのみ), 'auth_code'(TLDが対応している場合のみ), 'expiration_date', 'id', 'renewal_date', 'status'(ACT又はREQ)
122+ */
123+ public function registerDomain(string $name, int $period = 1, string $owner_handle = '',
124+ string $admin_handle = '', string $tech_handle = '',
125+ string $billing_handle = '', string $reseller_handle = '',
126+ array $name_servers = [], string $autorenew = 'default'): \Result|array {
127+ if ($owner_handle === '') $owner_handle = OPENPROVIDER['owner_handle'];
128+ if ($admin_handle === '') $admin_handle = $owner_handle;
129+ if ($tech_handle === '') $tech_handle = $owner_handle;
130+ if ($billing_handle === '') $billing_handle = $owner_handle;
131+ if ($reseller_handle === '') $reseller_handle = $owner_handle;
132+
133+ $parts = explode('.', $name, 2);
134+ assert_exists($parts[0]);
135+ assert_exists($parts[1]);
136+ $domain = [
137+ 'name' => $parts[0],
138+ 'extension' => $parts[1],
139+ ];
140+
141+ $ns = [];
142+ if (empty($name_servers)) $name_servers = ['ns1.openprovider.nl', 'ns2.openprovider.be', 'ns3.openprovider.eu'];
143+ foreach ($name_servers as $n) {
144+ $ns[] = ['name' => $n];
145+ }
146+
147+ $payload = [
148+ 'name' => $domain,
149+ 'period' => $period,
150+ 'owner_handle' => $owner_handle,
151+ 'admin_handle' => $admin_handle,
152+ 'tech_handle' => $tech_handle,
153+ 'billing_handle' => $billing_handle,
154+ 'reseller_handle' => $reseller_handle,
155+ 'name_servers' => $ns,
156+ 'autorenew' => $autorenew,
157+ ];
158+
159+ $curl = $this->setupCurl('/domains/', 'POST', $payload);
160+ kys('TODO');
161+ $data = $this->curlResult($curl);
162+ if (isset($data['data'])) return $data['data'];
163+
164+ return \Result::Error("ドメインの確認に失敗。");
165+ }
166+
167+ //// 追加データ
168+
169+ //// 顧客様の追加データ
170+
171+ /**
172+ * 顧客様の検索
173+ * @param array $query 検索クエリー(可能:handle_pattern (string), email_pattern (string), first_name_pattern (string), last_name_pattern (string), company_name_pattern (string), comment_pattern (string), with_additional_data (bool), limit (int = 100、最大=1000), offset (int = 0)
174+ */
175+ public function searchCustomers(array $query = []): \Result|array {
176+ foreach ($query as $k => $v) { if (is_bool($v)) $query[$k] = $v ? '1' : '0'; }
177+
178+ $uri = '/customers?'.http_build_query($query, '', '&', PHP_QUERY_RFC3986);
179+ $curl = $this->setupCurl($uri);
180+ kys("TODO: 問題");
181+ $data = $this->curlResult($curl);
182+ kys($data);
183+ if (isset($data['data'])) return $data['data'];
184+
185+ return \Result::Error("TLD一覧の受け取りに失敗。");
186+ }
187+
188+ //// ドメイン値段
189+
190+ //// 認証コード
191+
192+ //// TLD
193+
194+ /**
195+ * TLD一覧
196+ *
197+ * @param array $query 検索クエリー(可能:limit (int),offset (int),order (string),order_by (string),extensions(array), name_pattern (string), only_names (bool), with_description (bool),with_restrictions (bool)with_usage_count (bool)with_application_mode (bool),with_price (bool),with_level_prices (bool)is_active (bool)is_new_gtld (bool),status (string),application_mode (string))
198+ */
199+ public function listTlds(array $query = []): \Result|array {
200+ if (empty($query)) $query = [ 'limit' => 10, 'offset' => 0, 'order' => 'ASC' ];
201+
202+ foreach ($query as $k => $v) {
203+ if (is_bool($v)) $query[$k] = $v ? '1' : '0';
204+ }
205+
206+ $uri = '/tlds?'.http_build_query($query, '', '&', PHP_QUERY_RFC3986);
207+ // kys($uri);
208+ $curl = $this->setupCurl($uri);
209+ kys("TODO: JSONの問題");
210+ $data = $this->curlResult($curl);
211+ kys($data);
212+ if (isset($data['data'])) return $data['data'];
213+
214+ return \Result::Error("TLD一覧の受け取りに失敗。");
215+ }
216+
217+ /**
218+ * TLDの受け取り
219+ */
220+
221+ // 請求
222+ //// 請求書
223+ //// 支払
224+ //// トランザクション
225+
226+ // DNS
227+ //// DomainToken
228+ //// ネームサーバー
229+ //// NSグループ
230+ //// テンプレート
231+ //// ゾーン
232+ //// ゾーンレコード
233+
234+ // Easydmarc
235+
236+ // ライセンス
237+
238+ // リセラー・顧客様
239+
240+ // SpamExpert
241+
242+ // SSL証明書
243+
244+ ////////
245+
246+ /**
247+ * トークンの受け取り。
248+ *
249+ * @return string トークン
250+ */
251+ public function getToken(): string {
252+ return $this->token;
253+ }
254+
255+ /**
256+ * リセラーIDの受け取り。
257+ *
258+ * @return int リセラーID
259+ */
260+ public function getResellerId(): int {
261+ return $this->reseller_id;
262+ }
263+
264+ //////////
265+
266+ private function setupCurl(string $uri, string $resType = 'GET', array $payload = []): Curl {
267+ $curl = new Curl("{$this->BASEURL}{$uri}");
268+
269+ $curl->setMethod($resType);
270+ if (!empty($payload)) $curl->setPostRaw(json_encode($payload));
271+ $curl->setBearerAuth($this->token);
272+ $curl->addHeader('Content-Type', 'application/json');
273+ $curl->addHeader('Accept', 'application/json');
274+
275+ return $curl;
276+ }
277+
278+ private function curlResult(Curl &$curl): \Result|array {
279+ $res = $curl->execute();
280+ // kys($curl->getRequestHeader());
281+ if (!$res->isSuccess) {
282+ $err = "CURL実行に失敗: {$curl->message}";
283+ assert_unless_success($res, $err);
284+ return \Result::Error($err);
285+ }
286+
287+ $body = $curl->getResponseBody();
288+ // kys($body);
289+ // kys($curl->getResponseHeaders());
290+ if ($curl->getResponseCode() != 200) {
291+ $err = json_decode($body, true);
292+ assert_not_null($err, "エラーの受け取りに失敗。");
293+ assert($curl->getResponseCode() == 200, $err['desc']);
294+ return \Result::Error();
295+ }
296+ assert_not_null($body, "返事ボディーは空です。");
297+
298+ // $body = str_
299+ kys($body);
300+ return json_decode($body, true);
301+ }
302+}
@@ -35,7 +35,6 @@
3535 }
3636
3737 $test->describe('マークダウン', function($test): void {
38-
3938 $test->it('メタデータをパーシング出来るはず', function($test): void {
4039 $md = new Markdown('feature-test', '/blog/');
4140 $test->assertNotNull($md);
@@ -0,0 +1,62 @@
1+<?php
2+namespace Std\Test;
3+
4+require_once __DIR__.'/../../../autoload.php';
5+
6+use Std\Lib\Tester;
7+use Std\Lib\Openprovider;
8+
9+$test = new Tester([
10+ 'colorOutput' => true,
11+ 'verboseOutput' => true
12+]);
13+
14+$test->describe('認証', function($test): void {
15+ $test->it('トークンを受け取れるはず', function($test): void {
16+ $op = new OpenProvider();
17+ $res = $op->login();
18+
19+ $expect = Res::Success();
20+ $test->assertEquals($expect, $res);
21+ });
22+
23+ $test->it('トークンを受け取れるはず', function($test): void {});
24+});
25+
26+$test->describe('ドメイン', function($test): void {
27+ $test->it('ドメイン名があるかのうか確認出来るはず', function($test): void {
28+ $op = new OpenProvider();
29+ $op->login();
30+ $res = $op->checkDomainAvailable(['076.moe', '076.xxx', '076.nigger']);
31+
32+ $expect = [
33+ 0 => [
34+ 'domain' => '076.nigger',
35+ 'status' => 'active',
36+ 'reason' => 'Your domain request contains an invalid extension!',
37+ ],
38+ 1 => [
39+ 'domain' => '076.moe',
40+ 'status' => 'active',
41+ 'reason' => 'In use',
42+ ],
43+ 2 => [
44+ 'domain' => '076.xxx',
45+ 'status' => 'free',
46+ ],
47+ ];
48+ $test->assertEquals($expect, $res);
49+ });
50+
51+ $test->it('ドメイン名(値段付き)があるかのうか確認出来るはず', function($test): void {
52+ $op = new OpenProvider();
53+ $op->login();
54+ $res = isset($op->checkDomainAvailable(['076.moe'], true)[0]['price']['product']);
55+
56+ $expect = true;
57+ $expect = Res::Success();
58+ $test->assertEquals($expect, $res);
59+ });
60+});
61+
62+$test->printSummary();
変更 util.php
@@ -268,6 +268,13 @@
268268 return bin2hex(random_bytes($len));
269269 }
270270
271+function assert_exists(mixed $assertion, Throwable|string|null $description = null): bool {
272+ if (ini_get('zend.assertions') < 1) trigger_error('assert機能性が無効です。有効するには、php.iniで「zend.assertions = 1」に設定して下さい。', E_USER_WARNING);
273+ if (isset($assertion)) return true;
274+ assert(false, $description ?? 'Assertion failed: value is not null');
275+ return false;
276+}
277+
271278 function assert_null(mixed $assertion, Throwable|string|null $description = null): bool {
272279 if (ini_get('zend.assertions') < 1) trigger_error('assert機能性が無効です。有効するには、php.iniで「zend.assertions = 1」に設定して下さい。', E_USER_WARNING);
273280 if (is_null($assertion)) return true;