PluginProbe
Media Cloud Sync / 1.3.11
Media Cloud Sync v1.3.11
1.4.0 1.3.12 1.3.11 1.3.10 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.2.0 1.2.10 1.2.11 1.2.12 1.2.13 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 All 34 releases
media-cloud-sync / includes / base / services / s3compatible.php

s3compatible.php in Media Cloud Sync 1.3.11, at includes/base/services/s3compatible.php

865 lines 36.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Dudlewebs\WPMCS;
3
4 defined('ABSPATH') || exit;
5
6 // Libraries
7 use Dudlewebs\WPMCS\s3\Aws\S3\S3Client;
8 use Dudlewebs\WPMCS\s3\Aws\Exception\AwsException;
9 use Dudlewebs\WPMCS\s3\Aws\S3\Exception\S3Exception;
10 use Dudlewebs\WPMCS\s3\Aws\S3\MultipartUploader;
11 use Dudlewebs\WPMCS\s3\Aws\Exception\MultipartUploadException;
12 use Exception;
13
14 class S3Compatible {
15 private $assets_url;
16 private $version;
17 private $token;
18
19 protected $config;
20 protected $bucketConfig;
21 protected $settings;
22 protected $credentials;
23 protected $bucket_name;
24 protected $cdnConfig;
25
26 public $service = 's3compatible';
27 public $S3CompatibleClient = false;
28
29 /**
30 * Admin constructor.
31 * @since 1.0.0
32 */
33 public function __construct() {
34 $this->assets_url = WPMCS_ASSETS_URL;
35 $this->version = WPMCS_VERSION;
36 $this->token = WPMCS_TOKEN;
37
38 // Initialize setup
39 $this->init();
40 }
41
42 /**
43 * Initialise Client
44 */
45 public function init() {
46 $this->settings = Utils::get_settings();
47 $this->credentials = Utils::get_credentials();
48 $this->config = isset($this->credentials['config']) && !empty($this->credentials['config'])
49 ? $this->credentials['config']
50 : [];
51 $this->bucketConfig = isset($this->credentials['bucketConfig']) && !empty($this->credentials['bucketConfig'])
52 ? $this->credentials['bucketConfig']
53 : [];
54 $this->bucket_name = isset($this->bucketConfig['bucket_name']) && !empty($this->bucketConfig['bucket_name'])
55 ? $this->bucketConfig['bucket_name']
56 : '';
57 $this->cdnConfig = isset($this->credentials['cdn']) && !empty($this->credentials['cdn'])
58 ? $this->credentials['cdn']
59 : [];
60
61 if (
62 isset($this->config['access_key']) && !empty($this->config['access_key']) &&
63 isset($this->config['secret_key']) && !empty($this->config['secret_key']) &&
64 isset($this->config['endpoint']) && !empty($this->config['endpoint'])
65 ) {
66 $this->S3CompatibleClient = new S3Client([
67 'version' => '2006-03-01',
68 'region' => $this->config['region'] ? $this->config['region'] : 'us-east-1',
69 'endpoint' => $this->config['endpoint'], // DigitalOcean Spaces requires a custom endpoint
70 'use_accelerate_endpoint' => isset($this->bucketConfig['transfer_acceleration'])
71 ? $this->bucketConfig['transfer_acceleration'] : false,
72 'use_path_style_endpoint' => true, // DigitalOcean Spaces often requires path-style endpoints
73 'use_aws_shared_config_files' => false,
74 'credentials' => [
75 'key' => $this->config['access_key'],
76 'secret' => $this->config['secret_key'],
77 ],
78 ]);
79 }
80
81 }
82
83
84 /**
85 * Verify Credentials
86 * @since 1.0.0
87 * @return boolean
88 */
89 public function verifyCredentials( $config = [] ){
90 $access_key = isset($config['access_key']) ? $config['access_key'] : '';
91 $secret_key = isset($config['secret_key']) ? $config['secret_key'] : '';
92 $endpoint = isset($config['endpoint']) ? $config['endpoint'] : '';
93 $region = isset($config['region']) ? $config['region'] : 'us-east-1';
94 if (!empty($endpoint) && !empty($access_key) && !empty($secret_key)) {
95 try {
96 $S3CompatibleClient = new S3Client([
97 'version' => '2006-03-01',
98 'region' => $region ? $region : 'us-east-1',
99 'endpoint' => $endpoint,
100 'use_path_style_endpoint' => true, // Required for DigitalOcean Spaces
101 'use_accelerate_endpoint' => false,
102 'use_aws_shared_config_files' => false,
103 'credentials' => [
104 'key' => $access_key,
105 'secret' => $secret_key,
106 ],
107 ]);
108
109 $result = [
110 'success' => false,
111 'code' => 200,
112 'message' => esc_html__('Please check the authorization details', 'media-cloud-sync'),
113 ];
114
115 try {
116 $S3CompatibleClient->listObjectsV2([
117 'Bucket' => $this->token . '_dummy-bucket-for-auth-check'
118 ]);
119
120 // If we reach here, the credentials are valid
121 $result = [
122 'success' => true,
123 'code' => 200,
124 'message' => esc_html__('Credentials are valid', 'media-cloud-sync'),
125 ];
126 } catch (AwsException $e) {
127 $code = $e->getAwsErrorCode();
128
129 $validErrors = [
130 'AccessDenied',
131 'NoSuchBucket',
132 'AllAccessDisabled',
133 'AuthorizationHeaderMalformed',
134 'PermanentRedirect',
135 'InvalidBucketName',
136 ];
137
138 if (in_array($code, $validErrors)) {
139 // If we reach here, the credentials are valid
140 $result = [
141 'success' => true,
142 'code' => 200,
143 'message' => esc_html__('Credentials are valid', 'media-cloud-sync'),
144 ];
145 }
146 }
147
148 if($result['success'] == false) {
149 return $result;
150 }
151 $result['buckets_data']['buckets'] = [];
152 $result['buckets_data']['message'] = esc_html__('Buckets listed successfully', 'media-cloud-sync');
153 $result['buckets_data']['status'] = true;
154 return $result;
155 } catch (S3Exception $ex) {
156 return array('message' => $ex->getAwsErrorMessage() ?? esc_html__('Please check the authorization details', 'media-cloud-sync'), 'code' => 200, 'success' => false);
157 } catch (Exception $ex) {
158 return array('message' => $ex->getMessage() ?? esc_html__('Please check the authorization details', 'media-cloud-sync'), 'code' => 200, 'success' => false);
159 }
160 }
161 return array('message' => esc_html__('Insufficient Data. Please try again', 'media-cloud-sync'), 'code' => 200, 'success' => false);
162 }
163
164 /**
165 * Verify Bucket
166 * @since 1.0.0
167 * @return boolean
168 */
169 public function verifyBucketExist( $config = [], $bucketConfig = [] ) {
170 $access_key = isset($config['access_key']) ? $config['access_key'] : '';
171 $secret_key = isset($config['secret_key']) ? $config['secret_key'] : '';
172 $endpoint = isset($config['endpoint']) ? $config['endpoint'] : '';
173 $region = isset($config['region']) && !empty($config['region']) ? $config['region'] : 'us-east-1';
174 $bucket_name = isset($bucketConfig['bucket_name']) ? $bucketConfig['bucket_name'] : '';
175
176 if ( !empty($endpoint) && !empty($access_key) && !empty($secret_key) && !empty($bucket_name) ) {
177 try {
178 $S3CompatibleClient = new S3Client([
179 'version' => '2006-03-01',
180 'region' => $region ? $region : 'us-east-1',
181 'endpoint' => $endpoint,
182 'use_path_style_endpoint' => true, // Required for DigitalOcean Spaces
183 'use_accelerate_endpoint' => false,
184 'use_aws_shared_config_files' => false,
185 'credentials' => [
186 'key' => $access_key,
187 'secret' => $secret_key,
188 ],
189 ]);
190
191 //get S3 object
192 $bucket_found = false;
193 try {
194 $S3CompatibleClient->getObject([
195 'Bucket' => $bucket_name,
196 'Key' => $this->token . '_dummy-object-for-bucket-exist-check'
197 ]);
198 $bucket_found = true;
199 } catch (AwsException $e) {
200 $code = $e->getAwsErrorCode();
201 if ($code === 'NoSuchKey') {
202 $bucket_found = true;
203 }
204 }
205
206 if($bucket_found) {
207 return array('message' => esc_html__('Bucket exist', 'media-cloud-sync'), 'code' => 200, 'success' => true);
208 } else {
209 return array('message' => esc_html__("Bucket choosen does not exist / does not have read permission", 'media-cloud-sync'), 'code' => 200, 'success' => false);
210 }
211 }
212 catch (S3Exception $ex) {
213 return array('message' => $ex->getAwsErrorMessage() ?? esc_html__('Please check the authorization details', 'media-cloud-sync'), 'code' => 200, 'success' => false);
214 } catch (Exception $ex) {
215 return array('message' => $ex->getMessage() ?? esc_html__('Please check the authorization details', 'media-cloud-sync'), 'code' => 200, 'success' => false);
216 }
217 }
218 return array('message' => esc_html__('Insufficient Data. Please try again', 'media-cloud-sync'), 'code' => 200, 'success' => false);
219 }
220
221 /**
222 * Create Bucket
223 * @since 1.0.0
224 * @return boolean
225 */
226 public function createBucket( $config = [], $bucketConfig = [] ){
227 $access_key = isset($config['access_key']) ? $config['access_key'] : '';
228 $secret_key = isset($config['secret_key']) ? $config['secret_key'] : '';
229 $endpoint = isset($config['endpoint']) ? $config['endpoint'] : '';
230 $region = isset($config['region']) && !empty($config['region']) ? $config['region'] : 'us-east-1';
231 $bucket_name = isset($bucketConfig['bucket_name']) ? $bucketConfig['bucket_name'] : '';
232
233 if (empty($access_key) || empty($secret_key) || empty($bucket_name) || empty($endpoint)) {
234 return ['message' => esc_html__('Insufficient Data. Please try again', 'media-cloud-sync'), 'code' => 200, 'success' => false];
235 }
236
237 try {
238 $S3CompatibleClient = new S3Client([
239 'version' => '2006-03-01',
240 'region' => $region ? $region : 'us-east-1',
241 'endpoint' => $endpoint,
242 'use_path_style_endpoint' => true, // Required for DigitalOcean Spaces
243 'use_accelerate_endpoint' => false,
244 'use_aws_shared_config_files' => false,
245 'credentials' => [
246 'key' => $access_key,
247 'secret' => $secret_key,
248 ],
249 ]);
250
251 // Create Bucket
252 $S3CompatibleClient->createBucket([
253 'Bucket' => $bucket_name,
254 ]);
255
256 return [
257 'message' => esc_html__('Bucket created successfully.', 'media-cloud-sync'),
258 'data' => [
259 'Name' => $bucket_name,
260 'CreationDate' => date('Y-m-d\TH:i:s\Z'),
261 ],
262 'code' => 200,
263 'success' => true,
264 ];
265 } catch (AwsException $ex) {
266 return ['message' => $ex->getAwsErrorMessage(), 'code' => 200, 'success' => false];
267 } catch (S3Exception $ex) {
268 return ['message' => $ex->getAwsErrorMessage() ?? esc_html__('Please check the authorization details', 'media-cloud-sync'), 'code' => 200, 'success' => false];
269 } catch (Exception $ex) {
270 return ['message' => $ex->getMessage() ?? esc_html__('Please check the authorization details', 'media-cloud-sync'), 'code' => 200, 'success' => false];
271 }
272 }
273
274
275 /**
276 * Check Bucket Write Permission
277 * @since 1.0.0
278 */
279 public function verifyObjectWritePermission( $config = [], $bucketConfig = [] ){
280 $region = isset($config['region']) && !empty($config['region']) ? $config['region'] : 'us-east-1';
281 $access_key = isset($config['access_key']) ? $config['access_key'] : '';
282 $secret_key = isset($config['secret_key']) ? $config['secret_key'] : '';
283 $endpoint = isset($config['endpoint']) ? $config['endpoint'] : '';
284 $bucket_name = isset($bucketConfig['bucket_name']) ? $bucketConfig['bucket_name'] : '';
285
286 if (empty($endpoint) || empty($access_key) || empty($secret_key) || empty($bucket_name)) {
287 return ['message' => esc_html__('Insufficient Data. Please try again', 'media-cloud-sync'), 'code' => 200, 'success' => false];
288 }
289
290 try {
291 $S3CompatibleClient = new S3Client([
292 'version' => '2006-03-01',
293 'region' => $region ? $region : 'us-east-1',
294 'endpoint' => $endpoint,
295 'use_path_style_endpoint' => true, // Required for DigitalOcean Spaces
296 'use_accelerate_endpoint' => false,
297 'use_aws_shared_config_files' => false,
298 'credentials' => [
299 'key' => $access_key,
300 'secret' => $secret_key,
301 ],
302 ]);
303
304 $object_key = Utils::generate_object_key($this->token . '_dummy-object-for-bucket-permission-check', '');
305
306
307 // Create a dummy object to check write permission
308 $S3CompatibleClient->putObject([
309 'Bucket' => $bucket_name,
310 'Key' => $object_key,
311 'Body' => 'This is a test object to check write permission.',
312 ]);
313 // Check if the object was created successfully
314 if ($this->exists($object_key, $bucket_name, $S3CompatibleClient)) {
315 return ['message' => esc_html__('Bucket write permission verified successfully', 'media-cloud-sync'), 'code' => 200, 'success' => true];
316 } else {
317 return ['message' => esc_html__('Bucket write permission not verified', 'media-cloud-sync'), 'code' => 200, 'success' => false];
318 }
319
320 } catch (AwsException $ex) {
321 return ['message' => $ex->getAwsErrorMessage(), 'code' => 200, 'success' => false];
322 } catch (S3Exception $ex) {
323 return ['message' => $ex->getAwsErrorMessage() ?? esc_html__('Please check the authorization details', 'media-cloud-sync'), 'code' => 200, 'success' => false];
324 } catch (Exception $ex) {
325 return ['message' => $ex->getMessage() ?? esc_html__('Please check the authorization details', 'media-cloud-sync'), 'code' => 200, 'success' => false];
326 }
327 }
328
329
330
331 /**
332 * Check Bucket Delete Permission
333 * @since 1.0.0
334 */
335 public function verifyObjectDeletePermission( $config = [], $bucketConfig = [] ) {
336 $region = isset($config['region']) && !empty($config['region']) ? $config['region'] : 'us-east-1';
337 $access_key = isset($config['access_key']) ? $config['access_key'] : '';
338 $secret_key = isset($config['secret_key']) ? $config['secret_key'] : '';
339 $endpoint = isset($config['endpoint']) ? $config['endpoint'] : '';
340 $bucket_name = isset($bucketConfig['bucket_name']) ? $bucketConfig['bucket_name'] : '';
341
342 if (empty($endpoint) || empty($access_key) || empty($secret_key) || empty($bucket_name)) {
343 return ['message' => esc_html__('Insufficient Data. Please try again', 'media-cloud-sync'), 'code' => 200, 'success' => false];
344 }
345
346 try {
347 $S3CompatibleClient = new S3Client([
348 'version' => '2006-03-01',
349 'region' => $region ? $region : 'us-east-1',
350 'endpoint' => $endpoint,
351 'use_path_style_endpoint' => true, // Required for DigitalOcean Spaces
352 'use_accelerate_endpoint' => false,
353 'use_aws_shared_config_files' => false,
354 'credentials' => [
355 'key' => $access_key,
356 'secret' => $secret_key,
357 ],
358 ]);
359
360 $object_key = Utils::generate_object_key($this->token . '_dummy-object-for-bucket-permission-check', '');
361
362 // Create a dummy object to check dlete permission
363 $S3CompatibleClient->deleteObject([
364 'Bucket' => $bucket_name,
365 'Key' => $object_key,
366 ]);
367
368 // Check if the object was created successfully
369 if (!$this->exists($object_key, $bucket_name, $S3CompatibleClient)) {
370 return ['message' => esc_html__('Bucket delete permission verified successfully', 'media-cloud-sync'), 'code' => 200, 'success' => true];
371 } else {
372 return ['message' => esc_html__('Bucket delete permission not verified', 'media-cloud-sync'), 'code' => 200, 'success' => false];
373 }
374
375 } catch (AwsException $ex) {
376 return ['message' => $ex->getAwsErrorMessage(), 'code' => 200, 'success' => false];
377 } catch (S3Exception $ex) {
378 return ['message' => $ex->getAwsErrorMessage() ?? esc_html__('Please check the authorization details', 'media-cloud-sync'), 'code' => 200, 'success' => false];
379 } catch (Exception $ex) {
380 return ['message' => $ex->getMessage() ?? esc_html__('Please check the authorization details', 'media-cloud-sync'), 'code' => 200, 'success' => false];
381 }
382 }
383
384
385 /**
386 * Check Bucket Read Permission
387 * @since 1.2.4
388 */
389 public function verifyObjectReadPermission() {
390 $result = [
391 'status' => false,
392 'message' => '',
393 'lastChecked' => time(),
394 ];
395
396 if (empty($this->S3CompatibleClient) || empty($this->bucket_name)) {
397 $result['message'] = esc_html__('Invalid Request', 'media-cloud-sync');
398 return ['message' => esc_html__('Invalid Request', 'media-cloud-sync'), 'code' => 200, 'success' => false, 'lastChecked' => time()];
399 }
400
401 try {
402 $object_key = Utils::generate_object_key($this->token . '_dummy-object-for-bucket-permission-check', '');
403
404 // Check if the object was created successfully
405 if (!$this->exists($object_key)) {
406 // Create a dummy object to check write permission
407 $this->S3CompatibleClient->putObject([
408 'Bucket' => $this->bucket_name,
409 'Key' => $object_key,
410 'Body' => 'This is a test object to check permission.',
411 ]);
412 }
413
414
415 $url = $this->generate_file_url($object_key);
416 $cdn_url = Cdn::may_generate_cdn_url($url, $object_key);
417 $headers = @get_headers($cdn_url);
418
419 if (strpos($headers[0], '200') !== false) {
420 $result['status'] = true;
421 $result['message'] = esc_html__('Objects are accessible to Read', 'media-cloud-sync');
422 } else if (strpos($headers[0], '403') !== false) {
423 $result['status'] = false;
424 if($this->cdnConfig['service'] == $this->service) {
425 $result['message'] = esc_html__('Access Denied. Please check your bucket policy. Public Read Access is required.', 'media-cloud-sync');
426 } else {
427 $result['message'] = esc_html__('Access Denied. Please check your bucket policy', 'media-cloud-sync');
428 }
429 $result['message'] = esc_html__('Access Denied. Please check your bucket policy', 'media-cloud-sync');
430 } else if (strpos($headers[0], '404') !== false) {
431 $result['status'] = false;
432 $result['message'] = esc_html__('Object not found. Please check your bucket policy', 'media-cloud-sync');
433 } else if (strpos($headers[0], '500') !== false) {
434 $result['status'] = false;
435 $result['message'] = esc_html__('Internal Server error. Please check your bucket policy', 'media-cloud-sync');
436 } else {
437 $result['status'] = false;
438 $result['message'] = esc_html__('Objects are not accessible to read', 'media-cloud-sync');
439 }
440
441 $this->deleteSingle($object_key);
442 return [
443 'message' => $result['message'],
444 'code' => 200,
445 'success' => $result['status'],
446 'lastChecked' => $result['lastChecked'],
447 ];
448 } catch (AwsException $ex) {
449 $result['message'] = $ex->getAwsErrorMessage() ?? esc_html__('Please check the authorization details', 'media-cloud-sync');
450 return ['message' => $ex->getAwsErrorMessage() ?? esc_html__('Please check the authorization details', 'media-cloud-sync'), 'code' => 200, 'success' => false, 'lastChecked' => $result['lastChecked']];
451 } catch (S3Exception $ex) {
452 $result['message'] = $ex->getAwsErrorMessage() ?? esc_html__('Please check the authorization details', 'media-cloud-sync');
453 return ['message' => $ex->getAwsErrorMessage() ?? esc_html__('Please check the authorization details', 'media-cloud-sync'), 'code' => 200, 'success' => false, 'lastChecked' => $result['lastChecked']];
454 } catch (Exception $ex) {
455 $result['message'] = $ex->getMessage() ?? esc_html__('Please check the authorization details', 'media-cloud-sync');
456 return ['message' => $ex->getMessage() ?? esc_html__('Please check the authorization details', 'media-cloud-sync'), 'code' => 200, 'success' => false, 'lastChecked' => $result['lastChecked'] ];
457 }
458 }
459
460
461 /**
462 * isConfigured Function To Identify the congfigurations are correct
463 * @since 1.0.0
464 */
465 public function isConfigured(){
466 if ($this->S3CompatibleClient) {
467 try {
468 $this->S3CompatibleClient->listObjectsV2([
469 'Bucket' => $this->token . '_dummy-bucket-for-auth-check'
470 ]);
471
472 // If we reach here, the credentials are valid
473 return true;
474 } catch (AwsException $ex) {
475 $code = $ex->getAwsErrorCode();
476
477 $validErrors = [
478 'AccessDenied',
479 'NoSuchBucket',
480 'AllAccessDisabled',
481 'AuthorizationHeaderMalformed',
482 'PermanentRedirect',
483 'InvalidBucketName'
484 ];
485
486 if (in_array($code, $validErrors)) {
487 // If we reach here, the credentials are valid
488 return true;
489 } else {
490 return false;
491 }
492 } catch (S3Exception $ex) {
493 return false;
494 } catch (Exception $ex) {
495 return false;
496 }
497 }
498 return false;
499 }
500
501 /**
502 * Make Object Private
503 * @since 1.0.0
504 *
505 */
506 public function toPrivate($key) {
507 if(!$key) return false;
508 try {
509 $this->S3CompatibleClient->putObjectAcl([
510 'Bucket' => $this->bucket_name,
511 'Key' => $key,
512 'ACL' => 'private'
513 ]);
514 return true;
515 } catch (AwsException $ex) {
516 return false;
517 }
518 return false;
519 }
520
521
522
523 /**
524 * Make Object Public
525 * @since 1.0.0
526 *
527 */
528 public function toPublic($key) {
529 if(!$key) return false;
530 try {
531 $this->S3CompatibleClient->putObjectAcl([
532 'Bucket' => $this->bucket_name,
533 'Key' => $key,
534 'ACL' => 'public-read'
535 ]);
536 return true;
537 } catch (AwsException $ex) {
538 return false;
539 }
540 return false;
541 }
542
543
544
545 /**
546 * Check the object exist
547 * @since 1.1.8
548 */
549 public function exists($key, $bucket_name = '', $client = null) {
550 if(!$key) return false;
551
552 try {
553 $bucket_name = $bucket_name ? $bucket_name : $this->bucket_name;
554 $client = $client ?? $this->S3CompatibleClient;
555 if($client->doesObjectExistV2($bucket_name, $key)) {
556 return true;
557 }
558 } catch (AwsException $ex) {
559 return false;
560 } catch (S3Exception $ex) {
561 return false;
562 } catch (Exception $ex) {
563 return false;
564 }
565 }
566
567 /**
568 * Upload Single
569 * @since 1.0.0
570 * @return boolean
571 */
572 public function uploadSingle($absolute_source_path, $relative_source_path, $prefix='') {
573 $result = array();
574 if (
575 isset($absolute_source_path) && !empty($absolute_source_path) &&
576 isset($relative_source_path) && !empty($relative_source_path)
577 ) {
578 $file_name = wp_basename( $relative_source_path );
579 if ($file_name) {
580 $upload_path = Utils::generate_object_key($relative_source_path, $prefix);
581
582 // Decide Multipart upload or normal put object
583 if (filesize($absolute_source_path) <= Schema::getConstant('S3COMPATIBLE_MULTIPART_MIN_FILE_SIZE')) {
584 // Upload a publicly accessible file. The file size and type are determined by the SDK.
585 try {
586 $handle = fopen($absolute_source_path, 'rb');
587 $upload = $this->S3CompatibleClient->putObject([
588 'Bucket' => $this->bucket_name,
589 'Key' => $upload_path,
590 'Body' => $handle
591 ]);
592 if (is_resource($handle)) {
593 fclose($handle);
594 }
595
596 $result = array(
597 'success' => true,
598 'code' => 200,
599 'file_url' => $this->generate_file_url($upload_path),
600 'key' => $upload_path,
601 'message' => esc_html__('File Uploaded Successfully', 'media-cloud-sync')
602 );
603 } catch (AwsException $e) {
604 $result = array(
605 'success' => false,
606 'code' => 200,
607 'message' => $e->getMessage()
608 );
609 }
610 } else {
611 $multiUploader = new MultipartUploader($this->S3CompatibleClient, $absolute_source_path, [
612 'bucket' => $this->bucket_name,
613 'key' => $upload_path
614 ]);
615
616 try {
617 do {
618 try {
619 $uploaded = $multiUploader->upload();
620 } catch (MultipartUploadException $e) {
621 $multiUploader = new MultipartUploader($this->S3CompatibleClient, $absolute_source_path, [
622 'state' => $e->getState(),
623 ]);
624 }
625 } while (!isset($uploaded));
626
627 if (isset($uploaded['ObjectURL']) && !empty($uploaded['ObjectURL'])) {
628 $result = array(
629 'success' => true,
630 'code' => 200,
631 'file_url' => $this->generate_file_url($upload_path),
632 'key' => $upload_path,
633 'message' => esc_html__('File Uploaded Successfully', 'media-cloud-sync')
634 );
635 } else {
636 $result = array(
637 'success' => false,
638 'code' => 200,
639 'message' => esc_html__('Something happened while uploading to server', 'media-cloud-sync')
640 );
641 }
642 } catch (MultipartUploadException $e) {
643 $result = array(
644 'success' => false,
645 'code' => 200,
646 'message' => $e->getMessage()
647 );
648 }
649 }
650 } else {
651 $result = array(
652 'success' => false,
653 'code' => 200,
654 'message' => esc_html__('Check the file you are trying to upload. Please try again', 'media-cloud-sync')
655 );
656 }
657 } else {
658 $result = array(
659 'success' => false,
660 'code' => 200,
661 'message' => esc_html__('Insufficient Data. Please try again', 'media-cloud-sync')
662 );
663 }
664 return $result;
665 }
666
667 /**
668 * Save object to server
669 * @since 1.0.0
670 */
671 public function object_to_server($key, $save_path) {
672 try {
673 $getObject = $this->S3CompatibleClient->GetObject([
674 'Bucket' => $this->bucket_name,
675 'Key' => $key,
676 'SaveAs' => $save_path
677 ]);
678 if (file_exists($save_path)) {
679 return true;
680 }
681 } catch (AwsException $e) {
682 return false;
683 }
684 return false;
685 }
686
687
688 /**
689 * Copy to new path
690 * @since 1.3.4
691 */
692 public function copy_to_new_path($key, $new_path) {
693 try {
694 // Step 1: Verify object exists at old location
695 if (!$this->exists($key)) {
696 return [
697 'message' => esc_html__('Original file not found' , 'media-cloud-sync'),
698 'code' => 200,
699 'success' => false
700 ];
701 }
702 // Step 2: Copy object
703 if (!$this->exists($new_path)) {
704 $this->S3CompatibleClient->copyObject([
705 'Bucket' => $this->bucket_name,
706 'CopySource' => "{$this->bucket_name}/{$key}",
707 'Key' => $new_path,
708 'MetadataDirective' => 'COPY',
709 ]);
710 }
711 // Step 3: Verify object exists at new location
712 if ($this->exists($new_path)) {
713 return [
714 'success' => true,
715 'code' => 200,
716 'message' => esc_html__('File copied successfully', 'media-cloud-sync')
717 ];
718 }
719 } catch (AwsException $e) {
720 return false;
721 }
722 return [
723 'success' => false,
724 'code' => 200,
725 'message' => esc_html__('File not copied', 'media-cloud-sync')
726 ];
727 }
728
729
730 /**
731 * Delete Single
732 * @since 1.0.0
733 * @return boolean
734 */
735 public function deleteSingle($key) {
736 $result = array();
737 if (isset($key) && !empty($key)) {
738 try {
739 $this->S3CompatibleClient->deleteObject([
740 'Bucket' => $this->bucket_name,
741 'Key' => $key
742 ]);
743
744 if (!$this->exists($key)) {
745 $result = array(
746 'success' => true,
747 'code' => 200,
748 'message' => esc_html__('Deleted Successfully', 'media-cloud-sync')
749 );
750 } else {
751 $result = array(
752 'success' => false,
753 'code' => 200,
754 'message' => esc_html__('File not deleted', 'media-cloud-sync')
755 );
756 }
757 } catch (AwsException $e) {
758 $result = array(
759 'success' => false,
760 'code' => 200,
761 'message' => $e->getMessage()
762 );
763 }
764 } else {
765 $result = array(
766 'success' => false,
767 'code' => 200,
768 'message' => esc_html__('Insufficient Data. Please try again', 'media-cloud-sync')
769 );
770 }
771 return $result;
772 }
773
774 /**
775 * get private URL
776 * @since 1.0.0
777 * @return boolean
778 */
779 public function get_private_url($key) {
780 $result = array();
781 if (isset($key) && !empty($key)) {
782 try {
783 $cmd = $this->S3CompatibleClient->getCommand('GetObject', [
784 'Bucket' => $this->bucket_name,
785 'Key' => $key
786 ]);
787
788 $expires = isset($this->settings['private_url_expire']) ? $this->settings['private_url_expire'] : 20;
789
790 $request = $this->S3CompatibleClient->createPresignedRequest($cmd, sprintf('+%s minutes', $expires));
791
792 if ($privateUrl = (string)$request->getUri()) {
793 $result = array(
794 'success' => true,
795 'code' => 200,
796 'file_url' => $privateUrl,
797 'message' => esc_html__('Got Private URL Successfully', 'media-cloud-sync')
798 );
799 } else {
800 $result = array(
801 'success' => false,
802 'code' => 200,
803 'message' => esc_html__('Error getting private URL', 'media-cloud-sync')
804 );
805 }
806 } catch (AwsException $e) {
807 $result = array(
808 'success' => false,
809 'code' => 200,
810 'message' => $e->getMessage()
811 );
812 } catch (S3Exception $e) {
813 $result = array(
814 'success' => false,
815 'code' => 200,
816 'message' => $e->getAwsErrorMessage() ?? esc_html__('Please check the authorization details', 'media-cloud-sync')
817 );
818 } catch (Exception $e) {
819 $result = array(
820 'success' => false,
821 'code' => 200,
822 'message' => $e->getMessage() ?? esc_html__('Please check the authorization details', 'media-cloud-sync')
823 );
824 }
825 } else {
826 $result = array(
827 'success' => false,
828 'code' => 200,
829 'message' => esc_html__('Insufficient Data. Please try again', 'media-cloud-sync')
830 );
831 }
832 return $result;
833 }
834
835 /**
836 * Generate file URL
837 */
838 public function generate_file_url($key){
839 $domain = $this->get_domain();
840
841 return apply_filters('wpmcs_generate_do_file_url',
842 $domain . '/' . $this->bucket_name . '/' . $key,
843 $domain,
844 $this->bucket_name,
845 $key
846 );
847 }
848
849 /**
850 * Is Provider URL
851 * @since 1.3.6
852 */
853 public function is_provider_url($url) {
854 $domain = $this->get_domain();
855 return (strpos($url, $domain . '/' . $this->bucket_name . '/') !== false);
856 }
857
858 /**
859 * Get domain URL
860 */
861 public function get_domain($region = '') {
862 return $this->config['endpoint'];
863 }
864
865 }