PluginProbe
WP-Stateless – Google Cloud Storage / 2.3.2
WP-Stateless – Google Cloud Storage v2.3.2
4.4.3 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.2.7 2.3.0 2.3.1 2.3.2 3.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.2.0 3.2.1 3.2.2 All 62 releases
wp-stateless / lib / classes / class-gs-client.php

class-gs-client.php in WP-Stateless – Google Cloud Storage 2.3.2, at lib/classes/class-gs-client.php

462 lines 14.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * GS API Client
4 *
5 * @since 0.2.0
6 * @author peshkov@UD
7 */
8 namespace wpCloud\StatelessMedia {
9
10 use Google_Client;
11 use Google_Service_Storage;
12 use WP_Error;
13 use Exception;
14 use Google_Service_Storage_ObjectAccessControl;
15 use Google_Auth_AssertionCredentials;
16
17 if( !class_exists( 'wpCloud\StatelessMedia\GS_Client' ) ) {
18
19 final class GS_Client {
20
21 /**
22 * Singleton object
23 *
24 * @var \wpCloud\StatelessMedia\GS_Client
25 */
26 private static $instance;
27
28 /**
29 * Google Client manager
30 *
31 * @var \Google_Client $client
32 */
33 public $client;
34
35 /**
36 * Google Storage Service manager
37 *
38 * @var \Google_Service_Storage $service
39 */
40 public $service;
41
42 /**
43 * Google Storage Bucket
44 *
45 * @var
46 */
47 private $bucket;
48
49 /**
50 * @var
51 */
52 private $temp_objects = array();
53
54 /**
55 * Constructor.
56 * Must not be called directly.
57 *
58 * @param $args
59 * @author peshkov@UD
60 */
61 protected function __construct( $args ) {
62 global $current_blog;
63 $this->bucket = $args[ 'bucket' ];
64 $this->key_json = json_decode($args['key_json'], 1);
65
66 // May be Loading Google SDK....
67 if( !class_exists( '\wpCloud\StatelessMedia\Google_Client\Google_Client' ) ) {
68 include_once( ud_get_stateless_media()->path('lib/Google/vendor/autoload.php', 'dir') );
69 }
70
71 /* Initialize our client */
72 $this->client = new \wpCloud\StatelessMedia\Google_Client\Google_Client();
73
74 // We're supporting Google SDK 1.X version since
75 // The plugins which also are using Google SDK may have its old version
76 // what may cause conflicts
77 //
78 if( version_compare( $this->client->getLibraryVersion(), '2.0', '<' ) ) {
79 // We should set the warning about potential issue
80 // If Google SDK has different version with already included
81 $this->_setWarning();
82
83 $wp_upload_dir = wp_upload_dir();
84 $dir = $wp_upload_dir[ 'path' ];
85 $filename = md5( wp_generate_password() ) . '.tmp';
86 $path = wp_normalize_path( $dir . '/' .$filename );
87 @file_put_contents( $path, json_encode( $this->key_json ) );
88 $cred = $this->client->loadServiceAccountJson( $path, ['https://www.googleapis.com/auth/devstorage.full_control'] );
89 $this->client->setAssertionCredentials($cred);
90 if ($this->client->getAuth()->isAccessTokenExpired()) {
91 $this->client->getAuth()->refreshTokenWithAssertion($cred);
92 }
93 @unlink( $path );
94 } else {
95 // May be delete warning transient if it was set
96 $this->_deleteWarning();
97 $this->client->setAuthConfig($this->key_json);
98 }
99
100 if( isset( $current_blog ) && isset( $current_blog->domain ) ) {
101 $this->client->setApplicationName( $current_blog->domain );
102 } else {
103 $this->client->setApplicationName( urlencode( str_replace( array( 'http://', 'https://' ), '', get_bloginfo( 'url' ) ) ) );
104 }
105
106 $this->client->setScopes(['https://www.googleapis.com/auth/devstorage.full_control']);
107
108 // May be Loading Google SDK. Because some bad plugins may load their Google SDK with not included Google_Service_Storage.
109 if( !class_exists( 'Google_Service_Storage' ) ) {
110 include_once( ud_get_stateless_media()->path('lib/Google/vendor/autoload.php', 'dir') );
111 }
112
113 /* Now, Initialize our Google Storage Service */
114 $this->service = new \wpCloud\StatelessMedia\Google_Client\Google_Service_Storage( $this->client );
115
116 }
117
118 /**
119 * Wrapper for listObjects()
120 */
121 public function list_objects( $options = array() ) {
122
123 $options = wp_parse_args( $options, array(
124 'delimiter' => '',
125 'maxResults' => 1000,
126 'pageToken' => '',
127 'prefix' => '',
128 'projection' => 'noAcl',
129 'versions' => false
130 ) );
131
132 return $this->service->objects->listObjects( $this->bucket, $options );
133 }
134
135 /**
136 * List all items page by page of maxResults
137 * @param $bucket
138 * @param array $options
139 * @return mixed
140 */
141 public function list_all_objects( $options = array() ) {
142
143 $options = wp_parse_args( $options, array(
144 'delimiter' => '',
145 'maxResults' => 1000,
146 'pageToken' => '',
147 'prefix' => '',
148 'projection' => 'noAcl',
149 'versions' => false
150 ) );
151
152 $response = $this->service->objects->listObjects( $this->bucket, $options );
153
154 $this->temp_objects = array_merge( $this->temp_objects, $response->getItems() );
155
156 if ( !empty( $response->nextPageToken ) ) {
157 $options['pageToken'] = $response->nextPageToken;
158 return $this->list_all_objects( $this->bucket, $options );
159 } else {
160 return $this->temp_objects;
161 }
162 }
163
164 /**
165 * Add/Update Media Object to Bucket
166 *
167 * @author peshkov@UD
168 * @param array $args
169 * @return bool
170 */
171 public function add_media( $args = array() ) {
172 try {
173
174 @set_time_limit( -1 );
175
176 $args = wp_parse_args( $args, array(
177 'force' => false,
178 'name' => false,
179 'absolutePath' => false,
180 'mimeType' => 'image/jpeg',
181 'metadata' => array(),
182 'is_webp' => '',
183 ) );
184 $args = apply_filters('wp_stateless_add_media_args', $args);
185 $name = $args['name'];
186
187 /* Be sure file exists. */
188 if( !file_exists( $args['absolutePath'] ) ) {
189 return new \WP_Error( 'sm_error', __( 'Unable to locate file on disk', ud_get_stateless_media()->domain ) );
190 }
191
192 /* Set default name if parameter was not passed. */
193 if( empty( $name ) ) {
194 $name = basename( $args['name'] );
195 }
196
197 $name = apply_filters( 'wp_stateless_file_name', $name );
198
199 // If media exists we just return it
200 if ( !$args['force'] && $media = $this->media_exists( $name ) ) {
201 if($media->getCacheControl() != $args['cacheControl']){
202 $media->setCacheControl($args['cacheControl']);
203 $media = $this->service->objects->patch($this->bucket, $name, $media);
204 }
205 return get_object_vars( $media );
206 }
207
208 $media = new \wpCloud\StatelessMedia\Google_Client\Google_Service_Storage_StorageObject();
209 $media->setName($name);
210 $media->setMetadata($args['metadata']);
211
212 if (isset($args['cacheControl'])) {
213 $media->setCacheControl($args['cacheControl']);
214 }
215
216 if (isset($args['contentEncoding'])) {
217 $media->setContentEncoding($args['contentEncoding']);
218 }
219
220 if (isset($args['contentDisposition'])) {
221 $media->getContentDisposition($args['contentDisposition']);
222 }
223
224 /* Upload Media file to Google storage */
225 $media = $this->service->objects->insert($this->bucket, $media, array_filter(array(
226 'data' => file_get_contents($args['absolutePath']),
227 'uploadType' => 'media',
228 'mimeType' => $args['mimeType'],
229 'predefinedAcl' => 'bucketOwnerFullControl',
230 )));
231
232 $this->mediaInsertACL($media);
233
234 } catch( Exception $e ) {
235 return new WP_Error( 'sm_error', $e->getMessage() );
236 }
237 return get_object_vars( $media );
238 }
239
240 /**
241 *
242 *
243 */
244 public function mediaInsertACL($media){
245 /* Make Media Public READ for all on success */
246 if (!empty($media->name)) {
247 $acl = new \wpCloud\StatelessMedia\Google_Client\Google_Service_Storage_ObjectAccessControl();
248 $acl->setEntity('allUsers');
249 $acl->setRole('READER');
250
251 $this->service->objectAccessControls->insert($this->bucket, $media->name, $acl);
252 }
253 }
254
255 /**
256 * get or save media file
257 * @param $path
258 * @param bool $save
259 * @param bool $save_path
260 * @return bool|\Google_Service_Storage_StorageObject|int
261 */
262 public function get_media( $path, $save = false, $save_path = false ) {
263 try {
264 $media = $this->service->objects->get($this->bucket, $path);
265 } catch ( \Exception $e ) {
266 return false;
267 }
268
269 if ( empty( $media->id ) ) return false;
270
271 if ( $save && $save_path ) {
272 if ( !file_exists( $_dir = dirname( $save_path ) ) ) {
273 wp_mkdir_p( $_dir );
274 }
275 return $this->client->getHttpClient()->get($media->getMediaLink(), ['save_to' => $save_path] )->getStatusCode();
276 }
277
278 return $media;
279 }
280
281 /**
282 * get or save media file
283 * @param $path
284 * @param bool $save
285 * @param bool $save_path
286 * @return bool|\Google_Service_Storage_StorageObject|int
287 */
288 public function copy_media( $path, $new_path ) {
289 try {
290 $media = $this->service->objects->get($this->bucket, $path);
291 $media = $this->service->objects->copy($this->bucket, $path, $this->bucket, $new_path, $media);
292 $this->mediaInsertACL($media);
293 } catch ( \Exception $e ) {
294 return false;
295 }
296
297 if ( empty( $media->id ) ) return false;
298
299 return $media;
300 }
301
302 /**
303 * get or save media file
304 * @param $path
305 * @param bool $save
306 * @param bool $save_path
307 * @return bool|\Google_Service_Storage_StorageObject|int
308 */
309 public function move_media( $path, $new_path ) {
310 try {
311 $media = $this->copy_media($path, $new_path);
312 $this->remove_media($path);
313 } catch ( \Exception $e ) {
314 return false;
315 }
316
317 if ( empty( $media->id ) ) return false;
318
319 return $media;
320 }
321
322 /**
323 * Check if media exists
324 * @param $path
325 * @return bool
326 */
327 public function media_exists( $path ) {
328 try {
329 $media = $this->service->objects->get($this->bucket, $path);
330 // Here we wanted to check if access allowed, but noticed it actually sets this ACL... Leaving it as is. @author korotkov@ud
331 $this->service->objectAccessControls->get($this->bucket, $path, 'allUsers');
332 } catch ( \Exception $e ) {
333 return false;
334 }
335
336 if ( empty( $media->id ) ) return false;
337 return $media;
338 }
339
340 /**
341 * Fired for every file remove action
342 *
343 * @author peshkov@UD
344 * @param string $name
345 * @return bool
346 */
347 public function remove_media( $name ) {
348 try {
349 $name = apply_filters( 'wp_stateless_file_name', $name );
350 $this->service->objects->delete( $this->bucket, $name );
351 } catch( Exception $e ) {
352 return new WP_Error( 'sm_error', $e->getMessage() );
353 }
354 return true;
355 }
356
357 /**
358 * Tests connection to Google Storage
359 * by trying to get passed bucket's data.
360 *
361 * @author peshkov@UD
362 */
363 public function is_connected() {
364 try {
365 $this->service->buckets->get( $this->bucket );
366 } catch( Exception $e ) {
367 return $e;
368 }
369 return true;
370 }
371
372 /**
373 * Determine if instance already exists and Return Instance
374 *
375 * @param array $args
376 *
377 * $args
378 * @param string client_id
379 * @param string service_account_name
380 * @param string key_file_path
381 *
382 * @author peshkov@UD
383 * @return \wpCloud\StatelessMedia\GS_Client
384 */
385 public static function get_instance( $args ) {
386 if( null === self::$instance ) {
387
388 try {
389
390 if( empty( $args[ 'bucket' ] ) ) {
391 throw new Exception( __( '<b>Bucket</b> parameter must be provided.' ) );
392 }
393
394 $json = "{}";
395
396 if ( !empty( $args[ 'key_json' ] ) ) {
397 $json = json_decode($args['key_json']);
398 }
399
400 if( !$json || !property_exists($json, 'private_key') ){
401 throw new Exception( __( '<b>Service Account JSON</b> is invalid.' ) );
402 }
403
404 self::$instance = new self( $args );
405 } catch( Exception $e ) {
406 return new WP_Error( 'sm_error', $e->getMessage() );
407 }
408 }
409 return self::$instance;
410 }
411
412 /**
413 * Set warning about potential conflict with Google SDK
414 *
415 * @since 2.0.1
416 */
417 private function _setWarning() {
418
419 $reflector = new \ReflectionClass('Google_Client');
420 $pluginBasename = wp_normalize_path( plugin_basename( $reflector->getFileName() ) );
421
422 // Check if get_plugins() function exists. This is required on the front end of the
423 // site, since it is in a file that is normally only loaded in the admin.
424 if ( ! function_exists( 'get_plugins' ) ) {
425 require_once ABSPATH . 'wp-admin/includes/plugin.php';
426 }
427
428 $pluginBasenameParts = explode( '/', $pluginBasename );
429 $pluginName = __( "UNDEFINED", ud_get_stateless_media()->domain );
430
431 foreach( get_plugins() as $path => $meta ) {
432 if( strpos( $path, trailingslashit( $pluginBasenameParts[0] ) ) === 0 ) {
433 $pluginName = $meta['Name'];
434 }
435 };
436
437 $error = sprintf( __( "%s plugin may have potential Google SDK version conflicts with %s plugin. %s is using Google SDK %s, when %s loads old Google SDK version %s.", ud_get_stateless_media()->domain ),
438 "<b>" . 'WP-Stateless' . "</b>",
439 "<b>" . $pluginName . "</b>",
440 'WP-Stateless',
441 "<b>v2.0</b>",
442 $pluginName,
443 "<b>v" . \wpCloud\StatelessMedia\Google_Client\Google_Client::LIBVER . "</b>"
444 );
445
446 set_transient( "wp_stateless_google_sdk_conflict", $error );
447 }
448
449 /**
450 * Removes Warning if it exists
451 *
452 */
453 private function _deleteWarning() {
454 delete_transient( "wp_stateless_google_sdk_conflict" );
455 }
456
457 }
458
459 }
460
461 }
462