Imsanity - Version 2.4.0

Version Description

  • added: deep scanning option for when attachment metadata isn't updating properly
  • fixed: uploads from Gutenberg not detected properly
  • fixed: some other plugin(s) trying to muck with the Imsanity settings links and breaking things
  • fixed: undefined notice for query during ajax operation
  • fixed: stale metadata could prevent further resizing
Download this release

Release Info

Developer nosilver4u
Plugin Icon 128x128 Imsanity
Version 2.4.0
Comparing to
See all releases

Code changes from version 2.3.10 to 2.4.0

Files changed (7) hide show
  1. ajax.php +131 -83
  2. imsanity.php +111 -119
  3. libs/imagecreatefrombmp.php +240 -69
  4. libs/utils.php +96 -54
  5. readme.txt +8 -21
  6. scripts/imsanity.js +22 -14
  7. settings.php +237 -294
ajax.php CHANGED
@@ -1,24 +1,29 @@
1
  <?php
2
  /**
3
- * ################################################################################
4
- * IMSANITY AJAX FUNCTIONS
5
- * ################################################################################
6
- */
7
 
8
- add_action('wp_ajax_imsanity_get_images', 'imsanity_get_images');
9
- add_action('wp_ajax_imsanity_resize_image', 'imsanity_resize_image');
10
 
11
  /**
12
  * Verifies that the current user has administrator permission and, if not,
13
  * renders a json warning and dies
14
  */
15
- function imsanity_verify_permission()
16
- {
17
- if ( ! current_user_can( 'administrator' ) ) { // this isn't a real capability, but super admins can do anything, so it works
18
- die( json_encode( array( 'success' => false, 'message' => esc_html__( 'Administrator permission is required', 'imsanity' ) ) ) );
 
 
19
  }
20
  if ( ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'imsanity-bulk' ) ) {
21
- die( json_encode( array( 'success' => false, 'message' => esc_html__( 'Access token has expired, please reload the page.', 'imsanity' ) ) ) );
 
 
 
22
  }
23
  }
24
 
@@ -27,48 +32,61 @@ function imsanity_verify_permission()
27
  * Searches for up to 250 images that are candidates for resize and renders them
28
  * to the browser as a json array, then dies
29
  */
30
- function imsanity_get_images()
31
- {
32
  imsanity_verify_permission();
33
 
34
  global $wpdb;
35
- $offset = 0;
36
- $limit = apply_filters( 'imsanity_attachment_query_limit', 3000 );
37
  $results = array();
38
- $maxW = imsanity_get_option( 'imsanity_max_width', IMSANITY_DEFAULT_MAX_WIDTH );
39
- $maxH = imsanity_get_option( 'imsanity_max_height', IMSANITY_DEFAULT_MAX_HEIGHT );
40
- $count = 0;
41
 
42
- while( $images = $wpdb->get_results( "SELECT metas.meta_value as file_meta,metas.post_id as ID FROM $wpdb->postmeta metas INNER JOIN $wpdb->posts posts ON posts.ID = metas.post_id WHERE posts.post_type LIKE 'attachment' AND posts.post_mime_type LIKE 'image%%' AND posts.post_mime_type NOT LIKE 'image/bmp' AND metas.meta_key = '_wp_attachment_metadata' LIMIT $offset,$limit" ) ) {
 
 
43
 
44
  foreach ( $images as $image ) {
45
  $meta = unserialize( $image->file_meta );
 
 
 
 
 
 
 
 
 
 
46
 
47
- if ( $meta['width'] > $maxW || $meta['height'] > $maxH ) {
48
  $count++;
49
 
50
  $results[] = array(
51
- 'id'=>$image->ID,
52
- 'width'=>$meta['width'],
53
- 'height'=>$meta['height'],
54
- 'file'=>$meta['file']
55
  );
56
  }
57
 
58
- // make sure we only return a limited number of records so we don't overload the ajax features
59
- if ( $count >= IMSANITY_AJAX_MAX_RECORDS ) break 2;
 
 
60
  }
61
  $offset += $limit;
 
62
  } // endwhile
63
  die( json_encode( $results ) );
64
  }
65
 
66
  /**
67
- * Resizes the image with the given id according to the configured max width and height settings
68
- * renders a json response indicating success/failure and dies
69
- */
70
- function imsanity_resize_image()
71
- {
72
  imsanity_verify_permission();
73
 
74
  global $wpdb;
@@ -76,100 +94,130 @@ function imsanity_resize_image()
76
  $id = (int) $_POST['id'];
77
 
78
  if ( ! $id ) {
79
- die( json_encode( array( 'success' => false, 'message' => esc_html__( 'Missing ID Parameter', 'imsanity' ) ) ) );
 
 
 
80
  }
81
 
82
  $meta = wp_get_attachment_metadata( $id );
83
 
84
  if ( $meta && is_array( $meta ) ) {
85
  $uploads = wp_upload_dir();
86
- // TODO: we can do better here, sub in a version of the EWWW file finder
87
- $oldPath = $uploads['basedir'] . "/" . $meta['file'];
88
- if ( ! is_writable( $oldPath ) ) {
89
- $msg = sprintf( esc_html__( '%s is not writable', 'imsanity' ), $oldPath );
90
- die( json_encode( array( 'success' => false, 'message' => $msg ) ) );
 
 
 
91
  }
92
 
93
- $maxW = imsanity_get_option( 'imsanity_max_width', IMSANITY_DEFAULT_MAX_WIDTH );
94
- $maxH = imsanity_get_option( 'imsanity_max_height', IMSANITY_DEFAULT_MAX_HEIGHT );
95
 
96
- // method one - slow but accurate, get file size from file itself
97
- list( $oldW, $oldH ) = getimagesize( $oldPath );
98
- // method two - get file size from meta, fast but resize will fail if meta is out of sync
99
- if ( ! $oldW || ! $oldH ) {
100
- $oldW = $meta['width'];
101
- $oldH = $meta['height'];
102
  }
103
 
104
- if ( ( $oldW > $maxW && $maxW > 0 ) || ( $oldH > $maxH && $maxH > 0 ) ) {
105
  $quality = imsanity_get_option( 'imsanity_quality', IMSANITY_DEFAULT_QUALITY );
106
 
107
- if ( $oldW > $maxW && $maxW > 0 && $oldH > $maxH && $maxH > 0 && apply_filters( 'imsanity_crop_image', false ) ) {
108
- $newW = $maxW;
109
- $newH = $maxH;
110
  } else {
111
- list( $newW, $newH ) = wp_constrain_dimensions( $oldW, $oldH, $maxW, $maxH );
112
  }
113
 
114
- $resizeResult = imsanity_image_resize( $oldPath, $newW, $newH, apply_filters( 'imsanity_crop_image', false ), null, null, $quality);
115
- // $resizeResult = new WP_Error('invalid_image', __('Could not read image size'), $oldPath); // uncomment to debug fail condition
116
 
117
- if ( $resizeResult && ! is_wp_error( $resizeResult ) ) {
118
- $newPath = $resizeResult;
119
 
120
- if ( $newPath != $oldPath && is_file( $newPath ) && filesize( $newPath ) < filesize( $oldPath ) ) {
121
- // we saved some file space. remove original and replace with resized image
122
- unlink( $oldPath );
123
- rename( $newPath, $oldPath );
124
- $meta['width'] = $newW;
125
- $meta['height'] = $newH;
126
 
127
  wp_update_attachment_metadata( $id, $meta );
128
 
129
- $results = array( 'success'=>true, 'id'=> $id, 'message' => sprintf( esc_html__( 'OK: %s', 'imsanity' ) , $oldPath ) );
130
- } elseif ( $newPath != $oldPath ) {
131
- // theresized image is actually bigger in filesize (most likely due to jpg quality).
132
- // keep the old one and just get rid of the resized image
133
- if ( is_file( $newPath ) ) {
134
- unlink( $newPath );
 
 
 
 
 
135
  }
136
- $results = array( 'success'=>false, 'id'=> $id, 'message' => sprintf( esc_html__( 'ERROR: %s (%s)', 'imsanity' ) , $oldPath, esc_html__( 'Resized image was larger than the original', 'imsanity' ) ) );
 
 
 
 
 
137
  } else {
138
- $results = array( 'success'=>false, 'id'=> $id, 'message' => sprintf( esc_html__( 'ERROR: %s (%s)', 'imsanity' ) , $oldPath, esc_html__( 'Unknown error, resizing function returned the same filename', 'imsanity' ) ) );
 
 
 
 
 
139
  }
140
-
141
- } else if ( $resizeResult === false ) {
142
  $results = array(
143
  'success' => false,
144
- 'id' => $id,
145
- 'message' => sprintf( esc_html__( 'ERROR: %s (%s)', 'imsanity' ), $oldPath, 'wp_get_image_editor missing' ),
 
146
  );
147
  } else {
148
  $results = array(
149
  'success' => false,
150
- 'id' => $id,
151
- 'message' => sprintf( esc_html__( 'ERROR: %s (%s)', 'imsanity' ), $oldPath, htmlentities( $resizeResult->get_error_message() ) )
 
152
  );
153
  }
154
  } else {
155
- $results = array('success'=>true,'id'=> $id, 'message' => sprintf( esc_html__( 'SKIPPED: %s (Resize not required)', 'imsanity' ) , $oldPath ) . " -- $oldW x $oldH" );
 
 
 
 
 
156
  if ( empty( $meta['width'] ) || empty( $meta['height'] ) ) {
157
- if ( empty( $meta['width'] ) || $meta['width'] > $oldW ) {
158
- $meta['width'] = $oldW;
159
  }
160
- if ( empty( $meta['height'] ) || $meta['height'] > $oldH ) {
161
- $meta['height'] = $oldH;
162
  }
163
  wp_update_attachment_metadata( $id, $meta );
164
  }
165
  }
166
  } else {
167
- $results = array( 'success' => false, 'id'=> $id, 'message' => sprintf( esc_html__( 'ERROR: Attachment with ID of %s not found', 'imsanity' ) , htmlentities( $id ) ) );
 
 
 
 
 
168
  }
169
 
170
- // if there is a quota we need to reset the directory size cache so it will re-calculate
171
  delete_transient( 'dirsize_cache' );
172
-
173
  die( json_encode( $results ) );
174
  }
175
- ?>
1
  <?php
2
  /**
3
+ * Imsanity AJAX functions.
4
+ *
5
+ * @package Imsanity
6
+ */
7
 
8
+ add_action( 'wp_ajax_imsanity_get_images', 'imsanity_get_images' );
9
+ add_action( 'wp_ajax_imsanity_resize_image', 'imsanity_resize_image' );
10
 
11
  /**
12
  * Verifies that the current user has administrator permission and, if not,
13
  * renders a json warning and dies
14
  */
15
+ function imsanity_verify_permission() {
16
+ if ( ! current_user_can( 'activate_plugins' ) ) { // this isn't a real capability, but super admins can do anything, so it works.
17
+ die( json_encode( array(
18
+ 'success' => false,
19
+ 'message' => esc_html__( 'Administrator permission is required', 'imsanity' ),
20
+ ) ) );
21
  }
22
  if ( ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'imsanity-bulk' ) ) {
23
+ die( json_encode( array(
24
+ 'success' => false,
25
+ 'message' => esc_html__( 'Access token has expired, please reload the page.', 'imsanity' ),
26
+ ) ) );
27
  }
28
  }
29
 
32
  * Searches for up to 250 images that are candidates for resize and renders them
33
  * to the browser as a json array, then dies
34
  */
35
+ function imsanity_get_images() {
 
36
  imsanity_verify_permission();
37
 
38
  global $wpdb;
39
+ $offset = 0;
40
+ $limit = apply_filters( 'imsanity_attachment_query_limit', 3000 );
41
  $results = array();
42
+ $maxw = imsanity_get_option( 'imsanity_max_width', IMSANITY_DEFAULT_MAX_WIDTH );
43
+ $maxh = imsanity_get_option( 'imsanity_max_height', IMSANITY_DEFAULT_MAX_HEIGHT );
44
+ $count = 0;
45
 
46
+ $images = $wpdb->get_results( $wpdb->prepare( "SELECT metas.meta_value as file_meta,metas.post_id as ID FROM $wpdb->postmeta metas INNER JOIN $wpdb->posts posts ON posts.ID = metas.post_id WHERE posts.post_type = 'attachment' AND posts.post_mime_type LIKE %s AND posts.post_mime_type != 'image/bmp' AND metas.meta_key = '_wp_attachment_metadata' ORDER BY ID DESC LIMIT %d,%d", '%image%', $offset, $limit ) );
47
+ /* $images = $wpdb->get_results( "SELECT metas.meta_value as file_meta,metas.post_id as ID FROM $wpdb->postmeta metas INNER JOIN $wpdb->posts posts ON posts.ID = metas.post_id WHERE posts.post_type LIKE 'attachment' AND posts.post_mime_type LIKE 'image%%' AND posts.post_mime_type NOT LIKE 'image/bmp' AND metas.meta_key = '_wp_attachment_metadata' LIMIT $offset,$limit" ); */
48
+ while ( $images ) {
49
 
50
  foreach ( $images as $image ) {
51
  $meta = unserialize( $image->file_meta );
52
+ if ( imsanity_get_option( 'imsanity_deep_scan', false ) ) {
53
+ $file_path = imsanity_attachment_path( $meta, $image->ID, '', false );
54
+ if ( $file_path ) {
55
+ list( $imagew, $imageh ) = getimagesize( $file_path );
56
+ }
57
+ }
58
+ if ( empty( $imagew ) || empty( $imageh ) ) {
59
+ $imagew = $meta['width'];
60
+ $imageh = $meta['height'];
61
+ }
62
 
63
+ if ( $imagew > $maxw || $imageh > $maxh ) {
64
  $count++;
65
 
66
  $results[] = array(
67
+ 'id' => $image->ID,
68
+ 'width' => $imagew,
69
+ 'height' => $imageh,
70
+ 'file' => $meta['file'],
71
  );
72
  }
73
 
74
+ // Make sure we only return a limited number of records so we don't overload the ajax features.
75
+ if ( $count >= IMSANITY_AJAX_MAX_RECORDS ) {
76
+ break 2;
77
+ }
78
  }
79
  $offset += $limit;
80
+ $images = $wpdb->get_results( $wpdb->prepare( "SELECT metas.meta_value as file_meta,metas.post_id as ID FROM $wpdb->postmeta metas INNER JOIN $wpdb->posts posts ON posts.ID = metas.post_id WHERE posts.post_type = 'attachment' AND posts.post_mime_type LIKE %s AND posts.post_mime_type != 'image/bmp' AND metas.meta_key = '_wp_attachment_metadata' ORDER BY ID DESC LIMIT %d,%d", '%image%', $offset, $limit ) );
81
  } // endwhile
82
  die( json_encode( $results ) );
83
  }
84
 
85
  /**
86
+ * Resizes the image with the given id according to the configured max width and height settings
87
+ * renders a json response indicating success/failure and dies
88
+ */
89
+ function imsanity_resize_image() {
 
90
  imsanity_verify_permission();
91
 
92
  global $wpdb;
94
  $id = (int) $_POST['id'];
95
 
96
  if ( ! $id ) {
97
+ die( json_encode( array(
98
+ 'success' => false,
99
+ 'message' => esc_html__( 'Missing ID Parameter', 'imsanity' ),
100
+ ) ) );
101
  }
102
 
103
  $meta = wp_get_attachment_metadata( $id );
104
 
105
  if ( $meta && is_array( $meta ) ) {
106
  $uploads = wp_upload_dir();
107
+ $oldpath = imsanity_attachment_path( $meta['file'], $id, '', false );
108
+ if ( ! is_writable( $oldpath ) ) {
109
+ /* translators: %s: File-name of the image */
110
+ $msg = sprintf( esc_html__( '%s is not writable', 'imsanity' ), $oldpath );
111
+ die( json_encode( array(
112
+ 'success' => false,
113
+ 'message' => $msg,
114
+ ) ) );
115
  }
116
 
117
+ $maxw = imsanity_get_option( 'imsanity_max_width', IMSANITY_DEFAULT_MAX_WIDTH );
118
+ $maxh = imsanity_get_option( 'imsanity_max_height', IMSANITY_DEFAULT_MAX_HEIGHT );
119
 
120
+ // method one - slow but accurate, get file size from file itself.
121
+ list( $oldw, $oldh ) = getimagesize( $oldpath );
122
+ // method two - get file size from meta, fast but resize will fail if meta is out of sync.
123
+ if ( ! $oldw || ! $oldh ) {
124
+ $oldw = $meta['width'];
125
+ $oldh = $meta['height'];
126
  }
127
 
128
+ if ( ( $oldw > $maxw && $maxw > 0 ) || ( $oldh > $maxh && $maxh > 0 ) ) {
129
  $quality = imsanity_get_option( 'imsanity_quality', IMSANITY_DEFAULT_QUALITY );
130
 
131
+ if ( $oldw > $maxw && $maxw > 0 && $oldh > $maxh && $maxh > 0 && apply_filters( 'imsanity_crop_image', false ) ) {
132
+ $neww = $maxw;
133
+ $newh = $maxh;
134
  } else {
135
+ list( $neww, $newh ) = wp_constrain_dimensions( $oldw, $oldh, $maxw, $maxh );
136
  }
137
 
138
+ $resizeresult = imsanity_image_resize( $oldpath, $neww, $newh, apply_filters( 'imsanity_crop_image', false ), null, null, $quality );
 
139
 
140
+ if ( $resizeresult && ! is_wp_error( $resizeresult ) ) {
141
+ $newpath = $resizeresult;
142
 
143
+ if ( $newpath != $oldpath && is_file( $newpath ) && filesize( $newpath ) < filesize( $oldpath ) ) {
144
+ // we saved some file space. remove original and replace with resized image.
145
+ unlink( $oldpath );
146
+ rename( $newpath, $oldpath );
147
+ $meta['width'] = $neww;
148
+ $meta['height'] = $newh;
149
 
150
  wp_update_attachment_metadata( $id, $meta );
151
 
152
+ $results = array(
153
+ 'success' => true,
154
+ 'id' => $id,
155
+ /* translators: %s: File-name of the image */
156
+ 'message' => sprintf( esc_html__( 'OK: %s', 'imsanity' ), $oldpath ),
157
+ );
158
+ } elseif ( $newpath != $oldpath ) {
159
+ // the resized image is actually bigger in filesize (most likely due to jpg quality).
160
+ // keep the old one and just get rid of the resized image.
161
+ if ( is_file( $newpath ) ) {
162
+ unlink( $newpath );
163
  }
164
+ $results = array(
165
+ 'success' => false,
166
+ 'id' => $id,
167
+ /* translators: 1: File-name of the image 2: the error message, translated elsewhere */
168
+ 'message' => sprintf( esc_html__( 'ERROR: %1$s (%2$s)', 'imsanity' ), $oldpath, esc_html__( 'Resized image was larger than the original', 'imsanity' ) ),
169
+ );
170
  } else {
171
+ $results = array(
172
+ 'success' => false,
173
+ 'id' => $id,
174
+ /* translators: 1: File-name of the image 2: the error message, translated elsewhere */
175
+ 'message' => sprintf( esc_html__( 'ERROR: %1$s (%2$s)', 'imsanity' ), $oldpath, esc_html__( 'Unknown error, resizing function returned the same filename', 'imsanity' ) ),
176
+ );
177
  }
178
+ } elseif ( false === $resizeresult ) {
 
179
  $results = array(
180
  'success' => false,
181
+ 'id' => $id,
182
+ /* translators: 1: File-name of the image 2: the error message, translated elsewhere */
183
+ 'message' => sprintf( esc_html__( 'ERROR: %1$s (%2$s)', 'imsanity' ), $oldpath, esc_html__( 'wp_get_image_editor missing', 'imsanity' ) ),
184
  );
185
  } else {
186
  $results = array(
187
  'success' => false,
188
+ 'id' => $id,
189
+ /* translators: 1: File-name of the image 2: the error message, translated elsewhere */
190
+ 'message' => sprintf( esc_html__( 'ERROR: %1$s (%2$s)', 'imsanity' ), $oldpath, htmlentities( $resizeresult->get_error_message() ) ),
191
  );
192
  }
193
  } else {
194
+ $results = array(
195
+ 'success' => true,
196
+ 'id' => $id,
197
+ /* translators: %s: File-name of the image */
198
+ 'message' => sprintf( esc_html__( 'SKIPPED: %s (Resize not required)', 'imsanity' ), $oldpath ) . " -- $oldw x $oldh",
199
+ );
200
  if ( empty( $meta['width'] ) || empty( $meta['height'] ) ) {
201
+ if ( empty( $meta['width'] ) || $meta['width'] > $oldw ) {
202
+ $meta['width'] = $oldw;
203
  }
204
+ if ( empty( $meta['height'] ) || $meta['height'] > $oldh ) {
205
+ $meta['height'] = $oldh;
206
  }
207
  wp_update_attachment_metadata( $id, $meta );
208
  }
209
  }
210
  } else {
211
+ $results = array(
212
+ 'success' => false,
213
+ 'id' => $id,
214
+ /* translators: %s: ID number of the image */
215
+ 'message' => sprintf( esc_html__( 'ERROR: Attachment with ID of %d not found', 'imsanity' ), intval( $id ) ),
216
+ );
217
  }
218
 
219
+ // If there is a quota we need to reset the directory size cache so it will re-calculate.
220
  delete_transient( 'dirsize_cache' );
221
+
222
  die( json_encode( $results ) );
223
  }
 
