PluginProbe
Metricool – Social media and site statistics / 2.0.2
Metricool – Social media and site statistics v2.0.2
2.1.0 2.0.2 2.0.1 2.0.0 1.27 trunk
metricool / app / Http / RSPAL / RspalApiClient.php

RspalApiClient.php in Metricool – Social media and site statistics 2.0.2, at app/Http/RSPAL/RspalApiClient.php

191 lines 5.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Metricool\Http\RSPAL;
4
5 use GuzzleHttp\Client;
6 use GuzzleHttp\Exception\GuzzleException;
7 use Metricool\Http\Metricool\MetricoolClient;
8 use Metricool\Support\Helpers\Storages\EnvironmentConfig;
9
10 class RspalApiClient
11 {
12 /**
13 * The option name for storing the InstallationID.
14 */
15 private const INSTALLATION_ID_OPTION = '_metricool_rspal_installation_id';
16
17 /**
18 * The default value for the InstallationID when it is not set.
19 */
20 private const UNKNOWN_INSTALLATION_ID = 'unknown';
21
22 /**
23 * The Guzzle HTTP client for making API requests
24 */
25 protected Client $client;
26
27 /**
28 * The base endpoint URL for the brand API
29 */
30 private string $baseEndpoint;
31
32 /**
33 * The default headers to send with each request
34 */
35 private array $headers = [
36 'Content-Type' => 'application/json',
37 'Accept' => 'application/json',
38 ];
39
40 private EnvironmentConfig $env;
41 private MetricoolClient $metricool;
42
43 public function __construct(EnvironmentConfig $env, MetricoolClient $metricool)
44 {
45 $this->env = $env;
46 $this->metricool = $metricool;
47
48 $this->baseEndpoint = $this->env->getUrl('metricool.rsp_auth_url');
49 $this->client = $this->client();
50 }
51
52 /**
53 * Sign Up Endpoint
54 *
55 * @throws GuzzleException
56 */
57 public function signUp(array $data, array $headers = []): RspalApiResponse
58 {
59 return $this->request('v2/integrations/wp-plugin/users/sign-ups', [
60 'json' => $data,
61 'headers' => $this->headers($headers)
62 ], 'post');
63 }
64
65 /**
66 * Make a request to the RSPAL API.
67 *
68 * @throws GuzzleException
69 */
70 private function request(string $path, array $params = [], string $method = 'get'): RspalApiResponse
71 {
72 // Request and store installationId if needed before any request
73 if (!$this->hasInstallationId()) {
74 $installation = $this->requestInstallation();
75
76 $this->setInstallationId($installation->data->uuid);
77 }
78
79 $response = $this->client->request(strtoupper($method), $this->uri($path), $params);
80
81 return RspalApiResponse::fromResponse($response);
82 }
83
84 /**
85 * Request a new InstallationID from the RSPAL API.
86 *
87 * @throws GuzzleException
88 */
89 private function requestInstallation(): RspalApiResponse
90 {
91 $response = $this->client->request('POST', $this->uri('installation/create'), [
92 'headers' => $this->headers()
93 ]);
94
95 return RspalApiResponse::fromResponse($response);
96 }
97
98 /**
99 * Create a new Guzzle HTTP client instance.
100 */
101 private function client(): Client
102 {
103 return new Client([
104 'http_errors' => false,
105 'verify' => false,
106 ]);
107 }
108
109 /**
110 * Get any headers that should be sent with the request.
111 */
112 private function headers(array $headers = []): array
113 {
114 $headers['User-Agent'] = $this->metricool->getRequestUserAgent();
115
116 return array_merge($this->headers, $this->rspalHeaders(), $headers);
117 }
118
119 protected function rspalHeaders(): array
120 {
121 $installationId = $this->getInstallationId();
122
123 $rspalHeaders = [
124 'RSPAL-PluginName' => $this->env->getString('plugin.name'),
125 'RSPAL-PluginVersion' => $this->env->getString('plugin.version'),
126 'RSPAL-PluginPath' => $this->getPluginPathHeader(),
127 'RSPAL-Origin' => trailingslashit(site_url()),
128 'RSPAL-InstallationId' => $installationId,
129 ];
130
131 $rspalHeaders['RSPAL-Signature'] = $this->getInstallationSignature($rspalHeaders, $installationId);
132
133 return $rspalHeaders;
134 }
135
136 /**
137 * Get the plugin path relative to the WordPress root directory.
138 */
139 private function getPluginPathHeader(): string
140 {
141 $pluginFullPath = wp_normalize_path(realpath($this->env->getString('plugin.path')));
142 $wpRoot = wp_normalize_path(realpath(ABSPATH));
143
144 return str_replace($wpRoot, '', $pluginFullPath);
145 }
146
147 /**
148 * Get the full URI for the given path.
149 */
150 private function uri(string $path): string
151 {
152 return rtrim($this->baseEndpoint, '/') . '/' . ltrim($path, '/');
153 }
154
155 /**
156 * Generate the installation signature.
157 */
158 private function getInstallationSignature(array $format, string $id): string
159 {
160 return hash_hmac('sha256', json_encode($format), $id);
161 }
162
163 /**
164 * Stores the InstallationID in wp_options
165 */
166 private function setInstallationId(string $installationId): void
167 {
168 $installation = update_option(self::INSTALLATION_ID_OPTION, $installationId, false);
169
170 if (!$installation) {
171 throw new \RuntimeException('Failed to store InstallationID');
172 }
173 }
174
175 /**
176 * Check if the InstallationID has already been stored
177 */
178 private function hasInstallationId(): bool
179 {
180 return $this->getInstallationId() !== self::UNKNOWN_INSTALLATION_ID;
181 }
182
183 /**
184 * Return the installationId from wp_options
185 */
186 private function getInstallationId(): string
187 {
188 return get_option(self::INSTALLATION_ID_OPTION, self::UNKNOWN_INSTALLATION_ID);
189 }
190 }
191