PluginProbe
WP-Stateless – Google Cloud Storage / trunk
WP-Stateless – Google Cloud Storage vtrunk
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-sync-non-media.php

class-sync-non-media.php in WP-Stateless – Google Cloud Storage trunk, at lib/classes/class-sync-non-media.php

398 lines 13.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Need to improve workflow.
5 * Maybe add a transient of few days to keep track of synced files.
6 */
7
8 namespace wpCloud\StatelessMedia {
9
10 if (!class_exists('wpCloud\StatelessMedia\SyncNonMedia')) {
11
12 class SyncNonMedia {
13
14 /**
15 * Status constants
16 */
17 const STATUS_SYNCED = 'synced';
18 const STATUS_QUEUED = 'queued';
19 const STATUS_COPIED = 'copied';
20 const STATUS_MOVED = 'moved';
21
22 /**
23 * @var array
24 *
25 * List of directories to scan for compatibility files.
26 */
27 private $registered_dir = array();
28
29 /**
30 * @var object|null
31 *
32 * Google Cloud client instance.
33 */
34 private $client = null;
35
36 public function __construct() {
37 // Manual sync using sync tab.
38 // Return files to be manually sync from sync tab.
39 add_filter('sm:sync::nonMediaFiles', array($this, 'sync_non_media_files'));
40 add_filter('sm:sync::queue_is_exists', array($this, 'queue_is_exists'), 10, 2);
41
42 // register a dir to sync from sync tab
43 add_action('sm:sync::register_dir', array($this, 'register_dir'));
44 add_action('sm:sync::addFile', array($this, 'add_file'), 10, 2);
45 add_action('sm:sync::removeFile', array($this, 'remove_file'));
46
47 // Sync a file.
48 add_action('sm:sync::syncFile', array($this, 'sync_file'), 10, 4);
49 add_action('sm:sync::copyFile', array($this, 'copy_file'), 10, 2);
50 add_action('sm:sync::moveFile', array($this, 'move_file'), 10, 2);
51 add_action('sm:sync::deleteFile', array($this, 'delete_file'));
52 add_action('sm:sync::deleteFiles', array($this, 'delete_files'));
53 add_action('sm:sync::unregister_file', array($this, 'unregister_file'), 10, 1);
54 }
55
56 /**
57 * Register dir to be sync from Sync tab.
58 * @param
59 * $dir: The directory to register
60 */
61 public function register_dir($dir) {
62 if (!in_array($dir, $this->registered_dir)) {
63 $this->registered_dir[] = $dir;
64 }
65 }
66 /**
67 * Add file to list of files to be sync from Sync tab.
68 * Save the file path to database.
69 * @param array $media
70 * @param string $status
71 */
72 public function add_file($media, $status = self::STATUS_QUEUED) {
73 ud_stateless_db()->update_non_library_file( (array) $media, $status);
74 }
75
76 /**
77 * Sync the file to GCS.
78 * @param $name: Relative path to upload dir.
79 * @param $absolutePath: Full path of the file
80 * @param bool $forced: Type: bool/int; Whether to force to move the file to GCS even it's already exists.
81 * true: Check whether it's already synced or not in database.
82 * 2 (int): Force to overwrite on GCS
83 * @param array $args
84 * @return bool|void $media: Media object returned from client->add_media() method.
85 * @throws: Exception File not found
86 */
87 public function sync_file($name, $absolutePath, $forced = false, $args = array()) {
88 $sm_mode = ud_get_stateless_media()->get('sm.mode');
89
90 $args = wp_parse_args($args, array(
91 'ephemeral' => true, // whether to delete local file in ephemeral mode.
92 'download' => false, // whether to delete local file in ephemeral mode.
93 'use_root' => 0,
94 'skip_db' => false,
95 'manual_sync' => false,
96 'remove_from_queue' => false, // removes entry from queue table if both file is missing.
97 'name_with_root' => true,
98 ));
99
100 $args = apply_filters('sm:sync::syncArgs', $args, $name, $absolutePath, $forced);
101
102 if ( apply_filters('sm:sync::queue_is_exists', $name, self::STATUS_SYNCED) && !$forced) {
103 return false;
104 }
105
106 $file_type = Utility::mimetype_from_extension(pathinfo($absolutePath, PATHINFO_EXTENSION));
107 if (empty($this->client)) {
108 $this->client = ud_get_stateless_media()->get_client();
109 }
110
111 if (is_wp_error($this->client)) {
112 return;
113 }
114
115 $file_copied_from_gcs = false;
116 $local_file_exists = file_exists($absolutePath);
117
118 do_action('sm::pre::sync::nonMediaFiles', $name, $absolutePath); // , $media
119
120 if (!$local_file_exists && ($args['download'] || ud_get_stateless_media()->get('sm.mode') !== 'ephemeral' || ud_get_stateless_media()->get('sm.mode') !== 'stateless')) {
121 // Try get it and save
122 $result_code = $this->client->get_media($name, true, $absolutePath);
123
124 if ($result_code == 200) {
125 $local_file_exists = true;
126 $file_copied_from_gcs = true;
127 }
128 }
129
130 $media = null;
131
132 if ($local_file_exists && !$file_copied_from_gcs && !$args['download']) {
133
134 if ($sm_mode == 'stateless' && !wp_doing_ajax()) {
135 global $gs_client;
136
137 $gs_name = apply_filters('wp_stateless_file_name', $name, $args['name_with_root']);
138
139 //Bucket
140 $bucket = ud_get_stateless_media()->get('sm.bucket');
141
142 $bucket = $gs_client->bucket($bucket);
143 $object = $bucket->object($gs_name);
144 $args = wp_parse_args($args, array(
145 'use_root' => $args['use_root'],
146 'force' => ($forced == 2),
147 'name' => $name,
148 'absolutePath' => $absolutePath,
149 'mimeType' => $file_type,
150 'metadata' => array(
151 'child-of' => dirname($name),
152 'file-hash' => md5($name),
153 'source' => $args['source'] ?? '',
154 'sourceVersion' => $args['source_version'] ?? '',
155 ),
156 'is_webp' => '',
157 ));
158
159 $args = apply_filters('wp_stateless_add_media_args', $args);
160
161 /**
162 * Updating object metadata, ACL, CacheControl and contentDisposition
163 * @return media object
164 */
165 try {
166 $mediaOptions = array(
167 'cacheControl' => apply_filters('sm:item:cacheControl', ud_get_stateless_media()->get_default_cache_control(), $absolutePath),
168 'contentDisposition' => apply_filters('sm:item:contentDisposition', null, $absolutePath)
169 );
170
171 if ( !defined('WP_STATELESS_SKIP_ACL_SET') || !WP_STATELESS_SKIP_ACL_SET) {
172 $mediaOptions['predefinedAcl'] = 'publicRead';
173 }
174
175 $media = $object->update(array('metadata' => $args['metadata']) + $mediaOptions);
176 } catch (\Throwable $th) {
177 //throw $th;
178 }
179 } else {
180 $media = $this->client->add_media(array(
181 'use_root' => $args['use_root'],
182 'name' => $name,
183 'force' => ($forced == 2),
184 'absolutePath' => $absolutePath,
185 'cacheControl' => apply_filters('sm:item:cacheControl', ud_get_stateless_media()->get_default_cache_control(), $absolutePath), //@todo use cacheControl from settings page.
186 'contentDisposition' => apply_filters('sm:item:contentDisposition', null, $absolutePath),
187 'mimeType' => $file_type,
188 'metadata' => array(
189 'child-of' => dirname($name),
190 'file-hash' => md5($name),
191 'source' => $args['source'] ?? '',
192 'sourceVersion' => $args['source_version'] ?? '',
193 ),
194 ));
195 }
196
197 // Addon can hook this function to modify database after manual sync done.
198 do_action('sm::synced::nonMediaFiles', $name, $absolutePath, $media); // , $media
199
200 // Ephemeral mode: we don't need the local version.
201 if ($args['ephemeral'] == true && ud_get_stateless_media()->get('sm.mode') === 'ephemeral') {
202 unlink($absolutePath);
203 }
204
205 if (!$args['skip_db']) {
206 // add file_path to the file list.
207 do_action('sm:sync::addFile', $media, self::STATUS_SYNCED);
208 }
209 return $media;
210 } elseif (!$local_file_exists && $args['remove_from_queue']) {
211 if (!$this->client->media_exists($name)) {
212 do_action('sm:sync::removeFile', $name);
213 if ($args['manual_sync']) {
214 throw new UnprocessableException(sprintf(__("Both local and remote files are missing. File: %s ", ud_get_stateless_media()->domain), $name));
215 }
216 }
217 }
218 }
219
220 /**
221 * Generate list for manual sync using sync tab. Sync all register files, dir and passed files.
222 * @param array $files - Additional files to sync.
223 * @return array
224 */
225 public function sync_non_media_files($files = array()) {
226 $upload_dir = wp_upload_dir();
227 $files = array_merge( $files, apply_filters('wp_stateless_get_non_library_files', array(), '') );
228 foreach ($this->registered_dir as $key => $dir) {
229 $dir = $upload_dir['basedir'] . "/" . trim($dir, '/') . "/";
230 if (is_dir($dir)) {
231 // Getting all the files from dir recursively.
232 $_files = Utility::get_files($dir);
233 // validating and adding to the $files array.
234 foreach ($_files as $id => $file) {
235 if (!file_exists($file)) {
236 continue;
237 }
238
239 $_file = str_replace(wp_normalize_path($upload_dir['basedir']), '', wp_normalize_path($file));
240 if (!in_array($_file, $files)) {
241 $files[] = trim($_file, '/');
242 }
243 }
244 }
245 }
246
247 // $files = array_values(array_unique($files));
248 return $files;
249 }
250
251 /**
252 * Delete a file from GCS.
253 *
254 * @param $file
255 * @param bool $force
256 * @return bool
257 */
258 public function delete_file($file) {
259 try {
260 $file = trim($file, '/');
261 if (empty($this->client)) {
262 $this->client = ud_get_stateless_media()->get_client();
263 }
264
265 if (is_wp_error($this->client)) {
266 return false;
267 }
268 // Removing file for GCS
269 $this->client->remove_media($file, "", 0);
270 do_action('sm:sync::removeFile', $file);
271 return true;
272 } catch (\Exception $e) {
273 return false;
274 }
275 }
276
277 /**
278 * Remove registered files of specified dir from GCS.
279 *
280 * @param $dir
281 * @return bool|void
282 */
283 public function delete_files($dir) {
284 if (empty($this->client)) {
285 $this->client = ud_get_stateless_media()->get_client();
286 }
287
288 if (is_wp_error($this->client)) {
289 return;
290 }
291
292 // Removing the files one by one.
293 $files = apply_filters('wp_stateless_get_non_library_files', array(), $dir);
294
295 if ( !empty($files) ) {
296 foreach ($files as $key => $file) {
297 if (strpos($file, $dir) !== false) {
298 $this->client->remove_media($file, "", 0);
299 do_action('sm:sync::removeFile', $file);
300 }
301 }
302 }
303
304 return true;
305 }
306
307 /**
308 * Checks whether a file is exist in database.
309 * @param $file: Path of file relative to upload dir.
310 * @param string $status: optional. queued|synced
311 * @return mixed: non boolean true. number of item found in db.
312 */
313 public function queue_is_exists($file, $status = '') {
314 return ud_stateless_db()->get_non_library_file_id($file, $status);
315 }
316
317 /**
318 * Deletes a entry from database.
319 * @param $file: Path of file relative to upload dir.
320 * @return mixed
321 */
322 public function remove_file($file) {
323 ud_stateless_db()->remove_non_library_file($file);
324 }
325
326 /**
327 * Delete a file from GCS.
328 * @param $old_file
329 * @param $new_file
330 * @param bool $force
331 * @param string $status
332 * @return bool
333 */
334 public function copy_file($old_file, $new_file, $force = false, $status = self::STATUS_COPIED) {
335 try {
336 if ( !$force && apply_filters('sm:sync::queue_is_exists', $new_file, $status) ) {
337 return false;
338 }
339
340 $client = $this->get_gs_client();
341
342 // Copying file on GCS
343 $media = $client->copy_media($old_file, $new_file);
344
345 do_action('sm:sync::addFile', $media, $status);
346
347 return true;
348 } catch (\Exception $e) {
349 return false;
350 }
351 }
352
353 /**
354 * Delete a file from GCS.
355 * @param $old_file
356 * @param $new_file
357 * @return bool
358 */
359 public function move_file($old_file, $new_file) {
360 try {
361
362 $this->copy_file($old_file, $new_file, true, self::STATUS_MOVED);
363 $this->delete_file($old_file);
364
365 return true;
366 } catch (\Exception $e) {
367 return false;
368 }
369 }
370
371 /**
372 * Get GS Client
373 * @return mixed
374 */
375 public function get_gs_client() {
376 if (empty($this->client)) {
377 $this->client = ud_get_stateless_media()->get_client();
378 }
379
380 return $this->client;
381 }
382
383 /**
384 * Remove file from DB after file deletion.
385 * @param string $file
386 */
387 public function unregister_file($file) {
388 $file = str_replace( ud_get_stateless_media()->get_gs_path(), '', $file);
389 $file = str_replace( ud_get_stateless_media()->get_gs_host(), '', $file);
390
391 $file = trim($file, '/');
392
393 do_action('sm:sync::removeFile', $file);
394 }
395 }
396 }
397 }
398