ShortPixel Image Optimizer - Version 4.14.5

Version Description

Release date: 29th August 2019 * If constant SHORTPIXEL_USE_DOUBLE_WEBP_EXTENSION is defined as true, use double extension for WebP (.jpg.webp) * Fixed: Javascript - String.prototype causes errors on React apps * Fixed: Undefined page load when using ShortPixel and Divi preloaded images * Fixed: Offload Media - When removing PNG2JPG converted file, the files / folder are not removed. * Fixed: When the constant that enables using double extensions for WebP (.jpg.webp) is active, the webp's are found as unlisted thumbnails and sent to optimization. * Fixed: missing call to apply_filters('shortpixel_image_exists'...) on a particular case. * Language 0 new strings added, 1 updated, 0 fuzzied, and 0 obsoleted

Download this release

Release Info

Developer ShortPixel
Plugin Icon 128x128 ShortPixel Image Optimizer
Version 4.14.5
Comparing to
See all releases

Code changes from version 4.14.4 to 4.14.5

class/controller/filesystem_controller.php CHANGED
@@ -84,9 +84,6 @@ Class FileSystemController extends ShortPixelController
84
  $filepath = $file->getFullPath();
85
  $directory = $file->getFileDir();
86
 
87
- // $relpath = $directory->getRelativePath();
88
- //$relfile =
89
-
90
  // stolen from wp_get_attachment_url
91
  if ( ( $uploads = wp_get_upload_dir() ) && false === $uploads['error'] ) {
92
  // Check that the upload base exists in the file location.
@@ -101,10 +98,11 @@ Class FileSystemController extends ShortPixelController
101
  $url = $uploads['baseurl'] . "/$filepath";
102
  }
103
  }
104
-
105
  return $url;
106
  }
107
 
108
 
109
 
 
 
110
  }
84
  $filepath = $file->getFullPath();
85
  $directory = $file->getFileDir();
86
 
 
 
 
87
  // stolen from wp_get_attachment_url
88
  if ( ( $uploads = wp_get_upload_dir() ) && false === $uploads['error'] ) {
89
  // Check that the upload base exists in the file location.
98
  $url = $uploads['baseurl'] . "/$filepath";
99
  }
100
  }
 
101
  return $url;
102
  }
103
 
104
 
105
 
106
+
107
+
108
  }
class/db/shortpixel-meta-facade.php CHANGED
@@ -239,17 +239,8 @@ class ShortPixelMetaFacade {
239
  unset($rawMeta['ShortPixel']);
240
  unset($rawMeta['ShortPixelPng2Jpg']);
241
  }
242
- if (isset($rawMeta['sizes'])) // search for custom sizes set by SP.
243
- {
244
- foreach($rawMeta['sizes'] as $size => $data)
245
- {
246
- if (strpos($size, ShortPixelMeta::FOUND_THUMB_PREFIX) !== false)
247
- {
248
- unset($rawMeta['sizes'][$size]);
249
- Log::addDebug('Unset sp-found- size' . $size);
250
- }
251
- }
252
- }
253
  unset($this->meta);
254
  update_post_meta($this->ID, '_wp_attachment_metadata', $rawMeta);
255
  //wp_update_attachment_metadata($this->ID, $rawMeta);
@@ -259,6 +250,31 @@ class ShortPixelMetaFacade {
259
  }
260
  }