imsanity.php CHANGED
@@ -1,16 +1,29 @@
1
  <?php
 
 
 
 
 
 
 
 
 
2
  /*
3
  Plugin Name: Imsanity
4
  Plugin URI: https://wordpress.org/plugins/imsanity/
5
  Description: Imsanity stops insanely huge image uploads
6
  Author: Shane Bishop
7
- Version: 2.3.10
8
- Author URI: https://ewww.io/
9
  Text Domain: imsanity
 
 
10
  License: GPLv3
11
  */
12
 
13
- define( 'IMSANITY_VERSION', '2.3.10' );
 
 
 
 
14
  define( 'IMSANITY_SCHEMA_VERSION', '1.1' );
15
 
16
  define( 'IMSANITY_DEFAULT_MAX_WIDTH', 2048 );
@@ -27,10 +40,10 @@ if ( ! defined( 'IMSANITY_AJAX_MAX_RECORDS' ) ) {
27
  define( 'IMSANITY_AJAX_MAX_RECORDS', 250 );
28
  }
29
 
 
 
 
30
  function imsanity_init() {
31
- /**
32
- * Load Translations
33
- */
34
  load_plugin_textdomain( 'imsanity', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
35
  }
36
 
@@ -47,7 +60,7 @@ include_once( plugin_dir_path( __FILE__ ) . 'ajax.php' );
47
  * @return IMSANITY_SOURCE_POST | IMSANITY_SOURCE_LIBRARY | IMSANITY_SOURCE_OTHER
48
  */
49
  function imsanity_get_source() {
50
- $id = array_key_exists( 'post_id', $_REQUEST ) ? $_REQUEST['post_id'] : '';
51
  $action = array_key_exists( 'action', $_REQUEST ) ? $_REQUEST['action'] : '';
52
 
53
  // A post_id indicates image is attached to a post.
@@ -55,8 +68,13 @@ function imsanity_get_source() {
55
  return IMSANITY_SOURCE_POST;
56
  }
57
 
 
 
 
 
 
58
  // Post_id of 0 is 3.x otherwise use the action parameter.
59
- if ( 0 === $id || '0' === $id || 'upload-attachment' == $action ) {
60
  return IMSANITY_SOURCE_LIBRARY;
61
  }
62
 
@@ -65,25 +83,25 @@ function imsanity_get_source() {
65
  }
66
 
67
  /**
68
- * Given the source, returns the max width/height
69
  *
70
- * @example: list($w,$h) = imsanity_get_max_width_height(IMSANITY_SOURCE_LIBRARY);
71
- * @param int IMSANITY_SOURCE_POST | IMSANITY_SOURCE_LIBRARY | IMSANITY_SOURCE_OTHER
72
  */
73
  function imsanity_get_max_width_height( $source ) {
74
- $w = imsanity_get_option( 'imsanity_max_width',IMSANITY_DEFAULT_MAX_WIDTH );
75
- $h = imsanity_get_option( 'imsanity_max_height',IMSANITY_DEFAULT_MAX_HEIGHT );
76
 
77
  switch ( $source ) {
78
  case IMSANITY_SOURCE_POST:
79
  break;
80
  case IMSANITY_SOURCE_LIBRARY:
81
- $w = imsanity_get_option( 'imsanity_max_width_library',$w );
82
- $h = imsanity_get_option( 'imsanity_max_height_library',$h );
83
  break;
84
  default:
85
- $w = imsanity_get_option( 'imsanity_max_width_other',$w );
86
- $h = imsanity_get_option( 'imsanity_max_height_other',$h );
87
  break;
88
  }
89
 
@@ -92,173 +110,148 @@ function imsanity_get_max_width_height( $source ) {
92
 
93
  /**
94
  * Handler after a file has been uploaded. If the file is an image, check the size
95
- * to see if it is too big and, if so, resize and overwrite the original
96
- * @param Array $params
 
97
  */
98
  function imsanity_handle_upload( $params ) {
99
- /* debug logging... */
100
- // file_put_contents ( "debug.txt" , print_r($params,1) . "\n" );
101
 
102
- // if "noresize" is included in the filename then we will bypass imsanity scaling
103
- if ( strpos( $params['file'], 'noresize' ) !== false ) return $params;
 
 
104
 
105
- // if preferences specify so then we can convert an original bmp or png file into jpg
106
- if ( $params['type'] == 'image/bmp' && imsanity_get_option( 'imsanity_bmp_to_jpg', IMSANITY_DEFAULT_BMP_TO_JPG ) ) {
107
  $params = imsanity_convert_to_jpg( 'bmp', $params );
108
  }
109
 
110
- if ( $params['type'] == 'image/png' && imsanity_get_option( 'imsanity_png_to_jpg', IMSANITY_DEFAULT_PNG_TO_JPG ) ) {
111
  $params = imsanity_convert_to_jpg( 'png', $params );
112
  }
113
 
114
- // make sure this is a type of image that we want to convert and that it exists
115
- // @TODO when uploads occur via RPC the image may not exist at this location
116
- $oldPath = $params['file'];
117
 
118
- // @HACK not currently working
119
- // @see https://wordpress.org/support/topic/images-dont-resize-when-uploaded-via-mobile-device
120
- // if (!file_exists($oldPath)) {
121
- // $ud = wp_upload_dir();
122
- // $oldPath = $ud['path'] . DIRECTORY_SEPARATOR . $oldPath;
123
- // }
124
 
125
- if ( ( ! is_wp_error( $params ) ) && is_file( $oldPath ) && is_readable( $oldPath ) && is_writable( $oldPath ) && filesize( $oldPath ) > 0 && in_array( $params['type'], array( 'image/png', 'image/gif', 'image/jpeg' ) ) ) {
126
-
127
- // figure out where the upload is coming from
128
  $source = imsanity_get_source();
129
 
130
- list( $maxW,$maxH ) = imsanity_get_max_width_height( $source );
131
-
132
- list( $oldW, $oldH ) = getimagesize( $oldPath );
133
 
134
- /* HACK: if getimagesize returns an incorrect value (sometimes due to bad EXIF data..?)
135
- $img = imagecreatefromjpeg ($oldPath);
136
- $oldW = imagesx ($img);
137
- $oldH = imagesy ($img);
138
- imagedestroy ($img);
139
- //*/
140
 
141
- /* HACK: an animated gif may have different frame sizes. to get the "screen" size
142
- $data = ''; // TODO: convert file to binary
143
- $header = unpack('@6/vwidth/vheight', $data );
144
- $oldW = $header['width'];
145
- $oldH = $header['width'];
146
- //*/
147
-
148
- if ( ( $oldW > $maxW && $maxW > 0 ) || ( $oldH > $maxH && $maxH > 0 ) ) {
149
  $quality = imsanity_get_option( 'imsanity_quality', IMSANITY_DEFAULT_QUALITY );
150
 
151
- $ftype = imsanity_quick_mimetype( $oldPath );
152
- $orientation = imsanity_get_orientation( $oldPath, $ftype );
153
  // If we are going to rotate the image 90 degrees during the resize, swap the existing image dimensions.
154
  if ( 6 == $orientation || 8 == $orientation ) {
155
- $old_oldW = $oldW;
156
- $oldW = $oldH;
157
- $oldH = $old_oldW;
158
  }
159
 
160
- if ( $oldW > $maxW && $maxW > 0 && $oldH > $maxH && $maxH > 0 && apply_filters( 'imsanity_crop_image', false ) ) {
161
- $newW = $maxW;
162
- $newH = $maxH;
163
  } else {
164
- list( $newW, $newH ) = wp_constrain_dimensions( $oldW, $oldH, $maxW, $maxH );
165
  }
166
 
167
  remove_filter( 'wp_image_editors', 'ewww_image_optimizer_load_editor', 60 );
168
- $resizeResult = imsanity_image_resize( $oldPath, $newW, $newH, apply_filters( 'imsanity_crop_image', false ), null, null, $quality );
169
  if ( function_exists( 'ewww_image_optimizer_load_editor' ) ) {
170
  add_filter( 'wp_image_editors', 'ewww_image_optimizer_load_editor', 60 );
171
  }
172
 
173
- /* uncomment to debug error handling code: */
174
- // $resizeResult = new WP_Error('invalid_image', __(print_r($_REQUEST)), $oldPath);
175
-
176
- if ( $resizeResult && ! is_wp_error( $resizeResult ) ) {
177
- $newPath = $resizeResult;
178
 
179
- if ( is_file( $newPath ) && filesize( $newPath ) < filesize( $oldPath ) ) {
180
- // we saved some file space. remove original and replace with resized image
181
- unlink( $oldPath );
182
- rename( $newPath, $oldPath );
183
- } elseif ( is_file( $newPath ) ) {
184
  // theresized image is actually bigger in filesize (most likely due to jpg quality).
185
- // keep the old one and just get rid of the resized image
186
- unlink( $newPath );
187
  }
188
- } else if ( $resizeResult === false ) {
189
  return $params;
190
  } else {
191
- // resize didn't work, likely because the image processing libraries are missing
192
-
193
- // remove the old image so we don't leave orphan files hanging around
194
- unlink( $oldPath );
195
-
196
- $params = wp_handle_upload_error( $oldPath ,
197
- sprintf( esc_html__( "Imsanity was unable to resize this image for the following reason: %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: %s", 'imsanity' ), $resizeResult->get_error_message(), 'https://wordpress.org/support/plugin/imsanity' ) );
198
-
 
199
  }
200
  }
201
-
202
  }
203
  return $params;
204
  }
205
 
206
 
207
  /**
208
- * read in the image file from the params and then save as a new jpg file.
209
  * if successful, remove the original image and alter the return
210
  * parameters to return the new jpg instead of the original
211
  *
212
- * @param string 'bmp' or 'png'
213
- * @param array $params
214
  * @return array altered params
215
  */
216
- function imsanity_convert_to_jpg( $type, $params )
217
- {
218
 
219
  $img = null;
220
 
221
- if ( $type == 'bmp' ) {
222
  include_once( 'libs/imagecreatefrombmp.php' );
223
  $img = imagecreatefrombmp( $params['file'] );
224
- } elseif ( $type == 'png' ) {
225
- if( ! function_exists( 'imagecreatefrompng' ) ) {
226
  return wp_handle_upload_error( $params['file'], esc_html__( 'Imsanity requires the GD library to convert PNG images to JPG', 'imsanity' ) );
227
  }
228
 
229
  $input = imagecreatefrompng( $params['file'] );
230
- // convert png transparency to white
231
  $img = imagecreatetruecolor( imagesx( $input ), imagesy( $input ) );
232
  imagefill( $img, 0, 0, imagecolorallocate( $img, 255, 255, 255 ) );
233
- imagealphablending( $img, TRUE );
234
- imagecopy($img, $input, 0, 0, 0, 0, imagesx($input), imagesy($input));
235
- }
236
- else {
237
  return wp_handle_upload_error( $params['file'], esc_html__( 'Unknown image type specified in imsanity_convert_to_jpg', 'imsanity' ) );
238
  }
239
 
240
- // we need to change the extension from the original to .jpg so we have to ensure it will be a unique filename
241
- $uploads = wp_upload_dir();
242
- $oldFileName = basename($params['file']);
243
- $newFileName = basename(str_ireplace(".".$type, ".jpg", $oldFileName));
244
- $newFileName = wp_unique_filename( $uploads['path'], $newFileName );
245
 
246
- $quality = imsanity_get_option('imsanity_quality', IMSANITY_DEFAULT_QUALITY );
247
 
248
- if ( imagejpeg( $img, $uploads['path'] . '/' . $newFileName, $quality ) ) {
249
- // conversion succeeded. remove the original bmp & remap the params
250
- unlink($params['file']);
251
 
252
- $params['file'] = $uploads['path'] . '/' . $newFileName;
253
- $params['url'] = $uploads['url'] . '/' . $newFileName;
254
  $params['type'] = 'image/jpeg';
255
- }
256
- else
257
- {
258
- unlink($params['file']);
259
-
260
- return wp_handle_upload_error( $oldPath,
261
- 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 ) );
 
262
  }
263
 
264
  return $params;
@@ -267,4 +260,3 @@ function imsanity_convert_to_jpg( $type, $params )
267
  /* add filters to hook into uploads */
268
  add_filter( 'wp_handle_upload', 'imsanity_handle_upload' );
269
  add_action( 'plugins_loaded', 'imsanity_init' );
270
- ?>
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: Shane Bishop
 
 
16
  Text Domain: imsanity
17
+ Version: 2.4.0
18
+ Author URI: https://ewww.io/
19
  License: GPLv3
20
  */
21
 
22
+ if ( ! defined( 'ABSPATH' ) ) {
23
+ exit;
24
+ }
25
+
26
+ define( 'IMSANITY_VERSION', '2.4.0' );
27
  define( 'IMSANITY_SCHEMA_VERSION', '1.1' );
28
 
29
  define( 'IMSANITY_DEFAULT_MAX_WIDTH', 2048 );
40
  define( 'IMSANITY_AJAX_MAX_RECORDS', 250 );
41
  }
42
 
43
+ /**
44
+ * Load translations for Imsanity.
45
+ */
46
  function imsanity_init() {
 
 
 
47
  load_plugin_textdomain( 'imsanity', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
48
  }
49
 
60
  * @return IMSANITY_SOURCE_POST | IMSANITY_SOURCE_LIBRARY | IMSANITY_SOURCE_OTHER
61
  */
62
  function imsanity_get_source() {
63
+ $id = array_key_exists( 'post_id', $_REQUEST ) ? (int) $_REQUEST['post_id'] : '';
64
  $action = array_key_exists( 'action', $_REQUEST ) ? $_REQUEST['action'] : '';
65
 
66
  // A post_id indicates image is attached to a post.
68
  return IMSANITY_SOURCE_POST;
69
  }
70
 
71
+ // If the referrer is the post editor, that's a good indication the image is attached to a post.
72
+ if ( ! empty( $_SERVER['HTTP_REFERER'] ) && strpos( $_SERVER['HTTP_REFERER'], '/post.php' ) ) {
73
+ return IMSANITY_SOURCE_POST;
74
+ }
75
+
76
  // Post_id of 0 is 3.x otherwise use the action parameter.
77
+ if ( 0 === $id || 'upload-attachment' == $action ) {
78
  return IMSANITY_SOURCE_LIBRARY;
79
  }
80
 
83
  }
84
 
85
  /**
86
+ * Given the source, returns the max width/height.
87
  *
88
+ * @example: list( $w, $h ) = imsanity_get_max_width_height( IMSANITY_SOURCE_LIBRARY );
89
+ * @param int $source One of IMSANITY_SOURCE_POST | IMSANITY_SOURCE_LIBRARY | IMSANITY_SOURCE_OTHER.
90
  */
91
  function imsanity_get_max_width_height( $source ) {
92
+ $w = imsanity_get_option( 'imsanity_max_width', IMSANITY_DEFAULT_MAX_WIDTH );
93
+ $h = imsanity_get_option( 'imsanity_max_height', IMSANITY_DEFAULT_MAX_HEIGHT );
94
 
95
  switch ( $source ) {
96
  case IMSANITY_SOURCE_POST:
97
  break;
98
  case IMSANITY_SOURCE_LIBRARY:
99
+ $w = imsanity_get_option( 'imsanity_max_width_library', $w );
100
+ $h = imsanity_get_option( 'imsanity_max_height_library', $h );
101
  break;
102
  default:
103
+ $w = imsanity_get_option( 'imsanity_max_width_other', $w );
104
+ $h = imsanity_get_option( 'imsanity_max_height_other', $h );
105
  break;
106
  }
107
 
110
 
111
  /**
112
  * Handler after a file has been uploaded. If the file is an image, check the size
113
+ * to see if it is too big and, if so, resize and overwrite the original.
114
+ *
115
+ * @param Array $params The parameters submitted with the upload.
116
  */
117
  function imsanity_handle_upload( $params ) {
 
 
118
 
119
+ // If "noresize" is included in the filename then we will bypass imsanity scaling.
120
+ if ( strpos( $params['file'], 'noresize' ) !== false ) {
121
+ return $params;
122
+ }
123
 
124
+ // If preferences specify so then we can convert an original bmp or png file into jpg.
125
+ if ( 'image/bmp' == $params['type'] && imsanity_get_option( 'imsanity_bmp_to_jpg', IMSANITY_DEFAULT_BMP_TO_JPG ) ) {
126
  $params = imsanity_convert_to_jpg( 'bmp', $params );
127
  }
128
 
129
+ if ( 'image/png' == $params['type'] && imsanity_get_option( 'imsanity_png_to_jpg', IMSANITY_DEFAULT_PNG_TO_JPG ) ) {
130
  $params = imsanity_convert_to_jpg( 'png', $params );
131
  }
132
 
133
+ // Make sure this is a type of image that we want to convert and that it exists.
134
+ $oldpath = $params['file'];
 
135
 
136
+ if ( ( ! is_wp_error( $params ) ) && is_file( $oldpath ) && is_readable( $oldpath ) && is_writable( $oldpath ) && filesize( $oldpath ) > 0 && in_array( $params['type'], array( 'image/png', 'image/gif', 'image/jpeg' ) ) ) {
 
 
 
 
 
137
 
138
+ // figure out where the upload is coming from.
 
 
139
  $source = imsanity_get_source();
140
 
141
+ list( $maxw,$maxh ) = imsanity_get_max_width_height( $source );
 
 
142
 
143
+ list( $oldw, $oldh ) = getimagesize( $oldpath );
 
 
 
 
 
144
 
145
+ if ( ( $oldw > $maxw && $maxw > 0 ) || ( $oldh > $maxh && $maxh > 0 ) ) {
 
 
 
 
 
 
 
146
  $quality = imsanity_get_option( 'imsanity_quality', IMSANITY_DEFAULT_QUALITY );
147
 
148
+ $ftype = imsanity_quick_mimetype( $oldpath );
149
+ $orientation = imsanity_get_orientation( $oldpath, $ftype );
150
  // If we are going to rotate the image 90 degrees during the resize, swap the existing image dimensions.
151
  if ( 6 == $orientation || 8 == $orientation ) {
152
+ $old_oldw = $oldw;
153
+ $oldw = $oldh;
154
+ $oldh = $old_oldw;
155
  }
156
 
157
+ if ( $oldw > $maxw && $maxw > 0 && $oldh > $maxh && $maxh > 0 && apply_filters( 'imsanity_crop_image', false ) ) {
158
+ $neww = $maxw;
159
+ $newh = $maxh;
160
  } else {
161
+ list( $neww, $newh ) = wp_constrain_dimensions( $oldw, $oldh, $maxw, $maxh );
162
  }
163
 
164
  remove_filter( 'wp_image_editors', 'ewww_image_optimizer_load_editor', 60 );
165
+ $resizeresult = imsanity_image_resize( $oldpath, $neww, $newh, apply_filters( 'imsanity_crop_image', false ), null, null, $quality );
166
  if ( function_exists( 'ewww_image_optimizer_load_editor' ) ) {
167
  add_filter( 'wp_image_editors', 'ewww_image_optimizer_load_editor', 60 );
168
  }
169
 
170
+ if ( $resizeresult && ! is_wp_error( $resizeresult ) ) {
171
+ $newpath = $resizeresult;
 
 
 
172
 
173
+ if ( is_file( $newpath ) && filesize( $newpath ) < filesize( $oldpath ) ) {
174
+ // we saved some file space. remove original and replace with resized image.
175
+ unlink( $oldpath );
176
+ rename( $newpath, $oldpath );
177
+ } elseif ( is_file( $newpath ) ) {
178
  // theresized image is actually bigger in filesize (most likely due to jpg quality).
179
+ // keep the old one and just get rid of the resized image.
180
+ unlink( $newpath );
181
  }
182
+ } elseif ( false === $resizeresult ) {
183
  return $params;
184
  } else {
185
+ // resize didn't work, likely because the image processing libraries are missing.
186
+ // remove the old image so we don't leave orphan files hanging around.
187
+ unlink( $oldpath );
188
+
189
+ $params = wp_handle_upload_error(
190
+ $oldpath,
191
+ /* translators: 1: error message 2: link to support forums */
192
+ sprintf( 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: %$2s', 'imsanity' ), $resizeresult->get_error_message(), 'https://wordpress.org/support/plugin/imsanity' )
193
+ );
194
  }
195
  }
 
196
  }
197
  return $params;
198
  }
199
 
200
 
201
  /**
202
+ * Read in the image file from the params and then save as a new jpg file.
203
  * if successful, remove the original image and alter the return
204
  * parameters to return the new jpg instead of the original
205
  *
206
+ * @param string $type Type of the image to be converted: 'bmp' or 'png'.
207
+ * @param array $params The upload parameters.
208
  * @return array altered params
209
  */
210
+ function imsanity_convert_to_jpg( $type, $params ) {
 
211
 
212
  $img = null;
213
 
214
+ if ( 'bmp' == $type ) {
215
  include_once( 'libs/imagecreatefrombmp.php' );
216
  $img = imagecreatefrombmp( $params['file'] );
217
+ } elseif ( 'png' == $type ) {
218
+ if ( ! function_exists( 'imagecreatefrompng' ) ) {
219
  return wp_handle_upload_error( $params['file'], esc_html__( 'Imsanity requires the GD library to convert PNG images to JPG', 'imsanity' ) );
220
  }
221
 
222
  $input = imagecreatefrompng( $params['file'] );
223
+ // convert png transparency to white.
224
  $img = imagecreatetruecolor( imagesx( $input ), imagesy( $input ) );
225
  imagefill( $img, 0, 0, imagecolorallocate( $img, 255, 255, 255 ) );
226
+ imagealphablending( $img, true );
227
+ imagecopy( $img, $input, 0, 0, 0, 0, imagesx( $input ), imagesy( $input ) );
228
+ } else {
 
229
  return wp_handle_upload_error( $params['file'], esc_html__( 'Unknown image type specified in imsanity_convert_to_jpg', 'imsanity' ) );
230
  }
231
 
232
+ // We need to change the extension from the original to .jpg so we have to ensure it will be a unique filename.
233
+ $uploads = wp_upload_dir();
234
+ $oldfilename = basename( $params['file'] );
235
+ $newfilename = basename( str_ireplace( '.' . $type, '.jpg', $oldfilename ) );
236
+ $newfilename = wp_unique_filename( $uploads['path'], $newfilename );
237
 
238
+ $quality = imsanity_get_option( 'imsanity_quality', IMSANITY_DEFAULT_QUALITY );
239
 
240
+ if ( imagejpeg( $img, $uploads['path'] . '/' . $newfilename, $quality ) ) {
241
+ // Conversion succeeded: remove the original bmp & remap the params.
242
+ unlink( $params['file'] );
243
 
244
+ $params['file'] = $uploads['path'] . '/' . $newfilename;
245
+ $params['url'] = $uploads['url'] . '/' . $newfilename;
246
  $params['type'] = 'image/jpeg';
247
+ } else {
248
+ unlink( $params['file'] );
249
+
250
+ return wp_handle_upload_error(
251
+ $oldfilename,
252
+ /* translators: %s: the image mime type */
253
+ 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 )
254
+ );
255
  }
256
 
257
  return $params;
260
  /* add filters to hook into uploads */
261
  add_filter( 'wp_handle_upload', 'imsanity_handle_upload' );
262
  add_action( 'plugins_loaded', 'imsanity_init' );
 
libs/imagecreatefrombmp.php CHANGED
@@ -1,144 +1,315 @@
1
  <?php
2
-
3
  /**
4
- * imagecreatefrombmp converts a bmp to an image resource
5
  *
6
  * @author http://www.programmierer-forum.de/function-imagecreatefrombmp-laeuft-mit-allen-bitraten-t143137.htm
 
7
  */
8
 
9
- if (!function_exists('imagecreatefrombmp')) {
10
 
11
- function imagecreatefrombmp($filename) {
12
- // version 1.00
13
- if (!($fh = fopen($filename, 'rb'))) {
14
- trigger_error( sprintf( __( 'imagecreatefrombmp: Can not open %s!','imsanity') , $filename ), E_USER_WARNING );
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  return false;
16
  }
17
- // read file header
18
- $meta = unpack('vtype/Vfilesize/Vreserved/Voffset', fread( $fh, 14 ) );
19
- // check for bitmap
20
- if ($meta['type'] != 19778) {
 
21
  trigger_error( sprintf( __( 'imagecreatefrombmp: %s is not a bitmap!', 'imsanity' ), $filename ), E_USER_WARNING );
22
  return false;
23
  }
24
- // read image header
25
- $meta += unpack('Vheadersize/Vwidth/Vheight/vplanes/vbits/Vcompression/Vimagesize/Vxres/Vyres/Vcolors/Vimportant', fread($fh, 40));
26
- // read additional 16bit header
27
- if ($meta['bits'] == 16) {
28
- $meta += unpack('VrMask/VgMask/VbMask', fread($fh, 12));
 
 
 
29
  }
30
- // set bytes and padding
 
31
  $meta['bytes'] = $meta['bits'] / 8;
32
- $meta['decal'] = 4 - (4 * (($meta['width'] * $meta['bytes'] / 4)- floor($meta['width'] * $meta['bytes'] / 4)));
33
- if ($meta['decal'] == 4) {
34
  $meta['decal'] = 0;
35
  }
36
- // obtain imagesize
37
- if ($meta['imagesize'] < 1) {
 
38
  $meta['imagesize'] = $meta['filesize'] - $meta['offset'];
39
- // in rare cases filesize is equal to offset so we need to read physical size
40
- if ($meta['imagesize'] < 1) {
41
- $meta['imagesize'] = @filesize($filename) - $meta['offset'];
42
- if ($meta['imagesize'] < 1) {
 
43
  trigger_error( sprintf( __( 'imagecreatefrombmp: Cannot obtain filesize of %s !', 'imsanity' ), $filename ), E_USER_WARNING );
44
  return false;
45
  }
46
  }
47
  }
48
- // calculate colors
49
- $meta['colors'] = !$meta['colors'] ? pow(2, $meta['bits']) : $meta['colors'];
50
- // read color palette
 
 
51
  $palette = array();
52
- if ($meta['bits'] < 16) {
53
- $palette = unpack('l' . $meta['colors'], fread($fh, $meta['colors'] * 4));
54
- // in rare cases the color value is signed
55
- if ($palette[1] < 0) {
56
- foreach ($palette as $i => $color) {
57
- $palette[$i] = $color + 16777216;
58
  }
59
  }
60
  }
61
- // create gd image
62
- $im = imagecreatetruecolor($meta['width'], $meta['height']);
63
- $data = fread($fh, $meta['imagesize']);
64
- $p = 0;
65
- $vide = chr(0);
66
- $y = $meta['height'] - 1;
67
- $error = 'imagecreatefrombmp: ' . $filename . ' has not enough data!';
68
- // loop through the image data beginning with the lower left corner
69
- while ($y >= 0) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  $x = 0;
71
- while ($x < $meta['width']) {
72
- switch ($meta['bits']) {
73
  case 32:
74
  case 24:
75
- if (!($part = substr($data, $p, 3))) {
76
- trigger_error($error, E_USER_WARNING);
 
77
  return $im;
78
  }
79
- $color = unpack('V', $part . $vide);
80
  break;
81
  case 16:
82
- if (!($part = substr($data, $p, 2))) {
83
- trigger_error($error, E_USER_WARNING);
 
84
  return $im;
85
  }
86
- $color = unpack('v', $part);
87
- $color[1] = (($color[1] & 0xf800) >> 8) * 65536 + (($color[1] & 0x07e0) >> 3) * 256 + (($color[1] & 0x001f) << 3);
 
 
 
 
88
  break;
89
  case 8:
90
- $color = unpack('n', $vide . substr($data, $p, 1));
91
  $color[1] = $palette[ $color[1] + 1 ];
92
  break;
93
  case 4:
94
- $color = unpack('n', $vide . substr($data, floor($p), 1));
95
- $color[1] = ($p * 2) % 2 == 0 ? $color[1] >> 4 : $color[1] & 0x0F;
96
  $color[1] = $palette[ $color[1] + 1 ];
97
  break;
98
  case 1:
99
- $color = unpack('n', $vide . substr($data, floor($p), 1));
100
- switch (($p * 8) % 8) {
101
  case 0:
102
  $color[1] = $color[1] >> 7;
103
  break;
104
  case 1:
105
- $color[1] = ($color[1] & 0x40) >> 6;
106
  break;
107
  case 2:
108
- $color[1] = ($color[1] & 0x20) >> 5;
109
  break;
110
  case 3:
111
- $color[1] = ($color[1] & 0x10) >> 4;
112
  break;
113
  case 4:
114
- $color[1] = ($color[1] & 0x8) >> 3;
115
  break;
116
  case 5:
117
- $color[1] = ($color[1] & 0x4) >> 2;
118
  break;
119
  case 6:
120
- $color[1] = ($color[1] & 0x2) >> 1;
121
  break;
122
  case 7:
123
- $color[1] = ($color[1] & 0x1);
124
  break;
125
  }
126
  $color[1] = $palette[ $color[1] + 1 ];
127
  break;
128
  default:
129
- trigger_error( sprintf( __( 'imagecreatefrombmp: %s has %d bits and this is not supported!', 'imsanity' ), $filename, $meta['bits'] ), E_USER_WARNING );
 
130
  return false;
131
  }
132
- imagesetpixel($im, $x, $y, $color[1]);
133
  $x++;
134
  $p += $meta['bytes'];
135
  }
136
  $y--;
137
  $p += $meta['decal'];
138
  }
139
- fclose($fh);
140
  return $im;
141
  }
142
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
 
144
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
 
2
  /**
3
+ * The imagecreatefrombmp function converts a bmp to an image resource
4
  *
5
  * @author http://www.programmierer-forum.de/function-imagecreatefrombmp-laeuft-mit-allen-bitraten-t143137.htm
6
+ * @package Imsanity
7
  */
8
 
9
+ if ( ! function_exists( 'imagecreatefrombmp' ) ) {
10
 
11
+ /**
12
+ * Converts a bitmap (BMP) image into an image resource.
13
+ *
14
+ * @param string $filename The name of the image file.
15
+ * @return bool|object False, or a GD image resource.
16
+ */
17
+ function imagecreatefrombmp( $filename ) {
18
+ // version 1.1.
19
+ if ( ! is_readable( $filename ) ) {
20
+ /* translators: %s: the image filename */
21
+ trigger_error( sprintf( __( 'imagecreatefrombmp: Can not open %s!', 'imsanity' ), $filename ), E_USER_WARNING );
22
+ return false;
23
+ }
24
+ $fh = fopen( $filename, 'rb' );
25
+ if ( ! $fh ) {
26
+ /* translators: %s: the image filename */
27
+ trigger_error( sprintf( __( 'imagecreatefrombmp: Can not open %s!', 'imsanity' ), $filename ), E_USER_WARNING );
28
  return false;
29
  }
30
+ // read file header.
31
+ $meta = unpack( 'vtype/Vfilesize/Vreserved/Voffset', fread( $fh, 14 ) );
32
+ // check for bitmap.
33
+ if ( 19778 != $meta['type'] ) {
34
+ /* translators: %s: the image filename */
35
  trigger_error( sprintf( __( 'imagecreatefrombmp: %s is not a bitmap!', 'imsanity' ), $filename ), E_USER_WARNING );
36
  return false;
37
  }
38
+ // read image header.
39
+ $meta += unpack( 'Vheadersize/Vwidth/Vheight/vplanes/vbits/Vcompression/Vimagesize/Vxres/Vyres/Vcolors/Vimportant', fread( $fh, 40 ) );
40
+ $bytes_read = 40;
41
+
42
+ // read additional bitfield header.
43
+ if ( 3 == $meta['compression'] ) {
44
+ $meta += unpack( 'VrMask/VgMask/VbMask', fread( $fh, 12 ) );
45
+ $bytes_read += 12;
46
  }
47
+
48
+ // set bytes and padding.
49
  $meta['bytes'] = $meta['bits'] / 8;
50
+ $meta['decal'] = 4 - ( 4 * ( ( $meta['width'] * $meta['bytes'] / 4 ) - floor( $meta['width'] * $meta['bytes'] / 4 ) ) );
51
+ if ( 4 == $meta['decal'] ) {
52
  $meta['decal'] = 0;
53
  }
54
+
55
+ // obtain imagesize.
56
+ if ( $meta['imagesize'] < 1 ) {
57
  $meta['imagesize'] = $meta['filesize'] - $meta['offset'];
58
+ // in rare cases filesize is equal to offset so we need to read physical size.
59
+ if ( $meta['imagesize'] < 1 ) {
60
+ $meta['imagesize'] = filesize( $filename ) - $meta['offset'];
61
+ if ( $meta['imagesize'] < 1 ) {
62
+ /* translators: %s: the image filename */
63
  trigger_error( sprintf( __( 'imagecreatefrombmp: Cannot obtain filesize of %s !', 'imsanity' ), $filename ), E_USER_WARNING );
64
  return false;
65
  }
66
  }
67
  }
68
+
69
+ // calculate colors.
70
+ $meta['colors'] = ! $meta['colors'] ? pow( 2, $meta['bits'] ) : $meta['colors'];
71
+
72
+ // read color palette.
73
  $palette = array();
74
+ if ( $meta['bits'] < 16 ) {
75
+ $palette = unpack( 'l' . $meta['colors'], fread( $fh, $meta['colors'] * 4 ) );
76
+ // in rare cases the color value is signed.
77
+ if ( $palette[1] < 0 ) {
78
+ foreach ( $palette as $i => $color ) {
79
+ $palette[ $i ] = $color + 16777216;
80
  }
81
  }
82
  }
83
+
84
+ // ignore extra bitmap headers.
85
+ if ( $meta['headersize'] > $bytes_read ) {
86
+ fread( $fh, $meta['headersize'] - $bytes_read );
87
+ }
88
+
89
+ // create gd image.
90
+ $im = imagecreatetruecolor( $meta['width'], $meta['height'] );
91
+ $data = fread( $fh, $meta['imagesize'] );
92
+
93
+ // uncompress data.
94
+ switch ( $meta['compression'] ) {
95
+ case 1:
96
+ $data = rle8_decode( $data, $meta['width'] );
97
+ break;
98
+ case 2:
99
+ $data = rle4_decode( $data, $meta['width'] );
100
+ break;
101
+ }
102
+
103
+ $p = 0;
104
+ $vide = chr( 0 );
105
+ $y = $meta['height'] - 1;
106
+ /* translators: %s: the image filename */
107
+ $error = sprintf( __( 'imagecreatefrombmp: %s has not enough data!', 'imsanity' ), $filename );
108
+ // loop through the image data beginning with the lower left corner.
109
+ while ( $y >= 0 ) {
110
  $x = 0;
111
+ while ( $x < $meta['width'] ) {
112
+ switch ( $meta['bits'] ) {
113
  case 32:
114
  case 24:
115
+ $part = substr( $data, $p, 3 );
116
+ if ( ! $part ) {
117
+ trigger_error( $error, E_USER_WARNING );
118
  return $im;
119
  }
120
+ $color = unpack( 'V', $part . $vide );
121
  break;
122
  case 16:
123
+ $part = substr( $data, $p, 2 );
124
+ if ( ! $part ) {
125
+ trigger_error( $error, E_USER_WARNING );
126
  return $im;
127
  }
128
+ $color = unpack( 'v', $part );
129
+ if ( empty( $meta['rMask'] ) || 0xf800 != $meta['rMask'] ) {
130
+ $color[1] = ( ( $color[1] & 0x7c00 ) >> 7 ) * 65536 + ( ( $color[1] & 0x03e0 ) >> 2 ) * 256 + ( ( $color[1] & 0x001f ) << 3 ); // 555.
131
+ } else {
132
+ $color[1] = ( ( $color[1] & 0xf800 ) >> 8 ) * 65536 + ( ( $color[1] & 0x07e0 ) >> 3 ) * 256 + ( ( $color[1] & 0x001f ) << 3 ); // 565.
133
+ }
134
  break;
135
  case 8:
136
+ $color = unpack( 'n', $vide . substr( $data, $p, 1 ) );
137
  $color[1] = $palette[ $color[1] + 1 ];
138
  break;
139
  case 4:
140
+ $color = unpack( 'n', $vide . substr( $data, floor( $p ), 1 ) );
141
+ $color[1] = 0 == ( $p * 2 ) % 2 ? $color[1] >> 4 : $color[1] & 0x0F;
142
  $color[1] = $palette[ $color[1] + 1 ];
143
  break;
144
  case 1:
145
+ $color = unpack( 'n', $vide . substr( $data, floor( $p ), 1 ) );
146
+ switch ( ( $p * 8 ) % 8 ) {
147
  case 0:
148
  $color[1] = $color[1] >> 7;
149
  break;
150
  case 1:
151
+ $color[1] = ( $color[1] & 0x40 ) >> 6;
152
  break;
153
  case 2:
154
+ $color[1] = ( $color[1] & 0x20 ) >> 5;
155
  break;
156
  case 3:
157
+ $color[1] = ( $color[1] & 0x10 ) >> 4;
158
  break;
159
  case 4:
160
+ $color[1] = ( $color[1] & 0x8 ) >> 3;
161
  break;
162
  case 5:
163
+ $color[1] = ( $color[1] & 0x4 ) >> 2;
164
  break;
165
  case 6:
166
+ $color[1] = ( $color[1] & 0x2 ) >> 1;
167
  break;
168
  case 7:
169
+ $color[1] = ( $color[1] & 0x1 );
170
  break;
171
  }
172
  $color[1] = $palette[ $color[1] + 1 ];
173
  break;
174
  default:
175
+ /* translators: 1: the image filename 2: bitrate of image */
176
+ trigger_error( sprintf( __( 'imagecreatefrombmp: %1$s has %2$d bits and this is not supported!', 'imsanity' ), $filename, $meta['bits'] ), E_USER_WARNING );
177
  return false;
178
  }
179
+ imagesetpixel( $im, $x, $y, $color[1] );
180
  $x++;
181
  $p += $meta['bytes'];
182
  }
183
  $y--;
184
  $p += $meta['decal'];
185
  }
186
+ fclose( $fh );
187
  return $im;
188
  }
189
+ /**
190
+ * The original source for these functions no longer exists, but it appears to come from
191
+ * MSDN and has proliferated across many projects with only the stale link which now
192
+ * points to https://docs.microsoft.com/en-us/windows/desktop/gdi/bitmap-compression.
193
+ */
194
+ /**
195
+ * Decoder for RLE8 compression in windows bitmaps.
196
+ *
197
+ * @param string $str Data to decode.
198
+ * @param integer $width Image width.
199
+ *
200
+ * @return string
201
+ */
202
+ function rle8_decode( $str, $width ) {
203
+ $linewidth = $width + ( 3 - ( $width - 1 ) % 4 );
204
+ $out = '';
205
+ $cnt = strlen( $str );
206
 
207
+ for ( $i = 0; $i < $cnt; $i++ ) {
208
+ $o = ord( $str[ $i ] );
209
+ switch ( $o ) {
210
+ case 0: // ESCAPE.
211
+ $i++;
212
+ switch ( ord( $str[ $i ] ) ) {
213
+ case 0: // NEW LINE.
214
+ $padcnt = $linewidth - strlen( $out ) % $linewidth;
215
+ if ( $padcnt < $linewidth ) {
216
+ $out .= str_repeat( chr( 0 ), $padcnt ); // pad line.
217
+ }
218
+ break;
219
+ case 1: // END OF FILE.
220
+ $padcnt = $linewidth - strlen( $out ) % $linewidth;
221
+ if ( $padcnt < $linewidth ) {
222
+ $out .= str_repeat( chr( 0 ), $padcnt ); // pad line.
223
+ }
224
+ break 3;
225
+ case 2: // DELTA.
226
+ $i += 2;
227
+ break;
228
+ default: // ABSOLUTE MODE.
229
+ $num = ord( $str[ $i ] );
230
+ for ( $j = 0; $j < $num; $j++ ) {
231
+ $out .= $str[ ++$i ];
232
+ }
233
+ if ( $num % 2 ) {
234
+ $i++;
235
+ }
236
+ }
237
+ break;
238
+ default:
239
+ $out .= str_repeat( $str[ ++$i ], $o );
240
+ }
241
+ }
242
+ return $out;
243
+ }
244
+
245
+ /**
246
+ * Decoder for RLE4 compression in windows bitmaps.
247
+ *
248
+ * @param string $str Data to decode.
249
+ * @param integer $width Image width.
250
+ * @return string
251
+ */
252
+ function rle4_decode( $str, $width ) {
253
+ $w = floor( $width / 2 ) + ( $width % 2 );
254
+ $linewidth = $w + ( 3 - ( ( $width - 1 ) / 2 ) % 4 );
255
+ $pixels = array();
256
+ $cnt = strlen( $str );
257
+ $c = 0;
258
+
259
+ for ( $i = 0; $i < $cnt; $i++ ) {
260
+ $o = ord( $str[ $i ] );
261
+ switch ( $o ) {
262
+ case 0: // ESCAPE.
263
+ $i++;
264
+ switch ( ord( $str[ $i ] ) ) {
265
+ case 0: // NEW LINE.
266
+ while ( 0 != count( $pixels ) % $linewidth ) {
267
+ $pixels[] = 0;
268
+ }
269
+ break;
270
+ case 1: // END OF FILE.
271
+ while ( 0 != count( $pixels ) % $linewidth ) {
272
+ $pixels[] = 0;
273
+ }
274
+ break 3;
275
+ case 2: // DELTA.
276
+ $i += 2;
277
+ break;
278
+ default: // ABSOLUTE MODE.
279
+ $num = ord( $str[ $i ] );
280
+ for ( $j = 0; $j < $num; $j++ ) {
281
+ if ( 0 == $j % 2 ) {
282
+ $c = ord( $str[ ++$i ] );
283
+ $pixels[] = ( $c & 240 ) >> 4;
284
+ } else {
285
+ $pixels[] = $c & 15;
286
+ }
287
+ }
288
+
289
+ if ( 0 == $num % 2 ) {
290
+ $i++;
291
+ }
292
+ }
293
+ break;
294
+ default:
295
+ $c = ord( $str[ ++$i ] );
296
+ for ( $j = 0; $j < $o; $j++ ) {
297
+ $pixels[] = ( 0 == $j % 2 ? ( $c & 240 ) >> 4 : $c & 15 );
298
+ }
299
+ }
300
+ }
301
+
302
+ $out = '';
303
+ if ( count( $pixels ) % 2 ) {
304
+ $pixels[] = 0;
305
+ }
306
+
307
+ $cnt = count( $pixels ) / 2;
308
+
309
+ for ( $i = 0; $i < $cnt; $i++ ) {
310
+ $out .= chr( 16 * $pixels[ 2 * $i ] + $pixels[ 2 * $i + 1 ] );
311
+ }
312
+
313
+ return $out;
314
+ }
315
+ }
libs/utils.php CHANGED
@@ -1,19 +1,64 @@
1
- <?php
2
- /**
3
- * ################################################################################
4
- * UTILITIES
5
- * ################################################################################
6
  */
7
 
8
  /**
9
  * Util function returns an array value, if not defined then returns default instead.
10
  *
11
- * @param Array $array
12
- * @param string $key
13
- * @param variant $default
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  */
15
- function imsanity_val( $arr, $key, $default='' ) {
16
- return isset( $arr[$key] ) ? $arr[ $key ] : $default;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  }
18
 
19
  /**
@@ -58,82 +103,79 @@ function imsanity_get_orientation( $file, $type ) {
58
  }
59
 
60
  /**
61
- * output a fatal error and optionally die
62
- *
63
- * @param string $message
64
- * @param string $title
65
- * @param bool $die
66
  */
67
- function imsanity_fatal( $message, $title = "", $die = false ) {
68
  echo ( "<div style='margin:5px 0px 5px 0px;padding:10px;border: solid 1px red; background-color: #ff6666; color: black;'>"
69
- . ( $title ? "<h4 style='font-weight: bold; margin: 3px 0px 8px 0px;'>" . $title . "</h4>" : "" )
70
  . $message
71
- . "</div>" );
72
-
73
- if ( $die ) die();
 
74
  }
75
 
76
  /**
77
  * Replacement for deprecated image_resize function
 
78
  * @param string $file Image file path.
79
- * @param int $max_w Maximum width to resize to.
80
- * @param int $max_h Maximum height to resize to.
81
- * @param bool $crop Optional. Whether to crop image or resize.
82
  * @param string $suffix Optional. File suffix.
83
  * @param string $dest_path Optional. New image file path.
84
- * @param int $jpeg_quality Optional, default is 90. Image quality percentage.
85
  * @return mixed WP_Error on failure. String with new destination path.
86
  */
87
  function imsanity_image_resize( $file, $max_w, $max_h, $crop = false, $suffix = null, $dest_path = null, $jpeg_quality = 82 ) {
88
  if ( function_exists( 'wp_get_image_editor' ) ) {
89
- // WP 3.5 and up use the image editor
90
-
91
  $editor = wp_get_image_editor( $file );
92
- if ( is_wp_error( $editor ) )
93
  return $editor;
 
94
  $editor->set_quality( $jpeg_quality );
95
-
96
  $ftype = imsanity_quick_mimetype( $file );
97
 
98
  $orientation = imsanity_get_orientation( $file, $ftype );
99
- // try to correct for auto-rotation if the info is available
100
- // if ( function_exists( 'exif_read_data' ) && ( $ftype == 'image/jpeg' ) ) {
101
- // $exif = @exif_read_data( $file );
102
- // $orientation = is_array( $exif ) && array_key_exists( 'Orientation', $exif ) ? $exif['Orientation'] : 0;
103
- switch ( $orientation ) {
104
- case 3:
105
- $editor->rotate( 180 );
106
- break;
107
- case 6:
108
- $editor->rotate( -90 );
109
- break;
110
- case 8:
111
- $editor->rotate( 90 );
112
- break;
113
- }
114
- // }
115
-
116
  $resized = $editor->resize( $max_w, $max_h, $crop );
117
- if ( is_wp_error( $resized ) )
118
  return $resized;
 
119
 
120
  $dest_file = $editor->generate_filename( $suffix, $dest_path );
121
-
122
  // FIX: make sure that the destination file does not exist. this fixes
123
- // an issue during bulk resize where one of the optimized media filenames may get
124
  // used as the temporary file, which causes it to be deleted.
125
  while ( file_exists( $dest_file ) ) {
126
  $dest_file = $editor->generate_filename( 'TMP', $dest_path );
127
  }
128
-
129
  $saved = $editor->save( $dest_file );
130
-
131
- if ( is_wp_error( $saved ) )
132
  return $saved;
133
-
 
134
  return $dest_file;
135
  }
136
  return false;
137
  }
138
-
139
- ?>
1
+ <?php
2
+ /**
3
+ * Imsanity utility functions.
4
+ *
5
+ * @package Imsanity
6
  */
7
 
8
  /**
9
  * Util function returns an array value, if not defined then returns default instead.
10
  *
11
+ * @param array $arr Any array.
12
+ * @param string $key Any index from that array.
13
+ * @param mixed $default Whatever you want.
14
+ */
15
+ function imsanity_val( $arr, $key, $default = '' ) {
16
+ return isset( $arr[ $key ] ) ? $arr[ $key ] : $default;
17
+ }
18
+
19
+ /**
20
+ * Retrieves the path of an attachment via the $id and the $meta.
21
+ *
22
+ * @param array $meta The attachment metadata.
23
+ * @param int $id The attachment ID number.
24
+ * @param string $file Optional. Path relative to the uploads folder. Default ''.
25
+ * @param bool $refresh_cache Optional. True to flush cache prior to fetching path. Default true.
26
+ * @return string The full path to the image.
27
  */
28
+ function imsanity_attachment_path( $meta, $id, $file = '', $refresh_cache = true ) {
29
+ // Retrieve the location of the WordPress upload folder.
30
+ $upload_dir = wp_upload_dir( null, false, $refresh_cache );
31
+ $upload_path = trailingslashit( $upload_dir['basedir'] );
32
+ if ( is_array( $meta ) && ! empty( $meta['file'] ) ) {
33
+ $file_path = $meta['file'];
34
+ if ( strpos( $file_path, 's3' ) === 0 ) {
35
+ return '';
36
+ }
37
+ if ( is_file( $file_path ) ) {
38
+ return $file_path;
39
+ }
40
+ $file_path = $upload_path . $file_path;
41
+ if ( is_file( $file_path ) ) {
42
+ return $file_path;
43
+ }
44
+ $upload_path = trailingslashit( WP_CONTENT_DIR ) . 'uploads/';
45
+ $file_path = $upload_path . $meta['file'];
46
+ if ( is_file( $file_path ) ) {
47
+ return $file_path;
48
+ }
49
+ }
50
+ if ( ! $file ) {
51
+ $file = get_post_meta( $id, '_wp_attached_file', true );
52
+ }
53
+ $file_path = ( 0 !== strpos( $file, '/' ) && ! preg_match( '|^.:\\\|', $file ) ? $upload_path . $file : $file );
54
+ $filtered_file_path = apply_filters( 'get_attached_file', $file_path, $id );
55
+ if ( strpos( $filtered_file_path, 's3' ) === false && is_file( $filtered_file_path ) ) {
56
+ return str_replace( '//_imsgalleries/', '/_imsgalleries/', $filtered_file_path );
57
+ }
58
+ if ( strpos( $file_path, 's3' ) === false && is_file( $file_path ) ) {
59
+ return str_replace( '//_imsgalleries/', '/_imsgalleries/', $file_path );
60
+ }
61
+ return '';
62
  }
63
 
64
  /**
103
  }
104
 
105
  /**
106
+ * Output a fatal error and optionally die.
107
+ *
108
+ * @param string $message The message to output.
109
+ * @param string $title A title/header for the message.
110
+ * @param bool $die Default false. Whether we should die.
111
  */
112
+ function imsanity_fatal( $message, $title = '', $die = false ) {
113
  echo ( "<div style='margin:5px 0px 5px 0px;padding:10px;border: solid 1px red; background-color: #ff6666; color: black;'>"
114
+ . ( $title ? "<h4 style='font-weight: bold; margin: 3px 0px 8px 0px;'>" . $title . '</h4>' : '' )
115
  . $message
116
+ . '</div>' );
117
+ if ( $die ) {
118
+ die();
119
+ }
120
  }
121
 
122
  /**
123
  * Replacement for deprecated image_resize function
124
+ *
125
  * @param string $file Image file path.
126
+ * @param int $max_w Maximum width to resize to.
127
+ * @param int $max_h Maximum height to resize to.
128
+ * @param bool $crop Optional. Whether to crop image or resize.
129
  * @param string $suffix Optional. File suffix.
130
  * @param string $dest_path Optional. New image file path.
131
+ * @param int $jpeg_quality Optional, default is 90. Image quality percentage.
132
  * @return mixed WP_Error on failure. String with new destination path.
133
  */
134
  function imsanity_image_resize( $file, $max_w, $max_h, $crop = false, $suffix = null, $dest_path = null, $jpeg_quality = 82 ) {
135
  if ( function_exists( 'wp_get_image_editor' ) ) {
 
 
136
  $editor = wp_get_image_editor( $file );
137
+ if ( is_wp_error( $editor ) ) {
138
  return $editor;
139
+ }
140
  $editor->set_quality( $jpeg_quality );
141
+
142
  $ftype = imsanity_quick_mimetype( $file );
143
 
144
  $orientation = imsanity_get_orientation( $file, $ftype );
145
+ // Try to correct for auto-rotation if the info is available.
146
+ switch ( $orientation ) {
147
+ case 3:
148
+ $editor->rotate( 180 );
149
+ break;
150
+ case 6:
151
+ $editor->rotate( -90 );
152
+ break;
153
+ case 8:
154
+ $editor->rotate( 90 );
155
+ break;
156
+ }
157
+
 
 
 
 
158
  $resized = $editor->resize( $max_w, $max_h, $crop );
159
+ if ( is_wp_error( $resized ) ) {
160
  return $resized;
161
+ }
162
 
163
  $dest_file = $editor->generate_filename( $suffix, $dest_path );
164
+
165
  // FIX: make sure that the destination file does not exist. this fixes
166
+ // an issue during bulk resize where one of the optimized media filenames may get
167
  // used as the temporary file, which causes it to be deleted.
168
  while ( file_exists( $dest_file ) ) {
169
  $dest_file = $editor->generate_filename( 'TMP', $dest_path );
170
  }
171
+
172
  $saved = $editor->save( $dest_file );
173
+
174
+ if ( is_wp_error( $saved ) ) {
175
  return $saved;
176
+ }
177
+
178
  return $dest_file;
179
  }
180
  return false;
181
  }
 
 
readme.txt CHANGED
@@ -4,7 +4,7 @@ Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_i
4
  Tags: image, scale, resize, space saver, quality
5
  Requires at least: 4.0
6
  Tested up to: 4.9.4
7
- Stable tag: 2.3.10
8
 
9
  Imsanity automatically resizes huge image uploads. Are contributors uploading huge photos? Tired of manually scaling? Imsanity to the rescue!
10
 
@@ -40,7 +40,7 @@ Imsanity is available in several languages, each of which will be downloaded aut
40
 
41
  Automatic Installation:
42
 
43
- 1. Go to Admin - Plugins - Add New and search for "imsanity"
44
  2. Click the Install Button
45
  3. Click 'Activate'
46
 
@@ -70,8 +70,7 @@ the Imsanity settings page. The "Bulk Image Resize" feature allows you to selec
70
  = 2. Why aren't all of my images detected when I try to use the bulk resize feature? =
71
 
72
  Imsanity doesn't search your file system to find large files, instead it looks at the "metadata"
73
- in the WordPress media library database. When you upload files, WordPress stores all of the information
74
- about the image.
75
 
76
  = 3. Why am I getting an error saying that my "File is not an image" ? =
77
 
@@ -125,26 +124,14 @@ a size or value that is reasonable.
125
 
126
  = 9. Where do I go for support? =
127
 
128
- Questions may be posted on the support forum at https://wordpress.org/support/plugin/imsanity although I may move support to the helpscout platform we use for EWWW I.O.
129
-
130
- = TODO =
131
-
132
- * Add a network settings to override the individual plugin settings text
133
-
134
- == Upgrade Notice ==
135
-
136
- = 2.3.8 =
137
- * network settings page only available when plugin is network-activated, please let me know if that sounds crazy to you: https://ewww.io/contact-us/
138
-
139
- = 2.3.6 =
140
- * tested up to WP 4.4
141
- * if resized image is not smaller than original, then keep original
142
- * allow IMSANITY_AJAX_MAX_RECORDS to be overridden in wp-config.php
143
- * if png-to-jpg is enabled, replace png transparency with white
144
 
145
  == Changelog ==
146
 
147
- = 2.3.10 =
 
 
 
148
  * fixed: undefined notice for query during ajax operation
149
  * fixed: stale metadata could prevent further resizing
150
 
4
  Tags: image, scale, resize, space saver, quality
5
  Requires at least: 4.0
6
  Tested up to: 4.9.4
7
+ Stable tag: 2.4.0
8
 
9
  Imsanity automatically resizes huge image uploads. Are contributors uploading huge photos? Tired of manually scaling? Imsanity to the rescue!
10
 
40
 
41
  Automatic Installation:
42
 
43
+ 1. Go to Admin -> Plugins -> Add New and search for "imsanity"
44
  2. Click the Install Button
45
  3. Click 'Activate'
46
 
70
  = 2. Why aren't all of my images detected when I try to use the bulk resize feature? =
71
 
72
  Imsanity doesn't search your file system to find large files, instead it looks at the "metadata"
73
+ in the WordPress media library database. To override this behavior, enable deep scanning.
 
74
 
75
  = 3. Why am I getting an error saying that my "File is not an image" ? =
76
 
124
 
125
  = 9. Where do I go for support? =
126
 
127
+ Questions may be posted on the support forum at https://wordpress.org/support/plugin/imsanity but if you don't get an answer, please use https://ewww.io/contact-us/.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
 
129
  == Changelog ==
130
 
131
+ = 2.4.0 =
132
+ * added: deep scanning option for when attachment metadata isn't updating properly
133
+ * fixed: uploads from Gutenberg not detected properly
134
+ * fixed: some other plugin(s) trying to muck with the Imsanity settings links and breaking things
135
  * fixed: undefined notice for query during ajax operation
136
  * fixed: stale metadata could prevent further resizing
137
 
scripts/imsanity.js CHANGED
@@ -12,7 +12,7 @@ function imsanity_resize_images()
12
  images.push(this.value);
13
  });
14
 
15
- var target = jQuery('#resize_results');
16
  target.html('');
17
  //jQuery(document).scrollTop(target.offset().top);
18
 
@@ -20,22 +20,22 @@ function imsanity_resize_images()
20
  imsanity_resize_next(images,0);
21
  }
22
 
23
- /**
24
  * recursive function for resizing images
25
  */
26
  function imsanity_resize_next(images,next_index)
27
  {
28
  if (next_index >= images.length) return imsanity_resize_complete();
29
-
30
  jQuery.post(
31
  ajaxurl, // (defined by wordpress - points to admin-ajax.php)
32
- {_wpnonce: imsanity_vars._wpnonce, action: 'imsanity_resize_image', id: images[next_index]},
33
- function(response)
34
  {
35
  var result;
36
- var target = jQuery('#resize_results');
37
  target.show();
38
-
39
  try {
40
  result = JSON.parse(response);
41
  target.append('<div>' + (next_index+1) + '/' + images.length + ' &gt;&gt; ' + result['message'] +'</div>');
@@ -60,12 +60,12 @@ function imsanity_resize_next(images,next_index)
60
  */
61
  function imsanity_resize_complete()
62
  {
63
- var target = jQuery('#resize_results');
64
  target.append('<div><strong>' + imsanity_vars.resizing_complete + '</strong></div>');
65
  target.animate({scrollTop: target.prop('scrollHeight')});
66
  }
67
 
68
- /**
69
  * ajax post to return all images that are candidates for resizing
70
  * @param string the id of the html element into which results will be appended
71
  */
@@ -84,10 +84,18 @@ function imsanity_load_images(container_id)
84
 
85
  jQuery.post(
86
  ajaxurl, // (global defined by wordpress - points to admin-ajax.php)
87
- {_wpnonce: imsanity_vars._wpnonce, action: 'imsanity_get_images'},
88
- function(response)
89
- {
90
- var images = JSON.parse(response);
 
 
 
 
 
 
 
 
91
 
92
  jQuery('#imsanity_loading').hide();
93
  if (images.length > 0)
@@ -105,7 +113,7 @@ function imsanity_load_images(container_id)
105
  else
106
  {
107
  target.html('<div>' + imsanity_vars.none_found + '</div>');
108
-
109
  }
110
  }
111
  );
12
  images.push(this.value);
13
  });
14
 
15
+ var target = jQuery('#resize_results');
16
  target.html('');
17
  //jQuery(document).scrollTop(target.offset().top);
18
 
20
  imsanity_resize_next(images,0);
21
  }
22
 
23
+ /**
24
  * recursive function for resizing images
25
  */
26
  function imsanity_resize_next(images,next_index)
27
  {
28
  if (next_index >= images.length) return imsanity_resize_complete();
29
+
30
  jQuery.post(
31
  ajaxurl, // (defined by wordpress - points to admin-ajax.php)
32
+ {_wpnonce: imsanity_vars._wpnonce, action: 'imsanity_resize_image', id: images[next_index]},
33
+ function(response)
34
  {
35
  var result;
36
+ var target = jQuery('#resize_results');
37
  target.show();
38
+
39
  try {
40
  result = JSON.parse(response);
41
  target.append('<div>' + (next_index+1) + '/' + images.length + ' &gt;&gt; ' + result['message'] +'</div>');
60
  */
61
  function imsanity_resize_complete()
62
  {
63
+ var target = jQuery('#resize_results');
64
  target.append('<div><strong>' + imsanity_vars.resizing_complete + '</strong></div>');
65
  target.animate({scrollTop: target.prop('scrollHeight')});
66
  }
67
 
68
+ /**
69
  * ajax post to return all images that are candidates for resizing
70
  * @param string the id of the html element into which results will be appended
71
  */
84
 
85
  jQuery.post(
86
  ajaxurl, // (global defined by wordpress - points to admin-ajax.php)
87
+ {_wpnonce: imsanity_vars._wpnonce, action: 'imsanity_get_images'},
88
+ function(response) {
89
+ var is_json = true;
90
+ try {
91
+ var images = jQuery.parseJSON(response);
92
+ } catch ( err ) {
93
+ is_json = false;
94
+ }
95
+ if ( ! is_json ) {
96
+ console.log( response );
97
+ return false;
98
+ }
99
 
100
  jQuery('#imsanity_loading').hide();
101
  if (images.length > 0)
113
  else
114
  {
115
  target.html('<div>' + imsanity_vars.none_found + '</div>');
116
+
117
  }
118
  }
119
  );
settings.php CHANGED
@@ -1,34 +1,34 @@
1
  <?php
2
  /**
3
- * ################################################################################
4
- * IMSANITY ADMIN/SETTINGS UI
5
- * ################################################################################
6
  */
7
 
8
- // register the plugin settings menu
 
 
 
 
 
 
9
  add_action( 'admin_menu', 'imsanity_create_menu' );
10
  add_action( 'network_admin_menu', 'imsanity_register_network' );
11
  add_filter( 'plugin_action_links_imsanity/imsanity.php', 'imsanity_settings_link' );
12
  add_action( 'admin_enqueue_scripts', 'imsanity_queue_script' );
13
  add_action( 'admin_init', 'imsanity_register_settings' );
14
 
15
- // activation hooks
16
- // TODO: custom table is not removed because de-activating one site shouldn't affect the entire server
17
- register_activation_hook('imsanity/imsanity.php', 'imsanity_maybe_created_custom_table' );
18
- // add_action('plugins_loaded', 'imsanity_maybe_created_custom_table');
19
- // register_deactivation_hook('imsanity/imsanity.php', ...);
20
- // register_uninstall_hook('imsanity/imsanity.php', 'imsanity_maybe_remove_custom_table');
21
 
22
- // settings cache
23
  $_imsanity_multisite_settings = null;
24
 
25
  /**
26
  * Create the settings menu item in the WordPress admin navigation and
27
  * link it to the plugin settings page
28
  */
29
- function imsanity_create_menu()
30
- {
31
- // create new menu for site configuration
32
  add_options_page( esc_html__( 'Imsanity Plugin Settings', 'imsanity' ), 'Imsanity', 'administrator', __FILE__, 'imsanity_settings_page' );
33
  }
34
 
@@ -37,7 +37,7 @@ function imsanity_create_menu()
37
  */
38
  function imsanity_register_network() {
39
  if ( ! function_exists( 'is_plugin_active_for_network' ) && is_multisite() ) {
40
- // need to include the plugin library for the is_plugin_active function
41
  require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
42
  }
43
  if ( is_multisite() && is_plugin_active_for_network( 'imsanity/imsanity.php' ) ) {
@@ -47,104 +47,92 @@ function imsanity_register_network() {
47
 
48
  /**
49
  * Settings link that appears on the plugins overview page
50
- * @param array $links
51
- * @return array
 
52
  */
53
  function imsanity_settings_link( $links ) {
54
- $links[] = '<a href="'. get_admin_url( null, 'options-general.php?page=' . __FILE__ ) . '">' . esc_html__( 'Settings', 'imsanity' ) . '</a>';
 
 
 
 
55
  return $links;
56
  }
57
 
 
 
 
 
 
58
  function imsanity_queue_script( $hook ) {
59
- // make sure we are being called from the settings page
60
  if ( strpos( $hook, 'settings_page_imsanity' ) !== 0 ) {
61
  return;
62
  }
63
- // register the scripts that are used by the bulk resizer
64
  wp_enqueue_script( 'imsanity_script', plugins_url( '/scripts/imsanity.js', __FILE__ ), array( 'jquery' ), IMSANITY_VERSION );
65
  wp_localize_script( 'imsanity_script', 'imsanity_vars', array(
66
- '_wpnonce' => wp_create_nonce( 'imsanity-bulk' ),
67
- 'resizing_complete' => esc_html__( 'Resizing Complete', 'imsanity' ),
68
- 'resize_selected' => esc_html__( 'Resize Selected Images', 'imsanity' ),
69
- 'image' => esc_html__( 'Image', 'imsanity' ),
70
- 'invalid_response' => esc_html__( 'Received an invalid response, please check for errors in the Developer Tools console of your browser.', 'imsanity' ),
71
- 'none_found' => esc_html__( 'There are no images that need to be resized.', 'imsanity' ),
72
- )
73
- );
74
- }
75
-
76
- // TODO: legacy code to support previous MU version... ???
77
- // if ( dm_site_admin() && version_compare( $wp_version, '3.0.9', '<=' ) ) {
78
- // if ( version_compare( $wp_version, '3.0.1', '<=' ) ) {
79
- // add_submenu_page('wpmu-admin.php', __( 'Domain Mapping', 'wordpress-mu-domain-mapping' ), __( 'Domain Mapping', 'wordpress-mu-domain-mapping'), 'manage_options', 'dm_admin_page', 'dm_admin_page');
80
- // add_submenu_page('wpmu-admin.php', __( 'Domains', 'wordpress-mu-domain-mapping' ), __( 'Domains', 'wordpress-mu-domain-mapping'), 'manage_options', 'dm_domains_admin', 'dm_domains_admin');
81
- // } else {
82
- // add_submenu_page('ms-admin.php', __( 'Domain Mapping', 'wordpress-mu-domain-mapping' ), 'Domain Mapping', 'manage_options', 'dm_admin_page', 'dm_admin_page');
83
- // add_submenu_page('ms-admin.php', __( 'Domains', 'wordpress-mu-domain-mapping' ), 'Domains', 'manage_options', 'dm_domains_admin', 'dm_domains_admin');
84
- // }
85
- // }
86
- // add_action( 'admin_menu', 'dm_add_pages' );
87
-
88
- // TODO: put network options where they belong, not in a custom table
89
- /**
90
- * Returns the name of the custom multi-site settings table.
91
- * this will be the same table regardless of the blog
92
- */
93
- function imsanity_get_custom_table_name()
94
- {
95
- global $wpdb;
96
-
97
- // passing in zero seems to return $wpdb->base_prefix, which is not public
98
- return $wpdb->get_blog_prefix(0) . "imsanity";
99
  }
100
 
101
  /**
102
  * Return true if the multi-site settings table exists
103
- * @return bool
 
104
  */
105
- function imsanity_multisite_table_exists()
106
- {
107
  global $wpdb;
108
- $table_name = imsanity_get_custom_table_name();
109
- return $wpdb->get_var("SHOW TABLES LIKE '{$table_name}'") == $table_name;
110
  }
111
 
112
  /**
113
- * Return true if the multi-site settings table exists
114
- * @return bool
115
- */
116
- function imsanity_multisite_table_schema_version()
117
- {
118
- // if the table doesn't exist then there is no schema to report
119
- if (!imsanity_multisite_table_exists()) return '0';
 
 
120
 
121
  global $wpdb;
122
- $version = $wpdb->get_var('SELECT data FROM ' . imsanity_get_custom_table_name() . " WHERE setting = 'schema'");
123
 
124
- if (!$version) $version = '1.0'; // this is a legacy version 1.0 installation
 
 
125
 
126
  return $version;
127
-
128
  }
129
 
130
  /**
131
  * Returns the default network settings in the case where they are not
132
- * defined in the database, or multi-site is not enabled
 
133
  * @return stdClass
134
  */
135
- function imsanity_get_default_multisite_settings()
136
- {
137
  $data = new stdClass();
138
- $data->imsanity_override_site = false;
139
- $data->imsanity_max_height = IMSANITY_DEFAULT_MAX_HEIGHT;
140
- $data->imsanity_max_width = IMSANITY_DEFAULT_MAX_WIDTH;
 
141
  $data->imsanity_max_height_library = IMSANITY_DEFAULT_MAX_HEIGHT;
142
- $data->imsanity_max_width_library = IMSANITY_DEFAULT_MAX_WIDTH;
143
- $data->imsanity_max_height_other = IMSANITY_DEFAULT_MAX_HEIGHT;
144
- $data->imsanity_max_width_other = IMSANITY_DEFAULT_MAX_WIDTH;
145
- $data->imsanity_bmp_to_jpg = IMSANITY_DEFAULT_BMP_TO_JPG;
146
- $data->imsanity_png_to_jpg = IMSANITY_DEFAULT_PNG_TO_JPG;
147
- $data->imsanity_quality = IMSANITY_DEFAULT_QUALITY;
 
148
  return $data;
149
  }
150
 
@@ -153,148 +141,142 @@ function imsanity_get_default_multisite_settings()
153
  * On activation create the multisite database table if necessary. this is
154
  * called when the plugin is activated as well as when it is automatically
155
  * updated.
156
- *
157
- * @param bool set to true to force the query to run in the case of an upgrade
158
  */
159
- function imsanity_maybe_created_custom_table()
160
- {
161
- // if not a multi-site no need to do any custom table lookups
162
- if ( (!function_exists("is_multisite")) || (!is_multisite()) ) return;
 
163
 
164
  global $wpdb;
165
 
166
  $schema = imsanity_multisite_table_schema_version();
167
- $table_name = imsanity_get_custom_table_name();
168
 
169
- if ($schema == '0')
170
- {
171
- // this is an initial database setup
172
- $sql = "CREATE TABLE IF NOT EXISTS " . $table_name . " (
173
  setting varchar(55),
174
  data text NOT NULL,
175
  PRIMARY KEY (setting)
176
- );";
177
 
178
- require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
179
- dbDelta($sql);
180
  $data = imsanity_get_default_multisite_settings();
181
 
182
- // add the rows to the database
183
  $data = imsanity_get_default_multisite_settings();
184
- $wpdb->insert( $table_name, array( 'setting' => 'multisite', 'data' => maybe_serialize($data) ) );
185
- $wpdb->insert( $table_name, array( 'setting' => 'schema', 'data' => IMSANITY_SCHEMA_VERSION ) );
 
 
 
 
 
 
186
  }
187
 
188
- if ($schema != IMSANITY_SCHEMA_VERSION)
189
- {
190
- // this is a schema update. for the moment there is only one schema update available, from 1.0 to 1.1
191
- if ($schema == '1.0')
192
- {
193
- // update from version 1.0 to 1.1
194
- $wpdb->insert( $table_name, array( 'setting' => 'schema', 'data' => IMSANITY_SCHEMA_VERSION ) );
195
- $update1 = "ALTER TABLE " . $table_name . " CHANGE COLUMN data data TEXT NOT NULL;";
196
- $wpdb->query($update1);
197
- }
198
- else
199
- {
200
  // @todo we don't have this yet
201
  $wpdb->update(
202
- $table_name,
203
- array('data' => IMSANITY_SCHEMA_VERSION),
204
- array('setting' => 'schema')
205
  );
206
  }
207
-
208
  }
209
-
210
-
211
  }
212
 
213
  /**
214
- * display the form for the multi-site settings page
215
  */
216
- function imsanity_network_settings()
217
- {
218
  imsanity_settings_css();
219
 
220
  echo '
221
  <div class="wrap">
222
- <h1>' . esc_html__( 'Imsanity Network Settings' , 'imsanity' ) . '</h1>
223
  ';
224
 
225
- // we only want to update if the form has been submitted
226
- // if (isset($_POST['update_settings']))
227
- // {
228
- // imsanity_network_settings_update();
229
- // echo "<div id='imsanity-network-settings-saved' class='updated fade'><p><strong>". esc_html__( "Imsanity network settings saved.", 'imsanity' ) . "</strong></p></div>";
230
- // }
231
-
232
- // imsanity_settings_banner();
233
-
234
  $settings = imsanity_get_multisite_settings();
235
- // TODO: insert labels for all settings
236
  ?>
237
-
 
 
238
  <form method="post" action="settings.php?page=imsanity_network">
239
  <input type="hidden" name="update_imsanity_settings" value="1" />
240
- <?php wp_nonce_field( "imsanity_network_options" ); ?>
241
  <table class="form-table">
242
- <tr valign="top">
243
- <th scope="row"><?php esc_html_e( 'Global Settings Override', 'imsanity' ); ?></th>
244
  <td>
245
  <select name="imsanity_override_site">
246
- <option value="0" <?php if ($settings->imsanity_override_site == '0') echo "selected='selected'" ?> ><?php esc_html_e("Allow each site to configure Imsanity settings",'imsanity'); ?></option>
247
- <option value="1" <?php if ($settings->imsanity_override_site == '1') echo "selected='selected'" ?> ><?php esc_html_e("Use global Imsanity settings (below) for all sites",'imsanity'); ?></option>
248
  </select>
249
  </td>
250
  </tr>
251
 
252
- <tr valign="top">
253
- <th><?php esc_html_e("Images uploaded within a Page/Post",'imsanity');?></th>
254
  <td>
255
- <?php esc_html_e( 'Max Width', 'imsanity' ); ?> <input type="number" step="1" min="0" class='small-text' name="imsanity_max_width" value="<?php echo $settings->imsanity_max_width ?>" />
256
- <?php esc_html_e( 'Max Height', 'imsanity' ); ?> <input type="number" step="1" min="0" class="small-text" name="imsanity_max_height" value="<?php echo $settings->imsanity_max_height ?>" /> <?php esc_html_e( 'in pixels, enter 0 to disable','imsanity'); ?>
257
  </td>
258
  </tr>
259
 
260
- <tr valign="top">
261
- <th><?php esc_html_e("Images uploaded directly to the Media Library",'imsanity'); ?></th>
262
  <td>
263
- <?php esc_html_e( 'Max Width', 'imsanity' ); ?> <input type="number" step="1" min="0" class='small-text' name="imsanity_max_width_library" value="<?php echo $settings->imsanity_max_width_library ?>" />
264
- <?php esc_html_e( 'Max Height', 'imsanity' ); ?> <input type="number" step="1" min="0" class="small-text" name="imsanity_max_height_library" value="<?php echo $settings->imsanity_max_height_library ?>" /> <?php esc_html_e( 'in pixels, enter 0 to disable','imsanity'); ?>
265
  </td>
266
  </tr>
267
 
268
- <tr valign="top">
269
- <th scope="row"><?php esc_html_e("Images uploaded elsewhere (Theme headers, backgrounds, logos, etc)",'imsanity'); ?></th>
270
  <td>
271
- <?php esc_html_e( 'Max Width', 'imsanity' ); ?> <input type="number" step="1" min="0" class='small-text' name="imsanity_max_width_other" value="<?php echo $settings->imsanity_max_width_other ?>" />
272
- <?php esc_html_e( 'Max Height', 'imsanity' ); ?> <input type="number" step="1" min="0" class="small-text" name="imsanity_max_height_other" value="<?php echo $settings->imsanity_max_height_other ?>" /> <?php esc_html_e( 'in pixels, enter 0 to disable','imsanity'); ?>
273
  </td>
274
  </tr>
275
 
276
- <tr valign="top">
277
- <th scope="row"><?php esc_html_e("Convert BMP to JPG",'imsanity'); ?></th>
278
  <td><select name="imsanity_bmp_to_jpg">
279
- <option value="1" <?php if ($settings->imsanity_bmp_to_jpg == '1') echo "selected='selected'" ?> ><?php esc_html_e("Yes",'imsanity'); ?></option>
280
- <option value="0" <?php if ($settings->imsanity_bmp_to_jpg == '0') echo "selected='selected'" ?> ><?php esc_html_e("No",'imsanity'); ?></option>
281
  </select></td>
282
  </tr>
283
 
284
- <tr valign="top">
285
- <th scope="row"><?php esc_html_e("Convert PNG to JPG",'imsanity'); ?></th>
286
  <td><select name="imsanity_png_to_jpg">
287
- <option value="1" <?php if ($settings->imsanity_png_to_jpg == '1') echo "selected='selected'" ?> ><?php esc_html_e("Yes",'imsanity'); ?></option>
288
- <option value="0" <?php if ($settings->imsanity_png_to_jpg == '0') echo "selected='selected'" ?> ><?php esc_html_e("No",'imsanity'); ?></option>
289
  </select></td>
290
  </tr>
291
 
292
  <tr>
293
- <th><label for='imsanity_quality' ><?php esc_html_e( "JPG image quality", 'imsanity' ); ?></th>
294
  <td><input type='text' id='imsanity_quality' name='imsanity_quality' class='small-text' value='<?php echo (int) $settings->imsanity_quality; ?>' /> <?php esc_html_e( 'Valid values are 1-100.', 'imsanity' ); ?>
295
  <p class='description'><?php esc_html_e( 'WordPress default is 82', 'imsanity' ); ?></p></td>
296
  </tr>
297
 
 
 
 
 
 
298
  </table>
299
 
300
  <p class="submit"><input type="submit" class="button-primary" value="<?php esc_attr_e( 'Update Settings', 'imsanity' ); ?>" /></p>
@@ -318,36 +300,39 @@ function imsanity_network_settings_update() {
318
 
319
  // ensure that the custom table is created when the user updates network settings
320
  // this is not ideal but it's better than checking for this table existance
321
- // on every page load
322
  imsanity_maybe_created_custom_table();
323
 
324
- $table_name = imsanity_get_custom_table_name();
325
-
326
  $data = new stdClass();
327
- $data->imsanity_override_site = $_POST['imsanity_override_site'] == 1;
328
- $data->imsanity_max_height = sanitize_text_field($_POST['imsanity_max_height']);
329
- $data->imsanity_max_width = sanitize_text_field($_POST['imsanity_max_width']);
330
- $data->imsanity_max_height_library = sanitize_text_field($_POST['imsanity_max_height_library']);
331
- $data->imsanity_max_width_library = sanitize_text_field($_POST['imsanity_max_width_library']);
332
- $data->imsanity_max_height_other = sanitize_text_field($_POST['imsanity_max_height_other']);
333
- $data->imsanity_max_width_other = sanitize_text_field($_POST['imsanity_max_width_other']);
334
- $data->imsanity_bmp_to_jpg = $_POST['imsanity_bmp_to_jpg'] == 1;
335
- $data->imsanity_png_to_jpg = $_POST['imsanity_png_to_jpg'] == 1;
336
- $data->imsanity_quality = imsanity_jpg_quality($_POST['imsanity_quality']);
337
- $wpdb->update(
338
- $table_name,
339
- array('data' => maybe_serialize($data)),
340
- array('setting' => 'multisite')
 
 
 
341
  );
342
 
343
- // clear the cache
344
  $_imsanity_multisite_settings = null;
345
  add_action( 'network_admin_notices', 'imsanity_network_settings_saved' );
346
  }
347
 
 
 
 
348
  function imsanity_network_settings_saved() {
349
- // TODO: figure out why this won't fade
350
- echo "<div id='imsanity-network-settings-saved' class='updated fade'><p><strong>" . esc_html__( "Imsanity network settings saved.", 'imsanity' ) . "</strong></p></div>";
351
  }
352
 
353
  /**
@@ -355,65 +340,57 @@ function imsanity_network_settings_saved() {
355
  * defined in the database or multi-site is not enabled then the default settings
356
  * are returned. This is cached so it only loads once per page load, unless
357
  * imsanity_network_settings_update is called.
 
358
  * @return stdClass
359
  */
360
- function imsanity_get_multisite_settings()
361
- {
362
  global $_imsanity_multisite_settings;
363
  $result = null;
364
 
365
- if (!$_imsanity_multisite_settings)
366
- {
367
- if (function_exists("is_multisite") && is_multisite())
368
- {
369
  global $wpdb;
370
-
371
- $result = $wpdb->get_var('select data from ' . imsanity_get_custom_table_name() . " where setting = 'multisite'");
372
  }
373
 
374
- // if there's no results, return the defaults instead
375
  $_imsanity_multisite_settings = $result
376
- ? unserialize($result)
377
  : imsanity_get_default_multisite_settings();
378
 
379
- // this is for backwards compatibility
380
- if ($_imsanity_multisite_settings->imsanity_max_height_library == '')
381
- {
382
  $_imsanity_multisite_settings->imsanity_max_height_library = $_imsanity_multisite_settings->imsanity_max_height;
383
- $_imsanity_multisite_settings->imsanity_max_width_library = $_imsanity_multisite_settings->imsanity_max_width;
384
- $_imsanity_multisite_settings->imsanity_max_height_other = $_imsanity_multisite_settings->imsanity_max_height;
385
- $_imsanity_multisite_settings->imsanity_max_width_other = $_imsanity_multisite_settings->imsanity_max_width;
386
  }
387
-
388
  }
389
-
390
  return $_imsanity_multisite_settings;
391
  }
392
 
393
  /**
394
  * Gets the option setting for the given key, first checking to see if it has been
395
  * set globally for multi-site. Otherwise checking the site options.
396
- * @param string $key
397
- * @param string $ifnull value to use if the requested option returns null
 
398
  */
399
- function imsanity_get_option($key,$ifnull)
400
- {
401
  $result = null;
402
 
403
  $settings = imsanity_get_multisite_settings();
404
 
405
- if ($settings->imsanity_override_site)
406
- {
407
  $result = $settings->$key;
408
- if ($result == null) $result = $ifnull;
409
- }
410
- else
411
- {
412
- $result = get_option($key,$ifnull);
413
  }
414
 
415
  return $result;
416
-
417
  }
418
 
419
  /**
@@ -423,11 +400,11 @@ function imsanity_register_settings() {
423
  if ( ! function_exists( 'is_plugin_active_for_network' ) && is_multisite() ) {
424
  require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
425
  }
426
- // we only want to update if the form has been submitted
427
  if ( isset( $_POST['update_imsanity_settings'] ) && is_multisite() && is_plugin_active_for_network( 'imsanity/imsanity.php' ) ) {
428
  imsanity_network_settings_update();
429
  }
430
- //register our settings
431
  register_setting( 'imsanity-settings-group', 'imsanity_max_height' );
432
  register_setting( 'imsanity-settings-group', 'imsanity_max_width' );
433
  register_setting( 'imsanity-settings-group', 'imsanity_max_height_library' );
@@ -437,13 +414,17 @@ function imsanity_register_settings() {
437
  register_setting( 'imsanity-settings-group', 'imsanity_bmp_to_jpg' );
438
  register_setting( 'imsanity-settings-group', 'imsanity_png_to_jpg' );
439
  register_setting( 'imsanity-settings-group', 'imsanity_quality', 'imsanity_jpg_quality' );
 
440
  }
441
 
442
  /**
443
- * Validate and return the JPG quality setting
 
 
 
444
  */
445
  function imsanity_jpg_quality( $quality = null ) {
446
- if ( $quality === null ) {
447
  $quality = get_option( 'imsanity_quality' );
448
  }
449
  if ( preg_match( '/^(100|[1-9][0-9]?)$/', $quality ) ) {
@@ -457,9 +438,8 @@ function imsanity_jpg_quality( $quality = null ) {
457
  * Helper function to render css styles for the settings forms
458
  * for both site and network settings page
459
  */
460
- function imsanity_settings_css()
461
- {
462
- echo "
463
  <style>
464
  #imsanity_header {
465
  border: solid 1px #c6c6c6;
@@ -470,43 +450,7 @@ function imsanity_settings_css()
470
  #imsanity_header p {
471
  margin: .5em 0;
472
  }
473
- </style>";
474
- }
475
-
476
- /**
477
- * Helper function to render the settings banner
478
- * for both site and network settings page
479
- */
480
- function imsanity_settings_banner()
481
- {
482
-
483
- // echo '
484
- // <div id="imsanity_header" style="float: left;">';
485
-
486
- // if (!defined('IMSANITY_HIDE_LOGO'))
487
- // echo '<a href="http://verysimple.com/products/imsanity/"><img alt="Imsanity" src="' . plugins_url() . '/imsanity/images/imsanity.png" style="float: right; margin-left: 15px;"/></a>';
488
-
489
- /* echo '
490
- <h4>'.__("Imsanity automatically resizes insanely huge image uploads",'imsanity').'</h4>'.
491
-
492
- __("<p>Imsanity automaticaly reduces the size of images that are larger than the specified maximum and replaces the original
493
- with one of a more \"sane\" size. Site contributors don\'t need to concern themselves with manually scaling images
494
- and can upload them directly from their camera or phone.</p>
495
-
496
- <p>The resolution of modern cameras is larger than necessary for typical web display.
497
- The average computer screen is not big enough to display a 3 megapixel camera-phone image at full resolution.
498
- WordPress does a good job of creating scaled-down copies which can be used, however the original images
499
- are permanently stored, taking up disk quota and, if used on a page, create a poor viewer experience.</p>
500
-
501
- <p>This plugin is designed for sites where high-resolution images are not necessary and/or site contributors
502
- do not want (or understand how) to deal with scaling images. This plugin should not be used on
503
- sites for which original, high-resolution images must be stored.</p>
504
-
505
- <p>Be sure to save back-ups of your full-sized images if you wish to keep them.</p>",'imsanity') .
506
-
507
- sprintf( __("<p>Imsanity Version %s by %s </p>",'imsanity'),IMSANITY_VERSION ,'<a href="https://ewww.io/">Shane Bishop</a>') .
508
- '</div>
509
- <br style="clear:both" />';*/
510
  }
511
 
512
  /**
@@ -514,40 +458,38 @@ function imsanity_settings_banner()
514
  * and imsanity_override_site is true, then display a notice message that settings
515
  * are not editable instead of the settings form
516
  */
517
- function imsanity_settings_page()
518
- {
519
  imsanity_settings_css();
520
 
521
  ?>
 
 
 
522
  <div class="wrap">
523
  <h1><?php esc_html_e( 'Imsanity Settings', 'imsanity' ); ?></h1>
524
  <?php
525
 
526
- // imsanity_settings_banner();
527
-
528
  $settings = imsanity_get_multisite_settings();
529
 
530
- if ($settings->imsanity_override_site)
531
- {
532
  imsanity_settings_page_notice();
533
- }
534
- else
535
- {
536
  imsanity_settings_page_form();
537
  }
538
 
539
  ?>
540
 
541
- <h2 style="margin-top: 0px;"><?php _e("Bulk Resize Images",'imsanity'); ?></h2>
542
 
543
  <div id="imsanity_header">
544
  <p><?php esc_html_e( 'If you have existing images that were uploaded prior to installing Imsanity, you may resize them all in bulk to recover disk space. To begin, click the "Search Images" button to search all existing attachments for images that are larger than the configured limit.', 'imsanity' ); ?></p>
 
545
  <p><?php printf( esc_html__( 'NOTE: To give you greater control over the resizing process, a maximum of %d images will be returned at one time. Bitmap images cannot be bulk resized and will not appear in the search results.', 'imsanity' ), IMSANITY_AJAX_MAX_RECORDS ); ?></p>
546
  </div>
547
 
548
  <div style="border: solid 1px #ff6666; background-color: #ffbbbb; padding: 0 10px;">
549
  <h4><?php esc_html_e( 'WARNING: Bulk Resize will alter your original images and cannot be undone!', 'imsanity' ); ?></h4>
550
-
551
  <p><?php esc_html_e( 'It is HIGHLY recommended that you backup your wp-content/uploads folder before proceeding. You will have a chance to preview and select the images to convert.', 'imsanity' ); ?><br>
552
  <?php esc_html_e( 'It is also recommended that you initially select only 1 or 2 images and verify that everything is working properly before processing your entire library.', 'imsanity' ); ?></p>
553
  </div>
@@ -572,77 +514,78 @@ function imsanity_settings_page()
572
  /**
573
  * Multi-user config file exists so display a notice
574
  */
575
- function imsanity_settings_page_notice()
576
- {
577
  ?>
578
  <div class="updated settings-error">
579
- <p><strong><?php esc_html_e("Imsanity settings have been configured by the server administrator. There are no site-specific settings available.",'imsanity'); ?></strong></p>
580
  </div>
581
-
582
  <?php
583
  }
584
 
585
  /**
586
- * Render the site settings form. This is processed by
587
- * WordPress built-in options persistance mechanism
588
- */
589
- function imsanity_settings_page_form()
590
- {
591
  ?>
592
  <form method="post" action="options.php">
593
  <?php settings_fields( 'imsanity-settings-group' ); ?>
594
  <table class="form-table">
595
 
596
- <tr valign="middle">
597
- <th scope="row"><?php _e("Images uploaded within a Page/Post",'imsanity'); ?></th>
598
  <td>
599
- <?php esc_html_e( 'Max Width', 'imsanity' ); ?> <input type="number" step="1" min="0" class="small-text" name="imsanity_max_width" value="<?php echo get_option('imsanity_max_width',IMSANITY_DEFAULT_MAX_WIDTH); ?>" />
600
- <?php esc_html_e( 'Max Height', 'imsanity' ); ?> <input type="number" step="1" min="0" class="small-text" name="imsanity_max_height" value="<?php echo get_option('imsanity_max_height',IMSANITY_DEFAULT_MAX_HEIGHT); ?>" /> <?php esc_html_e( 'in pixels, enter 0 to disable','imsanity'); ?>
601
  </td>
602
  </tr>
603
 
604
- <tr valign="middle">
605
- <th scope="row"><?php _e("Images uploaded directly to the Media Library",'imsanity'); ?></th>
606
  <td>
607
- <?php esc_html_e( 'Max Width', 'imsanity' ); ?> <input type="number" step="1" min="0" class="small-text" name="imsanity_max_width_library" value="<?php echo get_option('imsanity_max_width_library',IMSANITY_DEFAULT_MAX_WIDTH); ?>" />
608
- <?php esc_html_e( 'Max Height', 'imsanity' ); ?> <input type="number" step="1" min="0" class="small-text" name="imsanity_max_height_library" value="<?php echo get_option('imsanity_max_height_library',IMSANITY_DEFAULT_MAX_HEIGHT); ?>" /> <?php esc_html_e( 'in pixels, enter 0 to disable','imsanity'); ?>
609
  </td>
610
  </tr>
611
 
612
- <tr valign="middle">
613
- <th scope="row"><?php _e("Images uploaded elsewhere (Theme headers, backgrounds, logos, etc)",'imsanity'); ?></th>
614
  <td>
615
- <?php esc_html_e( 'Max Width', 'imsanity' ); ?> <input type="number" step="1" min="0" class="small-text" name="imsanity_max_width_other" value="<?php echo get_option('imsanity_max_width_other',IMSANITY_DEFAULT_MAX_WIDTH); ?>" />
616
- <?php esc_html_e( 'Max Height', 'imsanity' ); ?> <input type="number" step="1" min="0" class="small-text" name="imsanity_max_height_other" value="<?php echo get_option('imsanity_max_height_other',IMSANITY_DEFAULT_MAX_HEIGHT); ?>" /> <?php esc_html_e( 'in pixels, enter 0 to disable','imsanity'); ?>
617
  </td>
618
  </tr>
619
 
620
 
621
  <tr>
622
- <th><label for='imsanity_quality' ><?php esc_html_e( "JPG image quality", 'imsanity' ); ?></th>
623
- <td><input type='text' id='imsanity_quality' name='imsanity_quality' class='small-text' value='<?php echo imsanity_jpg_quality(); ?>' /> <?php esc_html_e('Valid values are 1-100.', 'imsanity' ); ?>
624
- <p class='description'><?php esc_html_e( 'WordPress default is 82','imsanity' ); ?></p></td>
625
  </tr>
626
 
627
- <tr valign="middle">
628
- <th scope="row"><?php esc_html_e("Convert BMP To JPG",'imsanity'); ?></th>
629
  <td><select name="imsanity_bmp_to_jpg">
630
- <option <?php if ( get_option( 'imsanity_bmp_to_jpg', IMSANITY_DEFAULT_BMP_TO_JPG) == "1" ) { echo "selected='selected'"; } ?> value="1"><?php esc_html_e("Yes",'imsanity'); ?></option>
631
- <option <?php if ( get_option( 'imsanity_bmp_to_jpg', IMSANITY_DEFAULT_BMP_TO_JPG) == "0" ) { echo "selected='selected'"; } ?> value="0"><?php esc_html_e("No",'imsanity'); ?></option>
632
  </select></td>
633
  </tr>
634
 
635
- <tr valign="middle">
636
- <th scope="row"><?php esc_html_e("Convert PNG To JPG",'imsanity'); ?></th>
637
  <td><select name="imsanity_png_to_jpg">
638
- <option <?php if (get_option('imsanity_png_to_jpg',IMSANITY_DEFAULT_PNG_TO_JPG) == "1") {echo "selected='selected'";} ?> value="1"><?php esc_html_e("Yes",'imsanity'); ?></option>
639
- <option <?php if (get_option('imsanity_png_to_jpg',IMSANITY_DEFAULT_PNG_TO_JPG) == "0") {echo "selected='selected'";} ?> value="0"><?php esc_html_e("No",'imsanity'); ?></option>
640
  </select></td>
641
  </tr>
642
 
 
 
 
 
643
  </table>
644
 
645
- <p class="submit"><input type="submit" class="button-primary" value="<?php esc_attr_e('Save Changes') ?>" /></p>
646
 
647
  </form>
648
  <?php
1
  <?php
2
  /**
3
+ * Imsanity settings and admin UI.
4
+ *
5
+ * @package Imsanity
6
  */
7
 
8
+ // Setup custom $wpdb attribute for our image-tracking table.
9
+ global $wpdb;
10
+ if ( ! isset( $wpdb->imsanity_ms ) ) {
11
+ $wpdb->imsanity_ms = $wpdb->get_blog_prefix( 0 ) . 'imsanity';
12
+ }
13
+
14
+ // Register the plugin settings menu.
15
  add_action( 'admin_menu', 'imsanity_create_menu' );
16
  add_action( 'network_admin_menu', 'imsanity_register_network' );
17
  add_filter( 'plugin_action_links_imsanity/imsanity.php', 'imsanity_settings_link' );
18
  add_action( 'admin_enqueue_scripts', 'imsanity_queue_script' );
19
  add_action( 'admin_init', 'imsanity_register_settings' );
20
 
21
+ register_activation_hook( 'imsanity/imsanity.php', 'imsanity_maybe_created_custom_table' );
 
 
 
 
 
22
 
23
+ // settings cache.
24
  $_imsanity_multisite_settings = null;
25
 
26
  /**
27
  * Create the settings menu item in the WordPress admin navigation and
28
  * link it to the plugin settings page
29
  */
30
+ function imsanity_create_menu() {
31
+ // Create new menu for site configuration.
 
32
  add_options_page( esc_html__( 'Imsanity Plugin Settings', 'imsanity' ), 'Imsanity', 'administrator', __FILE__, 'imsanity_settings_page' );
33
  }
34
 
37
  */
38
  function imsanity_register_network() {
39
  if ( ! function_exists( 'is_plugin_active_for_network' ) && is_multisite() ) {
40
+ // Need to include the plugin library for the is_plugin_active function.
41
  require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
42
  }
43
  if ( is_multisite() && is_plugin_active_for_network( 'imsanity/imsanity.php' ) ) {
47
 
48
  /**
49
  * Settings link that appears on the plugins overview page
50
+ *
51
+ * @param array $links The plugin action links.
52
+ * @return array The action links, with a settings link pre-pended.
53
  */
54
  function imsanity_settings_link( $links ) {
55
+ if ( ! is_array( $links ) ) {
56
+ $links = array();
57
+ }
58
+ $settings_link = '<a href="' . get_admin_url( null, 'options-general.php?page=' . __FILE__ ) . '">' . esc_html__( 'Settings', 'imsanity' ) . '</a>';
59
+ array_unshift( $links, $settings_link );
60
  return $links;
61
  }
62
 
63
+ /**
64
+ * Queues up the AJAX script and any localized JS vars we need.
65
+ *
66
+ * @param string $hook The hook name for the current page.
67
+ */
68
  function imsanity_queue_script( $hook ) {
69
+ // Make sure we are being called from the settings page.
70
  if ( strpos( $hook, 'settings_page_imsanity' ) !== 0 ) {
71
  return;
72
  }
73
+ // Register the scripts that are used by the bulk resizer.
74
  wp_enqueue_script( 'imsanity_script', plugins_url( '/scripts/imsanity.js', __FILE__ ), array( 'jquery' ), IMSANITY_VERSION );
75
  wp_localize_script( 'imsanity_script', 'imsanity_vars', array(
76
+ '_wpnonce' => wp_create_nonce( 'imsanity-bulk' ),
77
+ 'resizing_complete' => esc_html__( 'Resizing Complete', 'imsanity' ),
78
+ 'resize_selected' => esc_html__( 'Resize Selected Images', 'imsanity' ),
79
+ 'image' => esc_html__( 'Image', 'imsanity' ),
80
+ 'invalid_response' => esc_html__( 'Received an invalid response, please check for errors in the Developer Tools console of your browser.', 'imsanity' ),
81
+ 'none_found' => esc_html__( 'There are no images that need to be resized.', 'imsanity' ),
82
+ ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  }
84
 
85
  /**
86
  * Return true if the multi-site settings table exists
87
+ *
88
+ * @return bool True if the Imsanity table exists.
89
  */
90
+ function imsanity_multisite_table_exists() {
 
91
  global $wpdb;
92
+ return $wpdb->get_var( "SHOW TABLES LIKE '$wpdb->imsanity_ms'" ) == $wpdb->imsanity_ms;
 
93
  }
94
 
95
  /**
96
+ * Checks the schema version for the Imsanity table.
97
+ *
98
+ * @return string The version identifier for the schema.
99
+ */
100
+ function imsanity_multisite_table_schema_version() {
101
+ // If the table doesn't exist then there is no schema to report.
102
+ if ( ! imsanity_multisite_table_exists() ) {
103
+ return '0';
104
+ }
105
 
106
  global $wpdb;
107
+ $version = $wpdb->get_var( "SELECT data FROM $wpdb->imsanity_ms WHERE setting = 'schema'" );
108
 
109
+ if ( ! $version ) {
110
+ $version = '1.0'; // This is a legacy version 1.0 installation.
111
+ }
112
 
113
  return $version;
 
114
  }
115
 
116
  /**
117
  * Returns the default network settings in the case where they are not
118
+ * defined in the database, or multi-site is not enabled.
119
+ *
120
  * @return stdClass
121
  */
122
+ function imsanity_get_default_multisite_settings() {
 
123
  $data = new stdClass();
124
+
125
+ $data->imsanity_override_site = false;
126
+ $data->imsanity_max_height = IMSANITY_DEFAULT_MAX_HEIGHT;
127
+ $data->imsanity_max_width = IMSANITY_DEFAULT_MAX_WIDTH;
128
  $data->imsanity_max_height_library = IMSANITY_DEFAULT_MAX_HEIGHT;
129
+ $data->imsanity_max_width_library = IMSANITY_DEFAULT_MAX_WIDTH;
130
+ $data->imsanity_max_height_other = IMSANITY_DEFAULT_MAX_HEIGHT;
131
+ $data->imsanity_max_width_other = IMSANITY_DEFAULT_MAX_WIDTH;
132
+ $data->imsanity_bmp_to_jpg = IMSANITY_DEFAULT_BMP_TO_JPG;
133
+ $data->imsanity_png_to_jpg = IMSANITY_DEFAULT_PNG_TO_JPG;
134
+ $data->imsanity_deep_scan = false;
135
+ $data->imsanity_quality = IMSANITY_DEFAULT_QUALITY;
136
  return $data;
137
  }
138
 
141
  * On activation create the multisite database table if necessary. this is
142
  * called when the plugin is activated as well as when it is automatically
143
  * updated.
 
 
144
  */
145
+ function imsanity_maybe_created_custom_table() {
146
+ // If not a multi-site no need to do any custom table lookups.
147
+ if ( ! function_exists( 'is_multisite' ) || ( ! is_multisite() ) ) {
148
+ return;
149
+ }
150
 
151
  global $wpdb;
152
 
153
  $schema = imsanity_multisite_table_schema_version();
 
154
 
155
+ if ( '0' == $schema ) {
156
+ // This is an initial database setup.
157
+ $sql = 'CREATE TABLE IF NOT EXISTS ' . $wpdb->imsanity_ms . ' (
 
158
  setting varchar(55),
159
  data text NOT NULL,
160
  PRIMARY KEY (setting)
161
+ );';
162
 
163
+ require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
164
+ dbDelta( $sql );
165
  $data = imsanity_get_default_multisite_settings();
166
 
167
+ // Add the rows to the database.
168
  $data = imsanity_get_default_multisite_settings();
169
+ $wpdb->insert( $wpdb->imsanity_ms, array(
170
+ 'setting' => 'multisite',
171
+ 'data' => maybe_serialize( $data ),
172
+ ) );
173
+ $wpdb->insert( $wpdb->imsanity_ms, array(
174
+ 'setting' => 'schema',
175
+ 'data' => IMSANITY_SCHEMA_VERSION,
176
+ ) );
177
  }
178
 
179
+ if ( IMSANITY_SCHEMA_VERSION != $schema ) {
180
+ // This is a schema update. for the moment there is only one schema update available, from 1.0 to 1.1.
181
+ if ( '1.0' == $schema ) {
182
+ // Update from version 1.0 to 1.1.
183
+ $wpdb->insert( $wpdb->imsanity_ms, array(
184
+ 'setting' => 'schema',
185
+ 'data' => IMSANITY_SCHEMA_VERSION,
186
+ ) );
187
+ $wpdb->query( "ALTER TABLE $wpdb->imsanity_ms CHANGE COLUMN data data TEXT NOT NULL;" );
188
+ } else {
 
 
189
  // @todo we don't have this yet
190
  $wpdb->update(
191
+ $wpdb->imsanity_ms,
192
+ array( 'data' => IMSANITY_SCHEMA_VERSION ),
193
+ array( 'setting' => 'schema' )
194
  );
195
  }
 
196
  }
 
 
197
  }
198
 
199
  /**
200
+ * Display the form for the multi-site settings page.
201
  */
202
+ function imsanity_network_settings() {
 
203
  imsanity_settings_css();
204
 
205
  echo '
206
  <div class="wrap">
207
+ <h1>' . esc_html__( 'Imsanity Network Settings', 'imsanity' ) . '</h1>
208
  ';
209
 
 
 
 
 
 
 
 
 
 
210
  $settings = imsanity_get_multisite_settings();
 
211
  ?>
212
+ <script type='text/javascript'>
213
+ jQuery(document).ready(function($) {$(".fade").fadeTo(5000,1).fadeOut(3000);});
214
+ </script>
215
  <form method="post" action="settings.php?page=imsanity_network">
216
  <input type="hidden" name="update_imsanity_settings" value="1" />
217
+ <?php wp_nonce_field( 'imsanity_network_options' ); ?>
218
  <table class="form-table">
219
+ <tr>
220
+ <th scope="row"><label for="imsanity_override_site"><?php esc_html_e( 'Global Settings Override', 'imsanity' ); ?></label></th>
221
  <td>
222
  <select name="imsanity_override_site">
223
+ <option value="0" <?php echo ( '0' == $settings->imsanity_override_site ) ? "selected='selected'" : ''; ?> ><?php esc_html_e( 'Allow each site to configure Imsanity settings', 'imsanity' ); ?></option>
224
+ <option value="1" <?php echo ( '1' == $settings->imsanity_override_site ) ? "selected='selected'" : ''; ?> ><?php esc_html_e( 'Use global Imsanity settings (below) for all sites', 'imsanity' ); ?></option>
225
  </select>
226
  </td>
227
  </tr>
228
 
229
+ <tr>
230
+ <th scope="row"><?php esc_html_e( 'Images uploaded within a Page/Post', 'imsanity' ); ?></th>
231
  <td>
232
+ <label for="imsanity_max_width"><?php esc_html_e( 'Max Width', 'imsanity' ); ?></label> <input type="number" step="1" min="0" class='small-text' name="imsanity_max_width" value="<?php echo (int) $settings->imsanity_max_width; ?>" />
233
+ <label for="imsanity_max_height"><?php esc_html_e( 'Max Height', 'imsanity' ); ?></label> <input type="number" step="1" min="0" class="small-text" name="imsanity_max_height" value="<?php echo (int) $settings->imsanity_max_height; ?>" /> <?php esc_html_e( 'in pixels, enter 0 to disable', 'imsanity' ); ?>
234
  </td>
235
  </tr>
236
 
237
+ <tr>
238
+ <th scope="row"><?php esc_html_e( 'Images uploaded directly to the Media Library', 'imsanity' ); ?></th>
239
  <td>
240
+ <label for="imsanity_max_width_library"><?php esc_html_e( 'Max Width', 'imsanity' ); ?></label> <input type="number" step="1" min="0" class='small-text' name="imsanity_max_width_library" value="<?php echo (int) $settings->imsanity_max_width_library; ?>" />
241
+ <label for="imsanity_max_height_library"><?php esc_html_e( 'Max Height', 'imsanity' ); ?></label> <input type="number" step="1" min="0" class="small-text" name="imsanity_max_height_library" value="<?php echo (int) $settings->imsanity_max_height_library; ?>" /> <?php esc_html_e( 'in pixels, enter 0 to disable', 'imsanity' ); ?>
242
  </td>
243
  </tr>
244
 
245
+ <tr>
246
+ <th scope="row"><?php esc_html_e( 'Images uploaded elsewhere (Theme headers, backgrounds, logos, etc)', 'imsanity' ); ?></th>
247
  <td>
248
+ <label for="imsanity_max_width_other"><?php esc_html_e( 'Max Width', 'imsanity' ); ?></label> <input type="number" step="1" min="0" class='small-text' name="imsanity_max_width_other" value="<?php echo (int) $settings->imsanity_max_width_other; ?>" />
249
+ <label for="imsanity_max_height_other"><?php esc_html_e( 'Max Height', 'imsanity' ); ?></label> <input type="number" step="1" min="0" class="small-text" name="imsanity_max_height_other" value="<?php echo (int) $settings->imsanity_max_height_other; ?>" /> <?php esc_html_e( 'in pixels, enter 0 to disable', 'imsanity' ); ?>
250
  </td>
251
  </tr>
252
 
253
+ <tr>
254
+ <th scope="row"><label for"imsanity_bmp_to_jpg"><?php esc_html_e( 'Convert BMP to JPG', 'imsanity' ); ?></label></th>
255
  <td><select name="imsanity_bmp_to_jpg">
256
+ <option value="1" <?php echo ( '1' == $settings->imsanity_bmp_to_jpg ) ? "selected='selected'" : ''; ?> ><?php esc_html_e( 'Yes', 'imsanity' ); ?></option>
257
+ <option value="0" <?php echo ( '0' == $settings->imsanity_bmp_to_jpg ) ? "selected='selected'" : ''; ?> ><?php esc_html_e( 'No', 'imsanity' ); ?></option>
258
  </select></td>
259
  </tr>
260
 
261
+ <tr>
262
+ <th scope="row"><label for="imsanity_png_to_jpg"><?php esc_html_e( 'Convert PNG to JPG', 'imsanity' ); ?></label></th>
263
  <td><select name="imsanity_png_to_jpg">
264
+ <option value="1" <?php echo ( '1' == $settings->imsanity_png_to_jpg ) ? "selected='selected'" : ''; ?> ><?php esc_html_e( 'Yes', 'imsanity' ); ?></option>
265
+ <option value="0" <?php echo ( '0' == $settings->imsanity_png_to_jpg ) ? "selected='selected'" : ''; ?> ><?php esc_html_e( 'No', 'imsanity' ); ?></option>
266
  </select></td>
267
  </tr>
268
 
269
  <tr>
270
+ <th scope="row"><label for='imsanity_quality' ><?php esc_html_e( 'JPG image quality', 'imsanity' ); ?></th>
271
  <td><input type='text' id='imsanity_quality' name='imsanity_quality' class='small-text' value='<?php echo (int) $settings->imsanity_quality; ?>' /> <?php esc_html_e( 'Valid values are 1-100.', 'imsanity' ); ?>
272
  <p class='description'><?php esc_html_e( 'WordPress default is 82', 'imsanity' ); ?></p></td>
273
  </tr>
274
 
275
+ <tr>
276
+ <th scope="row"><label for="imsanity_deep_scan"><?php esc_html_e( 'Deep Scan', 'imsanity' ); ?></label></th>
277
+ <td><input type="checkbox" id="imsanity_deep_scan" name="imsanity_deep_scan" value="true"<?php echo ( $settings->imsanity_deep_scan ) ? " checked='true'" : ''; ?> /><?php esc_html_e( 'If searching repeatedly returns the same images, deep scanning will check the actual image dimensions instead of relying on metadata from the database.', 'imsanity' ); ?></td>
278
+ </tr>
279
+
280
  </table>
281
 
282
  <p class="submit"><input type="submit" class="button-primary" value="<?php esc_attr_e( 'Update Settings', 'imsanity' ); ?>" /></p>
300
 
301
  // ensure that the custom table is created when the user updates network settings
302
  // this is not ideal but it's better than checking for this table existance
303
+ // on every page load.
304
  imsanity_maybe_created_custom_table();
305
 
 
 
306
  $data = new stdClass();
307
+
308
+ $data->imsanity_override_site = 1 == $_POST['imsanity_override_site'];
309
+ $data->imsanity_max_height = sanitize_text_field( $_POST['imsanity_max_height'] );
310
+ $data->imsanity_max_width = sanitize_text_field( $_POST['imsanity_max_width'] );
311
+ $data->imsanity_max_height_library = sanitize_text_field( $_POST['imsanity_max_height_library'] );
312
+ $data->imsanity_max_width_library = sanitize_text_field( $_POST['imsanity_max_width_library'] );
313
+ $data->imsanity_max_height_other = sanitize_text_field( $_POST['imsanity_max_height_other'] );
314
+ $data->imsanity_max_width_other = sanitize_text_field( $_POST['imsanity_max_width_other'] );
315
+ $data->imsanity_bmp_to_jpg = 1 == $_POST['imsanity_bmp_to_jpg'];
316
+ $data->imsanity_png_to_jpg = 1 == $_POST['imsanity_png_to_jpg'];
317
+ $data->imsanity_quality = imsanity_jpg_quality( $_POST['imsanity_quality'] );
318
+ $data->imsanity_deep_scan = (bool) $_POST['imsanity_deep_scan'];
319
+
320
+ $success = $wpdb->update(
321
+ $wpdb->imsanity_ms,
322
+ array( 'data' => maybe_serialize( $data ) ),
323
+ array( 'setting' => 'multisite' )
324
  );
325
 
326
+ // Clear the cache.
327
  $_imsanity_multisite_settings = null;
328
  add_action( 'network_admin_notices', 'imsanity_network_settings_saved' );
329
  }
330
 
331
+ /**
332
+ * Display a message to inform the user the multi-site setting have been saved.
333
+ */
334
  function imsanity_network_settings_saved() {
335
+ echo "<div id='imsanity-network-settings-saved' class='updated fade'><p><strong>" . esc_html__( 'Imsanity network settings saved.', 'imsanity' ) . '</strong></p></div>';
 
336
  }
337
 
338
  /**
340
  * defined in the database or multi-site is not enabled then the default settings
341
  * are returned. This is cached so it only loads once per page load, unless
342
  * imsanity_network_settings_update is called.
343
+ *
344
  * @return stdClass
345
  */
346
+ function imsanity_get_multisite_settings() {
 
347
  global $_imsanity_multisite_settings;
348
  $result = null;
349
 
350
+ if ( ! $_imsanity_multisite_settings ) {
351
+ if ( function_exists( 'is_multisite' ) && is_multisite() ) {
 
 
352
  global $wpdb;
353
+ $result = $wpdb->get_var( "SELECT data FROM $wpdb->imsanity_ms WHERE setting = 'multisite'" );
 
354
  }
355
 
356
+ // if there's no results, return the defaults instead.
357
  $_imsanity_multisite_settings = $result
358
+ ? unserialize( $result )
359
  : imsanity_get_default_multisite_settings();
360
 
361
+ // this is for backwards compatibility.
362
+ if ( empty( $_imsanity_multisite_settings->imsanity_max_height_library ) ) {
 
363
  $_imsanity_multisite_settings->imsanity_max_height_library = $_imsanity_multisite_settings->imsanity_max_height;
364
+ $_imsanity_multisite_settings->imsanity_max_width_library = $_imsanity_multisite_settings->imsanity_max_width;
365
+ $_imsanity_multisite_settings->imsanity_max_height_other = $_imsanity_multisite_settings->imsanity_max_height;
366
+ $_imsanity_multisite_settings->imsanity_max_width_other = $_imsanity_multisite_settings->imsanity_max_width;
367
  }
 
368
  }
 
369
  return $_imsanity_multisite_settings;
370
  }
371
 
372
  /**
373
  * Gets the option setting for the given key, first checking to see if it has been
374
  * set globally for multi-site. Otherwise checking the site options.
375
+ *
376
+ * @param string $key The name of the option to retrieve.
377
+ * @param string $ifnull Value to use if the requested option returns null.
378
  */
379
+ function imsanity_get_option( $key, $ifnull ) {
 
380
  $result = null;
381
 
382
  $settings = imsanity_get_multisite_settings();
383
 
384
+ if ( $settings->imsanity_override_site ) {
 
385
  $result = $settings->$key;
386
+ if ( is_null( $result ) ) {
387
+ $result = $ifnull;
388
+ }
389
+ } else {
390
+ $result = get_option( $key, $ifnull );
391
  }
392
 
393
  return $result;
 
394
  }
395
 
396
  /**
400
  if ( ! function_exists( 'is_plugin_active_for_network' ) && is_multisite() ) {
401
  require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
402
  }
403
+ // We only want to update if the form has been submitted.
404
  if ( isset( $_POST['update_imsanity_settings'] ) && is_multisite() && is_plugin_active_for_network( 'imsanity/imsanity.php' ) ) {
405
  imsanity_network_settings_update();
406
  }
407
+ // Register our settings.
408
  register_setting( 'imsanity-settings-group', 'imsanity_max_height' );
409
  register_setting( 'imsanity-settings-group', 'imsanity_max_width' );
410
  register_setting( 'imsanity-settings-group', 'imsanity_max_height_library' );
414
  register_setting( 'imsanity-settings-group', 'imsanity_bmp_to_jpg' );
415
  register_setting( 'imsanity-settings-group', 'imsanity_png_to_jpg' );
416
  register_setting( 'imsanity-settings-group', 'imsanity_quality', 'imsanity_jpg_quality' );
417
+ register_setting( 'imsanity-settings-group', 'imsanity_deep_scan' );
418
  }
419
 
420
  /**
421
+ * Validate and return the JPG quality setting.
422
+ *
423
+ * @param int $quality The JPG quality currently set.
424
+ * @return int The (potentially) adjusted quality level.
425
  */
426
  function imsanity_jpg_quality( $quality = null ) {
427
+ if ( is_null( $quality ) ) {
428
  $quality = get_option( 'imsanity_quality' );
429
  }
430
  if ( preg_match( '/^(100|[1-9][0-9]?)$/', $quality ) ) {
438
  * Helper function to render css styles for the settings forms
439
  * for both site and network settings page
440
  */
441
+ function imsanity_settings_css() {
442
+ echo '
 
443
  <style>
444
  #imsanity_header {
445
  border: solid 1px #c6c6c6;
450
  #imsanity_header p {
451
  margin: .5em 0;
452
  }
453
+ </style>';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
454
  }
455
 
456
  /**
458
  * and imsanity_override_site is true, then display a notice message that settings
459
  * are not editable instead of the settings form
460
  */
461
+ function imsanity_settings_page() {
 
462
  imsanity_settings_css();
463
 
464
  ?>
465
+ <script type='text/javascript'>
466
+ jQuery(document).ready(function($) {$(".fade").fadeTo(5000,1).fadeOut(3000);});
467
+ </script>
468
  <div class="wrap">
469
  <h1><?php esc_html_e( 'Imsanity Settings', 'imsanity' ); ?></h1>
470
  <?php
471
 
 
 
472
  $settings = imsanity_get_multisite_settings();
473
 
474
+ if ( $settings->imsanity_override_site ) {
 
475
  imsanity_settings_page_notice();
476
+ } else {
 
 
477
  imsanity_settings_page_form();
478
  }
479
 
480
  ?>
481
 
482
+ <h2 style="margin-top: 0px;"><?php esc_html_e( 'Bulk Resize Images', 'imsanity' ); ?></h2>
483
 
484
  <div id="imsanity_header">
485
  <p><?php esc_html_e( 'If you have existing images that were uploaded prior to installing Imsanity, you may resize them all in bulk to recover disk space. To begin, click the "Search Images" button to search all existing attachments for images that are larger than the configured limit.', 'imsanity' ); ?></p>
486
+ <?php /* translators: %d: the number of images */ ?>
487
  <p><?php printf( esc_html__( 'NOTE: To give you greater control over the resizing process, a maximum of %d images will be returned at one time. Bitmap images cannot be bulk resized and will not appear in the search results.', 'imsanity' ), IMSANITY_AJAX_MAX_RECORDS ); ?></p>
488
  </div>
489
 
490
  <div style="border: solid 1px #ff6666; background-color: #ffbbbb; padding: 0 10px;">
491
  <h4><?php esc_html_e( 'WARNING: Bulk Resize will alter your original images and cannot be undone!', 'imsanity' ); ?></h4>
492
+
493
  <p><?php esc_html_e( 'It is HIGHLY recommended that you backup your wp-content/uploads folder before proceeding. You will have a chance to preview and select the images to convert.', 'imsanity' ); ?><br>
494
  <?php esc_html_e( 'It is also recommended that you initially select only 1 or 2 images and verify that everything is working properly before processing your entire library.', 'imsanity' ); ?></p>
495
  </div>
514
  /**
515
  * Multi-user config file exists so display a notice
516
  */
517
+ function imsanity_settings_page_notice() {
 
518
  ?>
519
  <div class="updated settings-error">
520
+ <p><strong><?php esc_html_e( 'Imsanity settings have been configured by the server administrator. There are no site-specific settings available.', 'imsanity' ); ?></strong></p>
521
  </div>
 
522
  <?php
523
  }
524
 
525
  /**
526
+ * Render the site settings form. This is processed by
527
+ * WordPress built-in options persistance mechanism
528
+ */
529
+ function imsanity_settings_page_form() {
 
530
  ?>
531
  <form method="post" action="options.php">
532
  <?php settings_fields( 'imsanity-settings-group' ); ?>
533
  <table class="form-table">
534
 
535
+ <tr>
536
+ <th scope="row"><?php esc_html_e( 'Images uploaded within a Page/Post', 'imsanity' ); ?></th>
537
  <td>
538
+ <label for="imsanity_max_width"><?php esc_html_e( 'Max Width', 'imsanity' ); ?></label> <input type="number" step="1" min="0" class="small-text" name="imsanity_max_width" value="<?php echo (int) get_option( 'imsanity_max_width', IMSANITY_DEFAULT_MAX_WIDTH ); ?>" />
539
+ <label for="imsanity_max_height"><?php esc_html_e( 'Max Height', 'imsanity' ); ?></label> <input type="number" step="1" min="0" class="small-text" name="imsanity_max_height" value="<?php echo (int) get_option( 'imsanity_max_height', IMSANITY_DEFAULT_MAX_HEIGHT ); ?>" /> <?php esc_html_e( 'in pixels, enter 0 to disable', 'imsanity' ); ?>
540
  </td>
541
  </tr>
542
 
543
+ <tr>
544
+ <th scope="row"><?php esc_html_e( 'Images uploaded directly to the Media Library', 'imsanity' ); ?></th>
545
  <td>
546
+ <label for="imsanity_max_width_library"><?php esc_html_e( 'Max Width', 'imsanity' ); ?></label> <input type="number" step="1" min="0" class="small-text" name="imsanity_max_width_library" value="<?php echo (int) get_option( 'imsanity_max_width_library', IMSANITY_DEFAULT_MAX_WIDTH ); ?>" />
547
+ <label for="imsanity_max_height_library"><?php esc_html_e( 'Max Height', 'imsanity' ); ?></label> <input type="number" step="1" min="0" class="small-text" name="imsanity_max_height_library" value="<?php echo (int) get_option( 'imsanity_max_height_library', IMSANITY_DEFAULT_MAX_HEIGHT ); ?>" /> <?php esc_html_e( 'in pixels, enter 0 to disable', 'imsanity' ); ?>
548
  </td>
549
  </tr>
550
 
551
+ <tr>
552
+ <th scope="row"><?php esc_html_e( 'Images uploaded elsewhere (Theme headers, backgrounds, logos, etc)', 'imsanity' ); ?></th>
553
  <td>
554
+ <label for="imsanity_max_width_other"><?php esc_html_e( 'Max Width', 'imsanity' ); ?></label> <input type="number" step="1" min="0" class="small-text" name="imsanity_max_width_other" value="<?php echo (int) get_option( 'imsanity_max_width_other', IMSANITY_DEFAULT_MAX_WIDTH ); ?>" />
555
+ <label for="imsanity_max_height_other"><?php esc_html_e( 'Max Height', 'imsanity' ); ?></label> <input type="number" step="1" min="0" class="small-text" name="imsanity_max_height_other" value="<?php echo (int) get_option( 'imsanity_max_height_other', IMSANITY_DEFAULT_MAX_HEIGHT ); ?>" /> <?php esc_html_e( 'in pixels, enter 0 to disable', 'imsanity' ); ?>
556
  </td>
557
  </tr>
558
 
559
 
560
  <tr>
561
+ <th scope="row"><label for='imsanity_quality' ><?php esc_html_e( 'JPG image quality', 'imsanity' ); ?></th>
562
+ <td><input type='text' id='imsanity_quality' name='imsanity_quality' class='small-text' value='<?php echo imsanity_jpg_quality(); ?>' /> <?php esc_html_e( 'Valid values are 1-100.', 'imsanity' ); ?>
563
+ <p class='description'><?php esc_html_e( 'WordPress default is 82', 'imsanity' ); ?></p></td>
564
  </tr>
565
 
566
+ <tr>
567
+ <th scope="row"><label for="imsanity_bmp_to_jpg"><?php esc_html_e( 'Convert BMP To JPG', 'imsanity' ); ?></label></th>
568
  <td><select name="imsanity_bmp_to_jpg">
569
+ <option <?php echo ( '1' == get_option( 'imsanity_bmp_to_jpg', IMSANITY_DEFAULT_BMP_TO_JPG ) ) ? "selected='selected'" : ''; ?> value="1"><?php esc_html_e( 'Yes', 'imsanity' ); ?></option>
570
+ <option <?php echo ( '0' == get_option( 'imsanity_bmp_to_jpg', IMSANITY_DEFAULT_BMP_TO_JPG ) ) ? "selected='selected'" : ''; ?> value="0"><?php esc_html_e( 'No', 'imsanity' ); ?></option>
571
  </select></td>
572
  </tr>
573
 
574
+ <tr>
575
+ <th scope="row"><label for="imsanity_png_to_jpg"><?php esc_html_e( 'Convert PNG To JPG', 'imsanity' ); ?></label></th>
576
  <td><select name="imsanity_png_to_jpg">
577
+ <option <?php echo ( '1' == get_option( 'imsanity_png_to_jpg', IMSANITY_DEFAULT_PNG_TO_JPG ) ) ? "selected='selected'" : ''; ?> value="1"><?php esc_html_e( 'Yes', 'imsanity' ); ?></option>
578
+ <option <?php echo ( '0' == get_option( 'imsanity_png_to_jpg', IMSANITY_DEFAULT_PNG_TO_JPG ) ) ? "selected='selected'" : ''; ?> value="0"><?php esc_html_e( 'No', 'imsanity' ); ?></option>
579
  </select></td>
580
  </tr>
581
 
582
+ <tr>
583
+ <th scope="row"><label for="imsanity_deep_scan"><?php esc_html_e( 'Deep Scan', 'imsanity' ); ?></label></th>
584
+ <td><input type="checkbox" id="imsanity_deep_scan" name="imsanity_deep_scan" value="true"<?php echo ( get_option( 'imsanity_deep_scan' ) ) ? " checked='true'" : ''; ?> /><?php esc_html_e( 'If searching repeatedly returns the same images, deep scanning will check the actual image dimensions instead of relying on metadata from the database.', 'imsanity' ); ?></td>
585
+ </tr>
586
  </table>
587
 
588
+ <p class="submit"><input type="submit" class="button-primary" value="<?php esc_attr_e( 'Save Changes', 'imsanity' ); ?>" /></p>
589
 
590
  </form>
591
  <?php