PluginProbe
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF / 1.9.4
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF v1.9.4
2.3.4 2.3.3 2.3.2 2.3.1 2.3.0 2.2.9 2.2.8 trunk 1.10 1.3.3 1.3.4 1.3.5 1.3.5.1 1.3.5.2 1.3.6 1.3.6.1 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.5 All 103 releases
imagify / inc / deprecated / classes / class-imagify-file-attachment.php

class-imagify-file-attachment.php in Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF 1.9.4, at inc/deprecated/classes/class-imagify-file-attachment.php

761 lines 17.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 defined( 'ABSPATH' ) || die( 'Cheatin’ uh?' );
3
4 /**
5 * Imagify Attachment class for custom folders.
6 *
7 * @since 1.7
8 * @since 1.9 Deprecated
9 * @author Grégory Viguier
10 * @deprecated
11 */
12 class Imagify_File_Attachment extends Imagify_Attachment {
13
14 /**
15 * Class version.
16 *
17 * @var string
18 * @since 1.7
19 * @author Grégory Viguier
20 */
21 const VERSION = '1.1';
22
23 /**
24 * The attachment SQL DB class.
25 *
26 * @var string
27 * @since 1.7
28 * @access protected
29 */
30 protected $db_class_name = 'Imagify_Files_DB';
31
32 /**
33 * Tell if the optimization status is network-wide.
34 *
35 * @var bool
36 * @since 1.7.1
37 * @access protected
38 * @author Grégory Viguier
39 */
40 protected $optimization_state_network_wide = true;
41
42 /**
43 * The constructor.
44 *
45 * @since 1.7
46 * @access public
47 * @author Grégory Viguier
48 *
49 * @param int|array|object $id Thefile ID.
50 */
51 public function __construct( $id = 0 ) {
52 imagify_deprecated_class( get_class( $this ), '1.9', '\\Imagify\\Optimization\\Process\\CustomFolders( $id )' );
53
54 if ( is_numeric( $id ) ) {
55 $this->id = (int) $id;
56 $this->get_row();
57 } elseif ( is_array( $id ) || is_object( $id ) ) {
58 $prim_key = $this->get_row_db_instance()->get_primary_key();
59 $this->row = (array) $id;
60 $this->id = $this->row[ $prim_key ];
61 } else {
62 $this->invalidate_row();
63 }
64
65 $this->filesystem = Imagify_Filesystem::get_instance();
66 $this->optimization_state_transient = 'imagify-file-async-in-progress-' . $this->id;
67 }
68
69 /**
70 * Get the original file path.
71 *
72 * @since 1.7
73 * @access public
74 * @author Grégory Viguier
75 *
76 * @return string
77 */
78 public function get_original_path() {
79 $row = $this->get_row();
80
81 if ( ! $row || empty( $row['path'] ) ) {
82 return '';
83 }
84
85 return Imagify_Files_Scan::remove_placeholder( $row['path'] );
86 }
87
88 /**
89 * Get the original file URL.
90 *
91 * @since 1.7
92 * @access public
93 * @author Grégory Viguier
94 *
95 * @return string
96 */
97 public function get_original_url() {
98 $row = $this->get_row();
99
100 if ( ! $row || empty( $row['path'] ) ) {
101 return '';
102 }
103
104 return Imagify_Files_Scan::remove_placeholder( $row['path'], 'url' );
105 }
106
107 /**
108 * Get the backup file path, even if the file doesn't exist.
109 *
110 * @since 1.7
111 * @access public
112 * @author Grégory Viguier
113 *
114 * @return string|bool The file path. False on failure.
115 */
116 public function get_raw_backup_path() {
117 if ( ! $this->is_valid() ) {
118 return false;
119 }
120
121 return Imagify_Custom_Folders::get_file_backup_path( $this->get_original_path() );
122 }
123
124 /**
125 * Get the backup URL.
126 *
127 * @since 1.7
128 * @access public
129 * @author Grégory Viguier
130 *
131 * @return string|bool The file URL. False on failure.
132 */
133 public function get_backup_url() {
134 if ( ! $this->is_valid() ) {
135 return false;
136 }
137
138 return site_url( '/' ) . $this->filesystem->make_path_relative( $this->get_raw_backup_path() );
139 }
140
141 /**
142 * Get the optimization data.
143 *
144 * @since 1.7
145 * @access public
146 * @author Grégory Viguier
147 *
148 * @return array
149 */
150 public function get_data() {
151 if ( ! $this->is_valid() ) {
152 return array();
153 }
154
155 $data = array_merge( $this->get_row_db_instance()->get_column_defaults(), $this->get_row() );
156
157 unset( $data['file_id'] );
158 return $data;
159 }
160
161 /**
162 * Get the optimization level.
163 *
164 * @since 1.7
165 * @access public
166 * @author Grégory Viguier
167 *
168 * @return int|bool
169 */
170 public function get_optimization_level() {
171 $row = $this->get_row();
172 return isset( $row['optimization_level'] ) && is_int( $row['optimization_level'] ) ? $row['optimization_level'] : false;
173 }
174
175 /**
176 * Get the file optimization status (success, already_optimized, or error).
177 *
178 * @since 1.7
179 * @access public
180 * @author Grégory Viguier
181 *
182 * @return string
183 */
184 public function get_status() {
185 $row = $this->get_row();
186 return ! empty( $row['status'] ) ? $row['status'] : '';
187 }
188
189 /**
190 * Get width and height of the original image.
191 *
192 * @since 1.7
193 * @access public
194 * @author Grégory Viguier
195 *
196 * @return array
197 */
198 public function get_dimensions() {
199 $row = $this->get_row();
200
201 return array(
202 'width' => ! empty( $row['width'] ) ? $row['width'] : 0,
203 'height' => ! empty( $row['height'] ) ? $row['height'] : 0,
204 );
205 }
206
207 /**
208 * Get the attachment error if there is one.
209 *
210 * @since 1.7
211 * @access public
212 * @author Grégory Viguier
213 *
214 * @return string The message error
215 */
216 public function get_optimized_error() {
217 $row = $this->get_row();
218 return ! empty( $row['error'] ) && is_string( $row['error'] ) ? trim( $row['error'] ) : '';
219 }
220
221 /**
222 * Count number of optimized sizes.
223 *
224 * @since 1.7
225 * @access public
226 * @author Grégory Viguier
227 *
228 * @return int
229 */
230 public function get_optimized_sizes_count() {
231 return $this->get_status() === 'success' ? 1 : 0;
232 }
233
234 /**
235 * Delete the data related to optimization.
236 *
237 * @since 1.7
238 * @access public
239 * @author Grégory Viguier
240 */
241 public function delete_imagify_data() {
242 if ( ! $this->is_valid() ) {
243 return;
244 }
245
246 $this->update_row( $this->get_reset_imagify_data() );
247 }
248
249 /**
250 * Tell if the current file extension is supported.
251 * If it's in the DB, it's supported.
252 *
253 * @since 1.7
254 * @access public
255 * @author Grégory Viguier
256 *
257 * @return bool
258 */
259 public function is_extension_supported() {
260 return $this->is_valid();
261 }
262
263 /**
264 * Tell if the current file mime type is supported.
265 * If it's in the DB, it's supported.
266 *
267 * @since 1.7
268 * @access public
269 * @author Grégory Viguier
270 *
271 * @return bool
272 */
273 public function is_mime_type_supported() {
274 return $this->is_valid();
275 }
276
277 /**
278 * Tell if the current attachment has the required WP metadata.
279 * Well, these are not attachments, so...
280 *
281 * @since 1.7
282 * @access public
283 * @author Grégory Viguier
284 *
285 * @return bool
286 */
287 public function has_required_metadata() {
288 return $this->is_valid();
289 }
290
291 /**
292 * Get the original file size.
293 *
294 * @since 1.7
295 * @access public
296 * @author Grégory Viguier
297 *
298 * @param bool $human_format True to display the image human format size (1Mb).
299 * @param int $decimals Precision of number of decimal places.
300 * @return string|int
301 */
302 public function get_original_size( $human_format = true, $decimals = 2 ) {
303 if ( ! $this->is_valid() ) {
304 return $human_format ? imagify_size_format( 0, $decimals ) : 0;
305 }
306
307 $row = $this->get_row();
308
309 if ( ! empty( $row['original_size'] ) ) {
310 $size = $row['original_size'];
311 } else {
312 // Check for the backup file first.
313 $file_path = $this->get_backup_path();
314
315 if ( ! $file_path ) {
316 $file_path = $this->get_original_path();
317 $file_path = $file_path && $this->filesystem->exists( $file_path ) ? $file_path : false;
318 }
319
320 $size = $file_path ? $this->filesystem->size( $file_path ) : 0;
321 }
322
323 if ( $human_format ) {
324 return imagify_size_format( (int) $size, $decimals );
325 }
326
327 return (int) $size;
328 }
329
330 /**
331 * Get the optimized file size.
332 *
333 * @since 1.7
334 * @access public
335 * @author Grégory Viguier
336 *
337 * @param bool $human_format True to display the image human format size (1Mb).
338 * @param int $decimals Precision of number of decimal places.
339 * @return string|int
340 */
341 public function get_optimized_size( $human_format = true, $decimals = 2 ) {
342 if ( ! $this->is_valid() ) {
343 return $human_format ? imagify_size_format( 0, $decimals ) : 0;
344 }
345
346 $row = $this->get_row();
347
348 if ( ! empty( $row['optimized_size'] ) ) {
349 $size = $row['optimized_size'];
350 } else {
351 $file_path = $this->get_original_path();
352 $file_path = $file_path && $this->filesystem->exists( $file_path ) ? $file_path : false;
353 $size = $file_path ? $this->filesystem->size( $file_path ) : 0;
354 }
355
356 if ( $human_format ) {
357 return imagify_size_format( (int) $size, $decimals );
358 }
359
360 return (int) $size;
361 }
362
363 /**
364 * Get the optimized attachment size.
365 *
366 * @since 1.7
367 * @access public
368 * @author Grégory Viguier
369 *
370 * @return float A 2-decimals float.
371 */
372 public function get_saving_percent() {
373 if ( ! $this->is_valid() ) {
374 return round( (float) 0, 2 );
375 }
376
377 $row = $this->get_row();
378
379 if ( ! empty( $row['percent'] ) ) {
380 return $row['percent'] / 100;
381 }
382
383 $original_size = $this->get_original_size( false );
384
385 if ( ! $original_size ) {
386 return round( (float) 0, 2 );
387 }
388
389 $optimized_size = $this->get_optimized_size( false );
390
391 if ( ! $optimized_size ) {
392 return round( (float) 0, 2 );
393 }
394
395 return round( ( $original_size - $optimized_size ) / $original_size * 100, 2 );
396 }
397
398 /**
399 * Get the overall optimized size (all thumbnails).
400 * And since we don't have thumbnails...
401 *
402 * @since 1.7
403 * @access public
404 * @author Grégory Viguier
405 *
406 * @return float A 2-decimals float.
407 */
408 public function get_overall_saving_percent() {
409 return $this->get_saving_percent();
410 }
411
412 /**
413 * Get the statistics of the file.
414 *
415 * @since 1.7
416 * @access public
417 * @author Grégory Viguier
418 *
419 * @param string $size The thumbnail slug. Not used here.
420 * @param string $key The specific data slug.
421 * @return array|string
422 */
423 public function get_size_data( $size = null, $key = null ) {
424 if ( ! isset( $key ) ) {
425 $key = $size;
426 }
427
428 if ( ! $this->is_valid() ) {
429 return isset( $key ) ? '' : array();
430 }
431
432 $data = imagify_merge_intersect( $this->get_row(), array(
433 'original_size' => 0,
434 'optimized_size' => false,
435 'percent' => 0,
436 'status' => false,
437 'error' => false,
438 ) );
439
440 $data['success'] = 'success' === $data['status'];
441
442 if ( $data['status'] ) {
443 unset( $data['status'], $data['error'] );
444
445 if ( empty( $data['percent'] ) && $data['original_size'] && $data['optimized_size'] ) {
446 $data['percent'] = round( ( $data['original_size'] - $data['optimized_size'] ) / $data['original_size'] * 100, 2 );
447 } elseif ( ! empty( $data['percent'] ) ) {
448 $data['percent'] = $data['percent'] / 100;
449 }
450 } else {
451 unset( $data['status'], $data['original_size'], $data['optimized_size'], $data['percent'] );
452 }
453
454 if ( isset( $key ) ) {
455 return isset( $data[ $key ] ) ? $data[ $key ] : '';
456 }
457
458 return $data;
459 }
460
461 /**
462 * Get the global statistics data or a specific one.
463 *
464 * @since 1.7
465 * @access public
466 * @author Grégory Viguier
467 *
468 * @param string $key The specific data slug.
469 * @return array|string
470 */
471 public function get_stats_data( $key = null ) {
472 if ( ! $this->is_valid() ) {
473 return isset( $key ) ? '' : array();
474 }
475
476 $stats = $this->get_size_data( $key );
477 $default = array(
478 'original_size' => 0,
479 'optimized_size' => 0,
480 'percent' => 0,
481 );
482
483 return imagify_merge_intersect( $stats, $default );
484 }
485
486 /**
487 * Since these files are not resized, this method is not needed.
488 *
489 * @since 1.7
490 * @access public
491 * @author Grégory Viguier
492 *
493 * @return bool
494 */
495 public function update_metadata_size() {
496 return false;
497 }
498
499 /**
500 * Get the unoptimized sizes for a specific attachment.
501 *
502 * @since 1.7
503 * @access public
504 * @author Grégory Viguier
505 *
506 * @return array
507 */
508 public function get_unoptimized_sizes() {
509 return array();
510 }
511
512 /**
513 * Get default values used to reset Imagify data.
514 *
515 * @since 1.7
516 * @access public
517 * @author Grégory Viguier
518 */
519 public function get_reset_imagify_data() {
520 static $column_defaults;
521
522 if ( ! isset( $column_defaults ) ) {
523 $column_defaults = $this->get_row_db_instance()->get_column_defaults();
524
525 // All DB columns that have `null` as default value, are Imagify data.
526 foreach ( $column_defaults as $column_name => $value ) {
527 if ( 'hash' === $column_name || 'modified' === $column_name ) {
528 continue;
529 }
530
531 if ( isset( $value ) ) {
532 unset( $column_defaults[ $column_name ] );
533 }
534 }
535 }
536
537 $imagify_columns = $column_defaults;
538
539 // Also set the new file hash.
540 $file_path = $this->get_original_path();
541
542 if ( $file_path && $this->filesystem->exists( $file_path ) ) {
543 $imagify_columns['hash'] = md5_file( $file_path );
544 }
545
546 return $imagify_columns;
547 }
548
549 /**
550 * Fills statistics data with values from $data array.
551 *
552 * @since 1.7
553 * @access public
554 * @author Grégory Viguier
555 *
556 * @param array $data The statistics data.
557 * @param object $response The API response.
558 * @param string $size The attachment size key. Not used here.
559 * @return bool|array False if the original size has an error or an array contains the data for other result.
560 */
561 public function fill_data( $data, $response, $size = null ) {
562 $data = is_array( $data ) ? $data : array();
563 $data = imagify_merge_intersect( $data, $this->get_reset_imagify_data() );
564
565 if ( is_wp_error( $response ) ) {
566 // Error or already optimized.
567 $data['error'] = $response->get_error_message();
568
569 if ( false !== strpos( $data['error'], 'This image is already compressed' ) ) {
570 $data['status'] = 'already_optimized';
571 } else {
572 $data['status'] = 'error';
573 }
574
575 return $data;
576 }
577
578 // Success.
579 $old_data = $this->get_data();
580 $original_size = $old_data['original_size'];
581 $data['percent'] = 0;
582 $data['status'] = 'success';
583
584 if ( ! empty( $response->original_size ) && ! $original_size ) {
585 $data['original_size'] = (int) $response->original_size;
586 $original_size = $data['original_size'];
587 }
588
589 if ( ! empty( $response->new_size ) ) {
590 $data['optimized_size'] = (int) $response->new_size;
591 } else {
592 $file_path = $this->get_original_path();
593 $file_path = $file_path && $this->filesystem->exists( $file_path ) ? $file_path : false;
594
595 $data['optimized_size'] = $file_path ? $this->filesystem->size( $file_path ) : 0;
596 }
597
598 if ( $original_size && $data['optimized_size'] ) {
599 $data['percent'] = round( ( $original_size - $data['optimized_size'] ) / $original_size * 10000 );
600 }
601
602 return $data;
603 }
604
605 /**
606 * Optimize the file with Imagify.
607 *
608 * @since 1.7
609 * @access public
610 * @author Grégory Viguier
611 *
612 * @param int $optimization_level The optimization level (2=ultra, 1=aggressive, 0=normal).
613 * @param array $metadata The attachment meta data. Not used here.
614 * @return bool|object True on success (status success or already_optimized). A WP_Error object on failure.
615 */
616 public function optimize( $optimization_level = null, $metadata = null ) {
617 // Check if the file extension is allowed.
618 if ( ! $this->is_extension_supported() ) {
619 return new WP_Error( 'mime_type_not_supported', __( 'This type of file is not supported.', 'imagify' ) );
620 }
621
622 $optimization_level = is_numeric( $optimization_level ) ? (int) $optimization_level : get_imagify_option( 'optimization_level' );
623
624 // Check if the image is already optimized.
625 if ( $this->is_optimized() && ( $this->get_optimization_level() === $optimization_level ) ) {
626 return new WP_Error( 'same_optimization_level', __( 'This file is already optimized with this level.', 'imagify' ) );
627 }
628
629 /**
630 * Fires before optimizing a file.
631 *
632 * @since 1.7
633 * @author Grégory Viguier
634 *
635 * @param int $id The file ID.
636 */
637 do_action( 'before_imagify_optimize_file', $this->id );
638
639 $this->set_running_status();
640
641 // Optimize the image.
642 $response = do_imagify( $this->get_original_path(), array(
643 'optimization_level' => $optimization_level,
644 'context' => 'File',
645 'original_size' => $this->get_original_size( false ),
646 'backup_path' => $this->get_raw_backup_path(),
647 ) );
648
649 // Fill the data.
650 $data = $this->fill_data( array(
651 'optimization_level' => $optimization_level,
652 ), $response );
653
654 // Save the data.
655 $this->update_row( $data );
656
657 if ( is_wp_error( $response ) ) {
658 $this->delete_running_status();
659
660 if ( 'error' === $data['status'] ) {
661 return $response;
662 }
663
664 // Already optimized.
665 return true;
666 }
667
668 /**
669 * Fires after optimizing an attachment.
670 *
671 * @since 1.7
672 * @author Grégory Viguier
673 *
674 * @param int $id The attachment ID.
675 * @param array $optimized_data The optimization data.
676 */
677 do_action( 'after_imagify_optimize_file', $this->id, $this->get_data() );
678
679 $this->delete_running_status();
680
681 return true;
682 }
683
684 /**
685 * Process an attachment restoration from the backup file.
686 *
687 * @since 1.7
688 * @access public
689 * @author Grégory Viguier
690 *
691 * @return bool|object True on success (status success or already_optimized). A WP_Error object on failure.
692 */
693 public function restore() {
694 // Check if the file extension is allowed.
695 if ( ! $this->is_extension_supported() ) {
696 return new WP_Error( 'mime_type_not_supported', __( 'This type of file is not supported.', 'imagify' ) );
697 }
698
699 $backup_path = $this->get_backup_path();
700
701 // Stop the process if there is no backup file to restore.
702 if ( ! $backup_path ) {
703 return new WP_Error( 'source_doesnt_exist', __( 'The backup file does not exist.', 'imagify' ) );
704 }
705
706 $file_path = $this->get_original_path();
707
708 if ( ! $file_path ) {
709 return new WP_Error( 'empty_path', __( 'The file path is empty.', 'imagify' ) );
710 }
711
712 /**
713 * Fires before restoring a file.
714 *
715 * @since 1.7
716 * @author Grégory Viguier
717 *
718 * @param int $id The file ID.
719 */
720 do_action( 'before_imagify_restore_file', $this->id );
721
722 // Create the original image from the backup.
723 $this->filesystem->copy( $backup_path, $file_path, true );
724 $this->filesystem->chmod_file( $file_path );
725
726 // Remove old optimization data.
727 $this->delete_imagify_data();
728
729 /**
730 * Fires after restoring a file.
731 *
732 * @since 1.7
733 * @author Grégory Viguier
734 *
735 * @param int $id The file ID.
736 */
737 do_action( 'after_imagify_restore_file', $this->id );
738 }
739
740
741 /** ----------------------------------------------------------------------------------------- */
742 /** DB ROW ================================================================================== */
743 /** ----------------------------------------------------------------------------------------- */
744
745 /**
746 * Invalidate the row.
747 *
748 * @since 1.7
749 * @author Grégory Viguier
750 * @access public
751 *
752 * @return array The row
753 */
754 public function invalidate_row() {
755 // Since the ID doesn't exist in any other table (not a Post ID, not a NGG gallery ID), it must be reset.
756 $this->id = 0;
757 $this->row = array();
758 return $this->row;
759 }
760 }
761