261
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
262
  function deleteMeta() {
263
  if($this->type == self::CUSTOM_TYPE) {
264
  throw new Exception("Not implemented 1");
@@ -375,6 +391,7 @@ class ShortPixelMetaFacade {
375
 
376
  public function getURLsAndPATHs($processThumbnails, $onlyThumbs = false, $addRetina = true, $excludeSizes = array(), $includeOptimized = false) {
377
  $sizesMissing = array();
 
378
 
379
  if($this->type == self::CUSTOM_TYPE) {
380
  $meta = $this->getMeta();
@@ -386,16 +403,34 @@ class ShortPixelMetaFacade {
386
  $filePaths[] = $meta->getPath();
387
  } else {
388
  $path = get_attached_file($this->ID);//get the full file PATH
 
389
  $mainExists = apply_filters('shortpixel_image_exists', file_exists($path), $path, $this->ID);
390
- $url = self::safeGetAttachmentUrl($this->ID);
391
  $urlList = array(); $filePaths = array();
392
 
 
 
393
  if(!$mainExists) {
394
  //try and download the image from the URL (images present only on CDN)
395
  $downloadTimeout = max(SHORTPIXEL_MAX_EXECUTION_TIME - 10, 15);
396
- $tempOriginal = download_url($url, $downloadTimeout);
397
- if(!is_wp_error( $tempOriginal )) {
398
- $mainExists = @copy($tempOriginal, $path);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
399
  }
400
  }
401
 
@@ -407,6 +442,8 @@ class ShortPixelMetaFacade {
407
  }
408
  }
409
 
 
 
410
  $meta = $this->getMeta();
411
  $sizes = $meta->getThumbs();
412
 
@@ -422,6 +459,7 @@ class ShortPixelMetaFacade {
422
  $count = 1;
423
  foreach( $sizes as $thumbnailName => $thumbnailInfo ) {
424
 
 
425
  if(!isset($thumbnailInfo['file'])) { //cases when $thumbnailInfo is NULL
426
  continue;
427
  }
@@ -446,14 +484,18 @@ class ShortPixelMetaFacade {
446
  $count++;
447
 
448
  $origPath = $tPath = str_replace(ShortPixelAPI::MB_basename($path), $thumbnailInfo['file'], $path);
 
 
 
 
 
449
  $file_exists = apply_filters('shortpixel_image_exists', file_exists($origPath), $origPath, $this->ID);
450
- $tUrl = str_replace(ShortPixelAPI::MB_basename($url), $thumbnailInfo['file'], $url);
451
 
452
  // Working on low-key replacement for path handling via FileSystemController.
453
  // This specific fix is related to the possibility of URLs' in metadata
454
  if ( !$file_exists && !file_exists($tPath) )
455
  {
456
- $fs = new \ShortPixel\FileSystemController();
457
  $file = $fs->getFile($thumbnailInfo['file']);
458
 
459
  if ($file->exists())
@@ -466,7 +508,7 @@ class ShortPixelMetaFacade {
466
  }
467
 
468
  if ( !$file_exists && !file_exists($tPath) ) {
469
- $tPath = SHORTPIXEL_UPLOADS_BASE . substr($tPath, strpos($tPath, $StichString) + strlen($StichString));
470
  }
471
 
472
  if ( !$file_exists && !file_exists($tPath) ) {
@@ -475,13 +517,33 @@ class ShortPixelMetaFacade {
475
 
476
  if ( !$file_exists && !file_exists($tPath) ) {
477
  //try and download the image from the URL (images present only on CDN)
478
- $downloadTimeout = max(SHORTPIXEL_MAX_EXECUTION_TIME - 10, 15);
479
- $tempThumb = download_url($tUrl, $downloadTimeout);
480
- if(!is_wp_error( $tempThumb )) {
481
- if(@copy($tempThumb, $origPath)) {
482
- $tPath = $origPath;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
483
  }
484
  }
 
 
485
  }
486
 
487
  if ($file_exists || file_exists($tPath)) {
@@ -493,6 +555,7 @@ class ShortPixelMetaFacade {
493
  }
494
  }
495
  else {
 
496
  $sizesMissing[$thumbnailName] = ShortPixelAPI::MB_basename($tPath);
497
  }
498
  }
@@ -507,12 +570,12 @@ class ShortPixelMetaFacade {
507
  }
508
  }
509
 
 
510
  //convert the + which are replaced with spaces by wp_remote_post
511
  array_walk($urlList, array( &$this, 'replacePlusChar') );
512
 
513
  $filePaths = ShortPixelAPI::CheckAndFixImagePaths($filePaths);//check for images to make sure they exist on disk
514
 
515
- //die(var_dump(array("URLs" => $urlList, "PATHs" => $filePaths)));
516
  return array("URLs" => $urlList, "PATHs" => $filePaths, "sizesMissing" => $sizesMissing);
517
  }
518
 
@@ -534,6 +597,7 @@ class ShortPixelMetaFacade {
534
  return (substr($baseName, -3) === '@2x');
535
  }
536
 
 
537
  public static function getWPMLDuplicates( $id ) {
538
  global $wpdb;
539
 
@@ -714,6 +778,14 @@ class ShortPixelMetaFacade {
714
  */
715
  static public function returnSubDir($file)
716
  {
 
 
 
 
 
 
 
 
717
  $homePath = get_home_path();
718
  if($homePath == '/') {
719
  $homePath = ABSPATH;
@@ -721,6 +793,7 @@ class ShortPixelMetaFacade {
721
  $hp = wp_normalize_path($homePath);
722
  $file = wp_normalize_path($file);
723
 
 
724
  // $sp__uploads = wp_upload_dir();
725
 
726
  if(strstr($file, $hp)) {
239
  unset($rawMeta['ShortPixel']);
240
  unset($rawMeta['ShortPixelPng2Jpg']);
241
  }
242
+
243
+ $this->removeSPFoundMeta();
 
 
 
 
 
 
 
 
 
244
  unset($this->meta);
245
  update_post_meta($this->ID, '_wp_attachment_metadata', $rawMeta);
246
  //wp_update_attachment_metadata($this->ID, $rawMeta);
250
  }
251
  }
252
 
253
+ // remove SPFoudnMeta from image. Dirty. @todo <--
254
+ function removeSPFoundMeta()
255
+ {
256
+ if($this->type == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) {
257
+ if(!isset($this->rawMeta)) {
258
+ $rawMeta = $this->sanitizeMeta(wp_get_attachment_metadata($this->getId()));
259
+ } else {
260
+ $rawMeta = $this->rawMeta;
261
+ }
262
+ if (isset($rawMeta['sizes'])) // search for custom sizes set by SP.
263
+ {
264
+ foreach($rawMeta['sizes'] as $size => $data)
265
+ {
266
+ if (strpos($size, ShortPixelMeta::FOUND_THUMB_PREFIX) !== false)
267
+ {
268
+ unset($rawMeta['sizes'][$size]);
269
+ Log::addDebug('Unset sp-found- size' . $size);
270
+ }
271
+ }
272
+ }
273
+ $this->rawMeta = $rawMeta;
274
+ update_post_meta($this->ID, '_wp_attachment_metadata', $rawMeta);
275
+ }
276
+ }
277
+
278
  function deleteMeta() {
279
  if($this->type == self::CUSTOM_TYPE) {
280
  throw new Exception("Not implemented 1");
391
 
392
  public function getURLsAndPATHs($processThumbnails, $onlyThumbs = false, $addRetina = true, $excludeSizes = array(), $includeOptimized = false) {
393
  $sizesMissing = array();
394
+ $fs = new \ShortPixel\FileSystemController();
395
 
396
  if($this->type == self::CUSTOM_TYPE) {
397
  $meta = $this->getMeta();
403
  $filePaths[] = $meta->getPath();
404
  } else {
405
  $path = get_attached_file($this->ID);//get the full file PATH
406
+ $fsFile = $fs->getFile($path);
407
  $mainExists = apply_filters('shortpixel_image_exists', file_exists($path), $path, $this->ID);
408
+ $predownload_url = $url = self::safeGetAttachmentUrl($this->ID);
409
  $urlList = array(); $filePaths = array();
410
 
411
+ Log::addDebug('attached file path: ' . $path );
412
+
413
  if(!$mainExists) {
414
  //try and download the image from the URL (images present only on CDN)
415
  $downloadTimeout = max(SHORTPIXEL_MAX_EXECUTION_TIME - 10, 15);
416
+ //$tempOriginal = download_url($url, $downloadTimeout);
417
+ $args_for_get = array(
418
+ 'stream' => true,
419
+ 'filename' => $path,
420
+ );
421
+ Log::addDebug('Downloading main file ' . $url );
422
+ $response = wp_remote_get( $url, $args_for_get );
423
+ if(is_wp_error( $response )) {
424
+ Log::addError('Download Mailfile failed', array($response->get_error_messages()));
425
+ }
426
+ elseif ($fsFile->exists())
427
+ {
428
+ $mainExists = true;
429
+ $fsUrl = $fs->pathToUrl($fsFile);
430
+ if ($fsUrl !== false)
431
+ $url = $fsUrl; // more secure way of getting url
432
+
433
+ Log::addDebug('FSFILE TO URL -' . $fsUrl);
434
  }
435
  }
436
 
442
  }
443
  }
444
 
445
+ Log::addDebug('Main file turnout - ', array($url, $path));
446
+
447
  $meta = $this->getMeta();
448
  $sizes = $meta->getThumbs();
449
 
459
  $count = 1;
460
  foreach( $sizes as $thumbnailName => $thumbnailInfo ) {
461
 
462
+ // Reasons for skipping the thumb.
463
  if(!isset($thumbnailInfo['file'])) { //cases when $thumbnailInfo is NULL
464
  continue;
465
  }
484
  $count++;
485
 
486
  $origPath = $tPath = str_replace(ShortPixelAPI::MB_basename($path), $thumbnailInfo['file'], $path);
487
+ $origFile = $fs->getFile($origPath);
488
+
489
+ if ($origFile->getExtension() == 'webp') // never include any webp extension.
490
+ continue;
491
+
492
  $file_exists = apply_filters('shortpixel_image_exists', file_exists($origPath), $origPath, $this->ID);
493
+ $tUrl = str_replace(ShortPixelAPI::MB_basename($predownload_url), $thumbnailInfo['file'], $predownload_url);
494
 
495
  // Working on low-key replacement for path handling via FileSystemController.
496
  // This specific fix is related to the possibility of URLs' in metadata
497
  if ( !$file_exists && !file_exists($tPath) )
498
  {
 
499
  $file = $fs->getFile($thumbnailInfo['file']);
500
 
501
  if ($file->exists())
508
  }
509
 
510
  if ( !$file_exists && !file_exists($tPath) ) {
511
+ $tPath = SHORTPIXEL_UPLOADS_BASE . substr($origPath, strpos($origPath, $StichString) + strlen($StichString));
512
  }
513
 
514
  if ( !$file_exists && !file_exists($tPath) ) {
517
 
518
  if ( !$file_exists && !file_exists($tPath) ) {
519
  //try and download the image from the URL (images present only on CDN)
520
+ // Log::addDebug('URLs and Paths - File didnt exists, trying to download', array($tUrl, $origPath));
521
+ // $tempThumb = download_url($tUrl, $downloadTimeout);
522
+ $args_for_get = array(
523
+ 'stream' => true,
524
+ 'filename' => $origFile->getFullPath(),
525
+ 'timeout' => max(SHORTPIXEL_MAX_EXECUTION_TIME - 10, 15),
526
+ );
527
+
528
+ $response = wp_remote_get( $tUrl, $args_for_get );
529
+ Log::addDebug('Thumb not found, trying to download: ' . $tUrl);
530
+
531
+ if (is_wp_error($response))
532
+ {
533
+ Log::addError('Download Thumbnail failed', array($response->get_error_messages()));
534
+ }
535
+ elseif($origFile->exists())
536
+ {
537
+ $tPath = $origFile->getFullPath(); // download succesfull
538
+ $fsUrl = $fs->pathToUrl($origFile);
539
+ if ($fsUrl !== false) // this tranlation to domain url will not always hold to sendToProcessing when dealing w/ CDN and such.
540
+ $tUrl = $fsUrl; // more secure way of getting url
541
+ else {
542
+ Log::addError('Download - Could not tranlate to URL', array($fsUrl, $tPath, $origFile));
543
  }
544
  }
545
+
546
+ Log::addDebug('New TPath after download', array($tUrl, $tPath, $origPath, filesize($tPath)));
547
  }
548
 
549
  if ($file_exists || file_exists($tPath)) {
555
  }
556
  }
557
  else {
558
+ Log::addInfo('Missing Thumbnail :' . $tPath);
559
  $sizesMissing[$thumbnailName] = ShortPixelAPI::MB_basename($tPath);
560
  }
561
  }
570
  }
571
  }
572
 
573
+
574
  //convert the + which are replaced with spaces by wp_remote_post
575
  array_walk($urlList, array( &$this, 'replacePlusChar') );
576
 
577
  $filePaths = ShortPixelAPI::CheckAndFixImagePaths($filePaths);//check for images to make sure they exist on disk
578
 
 
579
  return array("URLs" => $urlList, "PATHs" => $filePaths, "sizesMissing" => $sizesMissing);
580
  }
581
 
597
  return (substr($baseName, -3) === '@2x');
598
  }
599
 
600
+ // @todo Not clear what this function does.
601
  public static function getWPMLDuplicates( $id ) {
602
  global $wpdb;
603
 
778
  */
779
  static public function returnSubDir($file)
780
  {
781
+
782
+ // Experimental FS handling for relativePath. Should be able to cope with more exceptions. See Unit Tests
783
+ $fs = new ShortPixel\FileSystemController();
784
+ $directory = $fs->getDirectory($file);
785
+ if ($relpath = $directory->getRelativePath())
786
+ return $relpath;
787
+
788
+
789
  $homePath = get_home_path();
790
  if($homePath == '/') {
791
  $homePath = ABSPATH;
793
  $hp = wp_normalize_path($homePath);
794
  $file = wp_normalize_path($file);
795
 
796
+
797
  // $sp__uploads = wp_upload_dir();
798
 
799
  if(strstr($file, $hp)) {
class/db/wp-shortpixel-media-library-adapter.php CHANGED
@@ -341,7 +341,7 @@ class WpShortPixelMediaLbraryAdapter {
341
  /** Find thumbnails that are not listed in the image metadata
342
  * These are usually thumbnails generated by other plugins
343
  * @param $mainFile String Full path the main Image of which to get thumbnails
344
- * @return Array Array of thumbnails or empty array
345
  */
346
  public static function findThumbs($mainFile) {
347
  // Old
@@ -354,6 +354,13 @@ class WpShortPixelMediaLbraryAdapter {
354
  // New
355
  $fs = new \ShortPixel\FileSystemController();
356
  $file = $fs->getFile($mainFile);
 
 
 
 
 
 
 
357
  $dirPath = $file->getFileDir()->getPath();
358
 
359
  $base = $file->getFileBase();
@@ -413,19 +420,44 @@ class WpShortPixelMediaLbraryAdapter {
413
  }
414
  }
415
  // }
416
- return $thumbs;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
417
  }
418
 
419
  private static function getFilesByPattern($path, $pattern)
420
  {
 
 
 
 
 
 
 
 
 
 
 
 
421
 
422
- $dirIterator = new \DirectoryIterator($path);
423
- $regExIterator = new \RegexIterator($dirIterator, $pattern);
424
 
425
  $images = array();
426
  foreach($regExIterator as $fileinfo)
427
  {
428
- $images[] = $fileinfo->getPathname();
429
  }
430
 
431
  return $images;
341
  /** Find thumbnails that are not listed in the image metadata
342
  * These are usually thumbnails generated by other plugins
343
  * @param $mainFile String Full path the main Image of which to get thumbnails
344
+ * @return Array Array of thumbnails or empty array. Filters non-existing and webp files.
345
  */
346
  public static function findThumbs($mainFile) {
347
  // Old
354
  // New
355
  $fs = new \ShortPixel\FileSystemController();
356
  $file = $fs->getFile($mainFile);
357
+
358
+ $directory = $file->getFileDir();
359
+ /* Directory could not exist if, for instance, the request path is URL, S3 or some external exotic. */
360
+ if (! $directory->check())
361
+ {
362
+ return array();
363
+ }
364
  $dirPath = $file->getFileDir()->getPath();
365
 
366
  $base = $file->getFileBase();
420
  }
421
  }
422
  // }
423
+
424
+ // Quality check on the thumbs. Must exist, must be same extension.
425
+ $results = array();
426
+
427
+ foreach($thumbs as $thumbfile)
428
+ {
429
+ if ($thumbfile->getExtension() != $ext) // remove false hits, webp and such.
430
+ continue;
431
+ if (! $thumbfile->exists()) // thing must exist.
432
+ continue;
433
+
434
+ $results[] = $thumbfile->getFullPath();
435
+ }
436
+
437
+ /* Returns array with full path, as string */
438
+ return $results;
439
  }
440
 
441
  private static function getFilesByPattern($path, $pattern)
442
  {
443
+ $fs = new \ShortPixel\FileSystemController();
444
+
445
+ try
446
+ {
447
+ $dirIterator = new \DirectoryIterator($path);
448
+ $regExIterator = new \RegexIterator($dirIterator, $pattern);
449
+ }
450
+ catch(\Exception $e)
451
+ {
452
+ Log::addWarn('GetFilesbyPattern issue with directory. ', $e->message());
453
+ return array();
454
+ }
455
 
 
 
456
 
457
  $images = array();
458
  foreach($regExIterator as $fileinfo)
459
  {
460
+ $images[] = $fs->getFile($fileinfo->getPathname());
461
  }
462
 
463
  return $images;
class/external/wp-offload-media.php ADDED
@@ -0,0 +1,173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace ShortPixel;
3
+ use ShortPixel\ShortPixelLogger\ShortPixelLogger as Log;
4
+ use ShortPixel\FileSystemController as FileSystem;
5
+
6
+ class wpOffload
7
+ {
8
+ protected $as3cf;
9
+ protected $active = false;
10
+
11
+ public function __construct()
12
+ {
13
+ // This must be called before WordPress' init.
14
+ add_action('as3cf_init', array($this, 'init'));
15
+ }
16
+
17
+ public function init($as3cf)
18
+ {
19
+
20
+ $this->as3cf = $as3cf;
21
+ $this->active = true;
22
+
23
+ add_action('shortpixel_image_optimised', array($this, 'image_upload'));
24
+ add_action('shortpixel_after_restore_image', array($this, 'image_restore')); // hit this when restoring.
25
+ add_action('shortpixel/image/convertpng2jpg_after', array($this, 'image_converted'));
26
+ add_action('shortpixel/image/convertpng2jpg_before', array($this, 'remove_remote'));
27
+ add_filter('as3cf_attachment_file_paths', array($this, 'add_webp_paths'));
28
+ add_filter('as3cf_remove_attachment_paths', array($this, 'remove_webp_paths'));
29
+
30
+ add_filter('shortpixel/restore/targetfile', array($this, 'returnOriginalFile'),10,2);
31
+
32
+ add_filter('get_attached_file', function($file, $id)
33
+ {
34
+ if (strpos($file, 's3:/') !== false)
35
+ {
36
+ return get_attached_file($id, true);
37
+ }
38
+ return $file;
39
+ },10, 2);
40
+ }
41
+
42
+ public function addURLforDownload($bool, $url, $host)
43
+ {
44
+ $provider = $this->as3cf->get_provider();
45
+ $provider->get_url_domain();
46
+
47
+ //as3cf_aws_s3_client_args filter?
48
+ return $url;
49
+ }
50
+
51
+ public function returnOriginalFile($file, $attach_id)
52
+ {
53
+ $file = get_attached_file($attach_id, true);
54
+ return $file;
55
+ }
56
+
57
+ public function image_restore($id)
58
+ {
59
+ //$provider_object = $this->as3cf->get_attachment_provider_info($id);
60
+ //$this->as3cf->remove_attachment_files_from_provider($id, $provider_object);
61
+ $this->remove_remote($id);
62
+
63
+ //Log::addDebug('S3Offload - Image restore - ', array($id, $provider_object, get_attached_file($id)));
64
+ // $provider_object['key'] =
65
+
66
+ // add_post_meta( $id, 'amazonS3_info', $provider_object );
67
+ // delete_post_meta( $post_id, 'amazonS3_info' );
68
+
69
+ $this->image_upload($id);
70
+
71
+ }
72
+
73
+ public function remove_remote($id)
74
+ {
75
+ $provider_object = $this->as3cf->get_attachment_provider_info($id);
76
+ $this->as3cf->remove_attachment_files_from_provider($id, $provider_object);
77
+ }
78
+
79
+ public function image_converted($id)
80
+ {
81
+ $fs = new \ShortPixel\FileSystemController();
82
+
83
+ // delete the old file.
84
+ $provider_object = $this->as3cf->get_attachment_provider_info($id);
85
+ // $this->as3cf->remove_attachment_files_from_provider($id, $provider_object);
86
+
87
+ // get some new ones.
88
+ $providerFile = $fs->getFile($provider_object['key']);
89
+ $newFile = $fs->getFile($this->returnOriginalFile(null, $id));
90
+
91
+ // convert
92
+ $newfilemeta = $provider_object['key'];
93
+ if ($providerFile->getExtension() !== $newFile->getExtension())
94
+ {
95
+ $newfilemeta = str_replace($providerFile->getFileName(), $newFile->getFileName(), $newfilemeta);
96
+ Log::addDebug('S3Offload, replacing image in provider meta', array($newfilemeta));
97
+ }
98
+ else {
99
+ Log::addDebug('ProviderFile and NewFile same extension', array($providerFile->getFullPath(), $newFile->getFullPath()));
100
+ }
101
+
102
+ // upload
103
+ $provider_object['key'] = $newfilemeta;
104
+ update_post_meta( $id, 'amazonS3_info', $provider_object );
105
+
106
+ $this->image_upload($id); // delete and reupload
107
+ }
108
+
109
+ public function image_upload($id)
110
+ {
111
+ Log::addDebug('Uploading New Attachment');
112
+ $this->as3cf->upload_attachment($id);
113
+ }
114
+
115
+
116
+ private function getWebpPaths($paths, $check_exists = true)
117
+ {
118
+ $newPaths = array();
119
+ $fs = new FileSystem();
120
+
121
+ foreach($paths as $size => $path)
122
+ {
123
+ $file = $fs->getFile($path);
124
+ $basepath = $file->getFileDir()->getPath();
125
+ $newPaths[$size] = $path;
126
+
127
+ $webpformat1 = $basepath . $file->getFileName() . '.webp';
128
+ $webpformat2 = $basepath . $file->getFileBase() . '.webp';
129
+
130
+ if ($check_exists)
131
+ {
132
+ if (file_exists($webpformat1))
133
+ $newPaths[$size . '_webp'] = $webpformat1;
134
+ }
135
+ else {
136
+ $newPaths[$size . '_webp1'] = $webpformat1;
137
+ }
138
+
139
+ if ($check_exists)
140
+ {
141
+ if(file_exists($webpformat2))
142
+ $newPaths[$size . '_webp'] = $webpformat2;
143
+ }
144
+ else {
145
+ $newPaths[$size . '_webp2'] = $webpformat2;
146
+ }
147
+
148
+ }
149
+
150
+ return $newPaths;
151
+ }
152
+
153
+ /** Get Webp Paths that might be generated and offload them as well.
154
+ * Paths - size : path values
155
+ */
156
+ public function add_webp_paths($paths)
157
+ {
158
+ // Log::addDebug('Received Paths', array($paths));
159
+ $paths = $this->getWebpPaths($paths, true);
160
+ Log::addDebug('Webp Path Founder (S3)', array($paths));
161
+ return $paths;
162
+ }
163
+
164
+ public function remove_webp_paths($paths)
165
+ {
166
+ $paths = $this->getWebpPaths($paths, false);
167
+ Log::addDebug('Remove S3 Paths', array($paths));
168
+ return $paths;
169
+ }
170
+
171
+ }
172
+
173
+ $wpOff = new wpOffload();
class/front/img-to-picture-webp.php CHANGED
@@ -211,7 +211,7 @@ class ShortPixelImgToPictureWebp
211
  . $parts[0].'.webp'
212
  . (isset($parts[1]) ? ' ' . $parts[1] : '');
213
  }
214
- if (file_exists($fileWebPCompat)) {
215
  $srcsetWebP .= (strlen($srcsetWebP) ? ',': '')
216
  .preg_replace('/\.[a-zA-Z0-9]+$/', '.webp', $parts[0])
217
  .(isset($parts[1]) ? ' ' . $parts[1] : '');
211
  . $parts[0].'.webp'
212
  . (isset($parts[1]) ? ' ' . $parts[1] : '');
213
  }
214
+ if (apply_filters( 'shortpixel_image_exists', file_exists($fileWebPCompat), $fileWebPCompat)) {
215
  $srcsetWebP .= (strlen($srcsetWebP) ? ',': '')
216
  .preg_replace('/\.[a-zA-Z0-9]+$/', '.webp', $parts[0])
217
  .(isset($parts[1]) ? ' ' . $parts[1] : '');
class/model/directory_model.php CHANGED
@@ -20,11 +20,31 @@ class DirectoryModel extends ShortPixelModel
20
 
21
  protected $new_directory_permission = 0755;
22
 
23
- /** Creates a directory model object. DirectoryModel directories don't need to exist on FileSystem */
 
 
 
24
  public function __construct($path)
25
  {
26
  //$this->new_directory_permission = octdec(06440);
27
- $this->path = wp_normalize_path(trailingslashit($path));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
  if (file_exists($this->path))
30
  {
@@ -60,23 +80,87 @@ class DirectoryModel extends ShortPixelModel
60
  }
61
 
62
  /** Try to obtain the path, minus the installation directory.
63
- * @return Mixed False if this didn't work, Path as string without basedir if it did.
64
  */
65
  public function getRelativePath()
66
  {
 
67
  $upload_dir = wp_upload_dir(null, false);
68
 
69
- Log::addDebug('Upload Dir - ', array($upload_dir));
70
- $relativePath = str_replace($upload_dir['basedir'], '', $this->getPath());
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
 
72
  // if relativePath has less amount of characters, changes are this worked.
73
- if (strlen($this->getPath()) > strlen($relativePath))
74
  {
75
- return $relativePath;
76
  }
77
  return false;
78
  }
79
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  /** Checks the directory
81
  *
82
  */
@@ -84,7 +168,7 @@ class DirectoryModel extends ShortPixelModel
84
  {
85
  if (! $this->exists())
86
  {
87
- Log::addInfo('Direct does not exists. Try to create recursive ' . $this->path . ' with ' . $this->new_directory_permission);
88
  $result = @mkdir($this->path, $this->new_directory_permission , true);
89
  if (! $result)
90
  {
20
 
21
  protected $new_directory_permission = 0755;
22
 
23
+ /** Creates a directory model object. DirectoryModel directories don't need to exist on FileSystem
24
+ *
25
+ * When a filepath is given, it will remove the file part.
26
+ */
27
  public function __construct($path)
28
  {
29
  //$this->new_directory_permission = octdec(06440);
30
+
31
+ $path = wp_normalize_path($path);
32
+ if (! is_dir($path)) // path is wrong, *or* simply doesn't exist.
33
+ {
34
+ /* Test for file input.
35
+ * If pathinfo is fed a fullpath, it rips of last entry without setting extension, don't further trust.
36
+ * If it's a file extension is set, then trust.
37
+ */
38
+ $pathinfo = pathinfo($path);
39
+ if (isset($pathinfo['extension']))
40
+ {
41
+ $path = $pathinfo['dirname'];
42
+ }
43
+ elseif (is_file($path))
44
+ $path = dirname($path);
45
+ }
46
+
47
+ $this->path = trailingslashit($path);
48
 
49
  if (file_exists($this->path))
50
  {
80
  }
81
 
82
  /** Try to obtain the path, minus the installation directory.
83
+ * @return Mixed False if this didn't work, Path as string without basedir if it did. With trailing slash, without starting slash.
84
  */
85
  public function getRelativePath()
86
  {
87
+ //$_SERVER['DOCUMENT_ROOT'] <!-- another tool.
88
  $upload_dir = wp_upload_dir(null, false);
89
 
90
+ $install_dir = get_home_path();
91
+ if($install_dir == '/') {
92
+ $install_dir = ABSPATH;
93
+ }
94
+
95
+ $install_dir = trailingslashit($install_dir);
96
+ //Log::addDebug('Install Dir - ' . $install_dir);
97
+
98
+ $path = $this->getPath();
99
+ // try to build relativePath without first slash.
100
+ $relativePath = str_replace($install_dir, '', $path);
101
+
102
+ if (! is_dir( $install_dir . $relativePath))
103
+ {
104
+ $test_path = $this->reverseConstructPath($path, $install_dir);
105
+ if ($test_path !== false)
106
+ {
107
+ $relativePath = $test_path;
108
+ }
109
+ else {
110
+ if($test_path = $this->constructUsualDirectories($path))
111
+ {
112
+ $relativePath = $test_path;
113
+ }
114
+
115
+ }
116
+ }
117
 
118
  // if relativePath has less amount of characters, changes are this worked.
119
+ if (strlen($path) > strlen($relativePath))
120
  {
121
+ return ltrim(trailingslashit($relativePath), '/');
122
  }
123
  return false;
124
  }
125
 
126
+ private function reverseConstructPath($path, $install_path)
127
+ {
128
+ $pathar = array_values(array_filter(explode('/', $path))); // array value to reset index
129
+ $parts = array(); //
130
+
131
+ if (is_array($pathar))
132
+ {
133
+ // reverse loop the structure until solid ground is found.
134
+ for ($i = (count($pathar)); $i > 0; $i--)
135
+ {
136
+ $parts[] = $pathar[$i-1];
137
+ $testpath = implode('/', array_reverse($parts));
138
+ if (is_dir($install_path . $testpath)) // if the whole thing exists
139
+ {
140
+ return $testpath;
141
+ }
142
+ }
143
+ }
144
+ return false;
145
+ }
146
+
147
+ /* Last Resort function to just reduce path to various known WorPress paths. */
148
+ private function constructUsualDirectories($path)
149
+ {
150
+ $pathar = array_values(array_filter(explode('/', $path))); // array value to reset index
151
+ $test_path = false;
152
+ if ( ($key = array_search('wp-content', $pathar)) !== false)
153
+ {
154
+ $testpath = implode('/', array_slice($pathar, $key));
155
+ }
156
+ elseif ( ($key = array_search('uploads', $pathar)) !== false)
157
+ {
158
+ $testpath = implode('/', array_slice($pathar, $key));
159
+ }
160
+
161
+ return $testpath;
162
+ }
163
+
164
  /** Checks the directory
165
  *
166
  */
168
  {
169
  if (! $this->exists())
170
  {
171
+ Log::addInfo('Directory does not exists. Try to create recursive ' . $this->path . ' with ' . $this->new_directory_permission);
172
  $result = @mkdir($this->path, $this->new_directory_permission , true);
173
  if (! $result)
174
  {
class/model/environment_model.php CHANGED
@@ -1,6 +1,10 @@
1
  <?php
2
  namespace ShortPixel;
3
 
 
 
 
 
4
  class EnvironmentModel extends ShortPixelModel
5
  {
6
  // Server and PHP
1
  <?php
2
  namespace ShortPixel;
3
 
4
+ /** Loads a few environment variables handy to have nearby
5
+ *
6
+ * Notice - This is meant to be loaded *often*, so it shouldn't do any heavy lifting without caching the results.
7
+ */
8
  class EnvironmentModel extends ShortPixelModel
9
  {
10
  // Server and PHP
class/model/file_model.php CHANGED
@@ -25,6 +25,7 @@ class FileModel extends ShortPixelModel
25
  // File Status
26
  protected $exists = false;
27
  protected $is_writable = false;
 
28
  protected $status;
29
 
30
  protected $backupDirectory;
@@ -62,11 +63,13 @@ class FileModel extends ShortPixelModel
62
  $this->filebase = isset($info['filename']) ? $info['filename'] : null; // only filename
63
  $this->extension = isset($info['extension']) ? $info['extension'] : null; // only (last) extension
64
  $this->directory = isset($info['dirname']) ? new DirectoryModel($info['dirname']) : null;
65
- $this->is_writable = is_writable($this->fullpath);
 
66
  }
67
  else {
68
  $this->exists = false;
69
- $this->writable = false;
 
70
 
71
  if (is_null($this->filename))
72
  $this->filename = basename($this->fullpath);
@@ -88,6 +91,12 @@ class FileModel extends ShortPixelModel
88
  return $this->is_writable;
89
  }
90
 
 
 
 
 
 
 
91
  public function hasBackup()
92
  {
93
  $directory = $this->getBackupDirectory();
@@ -132,6 +141,7 @@ class FileModel extends ShortPixelModel
132
  {
133
  $sourcePath = $this->getFullPath();
134
  $destinationPath = $destination->getFullPath();
 
135
 
136
  if (! strlen($sourcePath) > 0 || ! strlen($destinationPath) > 0)
137
  {
@@ -172,9 +182,10 @@ class FileModel extends ShortPixelModel
172
  public function delete()
173
  {
174
  \wp_delete_file($this->fullpath); // delete file hook via wp_delet_file
 
 
175
  if (! file_exists($this->fullpath))
176
  {
177
- $this->setFileInfo(); // update info
178
  return true;
179
  }
180
  else {
@@ -235,6 +246,7 @@ class FileModel extends ShortPixelModel
235
  */
236
  protected function processPath($path)
237
  {
 
238
  $path = trim($path);
239
 
240
  if ($this->pathIsUrl($path))
@@ -251,6 +263,8 @@ class FileModel extends ShortPixelModel
251
  if (strpos($path, ABSPATH) === false && strpos($path, $this->getUploadPath()) === false)
252
  $path = $this->relativeToFullPath($path);
253
 
 
 
254
  /* This needs some check here on malformed path's, but can't be test for existing since that's not a requirement.
255
  if (file_exists($path) === false) // failed to process path to something workable.
256
  {
@@ -308,6 +322,12 @@ class FileModel extends ShortPixelModel
308
  if (strlen($path) == 0)
309
  return $path;
310
 
 
 
 
 
 
 
311
  // Test if our 'relative' path is not a path to /tmp directory.
312
 
313
  // This ini value might not exist.
@@ -325,16 +345,12 @@ class FileModel extends ShortPixelModel
325
  return $path;
326
  }
327
 
328
- // if the file plainly exists, it's usable /**
329
- if (file_exists($path))
330
- {
331
- return $path;
332
- }
333
 
334
  // this is probably a bit of a sharp corner to take.
335
  // if path starts with / remove it due to trailingslashing ABSPATH
336
  $path = ltrim($path, '/');
337
  $fullpath = trailingslashit(ABSPATH) . $path;
 
338
  return $fullpath;
339
  }
340
 
25
  // File Status
26
  protected $exists = false;
27
  protected $is_writable = false;
28
+ protected $is_readable = false;
29
  protected $status;
30
 
31
  protected $backupDirectory;
63
  $this->filebase = isset($info['filename']) ? $info['filename'] : null; // only filename
64
  $this->extension = isset($info['extension']) ? $info['extension'] : null; // only (last) extension
65
  $this->directory = isset($info['dirname']) ? new DirectoryModel($info['dirname']) : null;
66
+ $this->is_writable();
67
+ $this->is_readable();
68
  }
69
  else {
70
  $this->exists = false;
71
+ $this->is_writable = false;
72
+ $this->is_readable = false;
73
 
74
  if (is_null($this->filename))
75
  $this->filename = basename($this->fullpath);
91
  return $this->is_writable;
92
  }
93
 
94
+ public function is_readable()
95
+ {
96
+ $this->is_readable = is_readable($this->fullpath);
97
+ return $this->is_readable;
98
+ }
99
+
100
  public function hasBackup()
101
  {
102
  $directory = $this->getBackupDirectory();
141
  {
142
  $sourcePath = $this->getFullPath();
143
  $destinationPath = $destination->getFullPath();
144
+ Log::addDebug("Copy from $sourcePath to $destinationPath ");
145
 
146
  if (! strlen($sourcePath) > 0 || ! strlen($destinationPath) > 0)
147
  {
182
  public function delete()
183
  {
184
  \wp_delete_file($this->fullpath); // delete file hook via wp_delet_file
185
+ $this->setFileInfo(); // update info
186
+
187
  if (! file_exists($this->fullpath))
188
  {
 
189
  return true;
190
  }
191
  else {
246
  */
247
  protected function processPath($path)
248
  {
249
+ $original_path = $path;
250
  $path = trim($path);
251
 
252
  if ($this->pathIsUrl($path))
263
  if (strpos($path, ABSPATH) === false && strpos($path, $this->getUploadPath()) === false)
264
  $path = $this->relativeToFullPath($path);
265
 
266
+
267
+ $path = apply_filters('shortpixel/filesystem/processFilePath', $path, $original_path);
268
  /* This needs some check here on malformed path's, but can't be test for existing since that's not a requirement.
269
  if (file_exists($path) === false) // failed to process path to something workable.
270
  {
322
  if (strlen($path) == 0)
323
  return $path;
324
 
325
+ // if the file plainly exists, it's usable /**
326
+ if (file_exists($path))
327
+ {
328
+ return $path;
329
+ }
330
+
331
  // Test if our 'relative' path is not a path to /tmp directory.
332
 
333
  // This ini value might not exist.
345
  return $path;
346
  }
347
 
 
 
 
 
 
348
 
349
  // this is probably a bit of a sharp corner to take.
350
  // if path starts with / remove it due to trailingslashing ABSPATH
351
  $path = ltrim($path, '/');
352
  $fullpath = trailingslashit(ABSPATH) . $path;
353
+ // We can't test for file_exists here, since file_model allows non-existing files.
354
  return $fullpath;
355
  }
356
 
class/shortpixel-png2jpg.php CHANGED
@@ -5,6 +5,9 @@
5
  * Time: 13:44
6
  */
7
 
 
 
 
8
  //TODO decouple from directly using WP metadata, in order to be able to use it for custom images
9
  class ShortPixelPng2Jpg {
10
  private $_settings = null;
@@ -230,7 +233,7 @@ class ShortPixelPng2Jpg {
230
  // set a temporary error in order to make sure user gets something if the image failed from memory limit.
231
  if( isset($meta['ShortPixel']['Retries']) && $meta['ShortPixel']['Retries'] > 3
232
  && isset($meta['ShortPixel']['ErrCode']) && $meta['ShortPixel']['ErrCode'] == ShortPixelAPI::ERR_PNG2JPG_MEMORY) {
233
- WPShortPixel::log("PNG2JPG too many memory failures!");
234
  throw new Exception('Not enough memory to convert from PNG to JPG.', ShortPixelAPI::ERR_PNG2JPG_MEMORY);
235
  }
236
  $meta['ShortPixelImprovement'] = 'Error: <i>Not enough memory to convert from PNG to JPG.</i>';
@@ -249,13 +252,13 @@ class ShortPixelPng2Jpg {
249
  $doConvert = $retC['notTransparent'];
250
  }
251
  if (!$doConvert) {
252
- WPShortPixel::log("PNG2JPG not a PNG");
253
  return $meta; //cannot convert it
254
  }
255
 
256
- WPShortPixel::log(" CONVERTING MAIN: $imagePath");
257
  $retMain = $this->doConvertPng2Jpg(array('file' => $imagePath, 'url' => false, 'type' => 'image/png'), $this->_settings->backupImages, false, isset($retC['img']) ? $retC['img'] : false);
258
- WPShortPixel::log("PNG2JPG doConvert Main RETURNED " . json_encode($retMain));
259
  $ret = $retMain->params;
260
  $toUnlink = array();
261
  $toReplace = array();
@@ -269,29 +272,30 @@ class ShortPixelPng2Jpg {
269
 
270
  if ($ret['type'] == 'image/jpeg') {
271
  $toUnlink[] = $retMain->unlink;
 
272
  //convert to the new URLs the urls in the existing posts.
273
  $baseRelPath = trailingslashit(dirname($image));
274
  $toReplace[self::removeUrlProtocol($imageUrl)] = $baseUrl . $baseRelPath . wp_basename($ret['file']);
275
  $pngSize = $ret['png_size'];
276
  $jpgSize = $ret['jpg_size'];
277
- WPShortPixel::log(" IMAGE PATH: $imagePath");
278
  $imagePath = isset($ret['original_file']) ? $ret['original_file'] : $imagePath;
279
- WPShortPixel::log(" SET IMAGE PATH: $imagePath");
280
 
281
  //conversion succeeded for the main image, update meta and proceed to thumbs. (It could also not succeed if the converted file is not smaller)
282
  $duplicates = $this->updateFileAlsoInWPMLDuplicates($ID, $meta, str_replace($basePath, '', $ret['file']));
283
- WPShortPixel::log(" WPML duplicates: " . json_encode($duplicates));
284
 
285
  $originalSizes = isset($meta['sizes']) ? $meta['sizes'] : array();
286
  $filesConverted = array();
287
  foreach($meta['sizes'] as $size => $info) {
288
  if(isset($filesConverted[$info['file']])) {
289
- WPShortPixel::log("PNG2JPG DUPLICATED THUMB: " . $size);
290
  if($filesConverted[$info['file']] === false) {
291
- WPShortPixel::log("PNG2JPG DUPLICATED THUMB not converted");
292
  continue;
293
  }
294
- WPShortPixel::log("PNG2JPG DUPLICATED THUMB already converted");
295
  $rett = $filesConverted[$info['file']];
296
  } else {
297
  $retThumb = $this->doConvertPng2Jpg(array('file' => $basePath . $baseRelPath . $info['file'], 'url' => false, 'type' => 'image/png'),
@@ -299,15 +303,15 @@ class ShortPixelPng2Jpg {
299
  $rett = $retThumb->params;
300
  }
301
 
302
- WPShortPixel::log("PNG2JPG doConvert thumb RETURNED " . json_encode($rett));
303
  if ($rett['type'] == 'image/jpeg') {
304
  $toUnlink[] = $retThumb->unlink;
305
- WPShortPixel::log("PNG2JPG thumb is jpg");
306
  $pngSize += $rett['png_size'];
307
  $jpgSize += $rett['jpg_size'];
308
- WPShortPixel::log("PNG2JPG total PNG size: $pngSize total JPG size: $jpgSize");
309
  $originalSizes[$size]['file'] = wp_basename($rett['file'], '.jpg') . '.png';
310
- WPShortPixel::log("PNG2JPG thumb original: " . $originalSizes[$size]['file']);
311
  $toReplace[$baseUrl . $baseRelPath . $info['file']] = $baseUrl . $baseRelPath . wp_basename($rett['file']);
312
 
313
  $filesConverted[$info['file']] = $rett;
@@ -321,17 +325,22 @@ class ShortPixelPng2Jpg {
321
  'optimizationPercent' => round(100.0 * (1.00 - $jpgSize / $pngSize)));
322
  //wp_update_attachment_metadata($ID, $meta);
323
  update_post_meta($ID, '_wp_attachment_metadata', $meta);
324
- WPShortPixel::log("Updated meta: " . json_encode($meta));
 
325
  }
326
 
327
  self::png2JpgUpdateUrls(array(), $toReplace);
 
 
328
  foreach($toUnlink as $unlink) {
329
  if($unlink) {
330
- WPShortPixel::log("PNG2JPG unlink $unlink");
331
- @unlink($unlink);
 
 
332
  }
333
  }
334
- WPShortPixel::log("PNG2JPG done. Return: " . json_encode($meta));
335
 
336
  return $meta;
337
  }
@@ -500,4 +509,4 @@ class ShortPixelPng2Jpg {
500
  }
501
  return (object)array('data' => $data, 'replaced' => $replaced);
502
  }
503
- }
5
  * Time: 13:44
6
  */
7
 
8
+ use ShortPixel\ShortPixelLogger\ShortPixelLogger as Log;
9
+
10
+
11
  //TODO decouple from directly using WP metadata, in order to be able to use it for custom images
12
  class ShortPixelPng2Jpg {
13
  private $_settings = null;
233
  // set a temporary error in order to make sure user gets something if the image failed from memory limit.
234
  if( isset($meta['ShortPixel']['Retries']) && $meta['ShortPixel']['Retries'] > 3
235
  && isset($meta['ShortPixel']['ErrCode']) && $meta['ShortPixel']['ErrCode'] == ShortPixelAPI::ERR_PNG2JPG_MEMORY) {
236
+ Log::addWarn("PNG2JPG too many memory failures!");
237
  throw new Exception('Not enough memory to convert from PNG to JPG.', ShortPixelAPI::ERR_PNG2JPG_MEMORY);
238
  }
239
  $meta['ShortPixelImprovement'] = 'Error: <i>Not enough memory to convert from PNG to JPG.</i>';
252
  $doConvert = $retC['notTransparent'];
253
  }
254
  if (!$doConvert) {
255
+ Log::addDebug("PNG2JPG not a PNG");
256
  return $meta; //cannot convert it
257
  }
258
 
259
+ Log::addDebug(" CONVERTING MAIN: $imagePath");
260
  $retMain = $this->doConvertPng2Jpg(array('file' => $imagePath, 'url' => false, 'type' => 'image/png'), $this->_settings->backupImages, false, isset($retC['img']) ? $retC['img'] : false);
261
+ Log::addDebug("PNG2JPG doConvert Main RETURNED " . json_encode($retMain));
262
  $ret = $retMain->params;
263
  $toUnlink = array();
264
  $toReplace = array();
272
 
273
  if ($ret['type'] == 'image/jpeg') {
274
  $toUnlink[] = $retMain->unlink;
275
+ do_action('shortpixel/image/convertpng2jpg_before', $ID, $meta);
276
  //convert to the new URLs the urls in the existing posts.
277
  $baseRelPath = trailingslashit(dirname($image));
278
  $toReplace[self::removeUrlProtocol($imageUrl)] = $baseUrl . $baseRelPath . wp_basename($ret['file']);
279
  $pngSize = $ret['png_size'];
280
  $jpgSize = $ret['jpg_size'];
281
+ Log::addDebug(" IMAGE PATH: $imagePath");
282
  $imagePath = isset($ret['original_file']) ? $ret['original_file'] : $imagePath;
283
+ Log::addDebug(" SET IMAGE PATH: $imagePath");
284
 
285
  //conversion succeeded for the main image, update meta and proceed to thumbs. (It could also not succeed if the converted file is not smaller)
286
  $duplicates = $this->updateFileAlsoInWPMLDuplicates($ID, $meta, str_replace($basePath, '', $ret['file']));
287
+ Log::addDebug(" WPML duplicates: " . json_encode($duplicates));
288
 
289
  $originalSizes = isset($meta['sizes']) ? $meta['sizes'] : array();
290
  $filesConverted = array();
291
  foreach($meta['sizes'] as $size => $info) {
292
  if(isset($filesConverted[$info['file']])) {
293
+ Log::addDebug("PNG2JPG DUPLICATED THUMB: " . $size);
294
  if($filesConverted[$info['file']] === false) {
295
+ Log::addDebug("PNG2JPG DUPLICATED THUMB not converted");
296
  continue;
297
  }
298
+ Log::addDebug("PNG2JPG DUPLICATED THUMB already converted");
299
  $rett = $filesConverted[$info['file']];
300
  } else {
301
  $retThumb = $this->doConvertPng2Jpg(array('file' => $basePath . $baseRelPath . $info['file'], 'url' => false, 'type' => 'image/png'),
303
  $rett = $retThumb->params;
304
  }
305
 
306
+ Log::addDebug("PNG2JPG doConvert thumb RETURNED " . json_encode($rett));
307
  if ($rett['type'] == 'image/jpeg') {
308
  $toUnlink[] = $retThumb->unlink;
309
+ Log::addDebug("PNG2JPG thumb is jpg");
310
  $pngSize += $rett['png_size'];
311
  $jpgSize += $rett['jpg_size'];
312
+ Log::addDebug("PNG2JPG total PNG size: $pngSize total JPG size: $jpgSize");
313
  $originalSizes[$size]['file'] = wp_basename($rett['file'], '.jpg') . '.png';
314
+ Log::addDebug("PNG2JPG thumb original: " . $originalSizes[$size]['file']);
315
  $toReplace[$baseUrl . $baseRelPath . $info['file']] = $baseUrl . $baseRelPath . wp_basename($rett['file']);
316
 
317
  $filesConverted[$info['file']] = $rett;
325
  'optimizationPercent' => round(100.0 * (1.00 - $jpgSize / $pngSize)));
326
  //wp_update_attachment_metadata($ID, $meta);
327
  update_post_meta($ID, '_wp_attachment_metadata', $meta);
328
+ Log::addDebug("Updated meta: " . json_encode($meta));
329
+ do_action('shortpixel/image/convertpng2jpg_after', $ID, $meta);
330
  }
331
 
332
  self::png2JpgUpdateUrls(array(), $toReplace);
333
+ $fs = new \ShortPixel\FileSystemController();
334
+
335
  foreach($toUnlink as $unlink) {
336
  if($unlink) {
337
+ Log::addDebug("PNG2JPG remove file $unlink");
338
+ $fileObj = $fs->getFile($unlink);
339
+ $fileObj->delete();
340
+ // @unlink($unlink);
341
  }
342
  }
343
+ Log::addDebug("PNG2JPG done. Return: " . json_encode($meta));
344
 
345
  return $meta;
346
  }
509
  }
510
  return (object)array('data' => $data, 'replaced' => $replaced);
511
  }
512
+ }
class/view/settings/part-statistics.php CHANGED
@@ -67,7 +67,7 @@ $quotaData = $this->quotaData;
67
  </tr>
68
  <tr>
69
  <th scope="row">
70
- <?php _e('Bandwith* saved by ShortPixel:','shortpixel-image-optimiser');?>
71
  </th>
72
  <td><?php echo($view->savedBandwidth);?></td>
73
  </tr>
67
  </tr>
68
  <tr>
69
  <th scope="row">
70
+ <?php _e('Bandwidth* saved by ShortPixel:','shortpixel-image-optimiser');?>
71
  </th>
72
  <td><?php echo($view->savedBandwidth);?></td>
73
  </tr>
class/wp-short-pixel.php CHANGED
@@ -74,6 +74,8 @@ class WPShortPixel {
74
  //for cleaning up the WebP images when an attachment is deleted
75
  add_action( 'delete_attachment', array( &$this, 'onDeleteImage') );
76
 
 
 
77
  //for NextGen
78
  if($this->_settings->hasCustomFolders) {
79
  add_filter( 'ngg_manage_images_columns', array( &$this, 'nggColumns' ) );
@@ -465,24 +467,11 @@ class WPShortPixel {
465
 
466
  static function log($message, $force = false) {
467
  Log::addInfo($message);
468
- /*
469
- if (SHORTPIXEL_DEBUG === true || $force) {
470
- if (is_array($message) || is_object($message)) {
471
- self::doLog(print_r($message, true), $force);
472
- } else {
473
- self::doLog($message, $force);
474
- }
475
- } */
476
  }
477
 
478
  /** [TODO] This should report to the Shortpixel Logger **/
479
  static protected function doLog($message, $force = false) {
480
- // Log::addInfo($message);
481
- /*if(defined('SHORTPIXEL_DEBUG_TARGET') || $force) {
482
- file_put_contents(SHORTPIXEL_BACKUP_FOLDER . "/shortpixel_log", '[' . date('Y-m-d H:i:s') . "] $message\n", FILE_APPEND);
483
- } else {
484
- error_log($message);
485
- }*/
486
  }
487
 
488
  function headCSS() {
@@ -808,6 +797,7 @@ class WPShortPixel {
808
  $itemHandler = new ShortPixelMetaFacade($ID);
809
  $itemHandler->setRawMeta($meta);
810
  //that's a hack for watermarking plugins, don't send the image right away to processing, only add it in the queue
 
811
  include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
812
  if( !is_plugin_active('image-watermark/image-watermark.php')
813
  && !is_plugin_active('amazon-s3-and-cloudfront/wordpress-s3.php')
@@ -1643,7 +1633,10 @@ class WPShortPixel {
1643
  return 0;
1644
  }
1645
 
 
1646
  $meta = $itemHandler->getMeta();
 
 
1647
  $thumbs = WpShortPixelMediaLbraryAdapter::findThumbs($meta->getPath());
1648
 
1649
  $fs = new \ShortPixel\FileSystemController();
@@ -1654,8 +1647,9 @@ class WPShortPixel {
1654
 
1655
  // no thumbs, then done.
1656
  if (count($foundThumbs) == 0)
 
1657
  return 0;
1658
-
1659
  //first identify which thumbs are not in the sizes
1660
  $sizes = $meta->getThumbs();
1661
  $mimeType = false;
@@ -1674,21 +1668,18 @@ class WPShortPixel {
1674
  if(isset($size['mime-type'])) { //situation from support case #9351 Ramesh Mehay
1675
  $mimeType = $size['mime-type'];
1676
  }
1677
- Log::addDebug('Add Unlisted, add size' . $sizeFile->getFullPath() );
1678
  $allSizes[] = $sizeFile;
1679
  }
1680
 
1681
  foreach($foundThumbs as $id => $found) {
1682
  $foundFile = $fs->getFile($found);
1683
 
1684
-
1685
  foreach($allSizes as $sizeFile) {
1686
  if ($sizeFile->getExtension() !== $foundFile->getExtension())
1687
  {
1688
- continue;
1689
  }
1690
-
1691
- if ($sizeFile->getFileName() === $foundFile->getFileName())
1692
  {
1693
  $foundThumbs[$id] = false;
1694
  }
@@ -1708,6 +1699,8 @@ class WPShortPixel {
1708
  if($found !== false) {
1709
  Log::addDebug('Adding File to sizes -> ' . $found);
1710
  $size = getimagesize($found);
 
 
1711
  $sizes[ShortPixelMeta::FOUND_THUMB_PREFIX . str_pad("".$ind, 2, '0', STR_PAD_LEFT)]= array( // it's a file that has no corresponding thumb so it's the WEBP for the main file
1712
  'file' => ShortPixelAPI::MB_basename($found),
1713
  'width' => $size[0],
@@ -1736,12 +1729,14 @@ class WPShortPixel {
1736
  }
1737
  }
1738
 
 
 
1739
  //WpShortPixelMediaLbraryAdapter::cleanupFoundThumbs($itemHandler);
1740
  $URLsAndPATHs = $this->getURLsAndPATHs($itemHandler, NULL, $onlyThumbs);
 
1741
 
1742
- $meta = $itemHandler->getMeta();
1743
  //find thumbs that are not listed in the metadata and add them in the sizes array
1744
- $changes = $this->addUnlistedThumbs($itemHandler);
1745
 
1746
  //find any missing thumbs files and mark them as such
1747
  $miss = $meta->getThumbsMissing();
@@ -1752,10 +1747,31 @@ class WPShortPixel {
1752
  $meta->setThumbsMissing($URLsAndPATHs['sizesMissing']);
1753
  $itemHandler->updateMeta();
1754
  }
1755
- //die(var_dump($itemHandler));
 
 
1756
  $refresh = $meta->getStatus() === ShortPixelAPI::ERR_INCORRECT_FILE_SIZE;
1757
- //echo("URLS: "); die(var_dump($URLsAndPATHs));
1758
- $itemHandler->setWaitingProcessing();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1759
  $this->_apiInterface->doRequests($URLsAndPATHs['URLs'], false, $itemHandler,
1760
  $compressionType === false ? $this->_settings->compressionType : $compressionType, $refresh);//send a request, do NOT wait for response
1761
  //$meta = wp_get_attachment_metadata($ID);
@@ -1815,6 +1831,7 @@ class WPShortPixel {
1815
  if($this->isProcessable($imageId)) {
1816
  $this->prioQ->push($imageId);
1817
  $itemHandler = new ShortPixelMetaFacade($imageId);
 
1818
  $path = get_attached_file($imageId);//get the full file PATH
1819
  if(!$manual && 'pdf' === pathinfo($path, PATHINFO_EXTENSION) && !$this->_settings->optimizePdfs) {
1820
  $ret = array("Status" => ShortPixelAPI::STATUS_SKIP, "Message" => $imageId);
@@ -1826,6 +1843,7 @@ class WPShortPixel {
1826
  $itemHandler->getMeta();
1827
  $errCode = $e->getCode() < 0 ? $e->getCode() : ShortPixelAPI::ERR_FILE_NOT_FOUND;
1828
  $itemHandler->setError($errCode, $e->getMessage());
 
1829
  $ret = array("Status" => ShortPixelAPI::STATUS_FAIL, "Message" => $e->getMessage());
1830
  }
1831
  }
@@ -2020,7 +2038,13 @@ class WPShortPixel {
2020
  protected function doRestore($attachmentID, $rawMeta = null) {
2021
  do_action("shortpixel_before_restore_image", $attachmentID);
2022
 
2023
- $file = $origFile = get_attached_file($attachmentID);
 
 
 
 
 
 
2024
 
2025
  $itemHandler = new ShortPixelMetaFacade($attachmentID);
2026
  if($rawMeta) {
@@ -2037,29 +2061,50 @@ class WPShortPixel {
2037
  return false;
2038
  }
2039
 
2040
- $pathInfo = pathinfo($file);
2041
  $sizes = isset($rawMeta["sizes"]) ? $rawMeta["sizes"] : array();
 
 
 
 
 
2042
 
2043
  //check if the images were converted from PNG
2044
  $png2jpgMain = isset($rawMeta['ShortPixelPng2Jpg']['originalFile']) ? $rawMeta['ShortPixelPng2Jpg']['originalFile'] : false;
2045
- $bkFolder = $this->getBackupFolderAny($file, $sizes);
2046
  $toReplace = array();
 
 
2047
  if($png2jpgMain) {
2048
  $png2jpgSizes = $png2jpgMain ? $rawMeta['ShortPixelPng2Jpg']['originalSizes'] : array();
2049
- $image = $rawMeta['file'];
2050
- $imageUrl = wp_get_attachment_url($attachmentID);
2051
- $baseUrl = ShortPixelPng2Jpg::removeUrlProtocol(trailingslashit(str_replace($image, "", $imageUrl))); //make the base url protocol agnostic if it's not already
2052
- $baseRelPath = trailingslashit(dirname($image));
 
 
 
 
 
 
 
 
 
 
 
2053
  $toReplace[ShortPixelPng2Jpg::removeUrlProtocol($imageUrl)] = $baseUrl . $baseRelPath . wp_basename($png2jpgMain);
2054
  foreach($sizes as $key => $size) {
2055
  if(isset($png2jpgSizes[$key])) {
2056
  $toReplace[$baseUrl . $baseRelPath . $size['file']] = $baseUrl . $baseRelPath . wp_basename($png2jpgSizes[$key]['file']);
2057
  }
2058
  }
2059
- $file = $png2jpgMain;
 
2060
  $sizes = $png2jpgSizes;
 
 
 
2061
  }
2062
- $bkFile = trailingslashit($bkFolder) . ShortPixelAPI::MB_basename($file);
2063
 
2064
  //first check if the file is readable by the current user - otherwise it will be unaccessible for the web browser
2065
  // - collect the thumbs paths in the process
@@ -2070,55 +2115,98 @@ class WPShortPixel {
2070
  $this->_settings->bulkLastStatus = null;
2071
  }
2072
  }
2073
- if(file_exists($bkFile)) {
2074
- if(!is_readable($bkFile) || (file_exists($file) && !$this->setFilePerms($file)) ) {
2075
  $this->throwNotice('generic-err',
2076
- sprintf(__("File %s cannot be restored due to lack of permissions, please contact your hosting provider to assist you in fixing this.",'shortpixel-image-optimiser'),
2077
- (is_readable($bkFile) ? "" : "$bkFile and ") . "$file"));
 
2078
  return false;
2079
  }
2080
  $bkCount++;
2081
  $main = true;
2082
  }
2083
  $thumbsPaths = array();
2084
- if($bkFolder && !empty($rawMeta['file']) && count($sizes) ) {
 
 
2085
  foreach($sizes as $size => $imageData) {
2086
- $dest = $pathInfo['dirname'] . '/' . $imageData['file'];
2087
- $source = trailingslashit($bkFolder) . $imageData['file'];
2088
- if(!file_exists($source)) continue; // if thumbs were not optimized, then the backups will not be there.
2089
- if(!$this->setFilePerms($source) || (file_exists($dest) && !$this->setFilePerms($dest))) {
2090
- $failedFile = ($this->setFilePerms($bkFile) ? $file : $bkFile);
 
 
2091
  $this->throwNotice('generic-err',
2092
- sprintf(__("File %s cannot be restored due to lack of permissions, please contact your hosting provider to assist you in fixing this.",'shortpixel-image-optimiser'),
2093
  "$failedFile (current permissions: " . sprintf("%o", fileperms($failedFile)) . ")"));
2094
  return false;
2095
  }
2096
  $bkCount++;
2097
- $thumbsPaths[$source] = $dest;
2098
  }
2099
  }
2100
  if(!$bkCount) {
2101
  $this->throwNotice('generic-err', __("No backup files found. Restore not performed.",'shortpixel-image-optimiser'));
 
2102
  return false;
2103
  }
 
2104
  //either backups exist, or there was an error when trying to optimize, so it's normal no backup is present
 
 
 
 
2105
  try {
2106
  $width = false;
2107
  if($bkCount) { // backups, if exist
2108
  //main file
2109
  if($main) {
2110
- $this->renameWithRetina($bkFile, $file);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2111
  }
2112
  //getSize to update meta if image was resized by ShortPixel
2113
- if(file_exists($file)) {
2114
- $size = getimagesize($file);
2115
  $width = $size[0];
2116
  $height = $size[1];
2117
  }
2118
 
2119
  //overwriting thumbnails
2120
- foreach($thumbsPaths as $source => $destination) {
2121
- $this->renameWithRetina($source, $destination);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2122
  }
2123
  }
2124
 
@@ -2141,7 +2229,7 @@ class WPShortPixel {
2141
  $crtMeta['height'] = $height;
2142
  }
2143
  if($png2jpgMain) {
2144
- $crtMeta['file'] = trailingslashit(dirname($crtMeta['file'])) . ShortPixelAPI::MB_basename($file);
2145
  update_attached_file($ID, $crtMeta['file']);
2146
  if($png2jpgSizes && count($png2jpgSizes)) {
2147
  $crtMeta['sizes'] = $png2jpgSizes;
@@ -2188,6 +2276,7 @@ class WPShortPixel {
2188
 
2189
  /**
2190
  * used to store a notice to be displayed after the redirect, for ex. when having an error restoring.
 
2191
  * @param string $when
2192
  * @param string $extra
2193
  */
@@ -2211,17 +2300,6 @@ class WPShortPixel {
2211
  return false;
2212
  }
2213
 
2214
- protected function renameWithRetina($bkFile, $file) {
2215
- @rename($bkFile, $file);
2216
- @rename($this->retinaName($bkFile), $this->retinaName($file));
2217
-
2218
- }
2219
-
2220
- protected function retinaName($file) {
2221
- $ext = pathinfo($file, PATHINFO_EXTENSION);
2222
- return substr($file, 0, strlen($file) - 1 - strlen($ext)) . "@2x." . $ext;
2223
- }
2224
-
2225
  /** Restores a non-media-library image
2226
  * @param int $ID image_id, without any prefixes
2227
  */
@@ -3218,6 +3296,20 @@ class WPShortPixel {
3218
  : 0;
3219
  }
3220
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3221
  /**
3222
  *
3223
  * @param type $apiKey
@@ -3404,13 +3496,20 @@ class WPShortPixel {
3404
 
3405
  $file = get_attached_file($id);
3406
  $data = ShortPixelMetaFacade::sanitizeMeta(wp_get_attachment_metadata($id));
 
 
3407
 
3408
- if($extended && isset($_GET['SHORTPIXEL_DEBUG'])) {
3409
  // var_dump($data);
3410
- var_dump(wp_get_attachment_url($id));
 
 
3411
  echo('<br><br>' . json_encode(ShortPixelMetaFacade::getWPMLDuplicates($id)));
3412
- echo('<br><br>'); print_r($data); echo ''; //json_encode($data))
3413
- echo('<br><br>');
 
 
 
3414
  }
3415
 
3416
  $fileExtension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
@@ -3531,7 +3630,7 @@ class WPShortPixel {
3531
  /**
3532
  * return the thumbnails that remain to optimize and the total count of sizes registered in metadata (and not excluded)
3533
  * @param $data @todo Define what is data
3534
- * @param $file
3535
  * @return array Array of Thumbs to Optimize - only the filename - , and count of sizes not excluded ...
3536
  */
3537
  function getThumbsToOptimize($data, $filepath) {
@@ -3562,7 +3661,6 @@ class WPShortPixel {
3562
  continue;
3563
  }
3564
 
3565
-
3566
  if(!in_array($size, $exclude) && !in_array($file->getFileName(), $thumbsOptList)) {
3567
  $thumbsToOptimizeList[] = $file->getFileName();
3568
  }
@@ -3703,6 +3801,7 @@ class WPShortPixel {
3703
  }
3704
 
3705
  /** Removes webp and backup from specified paths
 
3706
  */
3707
  public function deleteBackupsAndWebPs($paths) {
3708
  /**
@@ -3927,7 +4026,7 @@ class WPShortPixel {
3927
  static public function folderSize($path) {
3928
  $total_size = 0;
3929
  if(file_exists($path)) {
3930
- $files = scandir($path);
3931
  } else {
3932
  return $total_size;
3933
  }
74
  //for cleaning up the WebP images when an attachment is deleted
75
  add_action( 'delete_attachment', array( &$this, 'onDeleteImage') );
76
 
77
+ add_action('mime_types', array($this, 'addWebpMime'));
78
+
79
  //for NextGen
80
  if($this->_settings->hasCustomFolders) {
81
  add_filter( 'ngg_manage_images_columns', array( &$this, 'nggColumns' ) );
467
 
468
  static function log($message, $force = false) {
469
  Log::addInfo($message);
 
 
 
 
 
 
 
 
470
  }
471
 
472
  /** [TODO] This should report to the Shortpixel Logger **/
473
  static protected function doLog($message, $force = false) {
474
+ Log::addInfo($message);
 
 
 
 
 
475
  }
476
 
477
  function headCSS() {
797
  $itemHandler = new ShortPixelMetaFacade($ID);
798
  $itemHandler->setRawMeta($meta);
799
  //that's a hack for watermarking plugins, don't send the image right away to processing, only add it in the queue
800
+ // @todo Unhack the hack
801
  include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
802
  if( !is_plugin_active('image-watermark/image-watermark.php')
803
  && !is_plugin_active('amazon-s3-and-cloudfront/wordpress-s3.php')
1633
  return 0;
1634
  }
1635
 
1636
+ $itemHandler->removeSPFoundMeta(); // remove all found meta. If will be re-added here every time.
1637
  $meta = $itemHandler->getMeta();
1638
+
1639
+ Log::addDebug('Finding Thumbs on path' . $meta->getPath());
1640
  $thumbs = WpShortPixelMediaLbraryAdapter::findThumbs($meta->getPath());
1641
 
1642
  $fs = new \ShortPixel\FileSystemController();
1647
 
1648
  // no thumbs, then done.
1649
  if (count($foundThumbs) == 0)
1650
+ {
1651
  return 0;
1652
+ }
1653
  //first identify which thumbs are not in the sizes
1654
  $sizes = $meta->getThumbs();
1655
  $mimeType = false;
1668
  if(isset($size['mime-type'])) { //situation from support case #9351 Ramesh Mehay
1669
  $mimeType = $size['mime-type'];
1670
  }
 
1671
  $allSizes[] = $sizeFile;
1672
  }
1673
 
1674
  foreach($foundThumbs as $id => $found) {
1675
  $foundFile = $fs->getFile($found);
1676
 
 
1677
  foreach($allSizes as $sizeFile) {
1678
  if ($sizeFile->getExtension() !== $foundFile->getExtension())
1679
  {
1680
+ $foundThumbs[$id] = false;
1681
  }
1682
+ elseif ($sizeFile->getFileName() === $foundFile->getFileName())
 
1683
  {
1684
  $foundThumbs[$id] = false;
1685
  }
1699
  if($found !== false) {
1700
  Log::addDebug('Adding File to sizes -> ' . $found);
1701
  $size = getimagesize($found);
1702
+ Log::addDebug('Add Unlisted, add size' . $found );
1703
+
1704
  $sizes[ShortPixelMeta::FOUND_THUMB_PREFIX . str_pad("".$ind, 2, '0', STR_PAD_LEFT)]= array( // it's a file that has no corresponding thumb so it's the WEBP for the main file
1705
  'file' => ShortPixelAPI::MB_basename($found),
1706
  'width' => $size[0],
1729
  }
1730
  }
1731
 
1732
+ $meta = $itemHandler->getMeta();
1733
+
1734
  //WpShortPixelMediaLbraryAdapter::cleanupFoundThumbs($itemHandler);
1735
  $URLsAndPATHs = $this->getURLsAndPATHs($itemHandler, NULL, $onlyThumbs);
1736
+ Log::addDebug('Send to PRocessing - URLS -', array($URLsAndPATHs) );
1737
 
 
1738
  //find thumbs that are not listed in the metadata and add them in the sizes array
1739
+ $this->addUnlistedThumbs($itemHandler);
1740
 
1741
  //find any missing thumbs files and mark them as such
1742
  $miss = $meta->getThumbsMissing();
1747
  $meta->setThumbsMissing($URLsAndPATHs['sizesMissing']);
1748
  $itemHandler->updateMeta();
1749
  }
1750
+
1751
+ $original_status = $meta->getStatus(); // get the real status, without the override below .
1752
+
1753
  $refresh = $meta->getStatus() === ShortPixelAPI::ERR_INCORRECT_FILE_SIZE;
1754
+ $itemHandler->setWaitingProcessing(); // @todo This, for some reason, put status to 'success', before processing.
1755
+
1756
+ // function to fix things if needed.
1757
+ //$meta = $this->getMeta();
1758
+ if ($original_status < 0 && count($URLsAndPATHs['URLs']) == 0)
1759
+ {
1760
+ if (! is_array($meta->getThumbsMissing()) || count($meta->getThumbsMissing()) == 0)
1761
+ {
1762
+ $meta->setStatus(ShortPixelAPI::STATUS_SUCCESS);
1763
+ $meta->setMessage(0);
1764
+ $meta->setThumbsTodo(0);
1765
+ $itemHandler->updateMeta($meta);
1766
+ Log::addWarn('Processing override, no URLS, no jobs, something was incorrect - ');
1767
+ return $URLsAndPATHs;
1768
+ }
1769
+ }
1770
+
1771
+ $thumbObtList = $meta->getThumbsOptList();
1772
+ $missing = $meta->getThumbsMissing();
1773
+
1774
+
1775
  $this->_apiInterface->doRequests($URLsAndPATHs['URLs'], false, $itemHandler,
1776
  $compressionType === false ? $this->_settings->compressionType : $compressionType, $refresh);//send a request, do NOT wait for response
1777
  //$meta = wp_get_attachment_metadata($ID);
1831
  if($this->isProcessable($imageId)) {
1832
  $this->prioQ->push($imageId);
1833
  $itemHandler = new ShortPixelMetaFacade($imageId);
1834
+
1835
  $path = get_attached_file($imageId);//get the full file PATH
1836
  if(!$manual && 'pdf' === pathinfo($path, PATHINFO_EXTENSION) && !$this->_settings->optimizePdfs) {
1837
  $ret = array("Status" => ShortPixelAPI::STATUS_SKIP, "Message" => $imageId);
1843
  $itemHandler->getMeta();
1844
  $errCode = $e->getCode() < 0 ? $e->getCode() : ShortPixelAPI::ERR_FILE_NOT_FOUND;
1845
  $itemHandler->setError($errCode, $e->getMessage());
1846
+
1847
  $ret = array("Status" => ShortPixelAPI::STATUS_FAIL, "Message" => $e->getMessage());
1848
  }
1849
  }
2038
  protected function doRestore($attachmentID, $rawMeta = null) {
2039
  do_action("shortpixel_before_restore_image", $attachmentID);
2040
 
2041
+ $fs = new \ShortPixel\FileSystemController();
2042
+ $origFile = get_attached_file($attachmentID);
2043
+ // $file = get_attached_file($attachmentID);
2044
+
2045
+ // Setup Original File and Data. This is used to determine backup path.
2046
+ $fsFile = $fs->getFile($origFile);
2047
+ $filePath = (string) $fsFile->getFileDir();
2048
 
2049
  $itemHandler = new ShortPixelMetaFacade($attachmentID);
2050
  if($rawMeta) {
2061
  return false;
2062
  }
2063
 
2064
+ // Get correct Backup Folder and file. .
2065
  $sizes = isset($rawMeta["sizes"]) ? $rawMeta["sizes"] : array();
2066
+ $bkFolder = $fs->getDirectory($this->getBackupFolderAny($fsFile->getFullPath(), $sizes));
2067
+ $bkFile = $fs->getFile($bkFolder->getPath() . $fsFile->getFileName());
2068
+
2069
+ Log::addDebug('Restore, Backup File -- ', array($bkFile->getFullPath(), $fsFile->getFullPath() ) );
2070
+ // $pathInfo = pathinfo($file);
2071
 
2072
  //check if the images were converted from PNG
2073
  $png2jpgMain = isset($rawMeta['ShortPixelPng2Jpg']['originalFile']) ? $rawMeta['ShortPixelPng2Jpg']['originalFile'] : false;
2074
+
2075
  $toReplace = array();
2076
+ // Checks if image was converted to JPG, and rewrites to restore original extension.
2077
+ // @todo Should have it's own function in php2jpg ( restore )
2078
  if($png2jpgMain) {
2079
  $png2jpgSizes = $png2jpgMain ? $rawMeta['ShortPixelPng2Jpg']['originalSizes'] : array();
2080
+ $image = $rawMeta['file']; // relative file
2081
+ $imageUrl = wp_get_attachment_url($attachmentID); // URL can be anything.
2082
+
2083
+ Log::addDebug('OriginFile -- ' . $fsFile->getFullPath() );
2084
+
2085
+ $imageName = $fsFile->getFileName();
2086
+
2087
+ $baseUrl = str_replace($fsFile->getFileName(), '', $imageUrl); // remove *only* filename from URL
2088
+ $baseUrl = ShortPixelPng2Jpg::removeUrlProtocol($baseUrl); // @todo parse_url with a util helper / model should be better here
2089
+
2090
+ // $baseUrl = ShortPixelPng2Jpg::removeUrlProtocol(trailingslashit(str_replace($image, "", $imageUrl))); //make the base url protocol agnostic if it's not already
2091
+
2092
+ // not needed, we don't do this weird remove anymore.
2093
+ $baseRelPath = ''; // trailingslashit(dirname($image)); // @todo Replace this (string) $fsFile->getFileDir();
2094
+
2095
  $toReplace[ShortPixelPng2Jpg::removeUrlProtocol($imageUrl)] = $baseUrl . $baseRelPath . wp_basename($png2jpgMain);
2096
  foreach($sizes as $key => $size) {
2097
  if(isset($png2jpgSizes[$key])) {
2098
  $toReplace[$baseUrl . $baseRelPath . $size['file']] = $baseUrl . $baseRelPath . wp_basename($png2jpgSizes[$key]['file']);
2099
  }
2100
  }
2101
+
2102
+ //$file = $png2jpgMain;
2103
  $sizes = $png2jpgSizes;
2104
+
2105
+ $fsFile = $fs->getFile($png2jpgMain); // original is non-existing at this time.
2106
+
2107
  }
 
2108
 
2109
  //first check if the file is readable by the current user - otherwise it will be unaccessible for the web browser
2110
  // - collect the thumbs paths in the process
2115
  $this->_settings->bulkLastStatus = null;
2116
  }
2117
  }
2118
+ if($bkFile->exists()) {
2119
+ if(! $bkFile->is_readable() || ($fsFile->exists() && ! $fsFile->is_writable() ) ) {
2120
  $this->throwNotice('generic-err',
2121
+ sprintf(__("File %s cannot be restored due to lack of permissions, please contact your hosting provider to assist you in fixing this.",'shortpixel-image-optimiser'),$fsFile->getFullPath() ) );
2122
+
2123
+ Log::addError('DoRestore could not restore file', array($bkFile->getFullPath(), $fsFile->getFullPath(), $fsFile->exists(), $bkFile->is_readable(), $fsFile->is_writable() ));
2124
  return false;
2125
  }
2126
  $bkCount++;
2127
  $main = true;
2128
  }
2129
  $thumbsPaths = array();
2130
+ // Check and Collect Thumb Sizes.
2131
+
2132
+ if($bkFolder->exists() && !empty($rawMeta['file']) && count($sizes) ) {
2133
  foreach($sizes as $size => $imageData) {
2134
+ //$dest = $pathInfo['dirname'] . '/' . $imageData['file'];
2135
+ $destination = $fs->getFile($filePath . $imageData['file']);
2136
+ $source = $fs->getFile($bkFolder->getPath() . $imageData['file']); //trailingslashit($bkFolder) . $imageData['file'];
2137
+
2138
+ if(! $source->exists() ) continue; // if thumbs were not optimized, then the backups will not be there.
2139
+ if(! $source->is_readable() || ($destination->exists() && !$destination->is_writable() )) {
2140
+ $failedFile = ($destination->is_writable() ? $source->getFullPath() : $destination->getFullPath());
2141
  $this->throwNotice('generic-err',
2142
+ sprintf(__("The file %s cannot be restored due to lack of permissions, please contact your hosting provider to assist you in fixing this.",'shortpixel-image-optimiser'),
2143
  "$failedFile (current permissions: " . sprintf("%o", fileperms($failedFile)) . ")"));
2144
  return false;
2145
  }
2146
  $bkCount++;
2147
+ $thumbsPaths[] = array('source' => $source, 'destination' => $destination);
2148
  }
2149
  }
2150
  if(!$bkCount) {
2151
  $this->throwNotice('generic-err', __("No backup files found. Restore not performed.",'shortpixel-image-optimiser'));
2152
+ Log::addError('No Backup Files Found. ', array($bkFile));
2153
  return false;
2154
  }
2155
+
2156
  //either backups exist, or there was an error when trying to optimize, so it's normal no backup is present
2157
+ /*protected function retinaName($file) {
2158
+ $ext = pathinfo($file, PATHINFO_EXTENSION);
2159
+ return substr($file, 0, strlen($file) - 1 - strlen($ext)) . "@2x." . $ext;
2160
+ }*/
2161
  try {
2162
  $width = false;
2163
  if($bkCount) { // backups, if exist
2164
  //main file
2165
  if($main) {
2166
+ //$this->renameWithRetina($bkFile, $file);
2167
+ if (! $bkFile->move($fsFile))
2168
+ {
2169
+ Log::addError('DoRestore failed restoring backup', array($bkFile->getFullPath(), $fsFile->getFullPath() ));
2170
+ }
2171
+ $retinaBK = $fs->getFile( $bkFile->getFileDir()->getPath() . $bkFile->getFileBase() . '@2x' . $bkFile->getExtension() );
2172
+ if ($retinaBK->exists())
2173
+ {
2174
+ $retinaDest = $fs->getFile($fsFile->getFileDir()->getPath() . $fsFile->getFileBase() . '@2x' . $fsFile->getExtension() );
2175
+ if (! $retinaBK->move($retinaDest))
2176
+ {
2177
+ Log::addError('DoRestore failed restoring retina backup', array($retinaBK->getFullPath(), $retinaDest->getFullPath() ));
2178
+ }
2179
+ }
2180
+
2181
+ //@rename($bkFile, $file);
2182
+ //@rename($this->retinaName($bkFile), $this->retinaName($file));
2183
  }
2184
  //getSize to update meta if image was resized by ShortPixel
2185
+ if($fsFile->exists()) {
2186
+ $size = getimagesize($fsFile->getFullPath());
2187
  $width = $size[0];
2188
  $height = $size[1];
2189
  }
2190
 
2191
  //overwriting thumbnails
2192
+
2193
+ foreach($thumbsPaths as $index => $data) {
2194
+ $source = $data['source'];
2195
+ $destination = $data['destination'];
2196
+ // $this->renameWithRetina($source, $destination);
2197
+ if (! $source->move($destination))
2198
+ {
2199
+ Log::addError('DoRestore failed restoring backup', array($source->getFullPath(), $destination->getFullPath() ));
2200
+ }
2201
+ $retinaBK = $fs->getFile( $source->getFileDir()->getPath() . $source->getFileBase() . '@2x' . $source->getExtension() );
2202
+ if ($retinaBK->exists())
2203
+ {
2204
+ $retinaDest = $fs->getFile($destination->getFileDir()->getPath() . $destination->getFileBase() . '@2x' . $destination->getExtension() );
2205
+ if (! $retinaBK->move($retinaDest))
2206
+ {
2207
+ Log::addError('DoRestore failed restoring retina backup', array($retinaBK->getFullPath(), $retinaDest->getFullPath() ));
2208
+ }
2209
+ }
2210
  }
2211
  }
2212
 
2229
  $crtMeta['height'] = $height;
2230
  }
2231
  if($png2jpgMain) {
2232
+ $crtMeta['file'] = trailingslashit(dirname($crtMeta['file'])) . $fsFile->getFileName();
2233
  update_attached_file($ID, $crtMeta['file']);
2234
  if($png2jpgSizes && count($png2jpgSizes)) {
2235
  $crtMeta['sizes'] = $png2jpgSizes;
2276
 
2277
  /**
2278
  * used to store a notice to be displayed after the redirect, for ex. when having an error restoring.
2279
+ * @todo move this to noticesModel
2280
  * @param string $when
2281
  * @param string $extra
2282
  */
2300
  return false;
2301
  }
2302
 
 
 
 
 
 
 
 
 
 
 
 
2303
  /** Restores a non-media-library image
2304
  * @param int $ID image_id, without any prefixes
2305
  */
3296
  : 0;
3297
  }
3298
 
3299
+ /** If webp generating functionality is on, give mime-permissions for webp extension
3300
+ *
3301
+ */
3302
+ public function addWebpMime($mimes)
3303
+ {
3304
+ if ($this->_settings->createWebp)
3305
+ {
3306
+ if (! isset($mimes['webp']))
3307
+ $mimes['webp'] = 'image/webp';
3308
+ }
3309
+
3310
+ return $mimes;
3311
+ }
3312
+
3313
  /**
3314
  *
3315
  * @param type $apiKey
3496
 
3497
  $file = get_attached_file($id);
3498
  $data = ShortPixelMetaFacade::sanitizeMeta(wp_get_attachment_metadata($id));
3499
+ $itemHandler = new ShortPixelMetaFacade($id);
3500
+ $meta = $itemHandler->getMeta();
3501
 
3502
+ if($extended && Log::debugIsActive()) {
3503
  // var_dump($data);
3504
+ $sizes = isset($data['sizes']) ? $data['sizes'] : array();
3505
+ echo "<PRE style='font-size:11px; overflow:hidden; white-space:pre-wrap'>";
3506
+ echo "<strong>URL: </strong>"; print_r(wp_get_attachment_url($id));
3507
  echo('<br><br>' . json_encode(ShortPixelMetaFacade::getWPMLDuplicates($id)));
3508
+ echo('<br><br><span class="array">'); print_r($data); echo ''; //json_encode($data))
3509
+ echo('</span><br><br>');
3510
+ echo '<p><strong>Backup Folder: </strong>' . $this->getBackupFolderAny($file, $sizes) . '</p>';
3511
+ echo '<p><strong>Status</strong>: ' . $meta->getStatus() . '</p>';
3512
+ echo "</PRE>";
3513
  }
3514
 
3515
  $fileExtension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
3630
  /**
3631
  * return the thumbnails that remain to optimize and the total count of sizes registered in metadata (and not excluded)
3632
  * @param $data @todo Define what is data
3633
+ * @param $filepath
3634
  * @return array Array of Thumbs to Optimize - only the filename - , and count of sizes not excluded ...
3635
  */
3636
  function getThumbsToOptimize($data, $filepath) {
3661
  continue;
3662
  }
3663
 
 
3664
  if(!in_array($size, $exclude) && !in_array($file->getFileName(), $thumbsOptList)) {
3665
  $thumbsToOptimizeList[] = $file->getFileName();
3666
  }
3801
  }
3802
 
3803
  /** Removes webp and backup from specified paths
3804
+ * @todo Implement Filesystem controller on this.
3805
  */
3806
  public function deleteBackupsAndWebPs($paths) {
3807
  /**
4026
  static public function folderSize($path) {
4027
  $total_size = 0;
4028
  if(file_exists($path)) {
4029
+ $files = scandir($path); // @todo This gives a warning if directory is not writable.
4030
  } else {
4031
  return $total_size;
4032
  }
readme.txt CHANGED
@@ -4,7 +4,7 @@ Tags: compressor, image, compression, optimize, image optimizer, image optimiser
4
  Requires at least: 3.2.0
5
  Tested up to: 5.2
6
  Requires PHP: 5.3
7
- Stable tag: 4.14.4
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -246,6 +246,16 @@ define('SHORTPIXEL_CUSTOM_THUMB_INFIXES', '-uae'); will handle custom thumbnails
246
 
247
  == Changelog ==
248
 
 
 
 
 
 
 
 
 
 
 
249
  = 4.14.4 =
250
  Release date: 19th August 2019
251
  * Check if unlisted thumbnails present for already optimized images (in case the thumbnails were added later) in Media Library list and when doing bulk. This also integrates with the Unicode plugin.
4
  Requires at least: 3.2.0
5
  Tested up to: 5.2
6
  Requires PHP: 5.3
7
+ Stable tag: 4.14.5
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
246
 
247
  == Changelog ==
248
 
249
+ = 4.14.5 =
250
+ Release date: 29th August 2019
251
+ * If constant SHORTPIXEL_USE_DOUBLE_WEBP_EXTENSION is defined as true, use double extension for WebP (.jpg.webp)
252
+ * Fixed: Javascript - String.prototype causes errors on React apps
253
+ * Fixed: Undefined page load when using ShortPixel and Divi preloaded images
254
+ * Fixed: Offload Media - When removing PNG2JPG converted file, the files / folder are not removed.
255
+ * Fixed: When the constant that enables using double extensions for WebP (.jpg.webp) is active, the webp's are found as unlisted thumbnails and sent to optimization.
256
+ * Fixed: missing call to apply_filters('shortpixel_image_exists'...) on a particular case.
257
+ * Language – 0 new strings added, 1 updated, 0 fuzzied, and 0 obsoleted
258
+
259
  = 4.14.4 =
260
  Release date: 19th August 2019
261
  * Check if unlisted thumbnails present for already optimized images (in case the thumbnails were added later) in Media Library list and when doing bulk. This also integrates with the Unicode plugin.
shortpixel-plugin.php CHANGED
@@ -10,7 +10,7 @@ use ShortPixel\Notices\NoticeController as Notices;
10
  */
11
  class ShortPixelPlugin
12
  {
13
- static $instance;
14
  private $paths = array('class', 'class/controller', 'class/external'); // classes that are autoloaded
15
 
16
  protected $is_noheaders = false;
@@ -205,6 +205,4 @@ class ShortPixelPlugin
205
  }
206
  }
207
 
208
-
209
-
210
- }
10
  */
11
  class ShortPixelPlugin
12
  {
13
+ static private $instance;
14
  private $paths = array('class', 'class/controller', 'class/external'); // classes that are autoloaded
15
 
16
  protected $is_noheaders = false;
205
  }
206
  }
207
 
208
+ } // class plugin
 
 
shortpixel_api.php CHANGED
@@ -88,7 +88,8 @@ class ShortPixelAPI {
88
 
89
  if(!count($URLs)) {
90
  $meta = $itemHandler->getMeta();
91
- if(count($meta->getThumbsMissing())) {
 
92
  $added = array();
93
  $files = " (";
94
  foreach ($meta->getThumbsMissing() as $miss) {
@@ -134,7 +135,7 @@ class ShortPixelAPI {
134
  }
135
 
136
  //WpShortPixel::log("ShortPixel API Request Settings: " . json_encode($requestParameters));
137
- Log::addDebug('ShortPixel API Request', array($requestParameters));
138
  $response = wp_remote_post($this->_apiEndPoint, $this->prepareRequest($requestParameters, $Blocking) );
139
 
140
  //WpShortPixel::log('RESPONSE: ' . json_encode($response));
@@ -476,7 +477,6 @@ class ShortPixelAPI {
476
  return array("Status" => self::STATUS_FAIL, "Message" => __('Backup folder does not exist and it cannot be created','shortpixel-image-optimiser'));
477
  }
478
  //create subdir in backup folder if needed
479
- //@mkdir( SHORTPIXEL_BACKUP_FOLDER . '/' . $fullSubDir, 0777, true);
480
  ShortPixelFolder::createBackUpFolder(SHORTPIXEL_BACKUP_FOLDER . '/' . $fullSubDir);
481
 
482
  foreach ( $source as $fileID => $filePATH )//create destination files array
@@ -583,7 +583,7 @@ class ShortPixelAPI {
583
  * @return array status/message
584
  */
585
  private function handleSuccess($APIresponse, $PATHs, $itemHandler, $compressionType) {
586
- Log::addDebug('Shortpixel API : Handling Success!', array($APIresponse));
587
 
588
  $counter = $savedSpace = $originalSpace = $optimizedSpace /* = $averageCompression */ = 0;
589
  $NoBackup = true;
@@ -669,6 +669,10 @@ class ShortPixelAPI {
669
  $thumbsOpt = 0;
670
  $thumbsOptList = array();
671
 
 
 
 
 
672
  if ( !empty($tempFiles) )
673
  {
674
  //overwrite the original files with the optimized ones
@@ -676,23 +680,27 @@ class ShortPixelAPI {
676
  {
677
  if(!is_array($tempFile)) continue;
678
 
679
- $targetFile = $PATHs[$tempFileID];
680
- $isRetina = ShortPixelMetaFacade::isRetina($targetFile);
681
 
682
  if( ($tempFile['Status'] == self::STATUS_UNCHANGED || $tempFile['Status'] == self::STATUS_SUCCESS) && !$isRetina
683
- && $targetFile !== $mainPath) {
684
  $thumbsOpt++;
685
- $thumbsOptList[] = self::MB_basename($targetFile);
686
  }
687
 
688
  if($tempFile['Status'] == self::STATUS_SUCCESS) { //if it's unchanged it will still be in the array but only for WebP (handled below)
689
- $tempFilePATH = $tempFile["Message"];
690
- if ( file_exists($tempFilePATH) && (!file_exists($targetFile) || is_writable($targetFile)) ) {
691
- copy($tempFilePATH, $targetFile);
692
- if(ShortPixelMetaFacade::isRetina($targetFile)) {
 
 
 
 
693
  $retinas ++;
694
  }
695
- if($resize && $itemHandler->getMeta()->getPath() == $targetFile) { //this is the main image
696
  $size = getimagesize($PATHs[$tempFileID]);
697
  $width = $size[0];
698
  $height = $size[1];
@@ -703,7 +711,7 @@ class ShortPixelAPI {
703
  $originalSpace += $fileData->OriginalSize;
704
  $optimizedSpace += $fileData->$fileSize;
705
  //$averageCompression += $fileData->PercentImprovement;
706
- WPShortPixel::log("HANDLE SUCCESS: Image " . $PATHs[$tempFileID] . " original size: ".$fileData->OriginalSize . " optimized: " . $fileData->$fileSize);
707
 
708
  //add the number of files with < 5% optimization
709
  if ( ( ( 1 - $APIresponse[$tempFileID]->$fileSize/$APIresponse[$tempFileID]->OriginalSize ) * 100 ) < 5 ) {
@@ -712,41 +720,43 @@ class ShortPixelAPI {
712
  }
713
  else {
714
  if($archive && SHORTPIXEL_DEBUG === true) {
715
- if(!file_exists($tempFilePATH)) {
716
- WPShortPixel::log("MISSING FROM ARCHIVE. tempFilePath: $tempFilePATH with ID: $tempFileID");
717
- } elseif(!wp_is_writable($targetFile)){
718
- WPShortPixel::log("TARGET NOT WRITABLE: $targetFile");
719
  }
720
  }
721
  $writeFailed++;
722
  }
723
- @unlink($tempFilePATH); // @todo Unlink is risky due to lack of checks.
 
724
  }
725
 
726
- $tempWebpFilePATH = $tempFile["WebP"];
727
- if(file_exists($tempWebpFilePATH)) {
728
- $targetWebPFileCompat = dirname($targetFile) . '/'. self::MB_basename($targetFile, '.' . pathinfo($targetFile, PATHINFO_EXTENSION)) . ".webp";
729
- $targetWebPFile = dirname($targetFile) . '/' . self::MB_basename($targetFile) . ".webp";
730
- //if the WebP fileCompat already exists, it means that there is another file with the same basename but different extension which has its .webP counterpart
731
- //save it with double extension
732
- if(file_exists($targetWebPFileCompat)) {
733
- copy($tempWebpFilePATH, $targetWebPFile);
 
734
  } else {
735
- copy($tempWebpFilePATH, $targetWebPFileCompat);
736
  }
737
- @unlink($tempWebpFilePATH);
738
  }
739
- }
740
  self::cleanupTemporaryFiles($archive, $tempFiles);
741
 
742
  if ( $writeFailed > 0 )//there was an error
743
  {
744
- if($archive && SHORTPIXEL_DEBUG === true) {
745
- WPShortPixel::log("ARCHIVE HAS MISSING FILES. EXPECTED: " . json_encode($PATHs)
746
- . " AND: " . json_encode($APIresponse)
747
- . " GOT ARCHIVE: " . $APIresponse[count($APIresponse) - 1]->ArchiveURL . " LOSSLESS: " . $APIresponse[count($APIresponse) - 1]->ArchiveLosslessURL
748
- . " CONTAINING: " . json_encode(scandir($archive['Path'])));
749
- }
 
750
  $msg = sprintf(__('Optimized version of %s file(s) couldn\'t be updated.','shortpixel-image-optimiser'),$writeFailed);
751
  $itemHandler->incrementRetries(1, self::ERR_SAVE, $msg);
752
  $this->_settings->bulkProcessingStatus = "error";
@@ -798,7 +808,7 @@ class ShortPixelAPI {
798
 
799
  $itemHandler->updateMeta($meta);
800
  $itemHandler->optimizationSucceeded();
801
- WPShortPixel::log("HANDLE SUCCESS: Metadata saved.");
802
 
803
  if(!$originalSpace) { //das kann nicht sein, alles klar?!
804
  throw new Exception("OriginalSpace = 0. APIResponse" . json_encode($APIresponse));
@@ -871,7 +881,7 @@ class ShortPixelAPI {
871
  foreach ( $PATHs as $Id => $File )
872
  {
873
  //we try again with a different path
874
- if ( !apply_filters( 'shortpixel_image_exists', file_exists($File), $File ) ){
875
  //$NewFile = $uploadDir['basedir'] . "/" . substr($File,strpos($File, $StichString));//+strlen($StichString));
876
  $NewFile = SHORTPIXEL_UPLOADS_BASE . substr($File,strpos($File, $StichString)+strlen($StichString));
877
  if (file_exists($NewFile)) {
88
 
89
  if(!count($URLs)) {
90
  $meta = $itemHandler->getMeta();
91
+ $thumbsMissing = $meta->getThumbsMissing();
92
+ if(is_array($thumbsMissing) && count($thumbsMissing)) {
93
  $added = array();
94
  $files = " (";
95
  foreach ($meta->getThumbsMissing() as $miss) {
135
  }
136
 
137
  //WpShortPixel::log("ShortPixel API Request Settings: " . json_encode($requestParameters));
138
+ //Log::addDebug('ShortPixel API Request');
139
  $response = wp_remote_post($this->_apiEndPoint, $this->prepareRequest($requestParameters, $Blocking) );
140
 
141
  //WpShortPixel::log('RESPONSE: ' . json_encode($response));
477
  return array("Status" => self::STATUS_FAIL, "Message" => __('Backup folder does not exist and it cannot be created','shortpixel-image-optimiser'));
478
  }
479
  //create subdir in backup folder if needed
 
480
  ShortPixelFolder::createBackUpFolder(SHORTPIXEL_BACKUP_FOLDER . '/' . $fullSubDir);
481
 
482
  foreach ( $source as $fileID => $filePATH )//create destination files array
583
  * @return array status/message
584
  */
585
  private function handleSuccess($APIresponse, $PATHs, $itemHandler, $compressionType) {
586
+ Log::addDebug('Shortpixel API : Handling Success!');
587
 
588
  $counter = $savedSpace = $originalSpace = $optimizedSpace /* = $averageCompression */ = 0;
589
  $NoBackup = true;
669
  $thumbsOpt = 0;
670
  $thumbsOptList = array();
671
 
672
+ $fs = new \ShortPixel\FileSystemController();
673
+
674
+ //Log::addDebug($tempFiles);
675
+ // Check and Run all tempfiles. Move it to appropiate places.
676
  if ( !empty($tempFiles) )
677
  {
678
  //overwrite the original files with the optimized ones
680
  {
681
  if(!is_array($tempFile)) continue;
682
 
683
+ $targetFile = $fs->getFile($PATHs[$tempFileID]);
684
+ $isRetina = ShortPixelMetaFacade::isRetina($targetFile->getFullPath());
685
 
686
  if( ($tempFile['Status'] == self::STATUS_UNCHANGED || $tempFile['Status'] == self::STATUS_SUCCESS) && !$isRetina
687
+ && $targetFile->getFullPath() !== $mainPath) {
688
  $thumbsOpt++;
689
+ $thumbsOptList[] = self::MB_basename($targetFile->getFullPath());
690
  }
691
 
692
  if($tempFile['Status'] == self::STATUS_SUCCESS) { //if it's unchanged it will still be in the array but only for WebP (handled below)
693
+ $tempFilePATH = $fs->getFile($tempFile["Message"]);
694
+
695
+ //@todo Move file logic to use FS controller / fileModel.
696
+ if ( $tempFilePATH->exists() && (! $targetFile->exists() || $targetFile->is_writable()) ) {
697
+ // copy($tempFilePATH, $targetFile);
698
+ $tempFilePATH->move($targetFile);
699
+
700
+ if(ShortPixelMetaFacade::isRetina($targetFile->getFullPath())) {
701
  $retinas ++;
702
  }
703
+ if($resize && $itemHandler->getMeta()->getPath() == $targetFile->getFullPath() ) { //this is the main image
704
  $size = getimagesize($PATHs[$tempFileID]);
705
  $width = $size[0];
706
  $height = $size[1];
711
  $originalSpace += $fileData->OriginalSize;
712
  $optimizedSpace += $fileData->$fileSize;
713
  //$averageCompression += $fileData->PercentImprovement;
714
+ Log::addInfo("HANDLE SUCCESS: Image " . $PATHs[$tempFileID] . " original size: ".$fileData->OriginalSize . " optimized: " . $fileData->$fileSize);
715
 
716
  //add the number of files with < 5% optimization
717
  if ( ( ( 1 - $APIresponse[$tempFileID]->$fileSize/$APIresponse[$tempFileID]->OriginalSize ) * 100 ) < 5 ) {
720
  }
721
  else {
722
  if($archive && SHORTPIXEL_DEBUG === true) {
723
+ if(! $tempFilePATH->exists()) {
724
+ Log::addWarn("MISSING FROM ARCHIVE. tempFilePath: " . $tempFilePATH->getFullPath() . " with ID: $tempFileID");
725
+ } elseif(! $targetFile->is_writable() ){
726
+ Log::addWarn("TARGET NOT WRITABLE: " . $targetFile->getFullPath() );
727
  }
728
  }
729
  $writeFailed++;
730
  }
731
+ //@unlink($tempFilePATH); // @todo Unlink is risky due to lack of checks.
732
+ // $tempFilePath->delete();
733
  }
734
 
735
+ $tempWebpFilePATH = $fs->getFile($tempFile["WebP"]);
736
+ if( $tempWebpFilePATH->exists() ) {
737
+ $targetWebPFileCompat = $fs->getFile($targetFile->getFileDir() . $targetFile->getFileName() . '.webp');
738
+ /*$targetWebPFileCompat = dirname($targetFile) . '/'. self::MB_basename($targetFile, '.' . pathinfo($targetFile, PATHINFO_EXTENSION)) . ".webp"; */
739
+
740
+ $targetWebPFile = $fs->getFile($targetFile->getFileDir() . $targetFile->getFileBase() . '.webp');
741
+ //if the Targetfile already exists, it means that there is another file with the same basename but different extension which has its .webP counterpart save it with double extension
742
+ if(SHORTPIXEL_USE_DOUBLE_WEBP_EXTENSION || $targetWebPFile->exists()) {
743
+ $tempWebpFilePATH->move($targetWebPFileCompat);
744
  } else {
745
+ $tempWebpFilePATH->move($targetWebPFile);
746
  }
 
747
  }
748
+ } // / For each tempFile
749
  self::cleanupTemporaryFiles($archive, $tempFiles);
750
 
751
  if ( $writeFailed > 0 )//there was an error
752
  {
753
+
754
+ /* Log::addDebug("ARCHIVE HAS MISSING FILES. EXPECTED: " . json_encode($PATHs)
755
+ . " AND: " . json_encode($APIresponse)
756
+ . " GOT ARCHIVE: " . $APIresponse[count($APIresponse) - 1]->ArchiveURL . " LOSSLESS: " . $APIresponse[count($APIresponse) - 1]->ArchiveLosslessURL
757
+ . " CONTAINING: " . json_encode(scandir($archive['Path']))); */
758
+ Log::addDebug('Archive files missing (expected paths, response)', array($PATHs, $APIresponse));
759
+
760
  $msg = sprintf(__('Optimized version of %s file(s) couldn\'t be updated.','shortpixel-image-optimiser'),$writeFailed);
761
  $itemHandler->incrementRetries(1, self::ERR_SAVE, $msg);
762
  $this->_settings->bulkProcessingStatus = "error";
808
 
809
  $itemHandler->updateMeta($meta);
810
  $itemHandler->optimizationSucceeded();
811
+ Log::addDebug("HANDLE SUCCESS: Metadata saved.");
812
 
813
  if(!$originalSpace) { //das kann nicht sein, alles klar?!
814
  throw new Exception("OriginalSpace = 0. APIResponse" . json_encode($APIresponse));
881
  foreach ( $PATHs as $Id => $File )
882
  {
883
  //we try again with a different path
884
+ if ( !apply_filters( 'shortpixel_image_exists', file_exists($File), $File, null ) ){
885
  //$NewFile = $uploadDir['basedir'] . "/" . substr($File,strpos($File, $StichString));//+strlen($StichString));
886
  $NewFile = SHORTPIXEL_UPLOADS_BASE . substr($File,strpos($File, $StichString)+strlen($StichString));
887
  if (file_exists($NewFile)) {
wp-shortpixel.php CHANGED
@@ -3,13 +3,12 @@
3
  * Plugin Name: ShortPixel Image Optimizer
4
  * Plugin URI: https://shortpixel.com/
5
  * Description: ShortPixel optimizes images automatically, while guarding the quality of your images. Check your <a href="options-general.php?page=wp-shortpixel-settings" target="_blank">Settings &gt; ShortPixel</a> page on how to start optimizing your image library and make your website load faster.
6
- * Version: 4.14.4
7
  * Author: ShortPixel
8
  * Author URI: https://shortpixel.com
9
  * Text Domain: shortpixel-image-optimiser
10
  * Domain Path: /lang
11
  */
12
-
13
  if (! defined('SHORTPIXEL_RESET_ON_ACTIVATE'))
14
  define('SHORTPIXEL_RESET_ON_ACTIVATE', false); //if true TODO set false
15
  //define('SHORTPIXEL_DEBUG', true);
@@ -20,7 +19,7 @@ define('SHORTPIXEL_PLUGIN_DIR', __DIR__);
20
 
21
  //define('SHORTPIXEL_AFFILIATE_CODE', '');
22
 
23
- define('SHORTPIXEL_IMAGE_OPTIMISER_VERSION', "4.14.4");
24
  define('SHORTPIXEL_MAX_TIMEOUT', 10);
25
  define('SHORTPIXEL_VALIDATE_MAX_TIMEOUT', 15);
26
  define('SHORTPIXEL_BACKUP', 'ShortpixelBackups');
@@ -31,6 +30,10 @@ if(!defined('SHORTPIXEL_MAX_THUMBS')) { //can be defined in wp-config.php
31
  define('SHORTPIXEL_MAX_THUMBS', 149);
32
  }
33
 
 
 
 
 
34
  define('SHORTPIXEL_PRESEND_ITEMS', 3);
35
  define('SHORTPIXEL_API', 'api.shortpixel.com');
36
 
@@ -70,8 +73,8 @@ define("SHORTPIXEL_MAX_RESULTS_QUERY", 30);
70
  function shortpixelInit() {
71
  global $shortPixelPluginInstance;
72
  //limit to certain admin pages if function available
73
- $loadOnThisPage = !function_exists('get_current_screen');
74
- if(!$loadOnThisPage) {
75
  $screen = get_current_screen();
76
  if(is_object($screen) && !in_array($screen->id, array('upload', 'edit', 'edit-tags', 'post-new', 'post'))) {
77
  return;
@@ -222,7 +225,10 @@ $log = ShortPixel\ShortPixelLogger\ShortPixelLogger::getInstance();
222
  $log->setLogPath(SHORTPIXEL_BACKUP_FOLDER . "/shortpixel_log");
223
 
224
  // Pre-Runtime Checks
 
225
  require_once('class/external/flywheel.php'); // check if SP runs on flywheel
 
 
226
 
227
  $option = get_option('wp-short-pixel-create-webp-markup');
228
  if ( $option ) {
3
  * Plugin Name: ShortPixel Image Optimizer
4
  * Plugin URI: https://shortpixel.com/
5
  * Description: ShortPixel optimizes images automatically, while guarding the quality of your images. Check your <a href="options-general.php?page=wp-shortpixel-settings" target="_blank">Settings &gt; ShortPixel</a> page on how to start optimizing your image library and make your website load faster.
6
+ * Version: 4.14.5
7
  * Author: ShortPixel
8
  * Author URI: https://shortpixel.com
9
  * Text Domain: shortpixel-image-optimiser
10
  * Domain Path: /lang
11
  */
 
12
  if (! defined('SHORTPIXEL_RESET_ON_ACTIVATE'))
13
  define('SHORTPIXEL_RESET_ON_ACTIVATE', false); //if true TODO set false
14
  //define('SHORTPIXEL_DEBUG', true);
19
 
20
  //define('SHORTPIXEL_AFFILIATE_CODE', '');
21
 
22
+ define('SHORTPIXEL_IMAGE_OPTIMISER_VERSION', "4.14.5");
23
  define('SHORTPIXEL_MAX_TIMEOUT', 10);
24
  define('SHORTPIXEL_VALIDATE_MAX_TIMEOUT', 15);
25
  define('SHORTPIXEL_BACKUP', 'ShortpixelBackups');
30
  define('SHORTPIXEL_MAX_THUMBS', 149);
31
  }
32
 
33
+ if(!defined('SHORTPIXEL_USE_DOUBLE_WEBP_EXTENSION')) { //can be defined in wp-config.php
34
+ define('SHORTPIXEL_USE_DOUBLE_WEBP_EXTENSION', false);
35
+ }
36
+
37
  define('SHORTPIXEL_PRESEND_ITEMS', 3);
38
  define('SHORTPIXEL_API', 'api.shortpixel.com');
39
 
73
  function shortpixelInit() {
74
  global $shortPixelPluginInstance;
75
  //limit to certain admin pages if function available
76
+ $loadOnThisPage = function_exists('get_current_screen');
77
+ if($loadOnThisPage) {
78
  $screen = get_current_screen();
79
  if(is_object($screen) && !in_array($screen->id, array('upload', 'edit', 'edit-tags', 'post-new', 'post'))) {
80
  return;
225
  $log->setLogPath(SHORTPIXEL_BACKUP_FOLDER . "/shortpixel_log");
226
 
227
  // Pre-Runtime Checks
228
+ // @todo Better solution for pre-runtime inclusions of externals.
229
  require_once('class/external/flywheel.php'); // check if SP runs on flywheel
230
+ require_once('class/external/wp-offload-media.php');
231
+
232
 
233
  $option = get_option('wp-short-pixel-create-webp-markup');
234
  if ( $option ) {