PluginProbe
Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization / 4.2.12
Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization v4.2.12
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 3.12.0 All 135 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.12, at inc/media_rename/attachment_replace.php

254 lines 6.6 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 global $wp_filesystem;
81
82 if ( ! $wp_filesystem->move( $this->file['tmp_name'], $original_file, true ) ) {
83 return new WP_Error( 'file_error', __( 'Could not move file.', 'optimole-wp' ) );
84 }
85
86 $permissions_normalized = $this->normalize_file_permissions( $original_file );
87
88 $this->remove_all_image_sizes();
89
90 clean_attachment_cache( $this->attachment_id );
91
92 $metadata = wp_generate_attachment_metadata( $this->attachment_id, $original_file );
93
94 if ( isset( $metadata['sizes'] ) ) {
95 $this->replace_image_sizes_links( $metadata['sizes'], $old_sizes_urls );
96 }
97
98 wp_update_attachment_metadata( $this->attachment_id, $metadata );
99 $this->new_attachment = new Optml_Attachment_Model( $this->attachment_id );
100
101 $this->handle_scaled_images();
102
103 do_action( 'optml_attachment_replaced', $this->attachment_id );
104
105 if ( ! $permissions_normalized ) {
106 return new WP_Error( 'file_permissions_error', __( 'Error replacing file', 'optimole-wp' ) );
107 }
108
109 return true;
110 }
111
112 /**
113 * Normalize the permissions of the replaced file.
114 *
115 * @param string $file File path.
116 *
117 * @return bool Whether the file ended up with the expected permissions.
118 */
119 private function normalize_file_permissions( $file ) {
120 global $wp_filesystem;
121
122 $mode = defined( 'FS_CHMOD_FILE' ) ? FS_CHMOD_FILE : 0644;
123
124 $applied = $wp_filesystem->chmod( $file, $mode );
125
126 $reason = '';
127
128 if ( ! $applied || ! $this->has_permissions( $file, $mode ) ) {
129 // Fallback for transports where the filesystem abstraction can't chmod.
130 set_error_handler(
131 function ( $errno, $errstr ) use ( &$reason ) {
132 $reason = $errstr;
133
134 return true;
135 }
136 );
137
138 $applied = chmod( $file, $mode );
139
140 restore_error_handler();
141 }
142
143 if ( $applied && $this->has_permissions( $file, $mode ) ) {
144 return true;
145 }
146
147 if ( OPTML_DEBUG ) {
148 do_action(
149 'optml_log',
150 sprintf( 'Could not normalize permissions to %o for replaced file %s. %s', $mode, $file, $reason )
151 );
152 }
153
154 return false;
155 }
156
157 /**
158 * Check the current permissions of a file against an expected mode.
159 *
160 * @param string $file File path.
161 * @param int $mode Expected mode.
162 *
163 * @return bool
164 */
165 private function has_permissions( $file, $mode ) {
166 clearstatcache( true, $file );
167
168 $perms = fileperms( $file );
169
170 return false !== $perms && ( $perms & 0777 ) === ( $mode & 0777 );
171 }
172
173 /**
174 * Remove all image sizes files.
175 *
176 * @return void
177 */
178 private function remove_all_image_sizes() {
179 $all_image_sizes_paths = $this->attachment->get_all_image_sizes_paths();
180 global $wp_filesystem;
181
182 foreach ( $all_image_sizes_paths as $path ) {
183 if ( file_exists( $path ) ) {
184 $wp_filesystem->delete( $path );
185 }
186 }
187 }
188
189 /**
190 * Handle scaled images.
191 *
192 * @return bool
193 */
194 private function handle_scaled_images() {
195 global $wp_filesystem;
196
197 $old_scaled = $this->attachment->is_scaled();
198 $new_scaled = $this->new_attachment->is_scaled();
199 $replacer = new Optml_Attachment_Db_Renamer( true );
200
201 $new_file_path = $this->new_attachment->get_source_file_path();
202 $file = apply_filters( 'update_attached_file', $new_file_path, $this->attachment_id );
203
204 // New is scaled, but old is not scaled. We don't replace anything.
205 if ( $old_scaled === $new_scaled || ( ! $old_scaled && $new_scaled ) ) {
206 return true;
207 }
208
209 // Delete the old scaled version and replace scaled URLs with non-scaled URLs.
210 if ( $old_scaled && ! $new_scaled ) {
211 $main_file_url = $this->attachment->get_main_url();
212 $unscaled_file = $this->attachment->get_filename_with_ext();
213 $old_scaled_file = $this->attachment->get_filename_with_ext( true );
214 $old_scaled_url = str_replace( $unscaled_file, $old_scaled_file, $main_file_url );
215
216 $replacer->replace( $old_scaled_url, $main_file_url );
217
218 // replace the old year/month/item-scaled.ext with the new year/month/item.ext
219 $scaled_path = str_replace( $unscaled_file, $old_scaled_file, $this->attachment->get_source_file_path() );
220 if ( file_exists( $scaled_path ) ) {
221 $wp_filesystem->delete( $scaled_path );
222 }
223
224 update_attached_file( $this->attachment_id, sprintf( '%s/%s', $this->attachment->get_metadata_prefix_path(), $unscaled_file ) );
225 }
226
227 return true;
228 }
229
230 /**
231 * Replace image sizes links.
232 *
233 * @param array $new_sizes New sizes.
234 * @param array $old_sizes_urls Old sizes URLs.
235 *
236 * @return void
237 */
238 private function replace_image_sizes_links( $new_sizes, $old_sizes_urls ) {
239 $replacer = new Optml_Attachment_Db_Renamer( true );
240
241 foreach ( $old_sizes_urls as $size => $old_url ) {
242 // If the size is not in the new sizes, we need to use the original URL.
243 if ( ! isset( $new_sizes[ $size ], $new_sizes[ $size ]['file'] ) ) {
244 $replacer->replace( $old_url, $this->attachment->get_main_url() );
245 continue;
246 }
247
248 // If the size is in the new sizes, we need to use the new URL.
249 $new_url = str_replace( $this->attachment->get_filename_with_ext(), $new_sizes[ $size ]['file'], $this->attachment->get_main_url() );
250 $replacer->replace( $old_url, $new_url );
251 }
252 }
253 }
254