沢山追加

諏訪子 <suwako@076.moe>、2026-04-27 13:18
コミット 1bc9e594e261b66cdf607818b13d2f9ea98cf71a ・親 f0f7512 ・ファイルを見る

21個のファイル、+956 -160

変更 .gitignore
@@ -1,5 +1,7 @@
11 data/*.pem
22 data/*.txt
3+data/*.json
4+data/cache/*.json
35 data/user/*.json
46 log/*.txt
57 public/static/user
@@ -25,7 +25,7 @@
2525 'username' => '',
2626 'password' => '',
2727 'ip' => '0.0.0.0',
28- 'owner_handle' => 'HK912631-JP',
28+ 'owner_handle' => '',
2929 ]);
3030
3131 define('MAILER_ENABLED', false);
@@ -34,6 +34,7 @@
3434 define('ACTIVITYPUB_ENABLED', false);
3535 define('CURL_ENABLED', true);
3636 define('AUTH_ENABLED', false);
37+define('OPENPROVIDER_ENABLED', false);
3738 define('AUTH_REGISTER_ENABLED', false);
3839 define('COPYRIGHT_YEAR', '2018-'.date('Y'));
3940 define('DEBUG_MODE', false);
@@ -0,0 +1,25 @@
1+textarea {
2+ background: #232023;
3+ color: #fcfcfc;
4+ width: 100%;
5+ max-width: 1260px;
6+ height: 300px;
7+}
8+
9+button {
10+ border: 1px solid #ea79d8;
11+ color: #fcfcfc;
12+ border-radius: 4px;
13+ background: #ea79d8;
14+ font-size: 16px;
15+ transition: background-color 0.2s ease-in-out;
16+}
17+
18+button:hover {
19+ background-color: #b421f8;
20+}
21+
22+tr.status-free { background-color: #34860e; color: #fff; }
23+tr.status-reserved { background-color: #c59e1d; color: #fff; }
24+tr.status-use { background-color: #850000; color: #fff; }
25+tr.status-fumei { background-color: #888; color: #000; }
変更 route.php
@@ -8,6 +8,7 @@
88 use Site\Controller\Fediverse;
99 use Site\Controller\Home;
1010 use Site\Controller\Notfound;
11+use Site\Controller\Op;
1112 use Site\Controller\Page;
1213 use Site\Controller\User;
1314
@@ -55,6 +56,17 @@
5556
5657 if (ATOM_ENABLED) {
5758 $routes[] = Route::add('GET', 'blog.atom', Atom::class.'@feed');
59+}
60+
61+if (OPENPROVIDER_ENABLED) {
62+ $routes[] = Route::add('GET', 'openprovider', Op::class.'@index');
63+ $routes[] = Route::add('GET', 'openprovider/searchcustomer', Op::class.'@opSearchCustomers');
64+ $routes[] = Route::add('GET', 'openprovider/listtlds', Op::class.'@opListTlds');
65+ $routes[] = Route::add('GET', 'openprovider/gettld/{tld}', Op::class.'@opGetTld');
66+ $routes[] = Route::add('GET', 'openprovider/checkdomain', Op::class.'@opCheckDomainAvailable');
67+ $routes[] = Route::add('GET', 'openprovider/getdomainprices', Op::class.'@opGetDomainPrices');
68+ $routes[] = Route::add('GET', 'openprovider/listdnszones', Op::class.'@opListDns');
69+ $routes[] = Route::add('GET', 'openprovider/getdns/{domain}', Op::class.'@opGetDns');
5870 }
5971
6072 $routes[] = Route::add('GET', '', Home::class.'@show');
@@ -46,6 +46,13 @@
4646 'text' => 'スタッフ限定',
4747 'show' => true,
4848 ],
49+ [
50+ 'class' => 'menu-item',
51+ 'href' => '/openprovider',
52+ 'page' => 'openprovider',
53+ 'text' => 'OpenProvider管理',
54+ 'show' => true,
55+ ],
4956 ];
5057 }
5158 }
@@ -0,0 +1,341 @@
1+<?php
2+namespace Site\Controller;
3+
4+use Site\Controller\Mods;
5+use Std\Lib\Auth;
6+use Std\Lib\Template;
7+
8+use Std\Lib\Openprovider;
9+
10+class Op {
11+ use Mods;
12+
13+ public function index(array $params): void {
14+ try {
15+ $tmpl = new Template('/openprovider/');
16+ $pagetit = 'OpenProvider管理 - ホーム';
17+ $description = '';
18+
19+ // ユーザー
20+ $auth = new Auth();
21+ $user = $auth->getLoggedInUser();
22+ $tmpl->assign('user', $user);
23+
24+ $tmpl->assign('pagetit', $pagetit);
25+ $tmpl->assign('curPage', 'openprovider');
26+ $tmpl->assign('custCss', false);
27+ $tmpl->assign('menu', $this->getMenu());
28+ $tmpl->assign('description', $description);
29+
30+ if (!$user || $user->role !== \Roles::ADMIN) goto noaccess;
31+ $tmpl->addCss('table');
32+ $tmpl->render('index');
33+ exit();
34+
35+ noaccess:
36+ $tmpl->render('nopermission');
37+ } catch (\Exception $e) {
38+ throw new \Exception($e->getMessage());
39+ }
40+ }
41+
42+ public function opSearchCustomers(array $params): void {
43+ try {
44+ $tmpl = new Template('/openprovider/');
45+ $pagetit = 'OpenProvider管理 - 顧客様検索';
46+ $description = '';
47+
48+ // ユーザー
49+ $auth = new Auth();
50+ $user = $auth->getLoggedInUser();
51+ $tmpl->assign('user', $user);
52+
53+ $tmpl->assign('pagetit', $pagetit);
54+ $tmpl->assign('curPage', 'openprovider');
55+ $tmpl->assign('custCss', true);
56+ $tmpl->assign('menu', $this->getMenu());
57+ $tmpl->assign('description', $description);
58+
59+ if (!$user || $user->role !== \Roles::ADMIN) goto noaccess;
60+ $op = new Openprovider();
61+ $op->login();
62+ $data = $op->searchCustomers();
63+ $tmpl->assign('data', $data);
64+
65+ $tmpl->addCss('table');
66+ $tmpl->render('searchcustomer');
67+ exit();
68+
69+ noaccess:
70+ $tmpl->render('nopermission');
71+ } catch (\Exception $e) {
72+ throw new \Exception($e->getMessage());
73+ }
74+ }
75+
76+ public function opListTlds(array $params): void {
77+ try {
78+ $tmpl = new Template('/openprovider/');
79+ $pagetit = 'OpenProvider管理 - TLD一覧';
80+ $description = '';
81+
82+ // ユーザー
83+ $auth = new Auth();
84+ $user = $auth->getLoggedInUser();
85+ $tmpl->assign('user', $user);
86+
87+ $tmpl->assign('pagetit', $pagetit);
88+ $tmpl->assign('curPage', 'openprovider');
89+ $tmpl->assign('custCss', false);
90+ $tmpl->assign('menu', $this->getMenu());
91+ $tmpl->assign('description', $description);
92+
93+ if (!$user || $user->role !== \Roles::ADMIN) goto noaccess;
94+ $op = new Openprovider();
95+ $op->login();
96+ $data = $op->listTlds();
97+ $tmpl->assign('data', $data);
98+
99+ $tmpl->addCss('table');
100+ $tmpl->render('listtlds');
101+ exit();
102+
103+ noaccess:
104+ $tmpl->render('nopermission');
105+ } catch (\Exception $e) {
106+ throw new \Exception($e->getMessage());
107+ }
108+ }
109+
110+ public function opGetTld(array $params): void {
111+ try {
112+ $tld = '';
113+ if (isset($params['tld'])) $tld = $params['tld'];
114+ if ($tld === '') {
115+ header('Location: /');
116+ exit();
117+ }
118+ $tmpl = new Template('/openprovider/');
119+ $pagetit = "OpenProvider管理 - .{$tld}の表示";
120+ $description = '';
121+
122+ // ユーザー
123+ $auth = new Auth();
124+ $user = $auth->getLoggedInUser();
125+ $tmpl->assign('user', $user);
126+
127+ $tmpl->assign('pagetit', $pagetit);
128+ $tmpl->assign('curPage', 'openprovider');
129+ $tmpl->assign('custCss', false);
130+ $tmpl->assign('menu', $this->getMenu());
131+ $tmpl->assign('description', $description);
132+
133+ if (!$user || $user->role !== \Roles::ADMIN) goto noaccess;
134+ $op = new Openprovider();
135+ $op->login();
136+ $data = $op->getTld($tld);
137+ $tmpl->assign('data', $data);
138+
139+ $tmpl->addCss('table');
140+ $tmpl->render('gettld');
141+ exit();
142+
143+ noaccess:
144+ $tmpl->render('nopermission');
145+ } catch (\Exception $e) {
146+ throw new \Exception($e->getMessage());
147+ }
148+ }
149+
150+ public function opListDomains(array $params): void {
151+ try {
152+ $tmpl = new Template('/openprovider/');
153+ $pagetit = 'OpenProvider管理 - ドメイン確認';
154+ $description = '';
155+
156+ // ユーザー
157+ $auth = new Auth();
158+ $user = $auth->getLoggedInUser();
159+ $tmpl->assign('user', $user);
160+
161+ $tmpl->assign('pagetit', $pagetit);
162+ $tmpl->assign('curPage', 'openprovider');
163+ $tmpl->assign('custCss', false);
164+ $tmpl->assign('menu', $this->getMenu());
165+ $tmpl->assign('description', $description);
166+
167+ if (!$user || $user->role !== \Roles::ADMIN) goto noaccess;
168+ $op = new Openprovider();
169+ $op->login();
170+ $data = $op->listDomains($domains, true);
171+ $tmpl->assign('data', $data);
172+
173+ $tmpl->assign('saved', $saved);
174+
175+ $tmpl->addCss('table');
176+ $tmpl->addCss('openprovider');
177+ $tmpl->render('checkdomain');
178+ exit();
179+
180+ noaccess:
181+ $tmpl->render('nopermission');
182+ } catch (\Exception $e) {
183+ throw new \Exception($e->getMessage());
184+ }
185+ }
186+
187+ public function opCheckDomainAvailable(array $params): void {
188+ try {
189+ $domains = isset($_GET['domains']) ? explode("\n", $_GET['domains']) : [];
190+ $saved = '';
191+
192+ $tmpl = new Template('/openprovider/');
193+ $pagetit = 'OpenProvider管理 - ドメイン確認';
194+ $description = '';
195+
196+ // ユーザー
197+ $auth = new Auth();
198+ $user = $auth->getLoggedInUser();
199+ $tmpl->assign('user', $user);
200+
201+ $tmpl->assign('pagetit', $pagetit);
202+ $tmpl->assign('curPage', 'openprovider');
203+ $tmpl->assign('custCss', false);
204+ $tmpl->assign('menu', $this->getMenu());
205+ $tmpl->assign('description', $description);
206+
207+ if (!$user || $user->role !== \Roles::ADMIN) goto noaccess;
208+ $op = new Openprovider();
209+ $op->login();
210+ if (!empty($domains)) {
211+ $data = $op->checkDomainAvailable($domains, true);
212+ $tmpl->assign('data', $data);
213+ $saved = $_GET['domains'];
214+ }
215+
216+ $tmpl->assign('saved', $saved);
217+
218+ $tmpl->addCss('table');
219+ $tmpl->addCss('openprovider');
220+ $tmpl->render('checkdomain');
221+ exit();
222+
223+ noaccess:
224+ $tmpl->render('nopermission');
225+ } catch (\Exception $e) {
226+ throw new \Exception($e->getMessage());
227+ }
228+ }
229+
230+ public function opGetDomainPrices(array $params): void {
231+ try {
232+ $domainname = $_GET['domain_name'] ?? '';
233+ $domainext = $_GET['domain_extension'] ?? '';
234+
235+ $tmpl = new Template('/openprovider/');
236+ $pagetit = 'OpenProvider管理 - ドメイン値段一覧';
237+ $description = '';
238+
239+ // ユーザー
240+ $auth = new Auth();
241+ $user = $auth->getLoggedInUser();
242+ $tmpl->assign('user', $user);
243+
244+ $tmpl->assign('pagetit', $pagetit);
245+ $tmpl->assign('curPage', 'openprovider');
246+ $tmpl->assign('custCss', false);
247+ $tmpl->assign('menu', $this->getMenu());
248+ $tmpl->assign('description', $description);
249+
250+ if (!$user || $user->role !== \Roles::ADMIN) goto noaccess;
251+ $op = new Openprovider();
252+ $op->login();
253+ $data = $op->getDomainPrices(['domain.name' => $domainname, 'domain.extension' => $domainext]);
254+ $tmpl->assign('data', $data);
255+
256+ $tmpl->addCss('table');
257+ $tmpl->render('getdomainprices');
258+ exit();
259+
260+ noaccess:
261+ $tmpl->render('nopermission');
262+ } catch (\Exception $e) {
263+ throw new \Exception($e->getMessage());
264+ }
265+ }
266+
267+ public function opListDns(array $params): void {
268+ try {
269+ $tmpl = new Template('/openprovider/');
270+ $pagetit = "OpenProvider管理 - DNS一覧";
271+ $description = '';
272+
273+ // ユーザー
274+ $auth = new Auth();
275+ $user = $auth->getLoggedInUser();
276+ $tmpl->assign('user', $user);
277+
278+ $tmpl->assign('pagetit', $pagetit);
279+ $tmpl->assign('curPage', 'openprovider');
280+ $tmpl->assign('custCss', true);
281+ $tmpl->assign('menu', $this->getMenu());
282+ $tmpl->assign('description', $description);
283+
284+ if (!$user || $user->role !== \Roles::ADMIN) goto noaccess;
285+ $op = new Openprovider();
286+ $op->login();
287+ $data = $op->listDnsZones();
288+ $tmpl->assign('data', $data);
289+
290+ $tmpl->addCss('table');
291+ if ($user && $user->role & (\Roles::ADMIN)) $tmpl->render('listdnszones');
292+ else goto noaccess;
293+ exit();
294+
295+ noaccess:
296+ $tmpl->render('nopermission');
297+ } catch (\Exception $e) {
298+ throw new \Exception($e->getMessage());
299+ }
300+ }
301+
302+ public function opGetDns(array $params): void {
303+ try {
304+ $domain = '';
305+ if (isset($params['domain'])) $domain = $params['domain'];
306+ if ($domain === '') {
307+ header('Location: /');
308+ exit();
309+ }
310+ $tmpl = new Template('/openprovider/');
311+ $pagetit = "OpenProvider管理 - {$domain}のDNS管理";
312+ $description = '';
313+
314+ // ユーザー
315+ $auth = new Auth();
316+ $user = $auth->getLoggedInUser();
317+ $tmpl->assign('user', $user);
318+
319+ $tmpl->assign('pagetit', $pagetit);
320+ $tmpl->assign('curPage', 'openprovider');
321+ $tmpl->assign('custCss', false);
322+ $tmpl->assign('menu', $this->getMenu());
323+ $tmpl->assign('description', $description);
324+
325+ if (!$user || $user->role !== \Roles::ADMIN) goto noaccess;
326+ $op = new Openprovider();
327+ $op->login();
328+ $data = ['rec' => $op->listZoneRecords($domain), 'zone' => $op->getDnsZone($domain)];
329+ $tmpl->assign('data', $data);
330+
331+ $tmpl->addCss('table');
332+ $tmpl->render('getdns');
333+ exit();
334+
335+ noaccess:
336+ $tmpl->render('nopermission');
337+ } catch (\Exception $e) {
338+ throw new \Exception($e->getMessage());
339+ }
340+ }
341+}
@@ -5,20 +5,11 @@
55 use Std\Lib\Auth;
66 use Std\Lib\Template;
77
8-
9-use Std\Lib\Openprovider;
10-
118 class Page {
129 use Mods;
1310
1411 public function about(array $params): void {
1512 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());
2213 $tmpl = new Template('/');
2314 $pagetit = '新ページ';
2415 $description = 'PHPフレームワークについて';
@@ -121,7 +112,6 @@
121112 // ユーザー
122113 $auth = new Auth();
123114 $user = $auth->getLoggedInUser();
124-
125115 $tmpl->assign('user', $user);
126116
127117 $tmpl->assign('pagetit', $pagetit);
@@ -456,80 +456,43 @@
456456 $headersComplete = false;
457457
458458 // ヘッダーとボディを分けて読み込む
459- while (!feof($socket)) {
460- $line = fgets($socket);
461- if ($line === false) {
462- break;
463- }
459+ while (!feof($socket)) $rawResponse .= fread($socket, 8192);
460+ fclose($socket);
464461
465- $rawResponse .= $line;
466-
467- if (!$headersComplete) {
468- if (trim($line) === '') {
469- $headersComplete = true;
470- } else {
471- $headers .= $line;
472- }
473- } else {
474- $body .= $line;
475- }
462+ if ($rawResponse === '') {
463+ $this->responseError = 'リスポンスエラー';
464+ return \Result::Error($this->responseError);
476465 }
477466
478- fclose($socket);
467+ list($headerLines, $body) = $this->parseResponse($rawResponse);
479468
480- // レスポンスヘッダーを解析
481- $headerLines = explode("\r\n", $headers);
482-
483- // ステータスコードを取得
484- $statusLine = isset($headerLines[0]) ? $headerLines[0] : '';
485- $statusParts = explode(' ', $statusLine, 3);
486- $this->responseCode = isset($statusParts[1]) ? (int)$statusParts[1] : 0;
487- $this->info['http_code'] = $this->responseCode;
488-
489469 // ヘッダーを解析
490470 $this->responseHeaders = [];
491- $redirectUrl = '';
471+ $this->responseCode = 0;
492472
493473 foreach ($headerLines as $index => $header) {
494- if ($index === 0) continue;
474+ if ($index === 0) {
475+ if (preg_match('#HTTP/\d\.\d (\d+)#', $header, $m))
476+ $this->responseCode = (int)$m[1];
477+ continue;
478+ }
495479
496480 if (strpos($header, ':') !== false) {
497- list($name, $value) = explode(':', $header, 2);
481+ [$name, $value] = explode(':', $header, 2);
498482 $name = trim($name);
499483 $value = trim($value);
500484 $this->responseHeaders[$name] = $value;
501-
502- if (strtolower($name) === 'content-type') {
503- $this->info['content_type'] = $value;
504- }
505-
506- // リダイレクトをチェック
507- if ($this->followRedirects &&
508- strtolower($name) === 'location' &&
509- $this->responseCode >= 300 &&
510- $this->responseCode < 400) {
511-
512- $redirectUrl = $value;
513-
514- // 相対URLを絶対URLに変換
515- if (strpos($redirectUrl, 'http') !== 0) {
516- if ($redirectUrl[0] === '/') {
517- $redirectUrl = "{$scheme}://{$host}"
518- .($port != 80 && $port != 443 ? ":{$port}" : '').$redirectUrl;
519- } else {
520- $redirectUrl = "{$scheme}://{$host}"
521- .($port != 80 && $port != 443 ? ":{$port}" : '')
522- .dirname($path).'/'.$redirectUrl;
523- }
524- }
525-
526- $this->info['redirect_url'] = $redirectUrl;
527- }
528485 }
529486 }
530487
488+ $this->info['http_code'] = $this->responseCode;
489+ if (isset($this->responseHeaders['Transfer-Encoding'])
490+ && stripos($this->responseHeaders['Transfer-Encoding'], 'chunked') !== false) {
491+ $body = $this->decodeChunkedBody($body);
492+ }
493+
531494 $this->info['header_size'] += strlen($headers);
532- $this->responseBody .= $body;
495+ $this->responseBody = $body;
533496
534497 if ($this->verbose && $this->stderr) {
535498 fwrite($this->stderr, "* レスポンスコード: {$this->responseCode}\n");
@@ -688,20 +651,11 @@
688651 */
689652 private function parseResponse(string $response): array {
690653 $parts = explode("\r\n\r\n", $response, 2);
691-
692- if (count($parts) < 2) {
693- return [[], ''];
694- }
695-
654+ if (count($parts) < 2) return [explode("\r\n", $response), ''];
655+
696656 $headers = explode("\r\n", $parts[0]);
697657 $body = $parts[1];
698-
699- // チャンク転送エンコーディングを処理
700- if (isset($this->responseHeaders['Transfer-Encoding']) &&
701- strtolower($this->responseHeaders['Transfer-Encoding']) === 'chunked') {
702- $body = $this->decodeChunkedBody($body);
703- }
704-
658+
705659 return [$headers, $body];
706660 }
707661
@@ -717,15 +671,9 @@
717671
718672 while ($position < strlen($body)) {
719673 $lineEnd = strpos($body, "\r\n", $position);
720- if ($lineEnd === false) {
721- break;
722- }
723-
674+ if ($lineEnd === false) break;
724675 $chunkSize = hexdec(substr($body, $position, $lineEnd - $position));
725-
726- if ($chunkSize === 0) {
727- break;
728- }
676+ if ($chunkSize === 0) break;
729677
730678 $position = $lineEnd + 2;
731679 $decodedBody .= substr($body, $position, $chunkSize);
@@ -4,14 +4,18 @@
44 use Std\Lib\Curl;
55
66 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;
7+ protected string $dataFile = ROOT."/data/session.json";
8+ protected int $tokenDuration = 172800; // 48時間
149
10+ private string $user = '';
11+ private string $pass = '';
12+ private string $token = '';
13+ private string $ip = '';
14+ private int $reseller_id = 0;
15+ private int $last_auth = 0;
16+ private string $BASEURL = DEBUG_MODE ? 'http://api.sandbox.openprovider.nl:8480/v1beta'
17+ : 'https://api.openprovider.eu/v1beta';
18+
1519 public function __construct() {
1620 if (!OPENPROVIDER_ENABLED) return;
1721 $this->user = OPENPROVIDER['username'];
@@ -22,10 +26,13 @@
2226 /***
2327 * トークンの受け取り。
2428 * このライブリリーを使ったら、一回「login()」を実行する事が必須となります。
25- *
26- * @return Result 結果
29+ *
30+ * @return Result|false 結果
2731 */
28- public function login(): \Result {
32+ public function login(): \Result|false {
33+ if (!OPENPROVIDER_ENABLED) return \Result::error('エラー:OpenProviderは無効です。');
34+ $this->getCache();
35+ if (time() < ($this->last_auth + $this->tokenDuration)) return false;
2936 $curl = new Curl("{$this->BASEURL}/auth/login");
3037
3138 $payload = [
@@ -58,7 +65,10 @@
5865 $data = json_decode($body, true);
5966 if (isset($data['data']['token'])) {
6067 $this->token = $data['data']['token'];
68+ $this->last_auth = time();
6169 $this->reseller_id = $data['data']['reseller_id'];
70+ $this->mkCache();
71+
6272 return \Result::Success();
6373 }
6474
@@ -72,34 +82,13 @@
7282 //// ドメイン
7383
7484 /***
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」の場合のみ。
85+ * ドメイン一覧。
86+ *
87+ * @return Result|array 結果。
8088 */
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);
89+ public function listDomains(array $query = []): \Result|array {
90+ if (!OPENPROVIDER_ENABLED) return \Result::error('エラー:OpenProviderは無効です。');
91+ $curl = $this->setupCurl('/domains');
10392 $data = $this->curlResult($curl);
10493 if (isset($data['data']['results'])) return $data['data']['results'];
10594
@@ -108,28 +97,24 @@
10897
10998 /**
11099 * ドメイン名の登録。
111- *
100+ *
112101 * @param string $name 登録したいドメイン名(例:"076studio.jp")
102+ * @param array $info カスタマー情報等
113103 * @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)
121104 * @return Result|array 結果。配列の場合:'activation_date'(リアルタイムで成功したのみ), 'auth_code'(TLDが対応している場合のみ), 'expiration_date', 'id', 'renewal_date', 'status'(ACT又はREQ)
122105 */
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;
106+ public function createDomain(string $name, array $info, int $period = 1): \Result|array {
107+ if (!OPENPROVIDER_ENABLED) return \Result::error('エラー:OpenProviderは無効です。');
108+ if (!isset($info['owner_handle']) || $info['owner_handle'] === '') $info['owner_handle'] = OPENPROVIDER['owner_handle'];
109+ if (!isset($info['admin_handle']) || $info['admin_handle'] === '') $info['admin_handle'] = OPENPROVIDER['owner_handle'];
110+ if (!isset($info['tech_handle']) || $info['tech_handle'] === '') $info['tech_handle'] = OPENPROVIDER['owner_handle'];
111+ if (!isset($info['billing_handle']) || $info['billing_handle'] === '') $info['billing_handle'] = OPENPROVIDER['owner_handle'];
112+ if (!isset($info['reseller_handle']) || $info['reseller_handle'] === '') $info['reseller_handle'] = OPENPROVIDER['owner_handle'];
113+ if (!isset($info['name_servers']) || empty($info['name_servers'])) $info['name_servers'] = ['ns1.openprovider.nl', 'ns2.openprovider.be', 'ns3.openprovider.eu'];
114+ if (!isset($info['autorenew']) || $info['autorenew'] === '') $info['autorenew'] = 'default';
132115
116+ // 新しい顧客の場合
117+
133118 $parts = explode('.', $name, 2);
134119 assert_exists($parts[0]);
135120 assert_exists($parts[1]);
@@ -139,8 +124,7 @@
139124 ];
140125
141126 $ns = [];
142- if (empty($name_servers)) $name_servers = ['ns1.openprovider.nl', 'ns2.openprovider.be', 'ns3.openprovider.eu'];
143- foreach ($name_servers as $n) {
127+ foreach ($info['name_servers'] as $n) {
144128 $ns[] = ['name' => $n];
145129 }
146130
@@ -164,22 +148,59 @@
164148 return \Result::Error("ドメインの確認に失敗。");
165149 }
166150
151+ /***
152+ * ドメインを登録可能かどうかの確認。
153+ *
154+ * @param array $domains ドメイン名リスト。例:['076.moe', '076.co.jp', '076.com']
155+ * @param bool $with_price 値段を表示するかどうか。デフォルトは「false」
156+ * @return Result|array 結果。配列の場合:'domain'と'status'はいつでもあり、'reason', 'premium', 'is_premium'が多分あり、そして'price'が「with_price」が「true」の場合のみ。
157+ */
158+ public function checkDomainAvailable(array $domains, bool $with_price = false): \Result|array {
159+ if (!OPENPROVIDER_ENABLED) return \Result::error('エラー:OpenProviderは無効です。');
160+ $domainList = [];
161+ foreach ($domains as $d) {
162+ $domain = explode('.', $d);
163+ assert_exists($domain[0]);
164+ assert_exists($domain[1]);
165+ if (count($domain) !== 2) {
166+ return \Result::Error("不正なドメイン形: {$d}");
167+ }
168+
169+ $domainList[] = [
170+ 'name' => $domain[0],
171+ 'extension' => $domain[1],
172+ ];
173+ }
174+
175+ $payload = [
176+ 'domains' => $domainList,
177+ 'with_price' => $with_price,
178+ ];
179+
180+ $curl = $this->setupCurl('/domains/check', 'POST', $payload);
181+ $data = $this->curlResult($curl);
182+ if (isset($data['data']['results'])) return $data['data']['results'];
183+
184+ return \Result::Error("ドメインの確認に失敗。");
185+ }
186+
167187 //// 追加データ
168188
169189 //// 顧客様の追加データ
170190
171191 /**
172192 * 顧客様の検索
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)
193+ *
194+ * @param array $query 検索クエリー
195+ * @return Result|array
174196 */
175197 public function searchCustomers(array $query = []): \Result|array {
198+ if (!OPENPROVIDER_ENABLED) return \Result::error('エラー:OpenProviderは無効です。');
176199 foreach ($query as $k => $v) { if (is_bool($v)) $query[$k] = $v ? '1' : '0'; }
177200
178201 $uri = '/customers?'.http_build_query($query, '', '&', PHP_QUERY_RFC3986);
179202 $curl = $this->setupCurl($uri);
180- kys("TODO: 問題");
181203 $data = $this->curlResult($curl);
182- kys($data);
183204 if (isset($data['data'])) return $data['data'];
184205
185206 return \Result::Error("TLD一覧の受け取りに失敗。");
@@ -187,16 +208,34 @@
187208
188209 //// ドメイン値段
189210
211+ /**
212+ * ドメイン値段一覧
213+ *
214+ * @param array $query 検索クエリー
215+ * @return Result|array
216+ */
217+ public function getDomainPrices(array $query): \Result|array {
218+ if (!OPENPROVIDER_ENABLED) return \Result::error('エラー:OpenProviderは無効です。');
219+ $uri = "/domains/prices?".http_build_query($query, '', '&', PHP_QUERY_RFC3986);
220+ $curl = $this->setupCurl($uri);
221+ $data = $this->curlResult($curl);
222+ if (isset($data['data'])) return $data['data'];
223+
224+ return \Result::Error("TLD一覧の受け取りに失敗。");
225+ }
226+
190227 //// 認証コード
191228
192229 //// TLD
193230
194231 /**
195232 * 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))
233+ *
234+ * @param array $query 検索クエリー
235+ * @return Result|array
198236 */
199237 public function listTlds(array $query = []): \Result|array {
238+ if (!OPENPROVIDER_ENABLED) return \Result::error('エラー:OpenProviderは無効です。');
200239 if (empty($query)) $query = [ 'limit' => 10, 'offset' => 0, 'order' => 'ASC' ];
201240
202241 foreach ($query as $k => $v) {
@@ -204,17 +243,37 @@
204243 }
205244
206245 $uri = '/tlds?'.http_build_query($query, '', '&', PHP_QUERY_RFC3986);
207- // kys($uri);
208246 $curl = $this->setupCurl($uri);
209- kys("TODO: JSONの問題");
210247 $data = $this->curlResult($curl);
211- kys($data);
212248 if (isset($data['data'])) return $data['data'];
213249
214250 return \Result::Error("TLD一覧の受け取りに失敗。");
215251 }
216252
217253 /**
254+ * TLDの表示
255+ *
256+ * @param string $tld TLD
257+ * @param array $query 検索クエリー
258+ * @return Result|array
259+ */
260+ public function getTld(string $tld, array $query = []): \Result|array {
261+ if (!OPENPROVIDER_ENABLED) return \Result::error('エラー:OpenProviderは無効です。');
262+ if (empty($query)) $query = [ 'limit' => 10, 'offset' => 0 ];
263+
264+ foreach ($query as $k => $v) {
265+ if (is_bool($v)) $query[$k] = $v ? '1' : '0';
266+ }
267+
268+ $uri = "/tlds/{$tld}?".http_build_query($query, '', '&', PHP_QUERY_RFC3986);
269+ $curl = $this->setupCurl($uri);
270+ $data = $this->curlResult($curl);
271+ if (isset($data['data'])) return $data['data'];
272+
273+ return \Result::Error("TLD一覧の受け取りに失敗。");
274+ }
275+
276+ /**
218277 * TLDの受け取り
219278 */
220279
@@ -229,8 +288,66 @@
229288 //// NSグループ
230289 //// テンプレート
231290 //// ゾーン
291+
292+ /**
293+ * DNSゾーン一覧
294+ *
295+ * @param array $query
296+ * @return Result|array
297+ */
298+ public function listDnsZones(array $query = []): \Result|array {
299+ if (!OPENPROVIDER_ENABLED) return \Result::error('エラー:OpenProviderは無効です。');
300+ if (empty($query)) $query = [ 'limit' => 25, 'offset' => 0, 'order_by.name' => 'asc' ];
301+
302+ foreach ($query as $k => $v) {
303+ if (is_bool($v)) $query[$k] = $v ? '1' : '0';
304+ }
305+
306+ $uri = "/dns/zones?".http_build_query($query, '', '&', PHP_QUERY_RFC3986);
307+ $curl = $this->setupCurl($uri);
308+ $data = $this->curlResult($curl);
309+ if (isset($data['data'])) return $data['data'];
310+
311+ return \Result::Error("TLD一覧の受け取りに失敗。");
312+ }
313+
314+ /**
315+ * DNSゾーン一覧
316+ *
317+ * @param string $domain ドメイン名
318+ * @param array $query 検索クエリー
319+ * @return Result|array
320+ */
321+ public function getDnsZone(string $domain, array $query = []): \Result|array {
322+ if (!OPENPROVIDER_ENABLED) return \Result::error('エラー:OpenProviderは無効です。');
323+ if (empty($query)) $query = [ 'limit' => 100, 'offset' => 0, 'order_by.name' => 'asc' ];
324+ foreach ($query as $k => $v) if (is_bool($v)) $query[$k] = $v ? '1' : '0';
325+
326+ $uri = "/dns/zones/{$domain}?".http_build_query($query, '', '&', PHP_QUERY_RFC3986);
327+ $curl = $this->setupCurl($uri);
328+ $data = $this->curlResult($curl);
329+ if (isset($data['data'])) return $data['data'];
330+
331+ return \Result::Error("TLD一覧の受け取りに失敗。");
332+ }
333+
232334 //// ゾーンレコード
233335
336+ /**
337+ * DNSレコード一覧
338+ *
339+ * @param string $domain
340+ * @return Result|array
341+ */
342+ public function listZoneRecords(string $domain): \Result|array {
343+ if (!OPENPROVIDER_ENABLED) return \Result::error('エラー:OpenProviderは無効です。');
344+ $curl = $this->setupCurl("/dns/zones/{$domain}/records");
345+ $data = $this->curlResult($curl);
346+ if (isset($data['data'])) return $data['data'];
347+
348+ return \Result::Error("TLD一覧の受け取りに失敗。");
349+ }
350+
234351 // Easydmarc
235352
236353 // ライセンス
@@ -245,19 +362,21 @@
245362
246363 /**
247364 * トークンの受け取り。
248- *
365+ *
249366 * @return string トークン
250367 */
251368 public function getToken(): string {
369+ if (!OPENPROVIDER_ENABLED) return '';
252370 return $this->token;
253371 }
254372
255373 /**
256374 * リセラーIDの受け取り。
257- *
375+ *
258376 * @return int リセラーID
259377 */
260378 public function getResellerId(): int {
379+ if (!OPENPROVIDER_ENABLED) return 0;
261380 return $this->reseller_id;
262381 }
263382
@@ -277,7 +396,6 @@
277396
278397 private function curlResult(Curl &$curl): \Result|array {
279398 $res = $curl->execute();
280- // kys($curl->getRequestHeader());
281399 if (!$res->isSuccess) {
282400 $err = "CURL実行に失敗: {$curl->message}";
283401 assert_unless_success($res, $err);
@@ -285,18 +403,40 @@
285403 }
286404
287405 $body = $curl->getResponseBody();
288- // kys($body);
289- // kys($curl->getResponseHeaders());
290406 if ($curl->getResponseCode() != 200) {
291407 $err = json_decode($body, true);
292408 assert_not_null($err, "エラーの受け取りに失敗。");
293409 assert($curl->getResponseCode() == 200, $err['desc']);
294- return \Result::Error();
410+ return \Result::Error($err['desc']);
295411 }
296412 assert_not_null($body, "返事ボディーは空です。");
297413
298- // $body = str_
299- kys($body);
300414 return json_decode($body, true);
415+ }
416+
417+ private function mkCache(): \Result {
418+ $session = new \stdClass;
419+ $session->lastAuth = $this->last_auth;
420+ $session->token = $this->token;
421+ $session->resellerId = $this->reseller_id;
422+
423+ $json = json_encode($session, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
424+ if (file_put_contents($this->dataFile, $json) === false) return \Result::Error('エラー:ユーザーデータの保存に失敗。');
425+
426+ return \Result::Success();
427+ }
428+
429+ private function getCache(): void {
430+ if (!file_exists($this->dataFile)) return;
431+
432+ $content = file_get_contents($this->dataFile);
433+ if ($content === false) return;
434+
435+ $data = json_decode($content, true);
436+ if (json_last_error() !== JSON_ERROR_NONE || !is_array($data)) return;
437+
438+ $this->token = $data['token'] ?? null;
439+ $this->reseller_id = $data['resellerId'] ?? null;
440+ $this->last_auth = $data['lastAuth'] ?? null;
301441 }
302442 }
@@ -0,0 +1,53 @@
1+{@ include(common/header) @}
2+ <h2>ドメイン確認</h2>
3+ <form method="GET" action="/openprovider/checkdomain">
4+ 各行列で1つのドメイン名をご入力下さい。<br />
5+ <textarea name="domains">{{ $saved }}</textarea><br />
6+ <button>送信</button>
7+ </form>
8+{@ if (isset($data) && !empty($data)) @}
9+ <hr />
10+ <h2>結果</h2>
11+ <table>
12+ <thead>
13+ <tr>
14+ <th>ドメイン名</th>
15+ <th>状況</th>
16+ <th>理由</th>
17+ <th>値段</th>
18+ </tr>
19+ </thead>
20+ <tbody>
21+{@ foreach ($data as $d) @}
22+{$ $status = '不明' $}
23+{$ $statusClass = 'status-fumei' $}
24+{@ if ($d['status'] === 'free') @}
25+{$ $status = '登録可能' $}
26+{$ $statusClass = 'status-free' $}
27+{@ elif ($d['status'] === 'reserved') @}
28+{$ $status = '予約済み' $}
29+{$ $statusClass = 'status-reserved' $}
30+{@ elif ($d['status'] === 'active') @}
31+{$ $status = '登録済み' $}
32+{$ $statusClass = 'status-use' $}
33+{@ endif @}
34+ <tr class="{{ $statusClass }}">
35+ <td><a href="/openprovider/registerdomain/{{ $d['domain'] }}">{{ $d['domain'] }}</a>{{ isset($d['is_premium']) && $d['is_premium'] ? '(プレミアム)' : '' }}</td>
36+ <td>{{ $status }}</td>
37+ <td>{{ $d['reason'] ?? '' }}</td>
38+ <td>
39+{@ if (isset($d['price'])) @}
40+{@ if (isset($d['price']['product'])) @}
41+ 商品: {{ $d['price']['product']['price'] }} {{ $d['price']['product']['currency'] }}
42+{@ endif @}
43+{@ if (isset($d['price']['reseller'])) @}
44+ <br />リセラー: {{ $d['price']['reseller']['price'] }} {{ $d['price']['reseller']['currency'] }}
45+{@ endif @}
46+{@ endif @}
47+ </td>
48+ </tr>
49+{@ endforeach @}
50+ </tbody>
51+ </table>
52+{@ endif @}
53+{@ include(common/footer) @}
@@ -0,0 +1,34 @@
1+{@ include(common/header) @}
2+ <a href="#" class="">DNSゾーンの追加ボタン</a><br />
3+{@ if (isset($data['results'])) @}
4+ 検索バー<br />
5+ <h2>編集</h2>
6+ <table>
7+ <thead>
8+ <tr>
9+ <th>名前</th>
10+ <th>種類</th>
11+ <th>内容</th>
12+ <th>プライオリティ</th>
13+ <th>TTL</th>
14+ </tr>
15+ </thead>
16+ <tbody>
17+{@ foreach ($data['results'] as $d) @}
18+ <tr>
19+ <td><a href="/openprovider/editdnszone/{{ $d['name'] }}">{{ $d['name'] }}</a></td>
20+ <td>{{ $d['type'] }}</td>
21+ <td>{{ substr($d['value'], 0, 40) }}</td>
22+ <td>{{ $d['prio'] ?? '' }}</td>
23+ <td>{{ $d['ttl'] }}</td>
24+ </tr>
25+{@ endforeach @}
26+ </tbody>
27+ </table>
28+ </div>
29+{@ else @}
30+ <p>何も見つけられませんでした。</p>
31+{@ endif @}
32+
33+ {@ kys($data) @}
34+{@ include(common/footer) @}
@@ -0,0 +1,150 @@
1+{@ include(common/header) @}
2+ <style>
3+ .tabs {
4+ border-radius: 2px;
5+ box-shadow: 0 4px 12px rgba(0,0,0,0.1);
6+ }
7+
8+ .tab-nav {
9+ display: flex;
10+ border-bottom: 1px solid #ea79d8;
11+ }
12+
13+ .tab-nav label {
14+ flex: 1;
15+ color: #ea79d8;
16+ padding: 16px 20px;
17+ text-align: center;
18+ cursor: pointer;
19+ background: #550f75;
20+ transition: all 0.3s;
21+ font-weight: 600;
22+ }
23+
24+ .tab-nav label:hover {
25+ background: #8952a3;
26+ }
27+
28+ .tab-input {
29+ display: none;
30+ }
31+
32+ #tab1:checked ~ .tab-nav label[for="tab1"],
33+ #tab2:checked ~ .tab-nav label[for="tab2"],
34+ #tab3:checked ~ .tab-nav label[for="tab3"],
35+ #tab4:checked ~ .tab-nav label[for="tab4"] {
36+ background: #2c023f;
37+ border-bottom: 3px solid #ea79d8;
38+ color: #ea79d8;
39+ }
40+
41+ .tab-content {
42+ display: none;
43+ min-height: 200px;
44+ }
45+
46+ #tab1:checked ~ .tab-content[data-tab="1"],
47+ #tab2:checked ~ .tab-nav ~ .tab-content[data-tab="2"],
48+ #tab3:checked ~ .tab-nav ~ .tab-content[data-tab="3"],
49+ #tab4:checked ~ .tab-nav ~ .tab-content[data-tab="4"] {
50+ display: block;
51+ }
52+ </style>
53+
54+ <a href="#" class="">DNSレコードの追加ボタン</a><br />
55+ <a href="#" class="">DNSゾーンの削除ボタン</a><br />
56+{@ if (isset($data['rec']['results']) || isset($data['zone'])) @}
57+ 検索バー<br />
58+ <div class="tabs">
59+ <input type="radio" id="tab1" name="tabs" class="tab-input" checked />
60+ <input type="radio" id="tab2" name="tabs" class="tab-input" />
61+ <input type="radio" id="tab3" name="tabs" class="tab-input" />
62+ <input type="radio" id="tab4" name="tabs" class="tab-input" />
63+
64+ <div class="tab-nav">
65+ <label for="tab1">レコード</label>
66+ <label for="tab2">詳細</label>
67+ <label for="tab3">DNSSEC鍵</label>
68+ <label for="tab4">履歴</label>
69+ </div>
70+
71+ <div class="tab-content" data-tab="1">
72+ <h2>レコード</h2>
73+ <table>
74+ <thead>
75+ <tr>
76+ <th>名前</th>
77+ <th>種類</th>
78+ <th>内容</th>
79+ <th>プライオリティ</th>
80+ <th>TTL</th>
81+ </tr>
82+ </thead>
83+ <tbody>
84+{@ foreach ($data['rec']['results'] as $d) @}
85+ <tr>
86+ <td><a href="/openprovider/editdnszone/{{ $d['name'] }}">{{ $d['name'] }}</a></td>
87+ <td>{{ $d['type'] }}</td>
88+ <td>{{ substr($d['value'], 0, 40) }}</td>
89+ <td>{{ $d['prio'] ?? '' }}</td>
90+ <td>{{ $d['ttl'] }}</td>
91+ </tr>
92+{@ endforeach @}
93+ </tbody>
94+ </table>
95+ </div>
96+
97+ <div class="tab-content" data-tab="2">
98+ <h2>詳細</h2>
99+ <table>
100+ <tbody>
101+ <tr>
102+ <td>ドメイン名</td>
103+ <td>{{ $data['zone']['name'] }}</td>
104+ </tr>
105+ <tr>
106+ <td>種類</td>
107+ <td>{{ $data['zone']['type'] }}</td>
108+ </tr>
109+ <tr>
110+ <td>DNSゾーンプロバイダー</td>
111+ <td>Openprovider</td>
112+ </tr>
113+ <tr>
114+ <td>追加日</td>
115+ <td>{{ $data['zone']['creation_date'] }}</td>
116+ </tr>
117+ <tr>
118+ <td>最終更新日</td>
119+ <td>{{ $data['zone']['modification_date'] }}</td>
120+ </tr>
121+ <tr>
122+ <td>レコード数</td>
123+ <td>{{ $data['rec']['total'] }}</td>
124+ </tr>
125+ <tr>
126+ <td>DNSSEC有効</td>
127+ <td></td>
128+ </tr>
129+ <tr>
130+ <td>SpamExperts</td>
131+ <td>{{ $data['zone']['is_spamexperts_enabled'] ? '有' : '無' }}</td>
132+ </tr>
133+ </tbody>
134+ </table>
135+ </div>
136+
137+ <div class="tab-content" data-tab="3">
138+ <h2>DNSSEC鍵</h2>
139+ <p>ささ</p>
140+ </div>
141+
142+ <div class="tab-content" data-tab="4">
143+ <h2>履歴</h2>
144+ <p>ささ</p>
145+ </div>
146+ </div>
147+{@ else @}
148+ <p>何も見つけられませんでした。</p>
149+{@ endif @}
150+{@ include(common/footer) @}
@@ -0,0 +1,3 @@
1+{@ include(common/header) @}
2+ {@ kys($data) @}
3+{@ include(common/footer) @}
@@ -0,0 +1,3 @@
1+{@ include(common/header) @}
2+ {@ kys($data) @}
3+{@ include(common/footer) @}
@@ -0,0 +1,20 @@
1+{@ include(common/header) @}
2+ <h1>{{ $description }}</h1>
3+ <ul>
4+ <li>顧客様</li>
5+ <ul>
6+ <li><a href="/openprovider/searchcustomer">顧客様検索</a></li>
7+ </ul>
8+ <li>ドメイン</li>
9+ <ul>
10+ <li><a href="/openprovider/checkdomain">ドメイン確認</a></li>
11+ <li><a href="/openprovider/getdomainprices?domain.name=076&domain.extension=sex">ドメイン値段一覧</a></li>
12+ <li><a href="/openprovider/listtlds">TLD一覧</a></li>
13+ <li><a href="/openprovider/gettld/moe">TLDの表示(.moe)</a></li>
14+ </ul>
15+ <li>DNS</li>
16+ <ul>
17+ <li><a href="/openprovider/listdnszones">DNSゾーン一覧</a></li>
18+ </ul>
19+ </ul>
20+{@ include(common/footer) @}
@@ -0,0 +1,32 @@
1+{@ include(common/header) @}
2+ 検索バー<br />
3+ <a href="#" class="">DNSゾーンの追加ボタン</a>
4+{@ if (isset($data['results'])) @}
5+ <table>
6+ <thead>
7+ <tr>
8+ <th>Domain name</th>
9+ <th>Type</th>
10+ <th>DNS provider</th>
11+ <th>Renewal date</th>
12+ <th>Date added</th>
13+ <th>Last change</th>
14+ </tr>
15+ </thead>
16+ <tbody>
17+{@ foreach ($data['results'] as $d) @}
18+ <tr>
19+ <td><a href="/openprovider/getdns/{{ $d['name'] }}">{{ $d['name'] }}</a></td>
20+ <td>{{ $d['type'] }}</td>
21+ <td>{{ $d['provider'] }}</td>
22+ <td></td>
23+ <td>{{ $d['creation_date'] }}</td>
24+ <td>{{ $d['modification_date'] }}</td>
25+ </tr>
26+{@ endforeach @}
27+ </tbody>
28+ </table>
29+{@ else @}
30+ <p>何も見つけられませんでした。</p>
31+{@ endif @}
32+{@ include(common/footer) @}
@@ -0,0 +1,3 @@
1+{@ include(common/header) @}
2+ {@ kys($data) @}
3+{@ include(common/footer) @}
@@ -0,0 +1,3 @@
1+{@ include(common/header) @}
2+ <p>表示許可却下。失礼。</p>
3+{@ include(common/footer) @}
@@ -0,0 +1,29 @@
1+{@ include(common/header) @}
2+ 検索<br />
3+{@ if (isset($data['results'])) @}
4+ <table>
5+ <thead>
6+ <tr>
7+ <th>Name</th>
8+ <th>Company</th>
9+ <th>E-mail address</th>
10+ <th>Handle</th>
11+ <th>Notes</th>
12+ </tr>
13+ </thead>
14+ <tbody>
15+{@ foreach ($data['results'] as $d) @}
16+ <tr>
17+ <td><a href="/openprovider/getcustomer/{{ $d['handle'] }}">{{ $d['name']['full_name'] }}</a></td>
18+ <td>{{ $d['company_name'] }}</td>
19+ <td>{{ $d['email'] }}</td>
20+ <td>{{ $d['handle'] }}</td>
21+ <td></td>
22+ </tr>
23+{@ endforeach @}
24+ </tbody>
25+ </table>
26+{@ else @}
27+ <p>何も見つけられませんでした。</p>
28+{@ endif @}
29+{@ include(common/footer) @}