Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
90.46% |
256 / 283 |
|
60.61% |
20 / 33 |
CRAP | |
0.00% |
0 / 1 |
Azure | |
90.46% |
256 / 283 |
|
60.61% |
20 / 33 |
132.51 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
create | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
initClient | |
100.00% |
17 / 17 |
|
100.00% |
1 / 1 |
3 | |||
setClient | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getClient | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
hasClient | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
setAuth | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getAuth | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
hasAuth | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
mkdir | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
rmdir | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
listDirs | |
69.70% |
23 / 33 |
|
0.00% |
0 / 1 |
25.04 | |||
listFiles | |
87.50% |
21 / 24 |
|
0.00% |
0 / 1 |
13.33 | |||
putFile | |
94.12% |
16 / 17 |
|
0.00% |
0 / 1 |
4.00 | |||
putFileContents | |
93.33% |
14 / 15 |
|
0.00% |
0 / 1 |
3.00 | |||
uploadFile | |
94.74% |
18 / 19 |
|
0.00% |
0 / 1 |
6.01 | |||
copyFile | |
94.44% |
17 / 18 |
|
0.00% |
0 / 1 |
9.01 | |||
copyFileToExternal | |
93.75% |
15 / 16 |
|
0.00% |
0 / 1 |
8.02 | |||
copyFileFromExternal | |
94.44% |
17 / 18 |
|
0.00% |
0 / 1 |
6.01 | |||
moveFileToExternal | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
moveFileFromExternal | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
3 | |||
renameFile | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
replaceFileContents | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
deleteFile | |
92.31% |
12 / 13 |
|
0.00% |
0 / 1 |
5.01 | |||
fetchFile | |
84.62% |
11 / 13 |
|
0.00% |
0 / 1 |
6.13 | |||
fetchFileInfo | |
93.75% |
15 / 16 |
|
0.00% |
0 / 1 |
4.00 | |||
fileExists | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
isDir | |
88.24% |
15 / 17 |
|
0.00% |
0 / 1 |
5.04 | |||
isFile | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getFileSize | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getFileType | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
3 | |||
getFileMTime | |
66.67% |
4 / 6 |
|
0.00% |
0 / 1 |
5.93 | |||
md5File | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
3 |
1 | <?php |
2 | /** |
3 | * Pop PHP Framework (http://www.popphp.org/) |
4 | * |
5 | * @link https://github.com/popphp/popphp-framework |
6 | * @author Nick Sagona, III <dev@nolainteractive.com> |
7 | * @copyright Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com) |
8 | * @license http://www.popphp.org/license New BSD License |
9 | */ |
10 | |
11 | /** |
12 | * @namespace |
13 | */ |
14 | namespace Pop\Storage\Adapter; |
15 | |
16 | use Pop\Storage\Adapter\Azure\Auth; |
17 | use Pop\Http\Client; |
18 | use Pop\Http\Client\Request; |
19 | use Pop\Utils\File; |
20 | |
21 | /** |
22 | * Storage adapter Azure class |
23 | * |
24 | * @category Pop |
25 | * @package Pop\Storage |
26 | * @author Nick Sagona, III <dev@nolainteractive.com> |
27 | * @copyright Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com) |
28 | * @license http://www.popphp.org/license New BSD License |
29 | * @version 2.0.0 |
30 | */ |
31 | class Azure extends AbstractAdapter |
32 | { |
33 | |
34 | /** |
35 | * HTTP client |
36 | * @var ?Client |
37 | */ |
38 | protected ?Client $client = null; |
39 | |
40 | /** |
41 | * Azure auth object |
42 | * @var ?Auth |
43 | */ |
44 | protected ?Auth $auth = null; |
45 | |
46 | /** |
47 | * Constructor |
48 | * |
49 | * @param string $location |
50 | * @param Auth $auth |
51 | */ |
52 | public function __construct(string $location, Auth $auth) |
53 | { |
54 | parent::__construct($location); |
55 | $this->setAuth($auth); |
56 | $this->initClient(); |
57 | } |
58 | |
59 | /** |
60 | * Create Azure client |
61 | * |
62 | * @param string $accountName |
63 | * @param string $accountKey |
64 | * @return Azure |
65 | */ |
66 | public static function create(string $accountName, string $accountKey): Azure |
67 | { |
68 | return new self($accountName, new Azure\Auth($accountName, $accountKey)); |
69 | } |
70 | |
71 | /** |
72 | * Initialize client |
73 | * |
74 | * @param string $method |
75 | * @param array $headers |
76 | * @param bool $auto |
77 | * @return Azure |
78 | */ |
79 | public function initClient(string $method = 'GET', array $headers = [], bool $auto = true): Azure |
80 | { |
81 | $request = new Request('/', $method); |
82 | $request->addHeader('Date', gmdate('D, d M Y H:i:s T')) |
83 | ->addHeader('Host', $this->auth->getAccountName() . '.blob.core.windows.net') |
84 | ->addHeader('Content-Type', Client\Request::URLFORM) |
85 | ->addHeader('User-Agent', 'pop-storage/2.0.0 (PHP ' . PHP_VERSION . ')/' . PHP_OS) |
86 | ->addHeader('x-ms-client-request-id', uniqid()) |
87 | ->addHeader('x-ms-version', '2023-11-03'); |
88 | |
89 | if (!empty($headers)) { |
90 | foreach ($headers as $header => $value) { |
91 | $request->addHeader($header, $value); |
92 | } |
93 | } |
94 | |
95 | $this->setClient(new Client( |
96 | $request, [ |
97 | 'base_uri' => $this->auth->getBaseUri(), |
98 | 'auto' => $auto |
99 | ] |
100 | )); |
101 | |
102 | return $this; |
103 | } |
104 | |
105 | /** |
106 | * Set client |
107 | * |
108 | * @param Client $client |
109 | * @return Azure |
110 | */ |
111 | public function setClient(Client $client): Azure |
112 | { |
113 | $this->client = $client; |
114 | return $this; |
115 | } |
116 | |
117 | /** |
118 | * Get client |
119 | * |
120 | * @return ?Client |
121 | */ |
122 | public function getClient(): ?Client |
123 | { |
124 | return $this->client; |
125 | } |
126 | |
127 | /** |
128 | * Has client |
129 | * |
130 | * @return bool |
131 | */ |
132 | public function hasClient(): bool |
133 | { |
134 | return ($this->client !== null); |
135 | } |
136 | |
137 | /** |
138 | * Set auth |
139 | * |
140 | * @param Auth $auth |
141 | * @return Azure |
142 | */ |
143 | public function setAuth(Auth $auth): Azure |
144 | { |
145 | $this->auth = $auth; |
146 | return $this; |
147 | } |
148 | |
149 | /** |
150 | * Get auth |
151 | * |
152 | * @return ?Auth |
153 | */ |
154 | public function getAuth(): ?Auth |
155 | { |
156 | return $this->auth; |
157 | } |
158 | |
159 | /** |
160 | * Has auth |
161 | * |
162 | * @return bool |
163 | */ |
164 | public function hasAuth(): bool |
165 | { |
166 | return ($this->auth !== null); |
167 | } |
168 | |
169 | /** |
170 | * Make directory |
171 | * |
172 | * @param string $directory |
173 | * @return void |
174 | */ |
175 | public function mkdir(string $directory): void |
176 | { |
177 | /** |
178 | * Azure storage doesn't allow the creation of empty "directories" (prefixes.) |
179 | * A new "directory" (prefix) is automatically created with an uploaded file that utilizes a prefix |
180 | */ |
181 | } |
182 | |
183 | /** |
184 | * Remove a directory |
185 | * |
186 | * @param string $directory |
187 | * @return void |
188 | */ |
189 | public function rmdir(string $directory): void |
190 | { |
191 | /** |
192 | * Azure storage doesn't allow the direct removal of "directories" (prefixes.) |
193 | * A "directory" (prefix) is automatically removed when the last file that utilizes the prefix is deleted. |
194 | */ |
195 | } |
196 | |
197 | /** |
198 | * List directories |
199 | * |
200 | * @param ?string $search |
201 | * @return array |
202 | */ |
203 | public function listDirs(?string $search = null): array |
204 | { |
205 | $dirs = []; |
206 | |
207 | if ($this->baseDirectory == $this->directory) { |
208 | $this->initClient(); |
209 | $this->client->getRequest()->setQuery(['comp' => 'list']); |
210 | $this->auth->signRequest($this->client->getRequest()); |
211 | |
212 | $response = $this->client->send(); |
213 | |
214 | if (is_array($response) && !empty($response['Containers'])) { |
215 | foreach ($response['Containers'] as $container) { |
216 | $dirs[] = $container['Name']; |
217 | } |
218 | } |
219 | } else { |
220 | $container = str_replace($this->baseDirectory, '', $this->directory); |
221 | |
222 | $params = ['restype' => 'container', 'comp' => 'list']; |
223 | if (substr_count($container, '/') > 1) { |
224 | $folders = array_filter(explode('/', $container)); |
225 | $container = '/' . array_shift($folders); |
226 | $params['prefix'] = implode('/', $folders) . '/'; |
227 | } |
228 | |
229 | $this->initClient(); |
230 | $this->client->getRequest()->setQuery($params); |
231 | $this->client->getRequest()->setUri($container); |
232 | $this->auth->signRequest($this->client->getRequest()); |
233 | |
234 | $response = $this->client->send(); |
235 | |
236 | if (is_array($response) && !empty($response['Blobs']) && !empty($response['Blobs']['Blob'])) { |
237 | $blobs = (!isset($response['Blobs']['Blob'][0])) ? |
238 | [$response['Blobs']['Blob']] : $response['Blobs']['Blob']; |
239 | foreach ($blobs as $blob) { |
240 | $name = (isset($params['prefix']) && str_starts_with($blob['Name'], $params['prefix'])) ? |
241 | substr($blob['Name'], strlen($params['prefix'])) : $blob['Name']; |
242 | if (!empty($name) && (substr_count($name, '/') >= 1)) { |
243 | $folder = substr($name, 0, (strpos($name, '/') + 1)); |
244 | if (!in_array($folder, $dirs)) { |
245 | $dirs[] = $folder; |
246 | } |
247 | } |
248 | } |
249 | } |
250 | } |
251 | |
252 | if ($search !== null) { |
253 | $dirs = $this->searchFilter($dirs, $search); |
254 | } |
255 | |
256 | return $dirs; |
257 | } |
258 | |
259 | /** |
260 | * List files |
261 | * |
262 | * @param ?string $search |
263 | * @return array |
264 | */ |
265 | public function listFiles(?string $search = null): array |
266 | { |
267 | $files = []; |
268 | |
269 | if ($this->baseDirectory !== $this->directory) { |
270 | $container = str_replace($this->baseDirectory, '', $this->directory); |
271 | |
272 | $params = ['restype' => 'container', 'comp' => 'list']; |
273 | if (substr_count($container, '/') > 1) { |
274 | $folders = array_filter(explode('/', $container)); |
275 | $container = '/' . array_shift($folders); |
276 | $params['prefix'] = implode('/', $folders) . '/'; |
277 | } |
278 | |
279 | $this->initClient(); |
280 | $this->client->getRequest()->setQuery($params); |
281 | $this->client->getRequest()->setUri($container); |
282 | $this->auth->signRequest($this->client->getRequest()); |
283 | |
284 | $response = $this->client->send(); |
285 | |
286 | if (is_array($response) && !empty($response['Blobs']) && !empty($response['Blobs']['Blob'])) { |
287 | $blobs = (!isset($response['Blobs']['Blob'][0])) ? |
288 | [$response['Blobs']['Blob']] : $response['Blobs']['Blob']; |
289 | foreach ($blobs as $blob) { |
290 | $name = (isset($params['prefix']) && str_starts_with($blob['Name'], $params['prefix'])) ? |
291 | substr($blob['Name'], strlen($params['prefix'])) : $blob['Name']; |
292 | if (!empty($name) && !str_contains($name, '/')) { |
293 | $files[] = $name; |
294 | } |
295 | } |
296 | } |
297 | } |
298 | |
299 | if ($search !== null) { |
300 | $files = $this->searchFilter($files, $search); |
301 | } |
302 | |
303 | return $files; |
304 | } |
305 | |
306 | /** |
307 | * Put file |
308 | * |
309 | * @param string $fileFrom |
310 | * @param bool $copy |
311 | * @throws Exception|Client\Handler\Exception|\Pop\Http\Exception|\Pop\Utils\Exception |
312 | * @return void |
313 | */ |
314 | public function putFile(string $fileFrom, bool $copy = true): void |
315 | { |
316 | if (file_exists($fileFrom)) { |
317 | $uri = '/' . basename($fileFrom); |
318 | if ($this->baseDirectory !== $this->directory) { |
319 | $directory = str_replace($this->baseDirectory, '', $this->directory); |
320 | if (str_ends_with($directory, '/')) { |
321 | $directory = substr($directory, 0, -1); |
322 | } |
323 | $uri = $directory . $uri; |
324 | } |
325 | |
326 | $fileContents = file_get_contents($fileFrom); |
327 | |
328 | $this->initClient('PUT', [ |
329 | 'content-length' => strlen($fileContents), |
330 | 'x-ms-blob-type' => 'BlockBlob', |
331 | 'x-ms-blob-content-type' => File::getFileMimeType($fileFrom) |
332 | ]); |
333 | $this->client->getRequest()->setUri($uri); |
334 | $this->client->getRequest()->setBody($fileContents); |
335 | $this->auth->signRequest($this->client->getRequest()); |
336 | $this->client->send(); |
337 | } |
338 | } |
339 | |
340 | /** |
341 | * Put file contents |
342 | * |
343 | * @param string $filename |
344 | * @param string $fileContents |
345 | * @return void |
346 | */ |
347 | public function putFileContents(string $filename, string $fileContents): void |
348 | { |
349 | $uri = '/' . $filename; |
350 | if ($this->baseDirectory !== $this->directory) { |
351 | $directory = str_replace($this->baseDirectory, '', $this->directory); |
352 | if (str_ends_with($directory, '/')) { |
353 | $directory = substr($directory, 0, -1); |
354 | } |
355 | $uri = $directory . $uri; |
356 | } |
357 | |
358 | $this->initClient('PUT', [ |
359 | 'content-length' => strlen($fileContents), |
360 | 'x-ms-blob-type' => 'BlockBlob', |
361 | 'x-ms-blob-content-type' => File::getFileMimeType($filename) |
362 | ]); |
363 | $this->client->getRequest()->setUri($uri); |
364 | $this->client->getRequest()->setBody($fileContents); |
365 | $this->auth->signRequest($this->client->getRequest()); |
366 | $this->client->send(); |
367 | } |
368 | |
369 | /** |
370 | * Upload file from server request $_FILES['file'] |
371 | * |
372 | * @param array $file |
373 | * @throws Exception |
374 | * @return void |
375 | */ |
376 | public function uploadFile(array $file): void |
377 | { |
378 | if (!isset($file['tmp_name']) || !isset($file['name'])) { |
379 | throw new Exception('Error: The uploaded file array was not valid'); |
380 | } |
381 | if (file_exists($file['tmp_name'])) { |
382 | $uri = '/' . $file['name']; |
383 | if ($this->baseDirectory !== $this->directory) { |
384 | $directory = str_replace($this->baseDirectory, '', $this->directory); |
385 | if (str_ends_with($directory, '/')) { |
386 | $directory = substr($directory, 0, -1); |
387 | } |
388 | $uri = $directory . $uri; |
389 | } |
390 | |
391 | $fileContents = file_get_contents($file['tmp_name']); |
392 | |
393 | $this->initClient('PUT', [ |
394 | 'content-length' => strlen($fileContents), |
395 | 'x-ms-blob-type' => 'BlockBlob', |
396 | 'x-ms-blob-content-type' => File::getFileMimeType($file['name']) |
397 | ]); |
398 | $this->client->getRequest()->setUri($uri); |
399 | $this->client->getRequest()->setBody($fileContents); |
400 | $this->auth->signRequest($this->client->getRequest()); |
401 | $this->client->send(); |
402 | } |
403 | } |
404 | |
405 | /** |
406 | * Copy file |
407 | * |
408 | * @param string $sourceFile |
409 | * @param string $destFile |
410 | * @return void |
411 | */ |
412 | public function copyFile(string $sourceFile, string $destFile): void |
413 | { |
414 | $sourceFileInfo = $this->fetchFileInfo($sourceFile); |
415 | |
416 | if (is_array($sourceFileInfo) && isset($sourceFileInfo['headers']) && |
417 | isset($sourceFileInfo['headers']['Content-Type']) && (!$sourceFileInfo['isError'])) { |
418 | $sourceUri = (!str_starts_with($sourceFile, '/')) ? '/' . $sourceFile : $sourceFile; |
419 | $destUri = (!str_starts_with($destFile, '/')) ? '/' . $destFile : $destFile; |
420 | |
421 | if ($this->baseDirectory !== $this->directory) { |
422 | $directory = str_replace($this->baseDirectory, '', $this->directory); |
423 | if (str_ends_with($directory, '/')) { |
424 | $directory = substr($directory, 0, -1); |
425 | } |
426 | $sourceUri = $directory . $sourceUri; |
427 | $destUri = $directory . $destUri; |
428 | } |
429 | |
430 | $this->initClient('PUT', [ |
431 | 'content-length' => $sourceFileInfo['headers']['Content-Length'], |
432 | 'x-ms-copy-source' => $this->auth->getBaseUri() . $sourceUri, |
433 | ]); |
434 | $this->client->getRequest()->setUri($destUri); |
435 | $this->auth->signRequest($this->client->getRequest()); |
436 | $this->client->send(); |
437 | } |
438 | } |
439 | |
440 | /** |
441 | * Copy file to a location external to the current location |
442 | * |
443 | * @param string $sourceFile |
444 | * @param string $externalFile |
445 | * @return void |
446 | */ |
447 | public function copyFileToExternal(string $sourceFile, string $externalFile): void |
448 | { |
449 | $sourceFileInfo = $this->fetchFileInfo($sourceFile); |
450 | |
451 | if (is_array($sourceFileInfo) && isset($sourceFileInfo['headers']) && |
452 | isset($sourceFileInfo['headers']['Content-Type']) && (!$sourceFileInfo['isError'])) { |
453 | $sourceUri = (!str_starts_with($sourceFile, '/')) ? '/' . $sourceFile : $sourceFile; |
454 | |
455 | if ($this->baseDirectory !== $this->directory) { |
456 | $directory = str_replace($this->baseDirectory, '', $this->directory); |
457 | if (str_ends_with($directory, '/')) { |
458 | $directory = substr($directory, 0, -1); |
459 | } |
460 | $sourceUri = $directory . $sourceUri; |
461 | } |
462 | |
463 | $this->initClient('PUT', [ |
464 | 'content-length' => $sourceFileInfo['headers']['Content-Length'], |
465 | 'x-ms-copy-source' => $this->auth->getBaseUri() . $sourceUri, |
466 | ]); |
467 | $this->client->getRequest()->setUri($externalFile); |
468 | $this->auth->signRequest($this->client->getRequest()); |
469 | $this->client->send(); |
470 | } |
471 | } |
472 | |
473 | /** |
474 | * Copy file from a location external to the current location |
475 | * |
476 | * @param string $externalFile |
477 | * @param string $destFile |
478 | * @return void |
479 | */ |
480 | public function copyFileFromExternal(string $externalFile, string $destFile): void |
481 | { |
482 | $this->initClient('HEAD', [], false); |
483 | $this->client->getRequest()->setUri($externalFile); |
484 | $this->auth->signRequest($this->client->getRequest()); |
485 | $response = $this->client->send(); |
486 | |
487 | if (($response->isSuccess()) && ($response->hasHeader('Content-Length'))) { |
488 | $destUri = (!str_starts_with($destFile, '/')) ? '/' . $destFile : $destFile; |
489 | |
490 | if ($this->baseDirectory !== $this->directory) { |
491 | $directory = str_replace($this->baseDirectory, '', $this->directory); |
492 | if (str_ends_with($directory, '/')) { |
493 | $directory = substr($directory, 0, -1); |
494 | } |
495 | $destUri = $directory . $destUri; |
496 | } |
497 | |
498 | $this->initClient('PUT', [ |
499 | 'content-length' => $response->getHeader('Content-Length')->getValueAsString(), |
500 | 'x-ms-copy-source' => $this->auth->getBaseUri() . $externalFile, |
501 | ]); |
502 | $this->client->getRequest()->setUri($destUri); |
503 | $this->auth->signRequest($this->client->getRequest()); |
504 | $this->client->send(); |
505 | } |
506 | } |
507 | |
508 | /** |
509 | * Move file to a location external to the current location |
510 | * |
511 | * @param string $sourceFile |
512 | * @param string $externalFile |
513 | * @return void |
514 | */ |
515 | public function moveFileToExternal(string $sourceFile, string $externalFile): void |
516 | { |
517 | $this->copyFileToExternal($sourceFile, $externalFile); |
518 | $this->deleteFile($sourceFile); |
519 | } |
520 | |
521 | /** |
522 | * Move file from a location external to the current location |
523 | * |
524 | * @param string $externalFile |
525 | * @param string $destFile |
526 | * @param ?string $snapshots ['include', 'only', null] |
527 | * @return void |
528 | */ |
529 | public function moveFileFromExternal(string $externalFile, string $destFile, ?string $snapshots = 'include'): void |
530 | { |
531 | $this->copyFileFromExternal($externalFile, $destFile); |
532 | |
533 | $headers = []; |
534 | if ($snapshots !== null) { |
535 | $headers['x-ms-delete-snapshots'] = ($snapshots == 'only') ? 'only' : 'include'; |
536 | } |
537 | |
538 | $this->initClient('DELETE', $headers); |
539 | $this->client->getRequest()->setUri($externalFile); |
540 | $this->auth->signRequest($this->client->getRequest()); |
541 | $this->client->send(); |
542 | } |
543 | |
544 | /** |
545 | * Rename file |
546 | * |
547 | * @param string $oldFile |
548 | * @param string $newFile |
549 | * @return void |
550 | */ |
551 | public function renameFile(string $oldFile, string $newFile): void |
552 | { |
553 | $this->copyFile($oldFile, $newFile); |
554 | $this->deleteFile($oldFile); |
555 | } |
556 | |
557 | /** |
558 | * Replace file |
559 | * |
560 | * @param string $filename |
561 | * @param string $fileContents |
562 | * @return void |
563 | */ |
564 | public function replaceFileContents(string $filename, string $fileContents): void |
565 | { |
566 | $this->putFileContents($filename, $fileContents); |
567 | } |
568 | |
569 | /** |
570 | * Delete file |
571 | * |
572 | * @param string $filename |
573 | * @param ?string $snapshots ['include', 'only', null] |
574 | * @return void |
575 | */ |
576 | public function deleteFile(string $filename, ?string $snapshots = 'include'): void |
577 | { |
578 | $uri = '/' . $filename; |
579 | if ($this->baseDirectory !== $this->directory) { |
580 | $directory = str_replace($this->baseDirectory, '', $this->directory); |
581 | if (str_ends_with($directory, '/')) { |
582 | $directory = substr($directory, 0, -1); |
583 | } |
584 | $uri = $directory . $uri; |
585 | } |
586 | |
587 | $headers = []; |
588 | if ($snapshots !== null) { |
589 | $headers['x-ms-delete-snapshots'] = ($snapshots == 'only') ? 'only' : 'include'; |
590 | } |
591 | |
592 | $this->initClient('DELETE', $headers); |
593 | $this->client->getRequest()->setUri($uri); |
594 | $this->auth->signRequest($this->client->getRequest()); |
595 | $this->client->send(); |
596 | } |
597 | |
598 | /** |
599 | * Fetch file |
600 | * |
601 | * @param string $filename |
602 | * @param bool $raw |
603 | * @return mixed |
604 | */ |
605 | public function fetchFile(string $filename, bool $raw = true): mixed |
606 | { |
607 | $filename = (!str_starts_with($filename, '/')) ? '/' . $filename : $filename; |
608 | |
609 | if ($this->baseDirectory !== $this->directory) { |
610 | $directory = str_replace($this->baseDirectory, '', $this->directory); |
611 | if (str_ends_with($directory, '/')) { |
612 | $directory = substr($directory, 0, -1); |
613 | } |
614 | $filename = $directory . $filename; |
615 | } |
616 | |
617 | $this->initClient('GET', [], false); |
618 | $this->client->getRequest()->setUri($filename); |
619 | $this->auth->signRequest($this->client->getRequest()); |
620 | $response = $this->client->send(); |
621 | |
622 | if ($response->isSuccess()) { |
623 | return ($raw) ? $response->getBody()->getContent(): $response; |
624 | } else { |
625 | return null; |
626 | } |
627 | } |
628 | |
629 | /** |
630 | * Fetch file info |
631 | * |
632 | * @param string $filename |
633 | * @return array |
634 | */ |
635 | public function fetchFileInfo(string $filename): array |
636 | { |
637 | $filename = (!str_starts_with($filename, '/')) ? '/' . $filename : $filename; |
638 | |
639 | if ($this->baseDirectory !== $this->directory) { |
640 | $directory = str_replace($this->baseDirectory, '', $this->directory); |
641 | if (str_ends_with($directory, '/')) { |
642 | $directory = substr($directory, 0, -1); |
643 | } |
644 | $filename = $directory . $filename; |
645 | } |
646 | |
647 | $this->initClient('HEAD', [], false); |
648 | $this->client->getRequest()->setUri($filename); |
649 | $this->auth->signRequest($this->client->getRequest()); |
650 | $response = $this->client->send(); |
651 | |
652 | return [ |
653 | 'code' => $response->getCode(), |
654 | 'message' => $response->getMessage(), |
655 | 'headers' => $response->getHeadersAsArray(), |
656 | 'isError' => $response->isError() |
657 | ]; |
658 | } |
659 | |
660 | /** |
661 | * File exists |
662 | * |
663 | * @param string $filename |
664 | * @return bool |
665 | */ |
666 | public function fileExists(string $filename): bool |
667 | { |
668 | $info = $this->fetchFileInfo($filename); |
669 | return (isset($info['code']) && ((int)$info['code'] == 200)); |
670 | } |
671 | |
672 | /** |
673 | * Check if is a dir |
674 | * |
675 | * @param string $directory |
676 | * @return bool |
677 | */ |
678 | public function isDir(string $directory): bool |
679 | { |
680 | if (str_starts_with($directory, '/')) { |
681 | $directory = substr($directory, 1); |
682 | } |
683 | if (str_ends_with($directory, '/')) { |
684 | $directory = substr($directory, 0, -1); |
685 | } |
686 | |
687 | $directories = explode('/', $directory); |
688 | $result = false; |
689 | $curDirectory = $this->directory; |
690 | $dirString = substr(str_replace($this->baseDirectory, '', $this->directory), 1) . '/'; |
691 | foreach ($directories as $directory) { |
692 | $dirs = $this->listDirs(); |
693 | $dirString .= $directory . '/'; |
694 | if (in_array($directory . '/', $dirs)) { |
695 | $result = true; |
696 | } else { |
697 | $result = false; |
698 | } |
699 | $this->chdir($dirString); |
700 | } |
701 | |
702 | $this->directory = $curDirectory; |
703 | |
704 | return $result; |
705 | } |
706 | |
707 | /** |
708 | * Check if is a file |
709 | * |
710 | * @param string $filename |
711 | * @return bool |
712 | */ |
713 | public function isFile(string $filename): bool |
714 | { |
715 | return $this->fileExists($filename); |
716 | } |
717 | |
718 | /** |
719 | * Get file size |
720 | * |
721 | * @param string $filename |
722 | * @return int|bool |
723 | */ |
724 | public function getFileSize(string $filename): int|bool |
725 | { |
726 | $info = $this->fetchFileInfo($filename); |
727 | return $info['headers']['Content-Length'] ?? false; |
728 | } |
729 | |
730 | /** |
731 | * Get file type |
732 | * |
733 | * @param string $filename |
734 | * @return string|bool |
735 | */ |
736 | public function getFileType(string $filename): string|bool |
737 | { |
738 | if ($this->isFile($filename)) { |
739 | return 'file'; |
740 | } else if ($this->isDir($filename)) { |
741 | return 'dir'; |
742 | } else { |
743 | return false; |
744 | } |
745 | } |
746 | |
747 | /** |
748 | * Get file modified time |
749 | * |
750 | * @param string $filename |
751 | * @return int|string|bool |
752 | */ |
753 | public function getFileMTime(string $filename): int|string|bool |
754 | { |
755 | $info = $this->fetchFileInfo($filename); |
756 | if (isset($info['headers']) && !empty($info['headers']['Last-Modified'])) { |
757 | return $info['headers']['Last-Modified']; |
758 | } else if (isset($info['headers']) && !empty($info['headers']['x-ms-creation-time'])) { |
759 | return $info['headers']['x-ms-creation-time']; |
760 | } else { |
761 | return false; |
762 | } |
763 | } |
764 | |
765 | /** |
766 | * Create MD5 checksum of the file |
767 | * |
768 | * @param string $filename |
769 | * @return string|bool |
770 | */ |
771 | public function md5File(string $filename): string|bool |
772 | { |
773 | $info = $this->fetchFileInfo($filename); |
774 | if (isset($info['headers']) && !empty($info['headers']['Content-MD5'])) { |
775 | return $info['headers']['Content-MD5']; |
776 | } else { |
777 | return false; |
778 | } |
779 | } |
780 | |
781 | } |