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

409 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 $this->service->objects->delete( $this->bucket, $name );
298 } catch( Exception $e ) {
299 return new WP_Error( 'sm_error', $e->getMessage() );
300 }
301 return true;
302 }
303
304 /**
305 * Tests connection to Google Storage
306 * by trying to get passed bucket's data.
307 *
308 * @author peshkov@UD
309 */
310 public function is_connected() {
311 try {
312 $this->service->buckets->get( $this->bucket );
313 } catch( Exception $e ) {
314 return $e;
315 }
316 return true;
317 }
318
319 /**
320 * Determine if instance already exists and Return Instance
321 *
322 * @param array $args
323 *
324 * $args
325 * @param string client_id
326 * @param string service_account_name
327 * @param string key_file_path
328 *
329 * @author peshkov@UD
330 * @return \wpCloud\StatelessMedia\GS_Client
331 */
332 public static function get_instance( $args ) {
333 if( null === self::$instance ) {
334
335 try {
336
337 if( empty( $args[ 'bucket' ] ) ) {
338 throw new Exception( __( '<b>Bucket</b> parameter must be provided.' ) );
339 }
340
341 $json = "{}";
342
343 if ( !empty( $args[ 'key_json' ] ) ) {
344 $json = json_decode($args['key_json']);
345 }
346
347 if( !$json || !property_exists($json, 'private_key') ){
348 throw new Exception( __( '<b>Service Account JSON</b> is invalid.' ) );
349 }
350
351 self::$instance = new self( $args );
352 } catch( Exception $e ) {
353 return new WP_Error( 'sm_error', $e->getMessage() );
354 }
355 }
356 return self::$instance;
357 }
358
359 /**
360 * Set warning about potential conflict with Google SDK
361 *
362 * @since 2.0.1
363 */
364 private function _setWarning() {
365
366 $reflector = new \ReflectionClass('Google_Client');
367 $pluginBasename = wp_normalize_path( plugin_basename( $reflector->getFileName() ) );
368
369 // Check if get_plugins() function exists. This is required on the front end of the
370 // site, since it is in a file that is normally only loaded in the admin.
371 if ( ! function_exists( 'get_plugins' ) ) {
372 require_once ABSPATH . 'wp-admin/includes/plugin.php';
373 }
374
375 $pluginBasenameParts = explode( '/', $pluginBasename );
376 $pluginName = __( "UNDEFINED", ud_get_stateless_media()->domain );
377
378 foreach( get_plugins() as $path => $meta ) {
379 if( strpos( $path, trailingslashit( $pluginBasenameParts[0] ) ) === 0 ) {
380 $pluginName = $meta['Name'];
381 }
382 };
383
384 $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 ),
385 "<b>" . 'WP-Stateless' . "</b>",
386 "<b>" . $pluginName . "</b>",
387 'WP-Stateless',
388 "<b>v2.0</b>",
389 $pluginName,
390 "<b>v" . \wpCloud\StatelessMedia\Google_Client\Google_Client::LIBVER . "</b>"
391 );
392
393 set_transient( "wp_stateless_google_sdk_conflict", $error );
394 }
395
396 /**
397 * Removes Warning if it exists
398 *
399 */
400 private function _deleteWarning() {
401 delete_transient( "wp_stateless_google_sdk_conflict" );
402 }
403
404 }
405
406 }
407
408 }
409