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

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