PluginProbe
Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization / 4.2.15
Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization v4.2.15
4.2.15 4.2.14 4.2.13 4.2.12 4.2.11 4.2.10 4.2.9 4.2.8 4.2.7 4.2.6 4.2.5 2.5.5 2.5.6 2.5.7 3.0.0 3.0.1 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.11.0 3.11.1 3.11.2 3.11.3 All 136 releases
optimole-wp / inc / media_rename / attachment_replace.php

attachment_replace.php in Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization 4.2.15, at inc/media_rename/attachment_replace.php

260 lines 6.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Optml_Attachment_Replace
5 *
6 * @since 4.0.0
7 */
8 class Optml_Attachment_Replace {
9
10 /**
11 * Attachment ID.
12 *
13 * @var int
14 */
15 private $attachment_id;
16
17 /**
18 * File.
19 *
20 * @var array
21 */
22 private $file;
23
24 /**
25 * Attachment.
26 *
27 * @var \Optml_Attachment_Model
28 */
29 private $attachment;
30
31 /**
32 * New attachment.
33 *
34 * @var \Optml_Attachment_Model
35 */
36 private $new_attachment;
37
38 /**
39 * Constructor.
40 *
41 * @param int $attachment_id Attachment ID.
42 * @param array $file File.
43 */
44 public function __construct( $attachment_id, $file ) {
45 $this->attachment_id = $attachment_id;
46 $this->file = $file;
47 $this->attachment = new Optml_Attachment_Model( $attachment_id );
48
49 if ( ! function_exists( 'WP_Filesystem' ) ) {
50 require_once ABSPATH . 'wp-admin/includes/file.php';
51 }
52
53 WP_Filesystem();
54 }
55
56 /**
57 * Replace the attachment.
58 *
59 * @return bool|WP_Error
60 */
61 public function replace() {
62 if ( ! file_exists( $this->file['tmp_name'] ) ) {
63 return new WP_Error( 'file_error', __( 'Error uploading file.', 'optimole-wp' ) );
64 }
65
66 $original_file = $this->attachment->get_source_file_path();
67 $old_sizes_urls = $this->attachment->get_all_image_sizes_urls();
68
69 if ( ! file_exists( $original_file ) ) {
70 return new WP_Error( 'file_error', __( 'Original file does not exist.', 'optimole-wp' ) );
71 }
72
73 $original_filetype = wp_check_filetype( $original_file );
74 $uploaded_filetype = wp_check_filetype( $this->file['name'] );
75
76 if ( $original_filetype['type'] !== $uploaded_filetype['type'] ) {
77 return new WP_Error( 'file_error', __( 'The uploaded file type does not match the original file type.', 'optimole-wp' ) );
78 }
79
80 if ( $uploaded_filetype['type'] === 'image/svg+xml' ) {
81 if ( ! Optml_Main::instance()->admin->sanitize_svg( $this->file['tmp_name'] ) ) {
82 return new WP_Error( 'file_error', __( 'Error uploading file.', 'optimole-wp' ) );
83 }
84 }
85
86 global $wp_filesystem;
87
88 if ( ! $wp_filesystem->move( $this->file['tmp_name'], $original_file, true ) ) {
89 return new WP_Error( 'file_error', __( 'Could not move file.', 'optimole-wp' ) );
90 }
91
92 $permissions_normalized = $this->normalize_file_permissions( $original_file );
93
94 $this->remove_all_image_sizes();
95
96 clean_attachment_cache( $this->attachment_id );
97
98 $metadata = wp_generate_attachment_metadata( $this->attachment_id, $original_file );
99
100 if ( isset( $metadata['sizes'] ) ) {
101 $this->replace_image_sizes_links( $metadata['sizes'], $old_sizes_urls );
102 }
103
104 wp_update_attachment_metadata( $this->attachment_id, $metadata );
105 $this->new_attachment = new Optml_Attachment_Model( $this->attachment_id );
106
107 $this->handle_scaled_images();
108
109 do_action( 'optml_attachment_replaced', $this->attachment_id );
110
111 if ( ! $permissions_normalized ) {
112 return new WP_Error( 'file_permissions_error', __( 'Error replacing file', 'optimole-wp' ) );
113 }
114
115 return true;
116 }
117
118 /**
119 * Normalize the permissions of the replaced file.
120 *
121 * @param string $file File path.
122 *
123 * @return bool Whether the file ended up with the expected permissions.
124 */
125 private function normalize_file_permissions( $file ) {
126 global $wp_filesystem;
127
128 $mode = defined( 'FS_CHMOD_FILE' ) ? FS_CHMOD_FILE : 0644;
129
130 $applied = $wp_filesystem->chmod( $file, $mode );
131
132 $reason = '';
133
134 if ( ! $applied || ! $this->has_permissions( $file, $mode ) ) {
135 // Fallback for transports where the filesystem abstraction can't chmod.
136 set_error_handler(
137 function ( $errno, $errstr ) use ( &$reason ) {
138 $reason = $errstr;
139
140 return true;
141 }
142 );
143
144 $applied = chmod( $file, $mode );
145
146 restore_error_handler();
147 }
148
149 if ( $applied && $this->has_permissions( $file, $mode ) ) {
150 return true;
151 }
152
153 if ( OPTML_DEBUG ) {
154 do_action(
155 'optml_log',
156 sprintf( 'Could not normalize permissions to %o for replaced file %s. %s', $mode, $file, $reason )
157 );
158 }
159
160 return false;
161 }
162
163 /**
164 * Check the current permissions of a file against an expected mode.
165 *
166 * @param string $file File path.
167 * @param int $mode Expected mode.
168 *
169 * @return bool
170 */
171 private function has_permissions( $file, $mode ) {
172 clearstatcache( true, $file );
173
174 $perms = fileperms( $file );
175
176 return false !== $perms && ( $perms & 0777 ) === ( $mode & 0777 );
177 }
178
179 /**
180 * Remove all image sizes files.
181 *
182 * @return void
183 */
184 private function remove_all_image_sizes() {
185 $all_image_sizes_paths = $this->attachment->get_all_image_sizes_paths();
186 global $wp_filesystem;
187
188 foreach ( $all_image_sizes_paths as $path ) {
189 if ( file_exists( $path ) ) {
190 $wp_filesystem->delete( $path );
191 }
192 }
193 }
194
195 /**
196 * Handle scaled images.
197 *
198 * @return bool
199 */
200 private function handle_scaled_images() {
201 global $wp_filesystem;
202
203 $old_scaled = $this->attachment->is_scaled();
204 $new_scaled = $this->new_attachment->is_scaled();
205 $replacer = new Optml_Attachment_Db_Renamer( true );
206
207 $new_file_path = $this->new_attachment->get_source_file_path();
208 $file = apply_filters( 'update_attached_file', $new_file_path, $this->attachment_id );
209
210 // New is scaled, but old is not scaled. We don't replace anything.
211 if ( $old_scaled === $new_scaled || ( ! $old_scaled && $new_scaled ) ) {
212 return true;
213 }
214
215 // Delete the old scaled version and replace scaled URLs with non-scaled URLs.
216 if ( $old_scaled && ! $new_scaled ) {
217 $main_file_url = $this->attachment->get_main_url();
218 $unscaled_file = $this->attachment->get_filename_with_ext();
219 $old_scaled_file = $this->attachment->get_filename_with_ext( true );
220 $old_scaled_url = str_replace( $unscaled_file, $old_scaled_file, $main_file_url );
221
222 $replacer->replace( $old_scaled_url, $main_file_url );
223
224 // replace the old year/month/item-scaled.ext with the new year/month/item.ext
225 $scaled_path = str_replace( $unscaled_file, $old_scaled_file, $this->attachment->get_source_file_path() );
226 if ( file_exists( $scaled_path ) ) {
227 $wp_filesystem->delete( $scaled_path );
228 }
229
230 update_attached_file( $this->attachment_id, sprintf( '%s/%s', $this->attachment->get_metadata_prefix_path(), $unscaled_file ) );
231 }
232
233 return true;
234 }
235
236 /**
237 * Replace image sizes links.
238 *
239 * @param array $new_sizes New sizes.
240 * @param array $old_sizes_urls Old sizes URLs.
241 *
242 * @return void
243 */
244 private function replace_image_sizes_links( $new_sizes, $old_sizes_urls ) {
245 $replacer = new Optml_Attachment_Db_Renamer( true );
246
247 foreach ( $old_sizes_urls as $size => $old_url ) {
248 // If the size is not in the new sizes, we need to use the original URL.
249 if ( ! isset( $new_sizes[ $size ], $new_sizes[ $size ]['file'] ) ) {
250 $replacer->replace( $old_url, $this->attachment->get_main_url() );
251 continue;
252 }
253
254 // If the size is in the new sizes, we need to use the new URL.
255 $new_url = str_replace( $this->attachment->get_filename_with_ext(), $new_sizes[ $size ]['file'], $this->attachment->get_main_url() );
256 $replacer->replace( $old_url, $new_url );
257 }
258 }
259 }
260