PluginProbe
Media Cloud Sync / 1.0.2
Media Cloud Sync v1.0.2
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 / s3.php

s3.php in Media Cloud Sync 1.0.2, at includes/base/services/s3.php

698 lines 26.8 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 S3 {
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
25 public $service = 's3';
26 public $s3Client = false;
27
28 /**
29 * Admin constructor.
30 * @since 1.0.0
31 */
32 public function __construct() {
33 $this->assets_url = WPMCS_ASSETS_URL;
34 $this->version = WPMCS_VERSION;
35 $this->token = WPMCS_TOKEN;
36
37 // Initialize setup
38 $this->init();
39 }
40
41 /**
42 * Initialise Client
43 */
44 public function init() {
45 $this->settings = Utils::get_settings();
46 $this->credentials = Utils::get_credentials();
47 $this->config = isset($this->credentials['config']) && !empty($this->credentials['config'])
48 ? $this->credentials['config']
49 : [];
50 $this->bucketConfig = isset($this->credentials['bucketConfig']) && !empty($this->credentials['bucketConfig'])
51 ? $this->credentials['bucketConfig']
52 : [];
53 $this->bucket_name = isset($this->bucketConfig['bucket_name']) && !empty($this->bucketConfig['bucket_name'])
54 ? $this->bucketConfig['bucket_name']
55 : '';
56
57 if (
58 isset($this->config['region']) && !empty($this->config['region']) &&
59 isset($this->config['access_key']) && !empty($this->config['access_key']) &&
60 isset($this->config['secret_key']) && !empty($this->config['secret_key'])
61 ) {
62 $this->s3Client = new S3Client([
63 'version' => '2006-03-01',
64 'region' => $this->config['region'],
65 'use_accelerate_endpoint' => isset($this->bucketConfig['transfer_acceleration'])
66 ? $this->bucketConfig['transfer_acceleration'] : false,
67 'use_aws_shared_config_files' => false,
68 'credentials' => [
69 'key' => $this->config['access_key'],
70 'secret' => $this->config['secret_key'],
71 ],
72 ]);
73 }
74
75 }
76
77
78 /**
79 * Verify Credentials
80 * @since 1.0.0
81 * @return boolean
82 */
83 public function verifyCredentials($access_key, $secret_key, $region){
84 if (
85 isset($region) && !empty($region) &&
86 isset($access_key) && !empty($access_key) &&
87 isset($secret_key) && !empty($secret_key)
88 ) {
89 try {
90 $s3Client = new S3Client([
91 'version' => '2006-03-01',
92 'region' => $region,
93 'use_aws_shared_config_files' => false,
94 'credentials' => [
95 'key' => $access_key,
96 'secret' => $secret_key,
97 ],
98 ]);
99
100 //Listing all S3 Bucket
101 $buckets = $s3Client->listBuckets();
102
103 $newBucketFormat = [];
104 if(isset($buckets['Buckets']) && !empty($buckets['Buckets'])){
105 foreach($buckets['Buckets'] as $bucket) {
106 if(isset($bucket['Name'])) {
107 $newBucketFormat[] = ['Name' => $bucket['Name'], 'CreationDate' => $bucket['CreationDate']];
108 }
109 }
110 }
111
112 return array( 'message' => esc_html__('Credentials are valid', 'media-cloud-sync'), 'buckets' => $newBucketFormat, 'code' => 200, 'success' => true);
113 }
114 catch (S3Exception $ex) {
115 return array('message' => $ex->getAwsErrorMessage() ?? esc_html__('Please check the authorization details', 'media-cloud-sync'), 'code' => 200, 'success' => false);
116 } catch (Exception $ex) {
117 return array('message' => $ex->getMessage() ?? esc_html__('Please check the authorization details', 'media-cloud-sync'), 'code' => 200, 'success' => false);
118 }
119 }
120 return array('message' => esc_html__('Insufficient Data. Please try again', 'media-cloud-sync'), 'code' => 200, 'success' => false);
121 }
122
123 /**
124 * Verify Bucket
125 * @since 1.0.0
126 * @return boolean
127 */
128 public function verifyBucket($access_key, $secret_key, $region, $bucket_name, $transfer_acceleration=false){
129 if (
130 isset($region) && !empty($region) &&
131 isset($access_key) && !empty($access_key) &&
132 isset($secret_key) && !empty($secret_key) &&
133 isset($bucket_name) && !empty($bucket_name)
134 ) {
135 try {
136 $s3Client = new S3Client([
137 'version' => '2006-03-01',
138 'region' => $region,
139 'use_accelerate_endpoint' => $transfer_acceleration,
140 'use_aws_shared_config_files' => false,
141 'credentials' => [
142 'key' => $access_key,
143 'secret' => $secret_key,
144 ],
145 ]);
146
147 //Listing all S3 Bucket
148 $buckets = $s3Client->listBuckets();
149 $bucket_found = false;
150 $region_correct = false;
151 if ($buckets) {
152 foreach ($buckets['Buckets'] as $bucket) {
153 if ($bucket['Name']==$bucket_name) {
154 $bucket_found = true;
155 }
156 }
157 } else {
158 return array('message' => esc_html__('No matching bucket found', 'media-cloud-sync'), 'code' => 200, 'success' => false);
159 }
160 if ($bucket_found) {
161 $upload_dir = wp_upload_dir();
162 $file_dir = $upload_dir['basedir'] . '/' . Schema::getConstant('UPLOADS') . '/';
163
164 if (!is_dir($file_dir)) {
165 do_action( $this->token.'_create_plugin_dir' );
166 }
167
168 $fileName = $this->token."_verify.txt";
169 $localFileName = $file_dir.$this->token."-local-verify.txt";
170
171 $verify_file = fopen($file_dir.$fileName, "w");
172 $txt = "We are verifying input/output operations in s3\n";
173 fwrite($verify_file, $txt);
174 fclose($verify_file);
175
176 $upload = $s3Client->putObject([
177 'Bucket' => $bucket_name,
178 'Key' => $fileName,
179 'Body' => fopen($file_dir.$fileName, "r"),
180 'ACL' => 'public-read', // make file 'public'
181 ]);
182
183 @unlink($file_dir.$fileName);
184 if ($upload->get('ObjectURL')) {
185 try {
186 $getObject = $s3Client->GetObject([
187 'Bucket' => $bucket_name,
188 'Key' => $fileName,
189 'SaveAs' => $localFileName
190 ]);
191
192 if (file_exists($localFileName)) {
193 @unlink($localFileName);
194 $s3Client->deleteObject([
195 'Bucket' => $bucket_name,
196 'Key' => $fileName,
197 ]);
198
199 if (!$s3Client->doesObjectExist($bucket_name, $fileName)) {
200 return array('message' => esc_html__('Configuration for AWS/S3 has verified successfully', 'media-cloud-sync'), 'code' => 200, 'success' => true);
201 } else {
202 return array('message' => esc_html__('Bucket has permission issues on deleting the object from bucket, Please check ACL permission as well as policies', 'media-cloud-sync'), 'code' => 200, 'success' => false);
203 }
204 } else {
205 return array('message' => esc_html__('Bucket has permission issues on getting the object from bucket, Please check ACL permission as well as policies', 'media-cloud-sync'), 'code' => 200, 'success' => false);
206 }
207 } catch (S3Exception $ex) {
208 return array('message' => $ex->getAwsErrorMessage(), 'code' => $ex->getAwsErrorCode(), 'success' => false);
209 }
210 } else {
211 return array('message' => esc_html__('Bucket has permission issues on putting object in to bucket, Please check ACL permission as well as policies', 'media-cloud-sync'), 'code' => 200, 'success' => false);
212 }
213 } else {
214 return array('message' => esc_html__('Bucket Name is incorrect', 'media-cloud-sync'), 'code' => 200, 'success' => false);
215 }
216 }
217 catch (S3Exception $ex) {
218 return array('message' => $ex->getAwsErrorMessage() ?? esc_html__('Please check the authorization details', 'media-cloud-sync'), 'code' => 200, 'success' => false);
219 } catch (Exception $ex) {
220 return array('message' => $ex->getMessage() ?? esc_html__('Please check the authorization details', 'media-cloud-sync'), 'code' => 200, 'success' => false);
221 }
222 }
223 return array('message' => esc_html__('Insufficient Data. Please try again', 'media-cloud-sync'), 'code' => 200, 'success' => false);
224 }
225
226 /**
227 * Create Bucket
228 * @since 1.0.0
229 * @return boolean
230 */
231 public function createBucket($access_key, $secret_key, $region, $bucket_name, $transfer_acceleration = false){
232 if (empty($region) || empty($access_key) || empty($secret_key) || empty($bucket_name)) {
233 return ['message' => esc_html__('Insufficient Data. Please try again', 'media-cloud-sync'), 'code' => 200, 'success' => false];
234 }
235
236 try {
237 $s3ClientConfig = [
238 'version' => '2006-03-01',
239 'region' => $region,
240 'use_aws_shared_config_files' => false,
241 'credentials' => [
242 'key' => $access_key,
243 'secret' => $secret_key,
244 ],
245 ];
246
247 $s3Client = new S3Client($s3ClientConfig);
248
249 // Create Bucket
250 $s3Client->createBucket(['Bucket' => $bucket_name]);
251 try {
252 $this->enablBucketPublicAccess($bucket_name, $s3Client);
253 $this->putBucketPolicy($bucket_name, $s3Client);
254 $this->changeBucketOwnership($bucket_name, $s3Client);
255 try {
256
257 $this->changeTransferAccilaration($bucket_name, $s3Client, $transfer_acceleration);
258
259 return [
260 'message' => esc_html__('Bucket created successfully. Choose bucket from list to select the bucket.', 'media-cloud-sync'),
261 'data' => [
262 'Name' => $bucket_name,
263 'CreationDate' => date('Y-m-d\TH:i:s\Z'),
264 ],
265 'code' => 200,
266 'success' => true,
267 ];
268 } catch (AwsException $ex) {
269 return ['message' => esc_html__('Bucket created and made public. But the following error happened while setting the transfer accilaration,', 'media-cloud-sync') . ' ' . $ex->getAwsErrorMessage(), 'code' => 200, 'success' => false];
270 }
271 } catch (AwsException $ex) {
272 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];
273 }
274 } catch (AwsException $ex) {
275 return ['message' => $ex->getAwsErrorMessage(), 'code' => 200, 'success' => false];
276 } catch (S3Exception $ex) {
277 return ['message' => $ex->getAwsErrorMessage() ?? esc_html__('Please check the authorization details', 'media-cloud-sync'), 'code' => 200, 'success' => false];
278 } catch (Exception $ex) {
279 return ['message' => $ex->getMessage() ?? esc_html__('Please check the authorization details', 'media-cloud-sync'), 'code' => 200, 'success' => false];
280 }
281 }
282 /**
283 * Make Public Access Block Settings Enable
284 * @since 1.0.0
285 */
286
287 private function enablBucketPublicAccess($bucket, $s3Client = false) {
288 if($s3Client == false) {
289 $s3Client = $this->s3Client;
290 }
291
292 if(empty($bucket)) return false;
293
294 $s3Client->putPublicAccessBlock([
295 'Bucket' => $bucket,
296 'PublicAccessBlockConfiguration' => [
297 'BlockPublicPolicy' => false,
298 'BlockPublicAcls' => false,
299 'IgnorePublicAcls' => false,
300 'RestrictPublicBuckets' => false,
301 ]
302 ]);
303
304 return true;
305 }
306
307 /**
308 * Add Bucket Policy
309 */
310 private function putBucketPolicy($bucket, $s3Client = false) {
311 if($s3Client == false) {
312 $s3Client = $this->s3Client;
313 }
314
315 if(empty($bucket)) return false;
316
317 $policy = '{
318 "Version": "2012-10-17",
319 "Statement": [
320 {
321 "Effect": "Allow",
322 "Principal": "*",
323 "Action": [
324 "s3:DeleteObjectTagging",
325 "s3:ListBucketMultipartUploads",
326 "s3:DeleteObjectVersion",
327 "s3:ListBucket",
328 "s3:DeleteObjectVersionTagging",
329 "s3:GetBucketAcl",
330 "s3:ListMultipartUploadParts",
331 "s3:PutObject",
332 "s3:GetObjectAcl",
333 "s3:GetObject",
334 "s3:AbortMultipartUpload",
335 "s3:DeleteObject",
336 "s3:GetBucketLocation",
337 "s3:PutObjectAcl",
338 "s3:putBucketOwnershipControls",
339 "s3:putBucketPolicy"
340 ],
341 "Resource": [
342 "arn:aws:s3:::' . $bucket . '/*",
343 "arn:aws:s3:::' . $bucket . '"
344 ]
345 }
346 ]
347 }';
348
349 // Add bucket policy
350 $s3Client->putBucketPolicy(['Bucket' => $bucket, 'Policy' => $policy]);
351
352 return true;
353 }
354
355 /**
356 * Add Bucket Ownership
357 */
358 private function changeBucketOwnership($bucket, $s3Client = false, $ownership = 'BucketOwnerPreferred') {
359 if($s3Client == false) {
360 $s3Client = $this->s3Client;
361 }
362
363 if(empty($bucket)) return false;
364
365 // Change object ownership ACL enabled
366 $s3Client->putBucketOwnershipControls([
367 'Bucket' => $bucket,
368 'OwnershipControls' => [
369 'Rules' => [['ObjectOwnership' => $ownership]],
370 ],
371 ]);
372
373 return true;
374 }
375
376 /**
377 * Change transfer accilaration
378 */
379 private function changeTransferAccilaration($bucket, $s3Client = false, $enable=false, $force = false) {
380 if($s3Client == false) {
381 $s3Client = $this->s3Client;
382 }
383
384 if(empty($bucket)) return false;
385 if(!$force && !$enable) return true;
386
387 $s3Client->putBucketAccelerateConfiguration([
388 'Bucket' => $bucket,
389 'AccelerateConfiguration' => [
390 'Status' => $enable ? 'Enabled' : 'Suspended'
391 ]
392 ]);
393
394 return true;
395 }
396
397 /**
398 * isConfigured Function To Identify the congfigurations are correct
399 * @since 1.0.0
400 */
401 public function isConfigured(){
402 if ($this->s3Client) {
403 try {
404 $buckets = $s3Client->listBuckets();
405 if(!empty($buckets)){
406 foreach($buckets as $bucket) {
407 if ($bucket['Name']==$this->bucket_name) {
408 return true;
409 }
410 }
411 }
412 return false;
413 } catch (AwsException $ex) {
414 return false;
415 }
416 }
417 return false;
418 }
419
420 /**
421 * Make Object Private
422 * @since 1.0.0
423 *
424 */
425 public function toPrivate($key) {
426 if(!$key) return false;
427 try {
428 $this->s3Client->putObjectAcl([
429 'Bucket' => $this->bucket_name,
430 'Key' => $key,
431 'ACL' => 'private'
432 ]);
433 return true;
434 } catch (AwsException $ex) {
435 return false;
436 }
437 return false;
438 }
439
440
441
442 /**
443 * Make Object Public
444 * @since 1.0.0
445 *
446 */
447 public function toPublic($key) {
448 if(!$key) return false;
449 try {
450 $this->s3Client->putObjectAcl([
451 'Bucket' => $this->bucket_name,
452 'Key' => $key,
453 'ACL' => 'public-read'
454 ]);
455 return true;
456 } catch (AwsException $ex) {
457 return false;
458 }
459 return false;
460 }
461
462
463
464 /**
465 * Check the object exist
466 * @since 1.1.8
467 */
468 public function exists($key) {
469 if(!$key) return false;
470
471 if($this->s3Client->doesObjectExist($this->bucket_name, $key)) {
472 return true;
473 }
474
475 return false;
476 }
477
478 /**
479 * Upload Single
480 * @since 1.0.0
481 * @return boolean
482 */
483 public function uploadSingle($media_absolute_path, $media_path, $prefix='') {
484 $result = array();
485 if (
486 isset($media_absolute_path) && !empty($media_absolute_path) &&
487 isset($media_path) && !empty($media_path)
488 ) {
489 $file_name = wp_basename( $media_path );
490 if ($file_name) {
491 $upload_path = Utils::generate_object_key($file_name, $prefix);
492
493 // Decide Multipart upload or normal put object
494 if (filesize($media_absolute_path) <= Schema::getConstant('S3_MULTIPART_MIN_FILE_SIZE')) {
495 // Upload a publicly accessible file. The file size and type are determined by the SDK.
496 try {
497 $upload = $this->s3Client->putObject([
498 'Bucket' => $this->bucket_name,
499 'Key' => $upload_path,
500 'Body' => fopen($media_absolute_path, 'r'),
501 'ACL' => 'public-read', // make file 'public'
502 ]);
503
504 $result = array(
505 'success' => true,
506 'code' => 200,
507 'file_url' => $upload->get('ObjectURL'),
508 'key' => $upload_path,
509 'message' => esc_html__('File Uploaded Successfully', 'media-cloud-sync')
510 );
511 } catch (AwsException $e) {
512 $result = array(
513 'success' => false,
514 'code' => 200,
515 'message' => $e->getMessage()
516 );
517 }
518 } else {
519 $multiUploader = new MultipartUploader($this->s3Client, $media_absolute_path, [
520 'bucket' => $this->bucket_name,
521 'key' => $upload_path,
522 'acl' => 'public-read', // make file 'public'
523 ]);
524
525 try {
526 do {
527 try {
528 $uploaded = $multiUploader->upload();
529 } catch (MultipartUploadException $e) {
530 $multiUploader = new MultipartUploader($this->s3Client, $media_absolute_path, [
531 'state' => $e->getState(),
532 ]);
533 }
534 } while (!isset($uploaded));
535
536 if (isset($uploaded['ObjectURL']) && !empty($uploaded['ObjectURL'])) {
537 $result = array(
538 'success' => true,
539 'code' => 200,
540 'file_url' => urldecode($uploaded['ObjectURL']),
541 'key' => $upload_path,
542 'message' => esc_html__('File Uploaded Successfully', 'media-cloud-sync')
543 );
544 } else {
545 $result = array(
546 'success' => false,
547 'code' => 200,
548 'message' => esc_html__('Something happened while uploading to server', 'media-cloud-sync')
549 );
550 }
551 } catch (MultipartUploadException $e) {
552 $result = array(
553 'success' => false,
554 'code' => 200,
555 'message' => $e->getMessage()
556 );
557 }
558 }
559 } else {
560 $result = array(
561 'success' => false,
562 'code' => 200,
563 'message' => esc_html__('Check the file you are trying to upload. Please try again', 'media-cloud-sync')
564 );
565 }
566 } else {
567 $result = array(
568 'success' => false,
569 'code' => 200,
570 'message' => esc_html__('Insufficient Data. Please try again', 'media-cloud-sync')
571 );
572 }
573 return $result;
574 }
575
576 /**
577 * Save object to server
578 * @since 1.0.0
579 */
580 public function object_to_server($key, $save_path) {
581 try {
582 $getObject = $this->s3Client->GetObject([
583 'Bucket' => $this->bucket_name,
584 'Key' => $key,
585 'SaveAs' => $save_path
586 ]);
587 if (file_exists($save_path)) {
588 return true;
589 }
590 } catch (AwsException $e) {
591 return false;
592 }
593 return false;
594 }
595
596
597 /**
598 * Delete Single
599 * @since 1.0.0
600 * @return boolean
601 */
602 public function deleteSingle($key) {
603 $result = array();
604 if (isset($key) && !empty($key)) {
605 try {
606 $this->s3Client->deleteObject([
607 'Bucket' => $this->bucket_name,
608 'Key' => $key
609 ]);
610
611 if (!$this->s3Client->doesObjectExist($this->bucket_name, $key)) {
612 $result = array(
613 'success' => true,
614 'code' => 200,
615 'message' => esc_html__('Deleted Successfully', 'media-cloud-sync')
616 );
617 } else {
618 $result = array(
619 'success' => false,
620 'code' => 200,
621 'message' => esc_html__('File not deleted', 'media-cloud-sync')
622 );
623 }
624 } catch (AwsException $e) {
625 $result = array(
626 'success' => false,
627 'code' => 200,
628 'message' => $e->getMessage()
629 );
630 }
631 } else {
632 $result = array(
633 'success' => false,
634 'code' => 200,
635 'message' => esc_html__('Insufficient Data. Please try again', 'media-cloud-sync')
636 );
637 }
638 return $result;
639 }
640
641 /**
642 * get presigned URL
643 * @since 1.0.0
644 * @return boolean
645 */
646 public function get_presigned_url($key) {
647 $result = array();
648 if (isset($key) && !empty($key)) {
649 try {
650 $cmd = $this->s3Client->getCommand('GetObject', [
651 'Bucket' => $this->bucket_name,
652 'Key' => $key
653 ]);
654
655 $expires = isset($this->settings['presigned_expire']) ? $this->settings['presigned_expire'] : 20;
656
657 $request = $this->s3Client->createPresignedRequest($cmd, sprintf('+%s minutes', $expires));
658
659 if ($presignedUrl = (string)$request->getUri()) {
660 $result = array(
661 'success' => true,
662 'code' => 200,
663 'file_url' => $presignedUrl,
664 'message' => esc_html__('Got Presigned URL Successfully', 'media-cloud-sync')
665 );
666 } else {
667 $result = array(
668 'success' => false,
669 'code' => 200,
670 'message' => esc_html__('Error getting presigned URL', 'media-cloud-sync')
671 );
672 }
673 } catch (AwsException $e) {
674 $result = array(
675 'success' => false,
676 'code' => 200,
677 'message' => $e->getMessage()
678 );
679 }
680 } else {
681 $result = array(
682 'success' => false,
683 'code' => 200,
684 'message' => esc_html__('Insufficient Data. Please try again', 'media-cloud-sync')
685 );
686 }
687 return $result;
688 }
689
690 /**
691 * Get domain URL
692 */
693 public function get_domain() {
694 $region = isset($this->config['region']) ? $this->config['region'] : '';
695 return "https://{$this->bucket_name}.s3.{$region}.amazonaws.com";
696 }
697
698 }