PluginProbe
Media Cloud Sync / 1.3.10
Media Cloud Sync v1.3.10
1.4.1 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 All 35 releases
media-cloud-sync / includes / base / services / docean.php

docean.php in Media Cloud Sync 1.3.10, at includes/base/services/docean.php

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