PluginProbe
Media Cloud Sync / 1.2.4
Media Cloud Sync v1.2.4
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 / gcloud.php

gcloud.php in Media Cloud Sync 1.2.4, at includes/base/services/gcloud.php

671 lines 24.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\Google\Cloud\Storage\StorageClient;
8 use Dudlewebs\WPMCS\Google\Cloud\Core\Exception\ServiceException;
9
10 use Exception;
11
12 class GCloud {
13 private $assets_url;
14 private $version;
15 private $token;
16
17 protected $config;
18 protected $bucketConfig;
19 protected $settings;
20 protected $credentials;
21 protected $bucket_name;
22 protected $bucket; // Object
23
24 public $service = 'gcloud';
25 public $gcloudClient = false;
26
27 /**
28 * Admin constructor.
29 * @since 1.0.0
30 */
31 public function __construct() {
32 $this->assets_url = WPMCS_ASSETS_URL;
33 $this->version = WPMCS_VERSION;
34 $this->token = WPMCS_TOKEN;
35
36 // Initialize setup
37 $this->init();
38 }
39
40 /**
41 * Initialise Client
42 */
43 public function init() {
44 $this->settings = Utils::get_settings();
45 $this->credentials = Utils::get_credentials();
46 $this->config = isset($this->credentials['config']) && !empty($this->credentials['config'])
47 ? $this->credentials['config']
48 : [];
49 $this->bucketConfig = isset($this->credentials['bucketConfig']) && !empty($this->credentials['bucketConfig'])
50 ? $this->credentials['bucketConfig']
51 : [];
52 $this->bucket_name = isset($this->bucketConfig['bucket_name']) && !empty($this->bucketConfig['bucket_name'])
53 ? $this->bucketConfig['bucket_name']
54 : '';
55
56 if (
57 isset($this->config['config_json']) && !empty($this->config['config_json']) &&
58 isset($this->config['config_json']['path']) && !empty($this->config['config_json']['path']) &&
59 isset($this->bucket_name) && !empty($this->bucket_name)
60 ) {
61 if(file_exists($this->config['config_json']['path'])){
62 // Set google client
63 $this->gcloudClient = new StorageClient([
64 'keyFilePath' => $this->config['config_json']['path'],
65 ]);
66 // Set bucket object
67 $this->bucket = $this->gcloudClient->bucket($this->bucket_name);
68 } else {
69 add_action('admin_notices', function (){
70 echo wp_kses_post(sprintf( "<div class='error'><p><strong>%s: </strong><br>Google Cloud Storage configuration file missing from the directory.
71 It may break the media url's as well as media uploads.<br>
72 <a href='%s'>Re-configure</a> plugin to fix the issue.
73 </p></div>",
74 esc_html__('Media Cloud Sync', 'media-cloud-sync'),
75 admin_url('admin.php?page='.$this->token . '-admin-ui#/configure')
76 ));
77 });
78 }
79 }
80 }
81
82 /**
83 * Verify Credentials
84 * @since 1.0.0
85 * @return boolean
86 */
87 public function verifyCredentials( $config_file ){
88 if (
89 isset($config_file) && !empty($config_file) &&
90 isset($config_file['path']) && !empty($config_file['path']) &&
91 file_exists($config_file['path'])
92 ) {
93 try {
94 $googleClient = new StorageClient([
95 'keyFilePath' => $config_file['path'],
96 ]);
97
98 $result = [
99 'success' => false,
100 'code' => 200,
101 'message' => esc_html__('Please check the authorization details', 'media-cloud-sync'),
102 ];
103
104 try {
105 $bucket = $googleClient->bucket($this->token . '_dummy-bucket-for-auth-check');
106 $exists = $bucket->exists(); // Triggers the API call
107
108 // If we reach here, the credentials are valid
109 $result = [
110 'success' => true,
111 'code' => 200,
112 'message' => esc_html__('Credentials are valid', 'media-cloud-sync'),
113 ];
114 } catch (ServiceException $e) {
115 $statusCode = $e->getCode();
116
117 $validErrors = [200, 403, 404];
118
119 if (in_array($statusCode, $validErrors)) {
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 }
127 }
128
129 if($result['success'] == false) {
130 return $result;
131 }
132
133
134 try {
135 $buckets = $googleClient->buckets();
136 $newBucketFormat = [];
137 if(isset($buckets) && !empty($buckets)){
138 foreach($buckets as $bucket) {
139 $name = $bucket->name();
140 if(!empty($name)) {
141 // Fetch the bucket's metadata
142 $bucketInfo = $bucket->info();
143 $newBucketFormat[] = ['Name' => $name, 'CreationDate' => $bucketInfo['timeCreated']];
144 }
145 }
146 }
147 $result['buckets_data']['buckets'] = $newBucketFormat;
148 $result['buckets_data']['message'] = esc_html__('Buckets listed successfully', 'media-cloud-sync');
149 $result['buckets_data']['status'] = true;
150 } catch (Exception $e) {
151 $result ['buckets_data']['buckets'] = [];
152 $result ['buckets_data']['message'] = esc_html__('Unable to list buckets, Please check the bucket listing permission', 'media-cloud-sync');
153 $result ['buckets_data']['status'] = false;
154 }
155 return $result;
156 } catch (Exception $ex) {
157 return array('message' => $ex->getMessage() ?? esc_html__('Please check the authorization details', 'media-cloud-sync'), 'code' => 200, 'success' => false);
158 }
159 }
160 return array('message' => esc_html__('Insufficient Data. Please try again', 'media-cloud-sync'), 'code' => 200, 'success' => false);
161 }
162
163
164 /**
165 * Verify Bucket Exists
166 * @since 1.0.0
167 * @return boolean
168 */
169 public function verifyBucketExist( $config_file, $bucket_name ){
170 if ( !( isset($config_file['path']) && !empty($config_file['path']) && file_exists($config_file['path']) && !empty($bucket_name) ) ) {
171 return ['message' => esc_html__('Insufficient Data. Please try again', 'media-cloud-sync'), 'code' => 200, 'success' => false];
172 }
173
174 try {
175 $googleClient = new StorageClient([
176 'keyFilePath' => $config_file['path'],
177 ]);
178
179 try {
180 $bucket = $googleClient->bucket($bucket_name);
181
182 // Try fetching a dummy object to test access, like you did with S3
183 $object = $bucket->object($this->token . '_dummy-object-for-bucket-exist-check');
184 $object->info(); // Will throw if bucket doesn't exist or access is denied
185
186 return [
187 'message' => esc_html__('Bucket exists', 'media-cloud-sync'),
188 'code' => 200,
189 'success' => true,
190 ];
191 } catch (ServiceException $e) {
192 $code = $e->getCode();
193
194 if (in_array($code, [403, 404], true)) {
195 return [
196 'message' => esc_html__('Bucket exists', 'media-cloud-sync'),
197 'code' => 200,
198 'success' => true,
199 ];
200 }
201
202 return [
203 'message' => esc_html__('Bucket does not exist or credentials are invalid: ', 'media-cloud-sync') . $e->getMessage(),
204 'code' => 200,
205 'success' => false,
206 ];
207 }
208
209
210 if($bucket_found) {
211 return array('message' => esc_html__('Bucket exist', 'media-cloud-sync'), 'code' => 200, 'success' => true);
212 } else {
213 return array('message' => esc_html__("Bucket choosen does not exist / does not have read permission", 'media-cloud-sync'), 'code' => 200, 'success' => false);
214 }
215 } catch (Exception $ex) {
216 return ['message' => $ex->getMessage() ?? esc_html__('Please check the authorization details', 'media-cloud-sync'), 'code' => 200, 'success' => false];
217 }
218 }
219
220
221 /**
222 * Create Bucket
223 * @since 1.0.0
224 * @return boolean
225 */
226 public function createBucket( $config_file, $region, $bucket_name ){
227 if ( !( isset($config_file['path']) && !empty($config_file['path']) && file_exists($config_file['path']) && !empty($region) && !empty($bucket_name) ) ) {
228 return ['message' => esc_html__('Insufficient Data. Please try again', 'media-cloud-sync'), 'code' => 200, 'success' => false];
229 }
230
231 try {
232 $googleClient = new StorageClient([
233 'keyFilePath' => $config_file['path'],
234 ]);
235
236 // Create Bucket
237 $googleClient->createBucket($bucket_name, [
238 'location' => $region,
239 ]);
240
241 return [
242 'message' => esc_html__('Bucket created successfully. Choose bucket from list to select the bucket.', 'media-cloud-sync'),
243 'data' => [
244 'Name' => $bucket_name,
245 'CreationDate' => date('Y-m-d\TH:i:s\Z'),
246 ],
247 'code' => 200,
248 'success' => true,
249 ];
250
251 } catch (Exception $ex) {
252 return ['message' => $e->getMessage() ?? esc_html__('Please check the authorization details', 'media-cloud-sync'), 'code' => 200, 'success' => false];
253 }
254 }
255
256 /**
257 * Check Bucket Write Permission
258 * @since 1.0.0
259 */
260 public function verifyObjectWritePermission($config_file, $bucket_name){
261 if ( !( isset($config_file['path']) && !empty($config_file['path']) && file_exists($config_file['path']) && !empty($bucket_name) ) ) {
262 return ['message' => esc_html__('Insufficient Data. Please try again', 'media-cloud-sync'), 'code' => 200, 'success' => false];
263 }
264
265 try {
266 $googleClient = new StorageClient([
267 'keyFilePath' => $config_file['path'],
268 ]);
269
270 $bucket = $googleClient->bucket($bucket_name);
271 if ($bucket->exists()) {
272 $bucket_found = true;
273 } else {
274 return ['message' => esc_html__('No Buckets found', 'media-cloud-sync'), 'code' => 200, 'success' => false];
275 }
276 if ($bucket_found) {
277 $object_key = Utils::generate_object_key($this->token . '_dummy-object-for-bucket-permission-check', '');
278
279 // Prepare a temporary file with content to check write permission
280 $stream = fopen('php://temp', 'r+');
281 fwrite($stream, 'This is a test object to check write permission.');
282 rewind($stream);
283
284 // Upload the object to the bucket
285 $object = $bucket->upload(
286 $stream,
287 [
288 'name' => $object_key,
289 ]
290 );
291 if(is_resource($stream)) {
292 fclose($stream);
293 }
294
295 if ($object->exists()) {
296 return ['message' => esc_html__('Bucket write permission verified successfully', 'media-cloud-sync'), 'code' => 200, 'success' => true];
297 } else {
298 return ['message' => esc_html__('Bucket write permission not verified', 'media-cloud-sync'), 'code' => 200, 'success' => false];
299 }
300 }
301 } catch (Exception $ex) {
302 return ['message' => $ex->getMessage() ?? esc_html__('Please check the authorization details', 'media-cloud-sync'), 'code' => 200, 'success' => false];
303 }
304 }
305
306 /**
307 * Check Bucket Delete Permission
308 * @since 1.0.0
309 */
310 public function verifyObjectDeletePermission($config_file, $bucket_name){
311 if ( !( isset($config_file['path']) && !empty($config_file['path']) && file_exists($config_file['path']) && !empty($bucket_name) ) ) {
312 return ['message' => esc_html__('Insufficient Data. Please try again', 'media-cloud-sync'), 'code' => 200, 'success' => false];
313 }
314
315 try {
316 $googleClient = new StorageClient([
317 'keyFilePath' => $config_file['path'],
318 ]);
319
320 $bucket = $googleClient->bucket($bucket_name);
321 try {
322 $object_key = Utils::generate_object_key($this->token . '_dummy-object-for-bucket-permission-check', '');
323
324 // Try fetching a dummy object to test access, like you did with S3
325 $object = $bucket->object($object_key);
326 if ($object->exists()) {
327 $object->delete();
328 if (!$object->exists()) {
329 return [
330 'message' => esc_html__('Bucket exists', 'media-cloud-sync'),
331 'code' => 200,
332 'success' => true,
333 ];
334 } else {
335 return [
336 'message' => esc_html__('You do not have permission to delete object', 'media-cloud-sync'),
337 'code' => 200,
338 'success' => false,
339 ];
340 }
341 } else {
342 return [
343 'message' => esc_html__('Object does not exist', 'media-cloud-sync'),
344 'code' => 200,
345 'success' => false,
346 ];
347 }
348 } catch (Exception $ex) {
349 return [
350 'message' => esc_html__('Object does not exist or credentials are invalid: ', 'media-cloud-sync') . $e->getMessage(),
351 'code' => 200,
352 'success' => false,
353 ];
354 }
355
356 } catch (Exception $ex) {
357 return ['message' => $ex->getMessage() ?? esc_html__('Please check the authorization details', 'media-cloud-sync'), 'code' => 200, 'success' => false];
358 }
359 }
360
361 /**
362 * isConfigured Function To Identify the congfigurations are correct
363 * @since 1.0.0
364 */
365 public function isConfigured(){
366 if ($this->gcloudClient) {
367 try {
368 $buckets = $this->gcloudClient->buckets();
369 if(!empty($buckets)){
370 foreach($buckets as $bucket) {
371 $name = $bucket->name();
372 if (!empty($name) && $name == $this->bucket_name) {
373 return true;
374 }
375 }
376 }
377 return false;
378 } catch (Exception $ex) {
379 return false;
380 }
381 }
382 return false;
383 }
384
385 /**
386 * Make Object Private
387 * @since 1.0.0
388 *
389 */
390 public function toPrivate($key) {
391 if(!$key) return false;
392
393 $object = $this->bucket->object($key);
394 if ($object->exists()) {
395 $object->update(['acl' => []], ['predefinedAcl' => 'private']);
396 return true;
397 }
398 return false;
399 }
400
401
402 /**
403 * Make Object Public
404 * @since 1.0.0
405 *
406 */
407 public function toPublic($key) {
408 if(!$key) return false;
409
410 $object = $this->bucket->object($key);
411 if ($object->exists()) {
412 $object->update(['acl' => []], ['predefinedAcl' => 'publicRead']);
413 return true;
414 }
415 return false;
416 }
417
418
419 /**
420 * Check the object exist
421 * @since 1.1.8
422 */
423 public function exists($key) {
424 if(!$key) return false;
425
426 $object = $this->bucket->object($key);
427 if ($object->exists()) {
428 return true;
429 }
430
431 return false;
432 }
433
434
435 /**
436 * Upload Single
437 * @since 1.0.0
438 * @return boolean
439 */
440 public function uploadSingle($media_absolute_path, $media_path, $prefix=''){
441 $result = array();
442 if (
443 isset($media_absolute_path) && !empty($media_absolute_path) &&
444 isset($media_path) && !empty($media_path)
445 ) {
446 $file_name = wp_basename( $media_path );
447 if ($file_name) {
448 $upload_path = Utils::generate_object_key($media_path, $prefix);
449
450 // Decide Multipart upload or normal put object
451 if (filesize($media_absolute_path) <= Schema::getConstant('GCLOUD_MULTIPART_MIN_FILE_SIZE')) {
452 // Upload a publicly accessible file. The file size and type are determined by the SDK.
453 try {
454
455 $upload = $this->bucket->upload(
456 fopen($media_absolute_path, 'r'),
457 [
458 'name' => $upload_path,
459 ]
460 );
461
462 $object = $this->bucket->object($upload_path);
463
464 if ($object->exists()) {
465 $result = array(
466 'success' => true,
467 'code' => 200,
468 'file_url' => $this->generate_file_url($upload_path),
469 'key' => $upload_path,
470 'message' => esc_html__('File Uploaded Successfully', 'media-cloud-sync'),
471 );
472 } else {
473 $result = array(
474 'success' => false,
475 'code' => 200,
476 'message' => esc_html__('Object not found at server.', 'media-cloud-sync'),
477 );
478 }
479 } catch (Exception $e) {
480 $result = array(
481 'success' => false,
482 'code' => 200,
483 'message' => $e->getMessage(),
484 );
485 }
486 } else {
487 try {
488 $upload = $this->bucket->upload(
489 fopen($media_absolute_path, 'r'),
490 [
491 'name' => $upload_path,
492 'chunkSize' => 262144 * 2,
493 ]
494 );
495
496 $object = $this->bucket->object($upload_path);
497
498 if ($object->exists()) {
499 $result = array(
500 'success' => true,
501 'code' => 200,
502 'file_url' => $this->generate_file_url($upload_path),
503 'key' => $upload_path,
504 'message' => esc_html__('File Uploaded Successfully', 'media-cloud-sync'),
505 );
506 } else {
507 $result = array(
508 'success' => false,
509 'code' => 200,
510 'message' => esc_html__('Something happened while uploading to server', 'media-cloud-sync'),
511 );
512 }
513 } catch (Exception $e) {
514 $result = array(
515 'success' => false,
516 'code' => 200,
517 'message' => $e->getMessage(),
518 );
519 }
520 }
521 } else {
522 $result = array(
523 'success' => false,
524 'code' => 200,
525 'message' => esc_html__('Check the file you are trying to upload. Please try again', 'media-cloud-sync'),
526 );
527 }
528 } else {
529 $result = array(
530 'success' => false,
531 'code' => 200,
532 'message' => esc_html__('Insufficient Data. Please try again', 'media-cloud-sync'),
533 );
534 }
535 return $result;
536 }
537
538
539 /**
540 * Save object to server
541 * @since 1.0.0
542 */
543 public function object_to_server($key, $save_path){
544 try {
545 $object = $this->bucket->object($key);
546 if ($object->exists()) {
547 $object->downloadToFile($save_path);
548 if (file_exists($save_path)) {
549 return true;
550 }
551 }
552 } catch (Exception $e) {
553 return false;
554 }
555 return false;
556 }
557
558
559 /**
560 * Delete Single
561 * @since 1.0.0
562 * @return boolean
563 */
564 public function deleteSingle($key){
565 $result = array();
566 if (isset($key) && !empty($key)) {
567 try {
568 $object = $this->bucket->object($key);
569 $object->delete();
570
571 if (!$object->exists()) {
572 $result = array(
573 'success' => true,
574 'code' => 200,
575 'message' => esc_html__('Deleted Successfully', 'media-cloud-sync'),
576 );
577 } else {
578 $result = array(
579 'success' => false,
580 'code' => 200,
581 'message' => esc_html__('File not deleted', 'media-cloud-sync'),
582 );
583 }
584 } catch (Exception $e) {
585 $result = array(
586 'success' => false,
587 'code' => 200,
588 'message' => $e->getMessage(),
589 );
590 }
591 } else {
592 $result = array(
593 'success' => false,
594 'code' => 200,
595 'message' => esc_html__('Insufficient Data. Please try again', 'media-cloud-sync'),
596 );
597 }
598 return $result;
599 }
600
601
602 /**
603 * get presigned URL
604 * @since 1.0.0
605 * @return boolean
606 */
607 public function get_presigned_url($key) {
608 $result = array();
609 if (isset($key) && !empty($key)) {
610 try {
611 $object = $this->bucket->object($key);
612
613 $expires = isset($this->settings['presigned_expire']) ? $this->settings['presigned_expire'] : 20;
614
615 $presignedUrl = $object->signedUrl(new \DateTime(sprintf('+%s minutes', $expires)));
616
617 if ($presignedUrl) {
618 $result = array(
619 'success' => true,
620 'code' => 200,
621 'file_url' => $presignedUrl,
622 'message' => esc_html__('Got Presigned URL Successfully', 'media-cloud-sync'),
623 );
624 } else {
625 $result = array(
626 'success' => false,
627 'code' => 200,
628 'message' => esc_html__('Error getting presigned URL', 'media-cloud-sync'),
629 );
630 }
631 } catch (Exception $e) {
632 $result = array(
633 'success' => false,
634 'code' => 200,
635 'message' => $e->getMessage(),
636 );
637 }
638 } else {
639 $result = array(
640 'success' => false,
641 'code' => 200,
642 'message' => esc_html__('Insufficient Data. Please try again', 'media-cloud-sync'),
643 );
644 }
645 return $result;
646 }
647
648
649 /**
650 * Generate file URL
651 */
652 private function generate_file_url($key){
653 $domain = $this->get_domain();
654
655 return apply_filters('wpmcs_generate_google_file_url',
656 $domain . '/' . $this->bucket_name . '/' . $key,
657 $domain, $key,
658 $this->bucket_name
659 );
660 }
661
662
663 /**
664 * Get domain URL
665 */
666 public function get_domain() {
667 $url_base = 'https://storage.googleapis.com';
668
669 return $url_base;
670 }
671 }