PluginProbe
Imsanity / 2.5.0
Imsanity v2.5.0
2.9.4 2.9.3 2.9.2 trunk 2.4.3 2.5.0 2.6.0 2.7.0 2.7.2 2.8.0 2.8.1 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.9.0 2.9.1
imsanity / imsanity.php

imsanity.php in Imsanity 2.5.0, at imsanity.php

309 lines 10.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Main file for Imsanity plugin.
4 *
5 * This file includes the core of Imsanity and the top-level image handler.
6 *
7 * @link https://wordpress.org/plugins/imsanity/
8 * @package Imsanity
9 */
10
11 /*
12 Plugin Name: Imsanity
13 Plugin URI: https://wordpress.org/plugins/imsanity/
14 Description: Imsanity stops insanely huge image uploads
15 Author: Exactly WWW
16 Text Domain: imsanity
17 Domain Path: /languages
18 Version: 2.5.0
19 Author URI: https://ewww.io/
20 License: GPLv3
21 */
22
23 if ( ! defined( 'ABSPATH' ) ) {
24 exit;
25 }
26
27 define( 'IMSANITY_VERSION', '2.5.0' );
28 define( 'IMSANITY_SCHEMA_VERSION', '1.1' );
29
30 define( 'IMSANITY_DEFAULT_MAX_WIDTH', 1920 );
31 define( 'IMSANITY_DEFAULT_MAX_HEIGHT', 1920 );
32 define( 'IMSANITY_DEFAULT_BMP_TO_JPG', 1 );
33 define( 'IMSANITY_DEFAULT_PNG_TO_JPG', 0 );
34 define( 'IMSANITY_DEFAULT_QUALITY', 82 );
35
36 define( 'IMSANITY_SOURCE_POST', 1 );
37 define( 'IMSANITY_SOURCE_LIBRARY', 2 );
38 define( 'IMSANITY_SOURCE_OTHER', 4 );
39
40 if ( ! defined( 'IMSANITY_AJAX_MAX_RECORDS' ) ) {
41 define( 'IMSANITY_AJAX_MAX_RECORDS', 250 );
42 }
43
44 /**
45 * The full path of the main plugin file.
46 *
47 * @var string IMSANITY_PLUGIN_FILE
48 */
49 define( 'IMSANITY_PLUGIN_FILE', __FILE__ );
50 /**
51 * The path of the main plugin file, relative to the plugins/ folder.
52 *
53 * @var string IMSANITY_PLUGIN_FILE_REL
54 */
55 define( 'IMSANITY_PLUGIN_FILE_REL', plugin_basename( __FILE__ ) );
56
57 /**
58 * Load translations for Imsanity.
59 */
60 function imsanity_init() {
61 load_plugin_textdomain( 'imsanity', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
62 }
63
64 /**
65 * Import supporting libraries.
66 */
67 require_once( plugin_dir_path( __FILE__ ) . 'libs/utils.php' );
68 require_once( plugin_dir_path( __FILE__ ) . 'settings.php' );
69 require_once( plugin_dir_path( __FILE__ ) . 'ajax.php' );
70
71 /**
72 * Inspects the request and determines where the upload came from.
73 *
74 * @return IMSANITY_SOURCE_POST | IMSANITY_SOURCE_LIBRARY | IMSANITY_SOURCE_OTHER
75 */
76 function imsanity_get_source() {
77 $id = array_key_exists( 'post_id', $_REQUEST ) ? (int) $_REQUEST['post_id'] : '';
78 $action = array_key_exists( 'action', $_REQUEST ) ? $_REQUEST['action'] : '';
79
80 // A post_id indicates image is attached to a post.
81 if ( $id > 0 ) {
82 return IMSANITY_SOURCE_POST;
83 }
84
85 // If the referrer is the post editor, that's a good indication the image is attached to a post.
86 if ( ! empty( $_SERVER['HTTP_REFERER'] ) && strpos( $_SERVER['HTTP_REFERER'], '/post.php' ) ) {
87 return IMSANITY_SOURCE_POST;
88 }
89
90 // Post_id of 0 is 3.x otherwise use the action parameter.
91 if ( 0 === $id || 'upload-attachment' === $action ) {
92 return IMSANITY_SOURCE_LIBRARY;
93 }
94
95 // We don't know where this one came from but $_REQUEST['_wp_http_referer'] may contain info.
96 return IMSANITY_SOURCE_OTHER;
97 }
98
99 /**
100 * Given the source, returns the max width/height.
101 *
102 * @example: list( $w, $h ) = imsanity_get_max_width_height( IMSANITY_SOURCE_LIBRARY );
103 * @param int $source One of IMSANITY_SOURCE_POST | IMSANITY_SOURCE_LIBRARY | IMSANITY_SOURCE_OTHER.
104 */
105 function imsanity_get_max_width_height( $source ) {
106 $w = imsanity_get_option( 'imsanity_max_width', IMSANITY_DEFAULT_MAX_WIDTH );
107 $h = imsanity_get_option( 'imsanity_max_height', IMSANITY_DEFAULT_MAX_HEIGHT );
108
109 switch ( $source ) {
110 case IMSANITY_SOURCE_POST:
111 break;
112 case IMSANITY_SOURCE_LIBRARY:
113 $w = imsanity_get_option( 'imsanity_max_width_library', $w );
114 $h = imsanity_get_option( 'imsanity_max_height_library', $h );
115 break;
116 default:
117 $w = imsanity_get_option( 'imsanity_max_width_other', $w );
118 $h = imsanity_get_option( 'imsanity_max_height_other', $h );
119 break;
120 }
121
122 // NOTE: filters MUST return an array of 2 items, or the defaults will be used.
123 return apply_filters( 'imsanity_get_max_width_height', array( $w, $h ), $source );
124 }
125
126 /**
127 * Handler after a file has been uploaded. If the file is an image, check the size
128 * to see if it is too big and, if so, resize and overwrite the original.
129 *
130 * @param Array $params The parameters submitted with the upload.
131 */
132 function imsanity_handle_upload( $params ) {
133
134 // If "noresize" is included in the filename then we will bypass imsanity scaling.
135 if ( strpos( $params['file'], 'noresize' ) !== false ) {
136 return $params;
137 }
138
139 // If preferences specify so then we can convert an original bmp or png file into jpg.
140 if ( 'image/bmp' === $params['type'] && imsanity_get_option( 'imsanity_bmp_to_jpg', IMSANITY_DEFAULT_BMP_TO_JPG ) ) {
141 $params = imsanity_convert_to_jpg( 'bmp', $params );
142 }
143
144 if ( 'image/png' === $params['type'] && imsanity_get_option( 'imsanity_png_to_jpg', IMSANITY_DEFAULT_PNG_TO_JPG ) ) {
145 $params = imsanity_convert_to_jpg( 'png', $params );
146 }
147
148 // Make sure this is a type of image that we want to convert and that it exists.
149 $oldpath = $params['file'];
150
151 // Let folks filter the allowed mime-types for resizing.
152 $allowed_types = apply_filters( 'imsanity_allowed_mimes', array( 'image/png', 'image/gif', 'image/jpeg' ), $oldpath );
153 if ( is_string( $allowed_types ) ) {
154 $allowed_types = array( $allowed_types );
155 } elseif ( ! is_array( $allowed_types ) ) {
156 $allowed_types = array();
157 }
158
159 if (
160 ( ! is_wp_error( $params ) ) &&
161 is_file( $oldpath ) &&
162 is_readable( $oldpath ) &&
163 is_writable( $oldpath ) &&
164 filesize( $oldpath ) > 0 &&
165 in_array( $params['type'], $allowed_types, true )
166 ) {
167
168 // figure out where the upload is coming from.
169 $source = imsanity_get_source();
170
171 $maxw = IMSANITY_DEFAULT_MAX_WIDTH;
172 $maxh = IMSANITY_DEFAULT_MAX_HEIGHT;
173 $max_width_height = imsanity_get_max_width_height( $source );
174 if ( is_array( $max_width_height ) && 2 === count( $max_width_height ) ) {
175 list( $maxw, $maxh ) = $max_width_height;
176 }
177
178 list( $oldw, $oldh ) = getimagesize( $oldpath );
179
180 if ( ( $oldw > $maxw && $maxw > 0 ) || ( $oldh > $maxh && $maxh > 0 ) ) {
181 $quality = imsanity_get_option( 'imsanity_quality', IMSANITY_DEFAULT_QUALITY );
182
183 $ftype = imsanity_quick_mimetype( $oldpath );
184 $orientation = imsanity_get_orientation( $oldpath, $ftype );
185 // If we are going to rotate the image 90 degrees during the resize, swap the existing image dimensions.
186 if ( 6 === (int) $orientation || 8 === (int) $orientation ) {
187 $old_oldw = $oldw;
188 $oldw = $oldh;
189 $oldh = $old_oldw;
190 }
191
192 if ( $maxw > 0 && $maxh > 0 && $oldw >= $maxw && $oldh >= $maxh && ( $oldh > $maxh || $oldw > $maxw ) && apply_filters( 'imsanity_crop_image', false ) ) {
193 $neww = $maxw;
194 $newh = $maxh;
195 } else {
196 list( $neww, $newh ) = wp_constrain_dimensions( $oldw, $oldh, $maxw, $maxh );
197 }
198
199 global $ewww_preempt_editor;
200 if ( ! isset( $ewww_preempt_editor ) ) {
201 $ewww_preempt_editor = false;
202 }
203 $original_preempt = $ewww_preempt_editor;
204 $ewww_preempt_editor = true;
205 $resizeresult = imsanity_image_resize( $oldpath, $neww, $newh, apply_filters( 'imsanity_crop_image', false ), null, null, $quality );
206 $ewww_preempt_editor = $original_preempt;
207
208 if ( $resizeresult && ! is_wp_error( $resizeresult ) ) {
209 $newpath = $resizeresult;
210
211 if ( is_file( $newpath ) && filesize( $newpath ) < filesize( $oldpath ) ) {
212 // we saved some file space. remove original and replace with resized image.
213 unlink( $oldpath );
214 rename( $newpath, $oldpath );
215 } elseif ( is_file( $newpath ) ) {
216 // theresized image is actually bigger in filesize (most likely due to jpg quality).
217 // keep the old one and just get rid of the resized image.
218 unlink( $newpath );
219 }
220 } elseif ( false === $resizeresult ) {
221 return $params;
222 } elseif ( is_wp_error( $resizeresult ) ) {
223 // resize didn't work, likely because the image processing libraries are missing.
224 // remove the old image so we don't leave orphan files hanging around.
225 unlink( $oldpath );
226
227 $params = wp_handle_upload_error(
228 $oldpath,
229 sprintf(
230 /* translators: 1: error message 2: link to support forums */
231 esc_html__( 'Imsanity was unable to resize this image for the following reason: %1$s. If you continue to see this error message, you may need to install missing server components. If you think you have discovered a bug, please report it on the Imsanity support forum: %2$s', 'imsanity' ),
232 $resizeresult->get_error_message(),
233 'https://wordpress.org/support/plugin/imsanity'
234 )
235 );
236 } else {
237 return $params;
238 }
239 }
240 }
241 clearstatcache();
242 return $params;
243 }
244
245
246 /**
247 * Read in the image file from the params and then save as a new jpg file.
248 * if successful, remove the original image and alter the return
249 * parameters to return the new jpg instead of the original
250 *
251 * @param string $type Type of the image to be converted: 'bmp' or 'png'.
252 * @param array $params The upload parameters.
253 * @return array altered params
254 */
255 function imsanity_convert_to_jpg( $type, $params ) {
256
257 $img = null;
258
259 if ( 'bmp' === $type ) {
260 include_once( 'libs/imagecreatefrombmp.php' );
261 $img = imagecreatefrombmp( $params['file'] );
262 } elseif ( 'png' === $type ) {
263 if ( ! function_exists( 'imagecreatefrompng' ) ) {
264 return wp_handle_upload_error( $params['file'], esc_html__( 'Imsanity requires the GD library to convert PNG images to JPG', 'imsanity' ) );
265 }
266
267 $input = imagecreatefrompng( $params['file'] );
268 // convert png transparency to white.
269 $img = imagecreatetruecolor( imagesx( $input ), imagesy( $input ) );
270 imagefill( $img, 0, 0, imagecolorallocate( $img, 255, 255, 255 ) );
271 imagealphablending( $img, true );
272 imagecopy( $img, $input, 0, 0, 0, 0, imagesx( $input ), imagesy( $input ) );
273 } else {
274 return wp_handle_upload_error( $params['file'], esc_html__( 'Unknown image type specified in imsanity_convert_to_jpg', 'imsanity' ) );
275 }
276
277 // We need to change the extension from the original to .jpg so we have to ensure it will be a unique filename.
278 $uploads = wp_upload_dir();
279 $oldfilename = basename( $params['file'] );
280 $newfilename = basename( str_ireplace( '.' . $type, '.jpg', $oldfilename ) );
281 $newfilename = wp_unique_filename( $uploads['path'], $newfilename );
282
283 $quality = imsanity_get_option( 'imsanity_quality', IMSANITY_DEFAULT_QUALITY );
284
285 if ( imagejpeg( $img, $uploads['path'] . '/' . $newfilename, $quality ) ) {
286 // Conversion succeeded: remove the original bmp & remap the params.
287 unlink( $params['file'] );
288
289 $params['file'] = $uploads['path'] . '/' . $newfilename;
290 $params['url'] = $uploads['url'] . '/' . $newfilename;
291 $params['type'] = 'image/jpeg';
292 } else {
293 unlink( $params['file'] );
294
295 return wp_handle_upload_error(
296 $oldfilename,
297 /* translators: %s: the image mime type */
298 sprintf( esc_html__( 'Imsanity was unable to process the %s file. If you continue to see this error you may need to disable the conversion option in the Imsanity settings.', 'imsanity' ), $type )
299 );
300 }
301
302 return $params;
303 }
304
305 // Add filter to hook into uploads.
306 add_filter( 'wp_handle_upload', 'imsanity_handle_upload' );
307 // Run necessary actions on init (loading translations mostly).
308 add_action( 'plugins_loaded', 'imsanity_init' );
309