PluginProbe
WP-Stateless – Google Cloud Storage / 3.0
WP-Stateless – Google Cloud Storage v3.0
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 / compatibility / lite-speed-cache.php

lite-speed-cache.php in WP-Stateless – Google Cloud Storage 3.0, at lib/classes/compatibility/lite-speed-cache.php

381 lines 14.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plugin Name: LiteSpeed Cache
4 * Plugin URI: https://wordpress.org/plugins/litespeed-cache/
5 *
6 * Compatibility Description: Ensures compatibility with LiteSpeed Cache plugins "Image WebP Replacement" functions.
7 *
8 *
9 * Reference: https://www.litespeedtech.com/support/wiki/doku.php/litespeed_wiki:cache:lscwp:image-optimization#image_optimization_in_litespeed_cache_for_wordpress
10 *
11 */
12
13 namespace wpCloud\StatelessMedia {
14
15 if( !class_exists( 'wpCloud\StatelessMedia\LSCacheWP' ) ) {
16
17 class LSCacheWP extends ICompatibility {
18
19 protected $id = 'lscache_wp';
20 protected $title = 'LiteSpeed Cache';
21 protected $constant = 'WP_STATELESS_COMPATIBILITY_LITESPEED_CACHE';
22 protected $description = 'Ensures compatibility with LiteSpeed Cache plugins.';
23 protected $plugin_file = 'litespeed-cache/litespeed-cache.php';
24 protected $sm_mode_not_supported = [ 'stateless' ];
25
26 /**
27 * @param $sm
28 */
29 public function module_init( $sm ) {
30 // Sync image.
31 add_action( 'litespeed_img_pull_ori', array( $this, 'sync_image' ), 10, 2 );
32 add_action( 'litespeed_img_pull_webp', array( $this, 'sync_webp' ), 10, 2 );
33 // Deleting images from GCS.
34 add_action( 'litespeed_media_del', array( $this, 'litespeed_media_del' ), 10, 2 );
35 // moving images in GCS.
36 add_action( 'litespeed_media_rename', array( $this, 'litespeed_media_rename' ), 10, 3 );
37
38 // Adding file md5 for original image to cloud meta.
39 add_filter( 'wp_stateless_generate_cloud_meta', array( $this, 'cloud_meta_add_file_md5' ), 10, 5 );
40
41
42 // override is_internal_file check.
43 add_filter( 'litespeed_media_check_ori', array( $this, 'litespeed_media_check_img' ), 10, 2 );
44 add_filter( 'litespeed_media_check_webp', array( $this, 'litespeed_media_check_img' ), 10, 2 );
45
46 // litespeed_media_info
47 add_filter( 'litespeed_media_info', array( $this, 'litespeed_media_info' ), 10, 3 );
48
49 // Manual sync
50 add_action( 'sm:synced::image', array( $this, 'manual_sync_backup_file' ), 10, 2 );
51 add_action( 'sm:pre::synced::image', array( $this, 'update_md5_and_manual_sync' ), 10, 1 );
52
53 }
54
55 /**
56 * Sync the image when Lite Speed plugin pull the optimized image.
57 * We need to overwrite the existing image.
58 * @param stdClass Object $row_img
59 * stdClass Object
60 * (
61 * [id] => 28
62 * [post_id] => 494
63 * [optm_status] => notified
64 * [src] => 2019/10/22645b39-asdf.jpg
65 * [srcpath_md5] => ad206986974729e1c8edc9321ed9ba9b
66 * [src_md5] => 9d396b4f7a261a5fac1234b292a7d585
67 * [root_id] => 0
68 * [src_filesize] => 1
69 * [target_filesize] => 0
70 * [target_saved] => 827956
71 * [webp_filesize] => 0
72 * [webp_saved] => 830743
73 * [server_info] => {
74 * "server":"https:\/\/us1.wp.api.litespeedtech.com",
75 * "id":"SEU98",
76 * "ori_md5":"3a7bb6b684d34552d75291ed4c32d399",
77 * "ori":"https:\/\/us1.wp.api.litespeedtech.com\/dl\/20191011\/c91821\/47721644.jpg",
78 * "webp_md5":"61d80e1d2799af383c820492a1208846",
79 * "webp":"https:\/\/us1.wp.api.litespeedtech.com\/dl\/20191011\/c91821\/47721644.jpg.webp"
80 * }
81 * )
82 *
83 * @param String $local_file
84 * /var/www/wp-content/uploads/2019/10/22645b39-asdf.jpg
85 *
86 */
87 public function sync_image( $row_img, $local_file ) {
88 $rm_ori_bkup = apply_filters('litespeed_conf', 'img_optm-rm_bkup' );
89 $gs_name = apply_filters( 'wp_stateless_file_name', $row_img->src );
90 $cloud_meta = get_post_meta( $row_img->post_id, 'sm_cloud', true );
91
92 if(empty($cloud_meta)) $cloud_meta = array();
93
94 if( !$rm_ori_bkup ) {
95 $extension = pathinfo( $gs_name, PATHINFO_EXTENSION );
96 $bk_file = substr( $gs_name, 0, -strlen( $extension ) ) . 'bk.' . $extension;
97 $cloud_meta[ 'fileMd5' ][ $bk_file ] = $cloud_meta[ 'fileMd5' ][ $gs_name ];
98 do_action( 'sm:sync::copyFile', $gs_name, $bk_file );
99 }
100
101 $cloud_meta[ 'fileMd5' ][ $gs_name ] = md5_file( $local_file );
102 update_post_meta( $row_img->post_id, 'sm_cloud', $cloud_meta );
103 do_action( 'sm:sync::syncFile', $gs_name, $local_file, 2 );
104 }
105
106 /**
107 * Upload webp image after LS pulled the images.
108 * @todo put md5_file hash creating here. $row_img might have attachment_id
109 * @param $row_img
110 * @param $local_file
111 */
112 public function sync_webp( $row_img, $local_file ) {
113 $optm_webp = apply_filters('litespeed_conf', 'img_optm-webp' );
114 if( $optm_webp ) {
115 $gs_name = apply_filters( 'wp_stateless_file_name', $row_img->src . '.webp' );
116
117 $cloud_meta = get_post_meta( $row_img->post_id, 'sm_cloud', true );
118 $cloud_meta[ 'fileMd5' ][ $gs_name ] = md5_file( $local_file );
119 update_post_meta( $row_img->post_id, 'sm_cloud', $cloud_meta );
120
121 add_filter( 'upload_mimes', array( $this, 'add_webp_mime' ), 10, 2 );
122 do_action( 'sm:sync::syncFile', $gs_name, $local_file, 2 );
123 }
124 }
125
126 /**
127 * Bypassing the is_internal_file check on LiteSpeed Cache.
128 * That check fails because we are replacing URL with GCS URL.
129 * So we need to override it with filter.
130 *
131 * @todo maybe we can add some validation.
132 *
133 * @param $return
134 * @param $url
135 * @return bool
136 */
137 public function litespeed_media_check_img( $return, $url ) {
138 $image_host = ud_get_stateless_media()->get_gs_host();
139 if( strpos( $url, $image_host ) === 0 ) {
140 return true;
141 }
142 return $return;
143 }
144
145 /**
146 * Return information about a file from relative path.
147 *
148 * @param $info
149 * @param $short_file_path
150 * @param $post_id
151 * @return array( 'url', 'md5', 'size' )
152 */
153 public function litespeed_media_info( $info, $short_file_path, $post_id ) {
154 if( !$post_id ) return $info;
155
156 try {
157 $metadata = wp_get_attachment_metadata( $post_id );
158 $cloud_meta = get_post_meta( $post_id, 'sm_cloud', true );
159
160 if( !empty( $metadata[ 'gs_link' ] ) ) {
161 $short_file_path = apply_filters( 'wp_stateless_file_name', $short_file_path );
162 $url = ud_get_stateless_media()->get_gs_host() . '/' . $short_file_path;
163 $md5 = !empty( $cloud_meta[ 'fileMd5' ][ $short_file_path ] ) ? $cloud_meta[ 'fileMd5' ][ $short_file_path ] : null;
164
165 if( $metadata[ 'file' ] == $short_file_path ) {
166 $url = $metadata[ 'gs_link' ];
167 } else {
168 foreach( $metadata[ 'sizes' ] as $size => $meta ) {
169 if( $meta[ 'file' ] == basename( $short_file_path ) ) {
170 $url = $meta[ 'gs_link' ];
171 break;
172 }
173 }
174 }
175
176 if( $md5 ) {
177 $info = array( 'url' => $url, 'md5' => $md5, 'size' => 1, );
178 }
179 }
180 } catch( \Throwable $th ) {
181 error_log( print_r( $th, true ) );
182 }
183
184 return $info;
185 }
186
187
188 /**
189 * Deletes a file in GCS and remove the hash from cloud meta.
190
191 * @param $short_file_path
192 * @param $post_id
193 */
194 public function litespeed_media_del( $short_file_path, $post_id ) {
195 $short_file_path = apply_filters( 'wp_stateless_file_name', $short_file_path );
196 do_action( 'sm:sync::deleteFile', $short_file_path );
197 }
198
199 /**
200 * Hooks into the rename function of the LS cache.
201 * And move the file in GCS.
202 * Also update the md5_file hash on cloud meta.
203 *
204 * @param $short_file_path
205 * @param $short_file_path_new
206 * @param $post_id
207 */
208 public function litespeed_media_rename( $short_file_path, $short_file_path_new, $post_id ) {
209 $short_file_path = apply_filters( 'wp_stateless_file_name', $short_file_path );
210 $short_file_path_new = apply_filters( 'wp_stateless_file_name', $short_file_path_new );
211
212 // copy file to the new location and delete the old one.
213 do_action( 'sm:sync::moveFile', $short_file_path, $short_file_path_new );
214
215 $this->update_hash( $post_id, $short_file_path_new, $short_file_path );
216 }
217
218 /**
219 * add_webp_mime
220 * @param $t
221 * @param $user
222 * @return mixed
223 */
224 public function add_webp_mime( $t, $user ) {
225 $t[ 'webp' ] = 'image/webp';
226 return $t;
227 }
228
229 /**
230 * Move file hash from one key to another.
231 *
232 * @param $attachment_id
233 * @param $gs_name_new key to store md5_file.
234 * @param $gs_name_old whether to get md5 from another entry.
235 * @param bool $delete whether only remove the key.
236 * @return bool
237 */
238 public function update_hash( $attachment_id, $gs_name_new, $gs_name_old, $delete = false ) {
239 try {
240 $cloud_meta = get_post_meta( $attachment_id, 'sm_cloud', true );
241
242 if( !$delete ) {
243 if( $gs_name_old && !empty( $cloud_meta[ 'fileMd5' ][ $gs_name_old ] ) ) {
244 $cloud_meta[ 'fileMd5' ][ $gs_name_new ] = $cloud_meta[ 'fileMd5' ][ $gs_name_old ];
245 } else {
246 $url = ud_get_stateless_media()->get_gs_host() . '/' . $gs_name_new;
247 $cloud_meta[ 'fileMd5' ][ $gs_name_new ] = md5_file( $url );
248 }
249 }
250
251 if( isset( $cloud_meta[ 'fileMd5' ][ $gs_name_old ] ) ) unset( $cloud_meta[ 'fileMd5' ][ $gs_name_old ] );
252 update_post_meta( $attachment_id, 'sm_cloud', $cloud_meta );
253 return true;
254 } catch( \Throwable $th ) {
255 error_log( print_r( $th, true ) );
256 return false;
257 }
258 return false;
259 }
260
261 /**
262 * Adds file hash to cloud meta, so that we can use it later.
263 *
264 * @param $cloud_meta
265 * @param $media
266 * @param $image_size
267 * @param $img
268 * @param $bucketLink
269 * @return array $cloud_meta with fileMd5
270 */
271 public function cloud_meta_add_file_md5( $cloud_meta, $media, $image_size, $img, $bucketLink ) {
272 if( $file_hash = md5_file( $img[ 'path' ] ) ) {
273 $gs_name = !empty( $media[ 'name' ] ) ? $media[ 'name' ] : $img[ 'gs_name' ];
274 $extension = pathinfo( $gs_name, PATHINFO_EXTENSION );
275 $bk_file = substr( $gs_name, 0, -strlen( $extension ) ) . 'bk.' . $extension;
276
277 // Storing file hash
278 $cloud_meta[ 'fileMd5' ][ $gs_name ] = $file_hash;
279 }
280
281 return $cloud_meta;
282 }
283
284 /**
285 * On manual sync/regenerate we need to sync backup/webp files.
286 *
287 * @param $attachment_id
288 * @param $metadata
289 */
290 public function manual_sync_backup_file( $attachment_id, $metadata ) {
291 $cloud_meta = get_post_meta( $attachment_id, 'sm_cloud', true );
292
293 if( !empty( $cloud_meta[ 'fileMd5' ] ) ) {
294 $upload_dir = wp_upload_dir();
295 $fileMd5 = $cloud_meta[ 'fileMd5' ];
296 $root_dir = ud_get_stateless_media()->get( 'sm.root_dir' );
297 $root_dir = apply_filters("wp_stateless_handle_root_dir", $root_dir);
298 $root_dir = trim( $root_dir, '/ ' ); // Remove any forward slash and empty space.
299
300 foreach( $fileMd5 as $gs_name => $value ) {
301 $_gs_name = str_replace( $root_dir, '', $gs_name );
302 $local_file = $upload_dir[ 'basedir' ] . '/' . trim( $_gs_name, '/' );
303
304 do_action( 'sm:sync::syncFile', $gs_name, $local_file, true );
305 }
306 }
307 }
308
309 /**
310 * On manual sync/regenerate wp regenerate all image sizes.
311 * So to keep the file md5 accurate we need to update it after image is regenerated.
312 *
313 * Manual sync if it's the first time syncing and image optimized before enabling Stateless
314 *
315 * @param $attachment_id
316 */
317 public function update_md5_and_manual_sync( $attachment_id ) {
318 $cloud_meta = get_post_meta( $attachment_id, 'sm_cloud', true );
319 $metadata = wp_get_attachment_metadata( $attachment_id );
320 $image_sizes = Utility::get_path_and_url( $metadata, $attachment_id );
321
322 if( !empty( $cloud_meta[ 'fileMd5' ] ) ) {
323 foreach( $image_sizes as $img ) {
324 $cloud_meta[ 'fileMd5' ][ $img[ 'gs_name' ] ] = md5_file( $img[ 'path' ] );
325 }
326 }
327
328 if( empty( $cloud_meta[ 'fileMd5' ] ) || count( $cloud_meta[ 'fileMd5' ] ) <= 1 ) {
329 if( empty( $cloud_meta ) ) {
330 $cloud_meta = array();
331 }
332
333 // In case image optimized before enabling Stateless.
334 // We only need to copy from local to GCS, otherwise file_md5 meta should be available.
335 foreach( $image_sizes as $img ) {
336 $file_path = $img[ 'path' ];
337 $rm_ori_bkup = apply_filters('litespeed_conf', 'img_optm-rm_bkup' );
338 $optm_webp = apply_filters('litespeed_conf', 'img_optm-webp' );
339
340 if( !$rm_ori_bkup ) {
341 $extension = pathinfo( $file_path, PATHINFO_EXTENSION );
342 $bk_file = substr( $file_path, 0, -strlen( $extension ) ) . 'bk.' . $extension;
343 $bk_file_optm = substr( $file_path, 0, -strlen( $extension ) ) . 'bk.optm.' . $extension;
344 if( file_exists( $bk_file ) ) {
345 $gs_name = apply_filters( 'wp_stateless_file_name', $bk_file );
346 $cloud_meta[ 'fileMd5' ][ $gs_name ] = md5_file( $bk_file );
347 do_action( 'sm:sync::syncFile', $gs_name, $bk_file );
348 } elseif( file_exists( $bk_file_optm ) ) {
349 $gs_name = apply_filters( 'wp_stateless_file_name', $bk_file_optm );
350 $cloud_meta[ 'fileMd5' ][ $gs_name ] = md5_file( $bk_file_optm );
351 do_action( 'sm:sync::syncFile', $gs_name, $bk_file_optm );
352 }
353 }
354
355 if( $optm_webp ) {
356 $gs_name_webp = $file_path . '.webp';
357 $gs_name_webp_optm = $file_path . '.optm.webp';
358 if( file_exists( $gs_name_webp ) ) {
359 $gs_name = apply_filters( 'wp_stateless_file_name', $gs_name_webp );
360 $cloud_meta[ 'fileMd5' ][ $gs_name ] = md5_file( $gs_name_webp );
361 do_action( 'sm:sync::syncFile', $gs_name, $gs_name_webp );
362 } elseif( file_exists( $gs_name_webp_optm ) ) {
363 $gs_name = apply_filters( 'wp_stateless_file_name', $gs_name_webp_optm );
364 $cloud_meta[ 'fileMd5' ][ $gs_name ] = md5_file( $gs_name_webp_optm );
365 do_action( 'sm:sync::syncFile', $gs_name, $gs_name_webp_optm );
366 }
367 }
368
369 }
370
371 }
372
373 update_post_meta( $attachment_id, 'sm_cloud', $cloud_meta );
374 }
375
376 }
377
378 }
379
380 }
381