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 / service.php

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

644 lines 21.2 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 class Service {
7 private static $instance = null;
8 private $assets_url;
9 private $version;
10 private $token;
11 private $service = false;
12 private $providers = [
13 's3' => ['class' => 'S3', 'sdk' => 's3'],
14 'gcloud' => ['class' => 'GCloud', 'sdk' => 'google'],
15 'docean' => ['class' => 'DOcean', 'sdk' => 's3'],
16 'cloudflareR2' => ['class' => 'CloudflareR2', 'sdk' => 's3'],
17 's3compatible' => ['class' => 'S3Compatible', 'sdk' => 's3'],
18 ];
19
20 protected $settings;
21
22
23 /**
24 * Service constructor.
25 * @since 1.0.0
26 */
27 public function __construct() {
28 $this->assets_url = WPMCS_ASSETS_URL;
29 $this->version = WPMCS_VERSION;
30 $this->token = WPMCS_TOKEN;
31
32 $this->settings = Utils::get_settings();
33
34 $current_service = Utils::get_service();
35
36 if($current_service) {
37 $this->service = $this->get_handler_class($current_service);
38 }
39 }
40
41 /**
42 * Verify Service Credentials
43 * @since 1.0.0
44 */
45 public function verifyCredentials($data) {
46 $result = [
47 'success' => false,
48 'message' => esc_html__('Something went wrong', 'media-cloud-sync')
49 ];
50
51 $service = isset($data['service'])? $data['service'] : false;
52 $handler_class = $this->get_handler_class($service);
53
54 if($service == false || $handler_class == false) {
55 $result = [
56 'success' => false,
57 'message' => esc_html__('No service selected', 'media-cloud-sync')
58 ];
59 return $result;
60 }
61
62 $configSource = isset($data['configSource']) ? $data['configSource'] : 'database';
63
64 if($configSource === 'config') {
65 // Credentials are expected from the WPMCS_CONFIG constant in wp-config.php.
66 if(!Utils::is_wp_config_credentials_defined()) {
67 return [
68 'success' => false,
69 'message' => esc_html__('WPMCS_CONFIG is not defined in wp-config.php', 'media-cloud-sync')
70 ];
71 }
72
73 $config = Utils::get_wp_config_credentials();
74 $missing = [];
75 foreach(self::get_required_config_keys($service) as $key) {
76 if(!isset($config[$key]) || $config[$key] === '') {
77 $missing[] = $key;
78 }
79 }
80 if(!empty($missing)) {
81 return [
82 'success' => false,
83 /* translators: %s: comma separated list of missing configuration keys */
84 'message' => sprintf(esc_html__('WPMCS_CONFIG is missing key(s): %s', 'media-cloud-sync'), implode(', ', $missing))
85 ];
86 }
87 } else {
88 $config = $this->resolve_config($data);
89 }
90
91 return $handler_class->verifyCredentials($config);
92 }
93
94 /**
95 * Resolve the credential config for a wizard request.
96 * When the request indicates the 'config' source, credentials are pulled
97 * from the WPMCS_CONFIG constant (wp-config.php) instead of the payload.
98 * @since 1.3.11
99 * @param array $data
100 * @return array
101 */
102 private function resolve_config($data) {
103 $configSource = isset($data['configSource']) ? $data['configSource'] : 'database';
104 if($configSource === 'config') {
105 return Utils::get_wp_config_credentials();
106 }
107 return isset($data['config']) ? $data['config'] : [];
108 }
109
110 /**
111 * Required configuration keys per provider, used to validate the
112 * WPMCS_CONFIG constant before attempting credential verification.
113 * @since 1.3.11
114 * @param string $service
115 * @return array
116 */
117 public static function get_required_config_keys($service) {
118 $required = [
119 's3' => ['access_key', 'secret_key', 'region'],
120 'gcloud' => ['config_json'],
121 'docean' => ['access_key', 'secret_key', 'region'],
122 'cloudflareR2' => ['account_id', 'access_key', 'secret_key'],
123 's3compatible' => ['endpoint', 'access_key', 'secret_key'],
124 ];
125 return isset($required[$service]) ? $required[$service] : [];
126 }
127
128 /**
129 * Persist a connection status result and normalize the response payload.
130 * @since 1.3.11
131 * @param string $status_key
132 * @param array $result
133 * @return array
134 */
135 private function persist_connection_status($status_key, $result) {
136 $lastChecked = isset($result['lastChecked']) ? $result['lastChecked'] : time();
137 $success = !empty($result['success']);
138 $message = isset($result['message']) ? $result['message'] : '';
139
140 Utils::set_status($status_key, [
141 'status' => $success,
142 'message' => $message,
143 'lastChecked' => $lastChecked,
144 ]);
145
146 return [
147 'success' => $success,
148 'message' => $message,
149 'lastChecked' => $lastChecked,
150 ];
151 }
152
153 /**
154 * Verify saved storage credentials and bucket write access.
155 * @since 1.3.11
156 * @return array
157 */
158 private function run_storage_status_check() {
159 if(!Utils::is_service_enabled()) {
160 return $this->persist_connection_status('storageCredentials', [
161 'success' => false,
162 'message' => Utils::get_service_configuration_error(),
163 'lastChecked' => time(),
164 ]);
165 }
166
167 $credentials = Utils::get_credentials();
168 $data = [
169 'service' => isset($credentials['service']) ? $credentials['service'] : Utils::get_service(),
170 'configSource' => Utils::get_credentials_source(),
171 'config' => isset($credentials['config']) ? $credentials['config'] : [],
172 'bucketData' => [
173 'config' => isset($credentials['bucketConfig']) ? $credentials['bucketConfig'] : [],
174 ],
175 ];
176
177 $result = $this->verifyObjectWritePermission($data);
178
179 return $this->persist_connection_status('storageCredentials', $result);
180 }
181
182 /**
183 * Verify CDN / delivery read access using saved credentials.
184 * @since 1.3.11
185 * @return array
186 */
187 private function run_cdn_status_check() {
188 if(!Utils::is_service_enabled()) {
189 return $this->persist_connection_status('cdnRead', [
190 'success' => false,
191 'message' => Utils::get_service_configuration_error(),
192 'lastChecked' => time(),
193 ]);
194 }
195
196 if(!$this->service) {
197 return $this->persist_connection_status('cdnRead', [
198 'success' => false,
199 'message' => esc_html__('No service selected', 'media-cloud-sync'),
200 'lastChecked' => time(),
201 ]);
202 }
203
204 return $this->persist_connection_status('cdnRead', $this->service->verifyObjectReadPermission());
205 }
206
207 /**
208 * Run one or more saved-connection status checks.
209 * @since 1.3.11
210 * @param string $check storage|cdn|all
211 * @return array
212 */
213 public function verifyStatus($check = 'storage') {
214 $check = is_string($check) ? strtolower($check) : 'storage';
215
216 if($check === 'write') {
217 $check = 'storage';
218 } elseif($check === 'read') {
219 $check = 'cdn';
220 }
221
222 if($check === 'all') {
223 $storage = $this->run_storage_status_check();
224 $cdn = $this->run_cdn_status_check();
225
226 return [
227 'success' => !empty($storage['success']) && !empty($cdn['success']),
228 'checks' => [
229 'storageCredentials' => $storage,
230 'cdnRead' => $cdn,
231 ],
232 ];
233 }
234
235 if($check === 'cdn') {
236 return $this->run_cdn_status_check();
237 }
238
239 if($check !== 'storage') {
240 return [
241 'success' => false,
242 'message' => esc_html__('Invalid status check type', 'media-cloud-sync'),
243 ];
244 }
245
246 return $this->run_storage_status_check();
247 }
248
249 /**
250 * @deprecated 1.3.11 Use verifyStatus( 'storage' ).
251 */
252 public function verifyWrite() {
253 return $this->verifyStatus('storage');
254 }
255
256 /**
257 * @deprecated 1.3.11 Use verifyStatus( 'cdn' ).
258 */
259 public function verifyRead() {
260 return $this->verifyStatus('cdn');
261 }
262
263 /**
264 * Verify Bucket Exist
265 * @since 1.0.0
266 */
267 public function verifyBucketExist($data) {
268 $result = [
269 'success' => false,
270 'message' => esc_html__('Something went wrong', 'media-cloud-sync')
271 ];
272
273 $service = isset($data['service'])? $data['service'] : false;
274 $handler_class = $this->get_handler_class($service);
275
276 if($service == false || $handler_class == false) {
277 $result = [
278 'success' => false,
279 'message' => esc_html__('No service selected', 'media-cloud-sync')
280 ];
281 return $result;
282 }
283
284 $config = $this->resolve_config($data);
285 $bucketData = isset($data['bucketData']) ? $data['bucketData'] : [];
286 $bucketConfig = isset($bucketData['config']) ? $bucketData['config'] : [];
287
288 return $handler_class->verifyBucketExist($config, $bucketConfig);
289 }
290
291 /**
292 * Verify Bucket Credentials
293 * @since 1.0.0
294 */
295 public function createBucket($data) {
296 $result = [
297 'success' => false,
298 'message' => esc_html__('Something went wrong', 'media-cloud-sync')
299 ];
300
301 $service = isset($data['service'])? $data['service'] : false;
302 $handler_class = $this->get_handler_class($service);
303
304 if($service == false || $handler_class == false) {
305 $result = [
306 'success' => false,
307 'message' => esc_html__('No service selected', 'media-cloud-sync')
308 ];
309 return $result;
310 }
311
312 $config = $this->resolve_config($data);
313 $bucketData = isset($data['bucketData']) ? $data['bucketData'] : [];
314 $bucketAddNewConfig = isset($bucketData['addNewConfig']) ? $bucketData['addNewConfig'] : [];
315
316 return $handler_class->createBucket( $config, $bucketAddNewConfig );
317 }
318
319 /**
320 * Verify Object write permission
321 * @since 1.0.0
322 */
323 public function verifyObjectWritePermission($data) {
324 $result = [
325 'success' => false,
326 'message' => esc_html__('Something went wrong', 'media-cloud-sync')
327 ];
328
329 $service = isset($data['service'])? $data['service'] : false;
330 $handler_class = $this->get_handler_class($service);
331
332 if($service == false || $handler_class == false) {
333 $result = [
334 'success' => false,
335 'message' => esc_html__('No service selected', 'media-cloud-sync')
336 ];
337 return $result;
338 }
339
340 $config = $this->resolve_config($data);
341 $bucketData = isset($data['bucketData']) ? $data['bucketData'] : [];
342 if(isset($bucketData['addNew']) && $bucketData['addNew']) {
343 $bucketConfig = isset($bucketData['addNewConfig']) ? $bucketData['addNewConfig'] : [];
344 } else {
345 $bucketConfig = isset($bucketData['config']) ? $bucketData['config'] : [];
346 }
347
348 return $handler_class->verifyObjectWritePermission($config, $bucketConfig);
349 }
350
351
352 /**
353 * Verify Object delete permission
354 * @since 1.0.0
355 */
356 public function verifyObjectDeletePermission($data) {
357 $result = [
358 'success' => false,
359 'message' => esc_html__('Something went wrong', 'media-cloud-sync')
360 ];
361
362 $service = isset($data['service'])? $data['service'] : false;
363 $handler_class = $this->get_handler_class($service);
364
365 if($service == false || $handler_class == false) {
366 $result = [
367 'success' => false,
368 'message' => esc_html__('No service selected', 'media-cloud-sync')
369 ];
370 return $result;
371 }
372
373 $config = $this->resolve_config($data);
374 $bucketData = isset($data['bucketData']) ? $data['bucketData'] : [];
375 if(isset($bucketData['addNew']) && $bucketData['addNew']) {
376 $bucketConfig = isset($bucketData['addNewConfig']) ? $bucketData['addNewConfig'] : [];
377 } else {
378 $bucketConfig = isset($bucketData['config']) ? $bucketData['config'] : [];
379 }
380
381 return $handler_class->verifyObjectDeletePermission( $config, $bucketConfig );
382 }
383
384
385 /**
386 * Get Bucket Security Settings
387 */
388 public function getBucketSecuritySettings($data) {
389 $result = [
390 'success' => false,
391 'message' => esc_html__('Something went wrong', 'media-cloud-sync')
392 ];
393
394 $service = isset($data['service'])? $data['service'] : false;
395 $handler_class = $this->get_handler_class($service);
396
397 if($service == false || $handler_class == false) {
398 $result = [
399 'success' => false,
400 'message' => esc_html__('No service selected', 'media-cloud-sync')
401 ];
402 return $result;
403 }
404
405 if(!method_exists($handler_class, 'getBucketSecuritySettings')) {
406 $result = [
407 'success' => false,
408 'message' => esc_html__('Service does not have getBucketSecuritySettings method', 'media-cloud-sync')
409 ];
410 return $result;
411 }
412
413 $config = $this->resolve_config($data);
414 $bucketData = isset($data['bucketData']) ? $data['bucketData'] : [];
415 if(isset($bucketData['addNew']) && $bucketData['addNew']) {
416 $bucketConfig = isset($bucketData['addNewConfig']) ? $bucketData['addNewConfig'] : [];
417 } else {
418 $bucketConfig = isset($bucketData['config']) ? $bucketData['config'] : [];
419 }
420
421 return $handler_class->getBucketSecuritySettings( $config, $bucketConfig );
422 }
423
424
425 /**
426 * Change Bucket Public Access
427 * @since 1.0.0
428 * @param array $data
429 */
430 public function changePublicAccess($data) {
431 $result = [
432 'success' => false,
433 'message' => esc_html__('Something went wrong', 'media-cloud-sync')
434 ];
435
436 $service = isset($data['service'])? $data['service'] : false;
437 $handler_class = $this->get_handler_class($service);
438
439 if($service == false || $handler_class == false) {
440 $result = [
441 'success' => false,
442 'message' => esc_html__('No service selected', 'media-cloud-sync')
443 ];
444 return $result;
445 }
446
447 if(method_exists($handler_class, 'changePublicAccess') == false) {
448 $result = [
449 'success' => false,
450 'message' => esc_html__('Method not supported for this service', 'media-cloud-sync')
451 ];
452 return $result;
453 }
454
455 $config = $this->resolve_config($data);
456 $bucketData = isset($data['bucketData']) ? $data['bucketData'] : [];
457 if(isset($bucketData['addNew']) && $bucketData['addNew']) {
458 $bucketConfig = isset($bucketData['addNewConfig']) ? $bucketData['addNewConfig'] : [];
459 } else {
460 $bucketConfig = isset($bucketData['config']) ? $bucketData['config'] : [];
461 }
462 $value = isset($data['value']) ? $data['value'] : false;
463
464 return $handler_class->changePublicAccess( $config, $bucketConfig, $value );
465 }
466
467 /**
468 * Change bucket ownership
469 */
470 public function changeObjectOwnership($data) {
471 $result = [
472 'success' => false,
473 'message' => esc_html__('Something went wrong', 'media-cloud-sync')
474 ];
475
476 $service = isset($data['service'])? $data['service'] : false;
477 $handler_class = $this->get_handler_class($service);
478
479 if($service == false || $handler_class == false) {
480 $result = [
481 'success' => false,
482 'message' => esc_html__('No service selected', 'media-cloud-sync')
483 ];
484 return $result;
485 }
486
487 if(method_exists($handler_class, 'changeObjectOwnership') == false) {
488 $result = [
489 'success' => false,
490 'message' => esc_html__('Method not supported for this service', 'media-cloud-sync')
491 ];
492 return $result;
493 }
494
495 $config = $this->resolve_config($data);
496 $bucketData = isset($data['bucketData']) ? $data['bucketData'] : [];
497 if(isset($bucketData['addNew']) && $bucketData['addNew']) {
498 $bucketConfig = isset($bucketData['addNewConfig']) ? $bucketData['addNewConfig'] : [];
499 } else {
500 $bucketConfig = isset($bucketData['config']) ? $bucketData['config'] : [];
501 }
502 $value = isset($data['value']) ? $data['value'] : false;
503
504 return $handler_class->changeObjectOwnership( $config, $bucketConfig, $value );
505 }
506
507
508 /**
509 * Generates a URL for a given key in the cloud storage.
510 *
511 * @param string $key The key of the object in the cloud storage.
512 *
513 * @return string The URL of the object.
514 */
515 public function get_url($key) {
516 return $this->service->generate_file_url($key);
517 }
518
519
520 /**
521 * Checks if a given URL is from a provider.
522 *
523 * @param string $url The URL to be checked.
524 *
525 * @return bool True if the URL is from a provider, false otherwise.
526 */
527 public function is_provider_url($url) {
528 return $this->service->is_provider_url($url);
529 }
530
531
532 /**
533 * Get private URL
534 * @since 1.0.0
535 */
536 public function get_private_url($path) {
537 $url_result = $this->service->get_private_url($path);
538 if(isset($url_result['success']) && $url_result['success']) {
539 return isset($url_result['file_url']) ? $url_result['file_url'] : false;
540 }
541 return false;
542 }
543
544
545 /**
546 * Upload a single file to the cloud storage.
547 *
548 * @param string $file_path The absolute path to the file on the local server.
549 * @param string $relative_source_path The relative path to the file on the local server.
550 * @param string $prefix An optional prefix to add to the cloud storage path.
551 * @return array The result of the upload operation, including success status and any relevant messages.
552 */
553 public function uploadSingle($file_path, $relative_source_path, $prefix = '') {
554 return $this->service->uploadSingle($file_path, $relative_source_path, $prefix);
555 }
556
557
558 public function deleteSingle($key) {
559 return $this->service->deleteSingle($key);
560 }
561
562
563 /**
564 * Move object to server from cloud
565 */
566 public function object_to_server($key, $save_path) {
567 $path_parts = pathinfo($save_path);
568 if (!file_exists($path_parts['dirname'])) {
569 mkdir($path_parts['dirname'], 0755, true);
570 }
571 return $this->service->object_to_server($key, $save_path);
572 }
573
574 /**
575 * Copy an object to a new path in the cloud storage
576 *
577 * @param string $key The key of the object to be copied
578 * @param string $new_path The new path to move the object to
579 * @return array The result of the copy operation
580 */
581 public function copy_to_new_path($key, $new_path) {
582 return $this->service->copy_to_new_path($key, $new_path);
583 }
584
585 /**
586 * Get Service Handler
587 */
588 public function get_handler_class($service) {
589 if(isset($this->providers[$service])) {
590 $provider = $this->providers[$service];
591 if(!empty($provider['sdk'])) {
592 self::load_sdk($provider['sdk']);
593 }
594 $class = __NAMESPACE__ . '\\' . $provider['class'];
595 if(class_exists($class)) {
596 return new $class();
597 }
598 }
599 return false;
600 }
601
602 /**
603 * Lazy load the bundled SDK autoloader for the given service.
604 * Each SDK is required at most once per request.
605 *
606 * @since 1.3.10
607 */
608 private static function load_sdk($sdk) {
609 static $loaded = [];
610 if (isset($loaded[$sdk])) {
611 return;
612 }
613 if ($sdk === 's3') {
614 require_once WPMCS_SDK_PATH . 's3/aws-autoloader.php';
615 } elseif ($sdk === 'google') {
616 require_once WPMCS_SDK_PATH . 'google/autoload.php';
617 } else {
618 return;
619 }
620 $loaded[$sdk] = true;
621 }
622
623 /**
624 * Get the service domain
625 *
626 */
627 public function get_domain() {
628 return $this->service->get_domain();
629 }
630
631 /**
632 * Ensures only one instance of Class is loaded or can be loaded.
633 *
634 * @return Service Class instance
635 * @since 1.0.0
636 * @static
637 */
638 public static function instance(){
639 if (is_null(self::$instance)) {
640 self::$instance = new self();
641 }
642 return self::$instance;
643 }
644 }