Passed
Push — master ( cea66e...0061ac )
by Scrutinizer
01:24
created

ConfigProtectedMethods::getUrlHost()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * This file is part of the keinos/mastodon-streaming-api-config package.
5
 *
6
 * - Authors, copyright, license, usage and etc.:
7
 *   - See: https://github.com/KEINOS/Mastodon_StreamingAPI_Config/
8
 */
9
10
declare(strict_types=1);
11
12
namespace KEINOS\MSTDN_TOOLS;
13
14
use Symfony\Component\HttpClient\HttpClient           as HttpClient;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\HttpClient\HttpClient was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
15
use Symfony\Component\Cache\Adapter\FilesystemAdapter as FilesystemAdapter;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Cache\Adapter\FilesystemAdapter was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
16
17
/**
18
 * Parent class of \KEINOS\MSTDN_TOOLS\Config class.
19
 *
20
 * Note that the only public method allowed is "__construct()". Other public
21
 * methods and properties must be defined in "Config" child class.
22
 */
23
class ConfigProtectedMethods extends ConfigStaticMethods
24
{
25
    /** @var string */
26
    protected $access_token = '';
27
    /** @var string */
28
    protected $endpoint_api_instance;
29
    /** @var string */
30
    protected $id_hash_self;
31
    /** @var array<mixed,mixed> */
32
    protected $info_server;
33
    /** @var int */
34
    protected $ttl_cache;
35
    /** @var bool */
36
    protected $use_cache = true;
37
    /** @var string */
38
    protected $url_host;
39
    /** @var string */
40
    protected $url_api_instance;
41
42
    /**
43
     * {@inheritdoc}
44
     *
45
     * @param  array<string,string> $settings
46
     * @return void
47
     */
48
    public function __construct(array $settings)
49
    {
50
        $this->setIdHashSelf();
51
        $this->setEndpointApiInstance($settings);
52
        $this->setTtlCache($settings);
53
        $this->setFlagUseCache($settings);
54
        $this->setUrlHost($settings);
55
        $this->setToken($settings);
56
        $this->setUrlApiInstance($settings);
57
        $this->setServerInfo();
58
    }
59
60
    /**
61
     * Clears all the caches.
62
     *
63
     * @return void
64
     * @suppress PhanUndeclaredClassMethod
65
    */
66
    protected function clearCaches(): void
67
    {
68
        $cache_namespace = $this->getIdHashSelf();
69
        $cache_lifetime  = $this->getTtlCache();
70
71
        $cache_pool = new FilesystemAdapter($cache_namespace, $cache_lifetime);
72
        $cache_pool->clear();
73
    }
74
75
    /**
76
     * Delete cache
77
     *
78
     * @param  string $key
79
     * @return void
80
     * @suppress PhanUndeclaredClassMethod
81
     */
82
    protected function deleteCache(string $key): void
83
    {
84
        $cache_namespace = $this->getIdHashSelf();
85
        $cache_lifetime  = $this->getTtlCache();
86
87
        $cache_pool = new FilesystemAdapter($cache_namespace, $cache_lifetime);
88
        $cache_pool->deleteItem($key);
89
    }
90
91
    protected function getAccessToken(): string
92
    {
93
        return $this->access_token;
94
    }
95
96
    /**
97
     * @param string $url_api
98
     * @return array<mixed,mixed>
99
     * @throws \Exception
100
     * @suppress PhanUndeclaredClassMethod
101
     */
102
    protected function getContentsAsArray(string $url_api): array
103
    {
104
        try {
105
            $client_http = HttpClient::create();
106
            $response = $client_http->request('GET', $url_api);
107
            // Get contents as array
108
            return $response->toArray();
109
        } catch (\Exception $e) {
110
            $msg = 'Error while setting server info.' . PHP_EOL
111
                 . '- Error details: ' . $e->getMessage() . PHP_EOL;
112
            throw new \Exception($msg);
113
        }
114
    }
115
116
    /**
117
     * Get value from cache.
118
     *
119
     * @param  string $key
120
     * @return null|mixed
121
     * @suppress PhanUndeclaredClassMethod
122
     */
123
    protected function getCache(string $key)
124
    {
125
        $cache_namespace = $this->getIdHashSelf();
126
        $cache_lifetime  = $this->getTtlCache();
127
128
        $cache_pool = new FilesystemAdapter($cache_namespace, $cache_lifetime);
129
        $cache_item = $cache_pool->getItem($key);
130
131
        if (! $cache_item->isHit()) {
132
            return null;
133
        }
134
        return $cache_item->get();
135
    }
136
137
    protected function getEndpointApiInstance(): string
138
    {
139
        return $this->endpoint_api_instance;
140
    }
141
142
    protected function getFlagUseCache(): bool
143
    {
144
        return $this->use_cache;
145
    }
146
147
    protected function getIdHashSelf(): string
148
    {
149
        return $this->id_hash_self;
150
    }
151
152
    protected function getTtlCache(): int
153
    {
154
        return $this->ttl_cache;
155
    }
156
157
    protected function getUrlApiInstance(): string
158
    {
159
        return $this->url_api_instance;
160
    }
161
162
    protected function getUrlHost(): string
163
    {
164
        return $this->url_host;
165
    }
166
167
    /**
168
     * setCache
169
     *
170
     * @param  string $key
171
     * @param  mixed $value
172
     * @return void
173
     * @suppress PhanUndeclaredClassMethod
174
     */
175
    protected function setCache(string $key, $value): void
176
    {
177
        $cache_namespace = $this->getIdHashSelf();
178
        $cache_lifetime  = $this->getTtlCache();
179
180
        $cache_pool = new FilesystemAdapter($cache_namespace, $cache_lifetime);
181
        $cache_item = $cache_pool->getItem($key);
182
183
        $cache_item->set($value);
184
        $cache_pool->save($cache_item);
185
    }
186
187
    /**
188
     * setEndpointApiInstance
189
     *
190
     * @param  array<string,string> $settings
191
     * @return void
192
     */
193
    protected function setEndpointApiInstance(array $settings)
194
    {
195
        $url = self::ENDPOINT_API_INSTANCE;
196
        if (isset($settings['endpoint_api_instance'])) {
197
            $url = $settings['endpoint_api_instance'];
198
        }
199
        $this->endpoint_api_instance = $url;
200
    }
201
202
    /**
203
     * @param  array<string,string> $settings
204
     * @return void
205
     */
206
    protected function setFlagUseCache(array $settings): void
207
    {
208
        if (isset($settings['use_cache'])) {
209
            $this->use_cache = ($settings['use_cache'] === "true");
210
        }
211
    }
212
213
    protected function setIdHashSelf(): void
214
    {
215
        $this->id_hash_self = self::CACHE_PREFIX . strval(hash_file('md5', __FILE__));
216
    }
217
218
    protected function setServerInfo(): void
219
    {
220
        $info = null;
221
        if ($this->getFlagUseCache()) {
222
            $info = $this->getCache('info_server');
223
        } else {
224
            $this->clearCaches();
225
        }
226
227
        if (null === $info) {
228
            $url_api = $this->getUrlApiInstance();
229
            $info = $this->getContentsAsArray($url_api);
230
            // Check if must keys are set
231
            if (! isset($info['urls']['streaming_api'])) {
232
                throw new \Exception('The server did NOT return with "streaming_api" key.');
233
            }
234
        }
235
        // Set/update cache
236
        $this->setCache('info_server', $info);
237
        // Set property
238
        $this->info_server = $info;
239
    }
240
241
    /**
242
     * @param  array<string,string> $settings
243
     * @return void
244
     * @throws \Exception            If the token is in bad format.
245
     */
246
    protected function setToken(array $settings): void
247
    {
248
        if (! isset($settings['access_token'])) {
249
            return;
250
        }
251
252
        $access_token = $settings['access_token'];
253
254
        if (empty(trim($access_token))) {
255
            return;
256
        }
257
258
        if (! self::isAlphaNumeric($access_token)) {
259
            $msg = 'Invalid access token. Should be alpha numeric.';
260
            throw new \Exception($msg);
261
        }
262
263
        // Mastodon's token is 64 byte in length
264
        if (64 !== strlen($access_token)) {
265
            $msg = 'Invalid access token. Should be 64 chars in length.';
266
            throw new \Exception($msg);
267
        }
268
269
        // Set property
270
        $this->access_token = $access_token;
271
    }
272
273
    /**
274
     * @param  array<string,string> $settings
275
     * @return void
276
     */
277
    protected function setTtlCache(array $settings): void
278
    {
279
        $ttl = self::CACHE_TTL_DEFAULT;
280
        if (isset($settings['ttl_cache'])) {
281
            $ttl = $settings['ttl_cache'];
282
        }
283
        $this->ttl_cache = intval($ttl);
284
    }
285
286
    /**
287
     * @param  array<string,string> $settings
288
     * @return void
289
     */
290
    protected function setUrlApiInstance(array $settings): void
291
    {
292
        $endpoint_api_instance = $this->getEndpointApiInstance();
293
        $url_host = $this->getUrlHost();
294
295
        if (isset($settings['endpoint_api_instance'])) {
296
            $endpoint_api_instance = $settings['endpoint_api_instance'];
297
            $this->endpoint_api_instance = $endpoint_api_instance;
298
        }
299
300
        $this->url_api_instance = rtrim($url_host, '/') . $endpoint_api_instance;
301
    }
302
303
    /**
304
     * @param  array<string,string> $settings
305
     * @return void
306
     * @throws \Exception
307
     *   If the server isn't available.
308
     */
309
    protected function setUrlHost(array $settings): void
310
    {
311
        try {
312
            if (! isset($settings['url_host'])) {
313
                $msg = 'Must key "url_host" is missing in the setting array.';
314
                throw new \Exception($msg);
315
            }
316
317
            $url_host = $settings['url_host'];
318
319
            if (self::isUrlProtocolHttp($url_host)) {
320
                $msg = 'Not in "https:" protocol. We do not allow "http:" protocol.';
321
                throw new \Exception($msg);
322
            }
323
324
            /** @phan-suppress-next-line PhanUndeclaredClassMethod */
325
            $client_http = HttpClient::create();
326
327
            $response = $client_http->request('HEAD', $url_host);
328
            if (200 !== $response->getStatusCode()) {
329
                throw new \Exception('The server did not return 200 status.');
330
            }
331
            // Set property
332
            $this->url_host = $url_host;
333
        } catch (\Exception $e) {
334
            $msg = 'Error while setting server host URL.' . PHP_EOL
335
                 . '- Error details: ' . $e->getMessage() . PHP_EOL;
336
            throw new \Exception($msg);
337
        }
338
    }
339
}
340