PluginProbe
Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization / 4.2.11
Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization v4.2.11
4.2.13 4.2.12 4.2.11 4.2.10 4.2.9 4.2.8 4.2.7 4.2.6 4.2.5 2.5.5 2.5.6 2.5.7 3.0.0 3.0.1 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.11.0 3.11.1 3.11.2 3.11.3 3.12.0 3.12.1 All 134 releases
optimole-wp / vendor / codeinwp / optimole-sdk / src / Offload / Manager.php

Manager.php in Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization 4.2.11, at vendor/codeinwp/optimole-sdk/src/Offload/Manager.php

248 lines 8.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare(strict_types=1);
4
5 /*
6 * This file is part of Optimole PHP SDK.
7 *
8 * (c) Optimole Team <friends@optimole.com>
9 *
10 * For the full copyright and license information, please view the LICENSE
11 * file that was distributed with this source code.
12 */
13
14 namespace Optimole\Sdk\Offload;
15
16 use Optimole\Sdk\Exception\BadResponseException;
17 use Optimole\Sdk\Exception\InvalidArgumentException;
18 use Optimole\Sdk\Exception\InvalidDashboardApiResponseException;
19 use Optimole\Sdk\Exception\InvalidUploadApiResponseException;
20 use Optimole\Sdk\Exception\RuntimeException;
21 use Optimole\Sdk\Exception\UploadApiException;
22 use Optimole\Sdk\Exception\UploadFailedException;
23 use Optimole\Sdk\Exception\UploadLimitException;
24 use Optimole\Sdk\Http\ClientInterface;
25 use Optimole\Sdk\ValueObject\OffloadUsage;
26
27 class Manager
28 {
29 /**
30 * The HTTP client.
31 */
32 private ClientInterface $httpClient;
33
34 /**
35 * The manager options.
36 */
37 private array $options;
38
39 /**
40 * Constructor.
41 */
42 public function __construct(ClientInterface $httpClient, array $options = [])
43 {
44 if (empty($options['dashboard_api_url'])) {
45 throw new InvalidArgumentException('Missing "dashboard_api_url" option');
46 } elseif (empty($options['upload_api_url'])) {
47 throw new InvalidArgumentException('Missing "upload_api_url" option');
48 }
49
50 $this->httpClient = $httpClient;
51 $this->options = array_merge([
52 'upload_api_credentials' => [],
53 ], $options);
54
55 $this->options['dashboard_api_url'] = rtrim($this->options['dashboard_api_url'], '/');
56 $this->options['upload_api_url'] = rtrim($this->options['upload_api_url'], '/');
57 }
58
59 /**
60 * Delete the image with the given image ID.
61 */
62 public function deleteImage(string $imageId): void
63 {
64 try {
65 $this->requestToUploadApi([
66 'id' => $imageId,
67 'deleteUrl' => 'true',
68 ]);
69 } catch (BadResponseException $exception) {
70 }
71 }
72
73 /**
74 * Get the image URL for the given image ID.
75 */
76 public function getImageUrl(string $imageId): ?string
77 {
78 try {
79 $response = $this->requestToUploadApi([
80 'id' => $imageId,
81 'getUrl' => 'true',
82 ]);
83 } catch (BadResponseException $exception) {
84 return null;
85 }
86
87 if (empty($response['getUrl'])) {
88 throw new InvalidUploadApiResponseException('Unable to get image URL from upload API');
89 }
90
91 return (string) $response['getUrl'];
92 }
93
94 /**
95 * Get the offload service usage.
96 */
97 public function getUsage(): OffloadUsage
98 {
99 $response = $this->requestToDashboardApi();
100
101 if (!isset($response['data']['offload_limit'], $response['data']['offloaded_images'])) {
102 throw new InvalidDashboardApiResponseException('Dashboard API did not return details about the offload service usage');
103 }
104
105 return new OffloadUsage((int) $response['data']['offloaded_images'], (int) $response['data']['offload_limit']);
106 }
107
108 /**
109 * Update the metadata of the image with the given ID.
110 */
111 public function updateImageMetadata(string $imageId, int $fileSize = 0, $height = 'auto', $width = 'auto', $originalUrl = ''): void
112 {
113 if ('auto' !== $height && !is_int($height)) {
114 throw new InvalidArgumentException('Image height must be "auto" or an integer.');
115 } elseif ('auto' !== $width && !is_int($width)) {
116 throw new InvalidArgumentException('Image width must be "auto" or an integer.');
117 }
118
119 $this->requestToUploadApi([
120 'id' => $imageId,
121 'originalFileSize' => $fileSize,
122 'height' => is_int($height) ? max(0, $height) : $height,
123 'width' => is_int($width) ? max(0, $width) : $width,
124 'originalUrl' => $originalUrl,
125 'updateDynamo' => 'success',
126 ]);
127 }
128
129 /**
130 * Upload an image to Optimole and return its image ID.
131 */
132 public function uploadImage(string $filename, string $imageUrl): string
133 {
134 if (!file_exists($filename)) {
135 throw new InvalidArgumentException(sprintf('File "%s" does not exist', $filename));
136 } elseif (!is_readable($filename)) {
137 throw new InvalidArgumentException(sprintf('File "%s" is not readable', $filename));
138 }
139
140 $fileMimeType = $this->getMimeType($filename);
141
142 try {
143 $response = $this->requestToUploadApi([
144 'originalUrl' => $imageUrl,
145 ]);
146 } catch (BadResponseException $exception) {
147 throw new UploadApiException('Unable to get signed URL from upload API', 0, $exception);
148 }
149
150 if (isset($response['error']) && 'limit_exceeded' === $response['error']) {
151 throw new UploadLimitException(new OffloadUsage((int) $response['count'], (int) $response['limit']));
152 } elseif (isset($response['error'])) {
153 throw new UploadApiException(sprintf('Upload API returned an error: %s', $response['error']));
154 } elseif (isset($response['count'], $response['limit']) && $response['count'] >= $response['limit']) {
155 throw new UploadLimitException(new OffloadUsage((int) $response['count'], (int) $response['limit']));
156 } elseif (!isset($response['tableId'], $response['uploadUrl'])) {
157 throw new InvalidUploadApiResponseException('Upload API did not return the table ID and upload URL');
158 }
159
160 $imageId = (string) $response['tableId'];
161 $uploadUrl = (string) $response['uploadUrl'];
162
163 $image = file_get_contents($filename);
164
165 if (false === $image) {
166 throw new RuntimeException(sprintf('Unable to get file "%s" content', $filename));
167 }
168
169 try {
170 $this->httpClient->sendRequest('PUT', $uploadUrl, $image, [
171 'Content-Type' => $fileMimeType,
172 ]);
173 } catch (BadResponseException $exception) {
174 throw new UploadFailedException(sprintf('Unable to upload file "%s": %s', $filename, $exception->getMessage()), 0, $exception);
175 }
176
177 $imagesize = getimagesize($filename);
178
179 $this->updateImageMetadata($imageId, filesize($filename) ?: 0, $imagesize && !empty($imagesize[1]) ? $imagesize[1] : 'auto', $imagesize && !empty($imagesize[0]) ? $imagesize[0] : 'auto', $imageUrl);
180
181 return $imageId;
182 }
183
184 /**
185 * Get the MIME type of the given file.
186 */
187 private function getMimeType(string $filename): string
188 {
189 $finfo = finfo_open(FILEINFO_MIME_TYPE);
190
191 if (false === $finfo) {
192 throw new RuntimeException('Unable to open fileinfo database');
193 }
194
195 $mimeType = finfo_file($finfo, $filename);
196
197 finfo_close($finfo);
198
199 if (false === $mimeType) {
200 throw new RuntimeException(sprintf('Unable to get MIME type for file "%s"', $filename));
201 }
202
203 return $mimeType;
204 }
205
206 /**
207 * Get the upload API credentials from the dashboard API.
208 */
209 private function getUploadApiCredentialsFromDashboardApi(): array
210 {
211 $response = $this->requestToDashboardApi();
212
213 if (!isset($response['data']['cdn_key'], $response['data']['cdn_secret'])) {
214 throw new InvalidDashboardApiResponseException('Dashboard API did not return upload API credentials');
215 }
216
217 return [
218 'userKey' => $response['data']['cdn_key'],
219 'secret' => $response['data']['cdn_secret'],
220 ];
221 }
222
223 /**
224 * Make a request to the dashboard API.
225 */
226 private function requestToDashboardApi(): array
227 {
228 return $this->httpClient->sendRequest('POST', sprintf('%s/optml/v2/account/details', $this->options['dashboard_api_url']), null, [
229 'Authorization' => sprintf('Bearer %s', $this->options['dashboard_api_key']),
230 'Content-Type' => 'application/json',
231 ]);
232 }
233
234 /**
235 * Make a request to the upload API.
236 */
237 private function requestToUploadApi(array $body): array
238 {
239 if (!isset($this->options['upload_api_credentials']['userKey'], $this->options['upload_api_credentials']['secret'])) {
240 $this->options['upload_api_credentials'] = $this->getUploadApiCredentialsFromDashboardApi();
241 }
242
243 return $this->httpClient->sendRequest('POST', $this->options['upload_api_url'], array_merge($this->options['upload_api_credentials'], $body), [
244 'Content-Type' => 'application/json',
245 ]);
246 }
247 }
248