PluginProbe
WP-Stateless – Google Cloud Storage / 2.2.7
WP-Stateless – Google Cloud Storage v2.2.7
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.2.7, at lib/classes/class-gs-client.php

410 lines 12.7 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 extract( $args = wp_parse_args( $args, array(
177 'force' => false,
178 'name' => false,
179 'absolutePath' => false,
180 'mimeType' => 'image/jpeg',
181 'metadata' => array(),
182 ) ) );
183
184 /* Be sure file exists. */
185 if( !file_exists( $args['absolutePath'] ) ) {
186 return new \WP_Error( 'sm_error', __( 'Unable to locate file on disk', ud_get_stateless_media()->domain ) );
187 }
188
189 /* Set default name if parameter was not passed. */
190 if( empty( $name ) ) {
191 $name = basename( $args['name'] );
192 }
193
194 $name = apply_filters( 'wp_stateless_file_name', $name );
195
196 // If media exists we just return it
197 if ( !$args['force'] && $media = $this->media_exists( $name ) ) {
198 if($media->getCacheControl() != $args['cacheControl']){
199 $media->setCacheControl($args['cacheControl']);
200 $media = $this->service->objects->patch($this->bucket, $name, $media);
201 }
202 return get_object_vars( $media );
203 }
204
205 $media = new \wpCloud\StatelessMedia\Google_Client\Google_Service_Storage_StorageObject();
206 $media->setName($name);
207 $media->setMetadata($args['metadata']);
208
209 if (isset($args['cacheControl'])) {
210 $media->setCacheControl($args['cacheControl']);
211 }
212
213 if (isset($args['contentEncoding'])) {
214 $media->setContentEncoding($args['contentEncoding']);
215 }
216
217 if (isset($args['contentDisposition'])) {
218 $media->getContentDisposition($args['contentDisposition']);
219 }
220
221 /* Upload Media file to Google storage */
222 $media = $this->service->objects->insert($this->bucket, $media, array_filter(array(
223 'data' => file_get_contents($args['absolutePath']),
224 'uploadType' => 'media',
225 'mimeType' => $args['mimeType'],
226 'predefinedAcl' => 'bucketOwnerFullControl',
227 )));
228
229 /* Make Media Public READ for all on success */
230 if (is_object($media)) {
231 $acl = new \wpCloud\StatelessMedia\Google_Client\Google_Service_Storage_ObjectAccessControl();
232 $acl->setEntity('allUsers');
233 $acl->setRole('READER');
234
235 $this->service->objectAccessControls->insert($this->bucket, $name, $acl);
236 }
237
238 } catch( Exception $e ) {
239 return new WP_Error( 'sm_error', $e->getMessage() );
240 }
241 return get_object_vars( $media );
242 }
243
244 /**
245 * get or save media file
246 * @param $path
247 * @param bool $save
248 * @param bool $save_path
249 * @return bool|\Google_Service_Storage_StorageObject|int
250 */
251 public function get_media( $path, $save = false, $save_path = false ) {
252 try {
253 $media = $this->service->objects->get($this->bucket, $path);
254 } catch ( \Exception $e ) {
255 return false;
256 }
257
258 if ( empty( $media->id ) ) return false;
259
260 if ( $save && $save_path ) {
261 if ( !file_exists( $_dir = dirname( $save_path ) ) ) {
262 wp_mkdir_p( $_dir );
263 }
264 return $this->client->getHttpClient()->get($media->getMediaLink(), ['save_to' => $save_path] )->getStatusCode();
265 }
266
267 return $media;
268 }
269
270 /**
271 * Check if media exists
272 * @param $path
273 * @return bool
274 */
275 public function media_exists( $path ) {
276 try {
277 $media = $this->service->objects->get($this->bucket, $path);
278 // Here we wanted to check if access allowed, but noticed it actually sets this ACL... Leaving it as is. @author korotkov@ud
279 $this->service->objectAccessControls->get($this->bucket, $path, 'allUsers');
280 } catch ( \Exception $e ) {
281 return false;
282 }
283
284 if ( empty( $media->id ) ) return false;
285 return $media;
286 }
287
288 /**
289 * Fired for every file remove action
290 *
291 * @author peshkov@UD
292 * @param string $name
293 * @return bool
294 */
295 public function remove_media( $name ) {
296 try {
297 $name = apply_filters( 'wp_stateless_file_name', $name );
298 $this->service->objects->delete( $this->bucket, $name );
299 } catch( Exception $e ) {
300 return new WP_Error( 'sm_error', $e->getMessage() );
301 }
302 return true;
303 }
304
305 /**
306 * Tests connection to Google Storage
307 * by trying to get passed bucket's data.
308 *
309 * @author peshkov@UD
310 */
311 public function is_connected() {
312 try {
313 $this->service->buckets->get( $this->bucket );
314 } catch( Exception $e ) {
315 return $e;
316 }
317 return true;
318 }
319
320 /**
321 * Determine if instance already exists and Return Instance
322 *
323 * @param array $args
324 *
325 * $args
326 * @param string client_id
327 * @param string service_account_name
328 * @param string key_file_path
329 *
330 * @author peshkov@UD
331 * @return \wpCloud\StatelessMedia\GS_Client
332 */
333 public static function get_instance( $args ) {
334 if( null === self::$instance ) {
335
336 try {
337
338 if( empty( $args[ 'bucket' ] ) ) {
339 throw new Exception( __( '<b>Bucket</b> parameter must be provided.' ) );
340 }
341
342 $json = "{}";
343
344 if ( !empty( $args[ 'key_json' ] ) ) {
345 $json = json_decode($args['key_json']);
346 }
347
348 if( !$json || !property_exists($json, 'private_key') ){
349 throw new Exception( __( '<b>Service Account JSON</b> is invalid.' ) );
350 }
351
352 self::$instance = new self( $args );
353 } catch( Exception $e ) {
354 return new WP_Error( 'sm_error', $e->getMessage() );
355 }
356 }
357 return self::$instance;
358 }
359
360 /**
361 * Set warning about potential conflict with Google SDK
362 *
363 * @since 2.0.1
364 */
365 private function _setWarning() {
366
367 $reflector = new \ReflectionClass('Google_Client');
368 $pluginBasename = wp_normalize_path( plugin_basename( $reflector->getFileName() ) );
369
370 // Check if get_plugins() function exists. This is required on the front end of the
371 // site, since it is in a file that is normally only loaded in the admin.
372 if ( ! function_exists( 'get_plugins' ) ) {
373 require_once ABSPATH . 'wp-admin/includes/plugin.php';
374 }
375
376 $pluginBasenameParts = explode( '/', $pluginBasename );
377 $pluginName = __( "UNDEFINED", ud_get_stateless_media()->domain );
378
379 foreach( get_plugins() as $path => $meta ) {
380 if( strpos( $path, trailingslashit( $pluginBasenameParts[0] ) ) === 0 ) {
381 $pluginName = $meta['Name'];
382 }
383 };
384
385 $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 ),
386 "<b>" . 'WP-Stateless' . "</b>",
387 "<b>" . $pluginName . "</b>",
388 'WP-Stateless',
389 "<b>v2.0</b>",
390 $pluginName,
391 "<b>v" . \wpCloud\StatelessMedia\Google_Client\Google_Client::LIBVER . "</b>"
392 );
393
394 set_transient( "wp_stateless_google_sdk_conflict", $error );
395 }
396
397 /**
398 * Removes Warning if it exists
399 *
400 */
401 private function _deleteWarning() {
402 delete_transient( "wp_stateless_google_sdk_conflict" );
403 }
404
405 }
406
407 }
408
409 }
410