PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 4.7.0
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v4.7.0
4.7.0 4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 All 111 releases
wp-optimize / webp / class-wpo-webp-utils.php

class-wpo-webp-utils.php in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance 4.7.0, at webp/class-wpo-webp-utils.php

187 lines 5.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined('ABSPATH')) die('No direct access allowed');
4
5 use \WebPConvert\Convert\ConverterFactory;
6
7 require_once WPO_PLUGIN_MAIN_PATH . 'vendor/autoload.php';
8
9 if (!class_exists('WPO_WebP_Utils')) :
10
11 class WPO_WebP_Utils {
12
13 /**
14 * Minimum Firefox version that supports WebP images.
15 *
16 * @see https://caniuse.com/webp
17 */
18 const MIN_FIREFOX_VERSION_FOR_WEBP = '65.0.0';
19
20 /**
21 * Warning message patterns to suppress during WebP conversion.
22 *
23 * @var array<string>
24 */
25 private static $suppressed_warning_patterns = array(
26 '/unlink\(.+\): No such file or directory/',
27 '/rename\(.+\): No such file or directory/',
28 '/filesize\(\): stat failed for/',
29 );
30
31 /**
32 * Determines whether we can do webp conversion or not.
33 *
34 * @return bool
35 */
36 public static function can_do_webp_conversion(): bool {
37 $options = WP_Optimize()->get_options();
38 $webp_conversion = $options->get_option('webp_conversion');
39 $webp_converters = $options->get_option('webp_converters');
40
41 return $webp_conversion && !empty($webp_converters);
42 }
43
44 /**
45 * Convert given image file to webp format.
46 *
47 * @param string $source Path of image file.
48 * @param bool $convert_if_exists Whether to convert if the webp file already exists or not.
49 *
50 * @return void
51 */
52 public static function do_webp_conversion($source, $convert_if_exists = false): void {
53 if (file_exists(self::get_destination_path($source)) && !$convert_if_exists) {
54 return;
55 }
56
57 $webp_converter = WPO_WebP_Convert::get_instance();
58 $webp_converter->convert($source);
59 }
60
61 /**
62 * Returns the destination full path.
63 *
64 * @param string $source Path of the source file.
65 *
66 * @return string Path of destination file.
67 */
68 public static function get_destination_path($source): string {
69 return dirname($source) . '/' . basename($source) . '.webp';
70 }
71
72 /**
73 * Converts an image to WebP format using a specified converter.
74 *
75 * This method acts as a wrapper for the `WebPConvert\Convert\Converters\AbstractConverter::doConvert()` method
76 * from the `webp-convert` library.
77 *
78 * @param string $converter The converter to be used for the conversion process.
79 * @param string $source The path to the source image file.
80 * @param string $destination The path to the destination WebP image file.
81 *
82 * @return void
83 */
84 public static function perform_webp_conversion($converter, $source, $destination): void {
85 set_error_handler(array(__CLASS__, 'handle_webp_conversion_warnings'), E_WARNING); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_set_error_handler -- This is needed in order to suppress PHP warnings thrown by third party library
86
87 try {
88 $converter_instance = ConverterFactory::makeConverter(
89 $converter,
90 $source,
91 $destination
92 );
93
94 $converter_instance->doConvert();
95
96 restore_error_handler();
97 } catch (Exception $e) {
98 restore_error_handler(); // Make sure we restore even if an exception occurs
99
100 $log_details = 'Converter: '.$converter. ', '.WP_Optimize_Utils::get_wp_relative_path($source).' => '.WP_Optimize_Utils::get_wp_relative_path($destination);
101 WP_Optimize_WebP::get_instance()->log('Failed to convert to WebP: '. $log_details);
102 throw new Exception(esc_html(__('Failed to convert to WebP.', 'wp-optimize')));
103 }
104 }
105
106 /**
107 * Custom error handler for handling PHP warnings during the WebP conversion process.
108 *
109 * @param int $errno The level of the error raised.
110 * @param string $errstr The error message.
111 *
112 * @return bool
113 */
114 public static function handle_webp_conversion_warnings($errno, $errstr): bool {
115 foreach (self::$suppressed_warning_patterns as $pattern) {
116 if (preg_match($pattern, $errstr)) {
117 return true;
118 }
119 }
120
121 return false;
122 }
123
124 /**
125 * Decide whether the browser requesting the URL can accept webp images or not.
126 *
127 * @return bool
128 */
129 public static function is_browser_accepting_webp(): bool {
130 if (self::browser_accepts_webp_header()) {
131 return true;
132 }
133
134 return self::user_agent_supports_webp();
135 }
136
137 /**
138 * Check if the HTTP Accept header indicates WebP support.
139 *
140 * @return bool
141 */
142 private static function browser_accepts_webp_header(): bool {
143 $http_accept = TeamUpdraft\WP_Optimize\Includes\Fragments\fetch_superglobal(
144 'server',
145 'HTTP_ACCEPT',
146 'string',
147 'sanitize_text_field',
148 ''
149 );
150
151 if (!is_string($http_accept)) {
152 return false;
153 }
154
155 return false !== strpos($http_accept, 'image/webp');
156 }
157
158 /**
159 * Check if the user agent indicates WebP support based on known browser versions.
160 *
161 * @return bool
162 */
163 private static function user_agent_supports_webp(): bool {
164 $user_agent = TeamUpdraft\WP_Optimize\Includes\Fragments\fetch_superglobal(
165 'server',
166 'HTTP_USER_AGENT',
167 'string',
168 'sanitize_text_field',
169 ''
170 );
171
172 if (empty($user_agent) || !is_string($user_agent)) {
173 return false;
174 }
175
176 if (preg_match('/Firefox\/([\d\.]+[a-z\d]*)/', $user_agent, $matches)) {
177 if (version_compare(self::MIN_FIREFOX_VERSION_FOR_WEBP, $matches[1], '<=')) {
178 return true;
179 }
180 }
181
182 return false;
183 }
184 }
185
186 endif;
187