Apptrian_Image_Optimizer - Version 2.1.0

Version Notes

* Index is now saved to a file instead of database
WARNING! If you are upgrading from any previous version of Image Optimizer you will loose old index data. Previously optimized images will still be optimized but you will need to re-index and re-optimize all images again. Optimizing images twice or multiple times will not change quality of images. Image optimization utilities sense if images are optimized and just re-save images without changing them.

Download this release

Release Info

Developer Apptrian
Extension Apptrian_Image_Optimizer
Version 2.1.0
Comparing to
See all releases


Code changes from version 2.0.0 to 2.1.0

app/code/community/Apptrian/ImageOptimizer/Block/Adminhtml/Stats.php CHANGED
@@ -19,11 +19,10 @@ class Apptrian_ImageOptimizer_Block_Adminhtml_Stats
19
  Varien_Data_Form_Element_Abstract $element
20
  )
21
  {
22
- $element = null;
23
- $r = Mage::getResourceModel('apptrian_imageoptimizer/file');
24
-
25
- $indexed = $r->getFileCount();
26
- $optimized = $r->getFileCount(1);
27
 
28
  // Fix for division by zero possibility
29
  if ($indexed == 0) {
19
  Varien_Data_Form_Element_Abstract $element
20
  )
21
  {
22
+ $element = null;
23
+ $r = Mage::helper('apptrian_imageoptimizer')->getFileCount();
24
+ $indexed = $r['indexed'];
25
+ $optimized = $r['optimized'];
 
26
 
27
  // Fix for division by zero possibility
28
  if ($indexed == 0) {
app/code/community/Apptrian/ImageOptimizer/Helper/Data.php CHANGED
@@ -31,12 +31,47 @@ class Apptrian_ImageOptimizer_Helper_Data extends Mage_Core_Helper_Abstract
31
  protected $_utilPath = null;
32
 
33
  /**
34
- * extension (for win binaries)
35
  *
36
  * @var null|string
37
  */
38
  protected $_utilExt = null;
39
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  /**
41
  * Returns extension version.
42
  *
@@ -66,15 +101,15 @@ class Apptrian_ImageOptimizer_Helper_Data extends Mage_Core_Helper_Abstract
66
  */
67
  public function getBaseDir()
68
  {
69
-
70
  if ($this->_baseDir === null) {
71
 
72
  $this->_baseDir = Mage::getBaseDir();
73
 
74
  }
75
-
76
  return $this->_baseDir;
77
-
78
  }
79
 
80
  /**
@@ -235,74 +270,73 @@ class Apptrian_ImageOptimizer_Helper_Data extends Mage_Core_Helper_Abstract
235
  */
236
  public function optimize()
237
  {
 
 
 
238
  // Get Batch Size
239
- $batchSize = $this->getConfig(
240
  'apptrian_imageoptimizer/general/batch_size'
241
  );
242
 
243
- // Get Collection of files for optimization but limited by batch size
244
- $collection = Mage::getModel('apptrian_imageoptimizer/file')
245
- ->getCollection()
246
- ->addFieldToSelect(array('id', 'file_path'))
247
- ->addFieldToFilter('optimized', array('eq' => 0))
248
- ->setPageSize($batchSize)
249
- ->load();
250
 
 
 
251
  $toUpdate = array();
252
- $toDelete = array();
253
- $oldFileSize = 0;
 
254
 
255
- foreach ($collection as $item) {
256
-
257
- $id = $item->getId();
258
- $fPath = $item->getFilePath();
259
 
260
- $filePath = realpath($fPath);
 
 
261
 
262
  // If image exists, optimize else remove it from database
263
  if (file_exists($filePath)) {
264
 
265
- $oldFileSize = filesize($filePath);
266
-
267
  if ($this->optimizeFile($filePath)) {
268
 
269
- $toUpdate[$id]['file_path'] = $fPath;
270
- $toUpdate[$id]['old_file_size'] = $oldFileSize;
271
- $toUpdate[$id]['optimized'] = 1;
272
 
273
  }
274
 
275
  } else {
276
 
277
- $toDelete[] = $id;
 
278
 
279
  }
280
 
281
  }
282
 
283
- // Itereate over $toUpdate array and set modified time and new_file_size
284
- // (mtime etc) takes a split second to update
 
 
 
285
  foreach ($toUpdate as $i => $f) {
286
 
287
- $filePath = realpath($f['file_path']);
 
 
288
 
289
  if (file_exists($filePath)) {
290
- $toUpdate[$i]['new_file_size'] = filesize($filePath);
291
- $toUpdate[$i]['optimization_time'] = filemtime($filePath);
 
 
292
  }
293
 
 
 
 
294
  }
295
 
296
- $resource = Mage::getResourceModel('apptrian_imageoptimizer/file');
297
-
298
- $resultA = $resource->deleteFiles($toDelete);
299
- $resultB = $resource->updateFiles($toUpdate);
300
-
301
- if ($resultA === true && $resultB === true) {
302
- return true;
303
- } else {
304
- return false;
305
- }
306
 
307
  }
308
 
@@ -314,82 +348,102 @@ class Apptrian_ImageOptimizer_Helper_Data extends Mage_Core_Helper_Abstract
314
  public function scanAndReindex()
315
  {
316
 
317
- $collection = Mage::getModel('apptrian_imageoptimizer/file')
318
- ->getCollection()
319
- ->addFieldToSelect(array('id', 'file_path', 'optimization_time'))
320
- ->load();
321
 
322
- $inIndex = array();
323
- $toAdd = array();
324
- $toUpdate = array();
325
- $toDelete = array();
326
- $id = 0;
327
- $filePath = '';
328
 
329
- foreach ($collection as $item) {
330
-
331
- $id = $item->getId();
332
 
333
- $inIndex[$id] = 0;
334
-
335
- $filePath = realpath($item->getFilePath());
336
 
337
  if (file_exists($filePath)) {
338
- if (filemtime($filePath) != $item->getOptimizationTime()) {
339
- $toUpdate[] = $id;
 
 
 
340
  }
341
  } else {
342
- $toDelete[] = $id;
 
 
 
343
  }
344
 
345
  }
346
 
 
 
347
 
348
- $files = array();
349
- $paths = $this->getPaths();
350
-
351
  foreach ($paths as $path) {
352
 
353
- $iterator = new RecursiveIteratorIterator(
354
- new RecursiveDirectoryIterator(
355
- $this->getBaseDir() . DS . $path,
356
- RecursiveDirectoryIterator::FOLLOW_SYMLINKS
357
- )
358
- );
359
 
360
- foreach ( $iterator as $filename => $file ) {
361
- if ($file->isFile()
362
- && preg_match(
363
- '/^.+\.(jpe?g|gif|png)$/i', $file->getFilename()
364
- )
365
- ) {
366
- $filePath = $file->getRealPath();
367
- if (!is_writable($filePath)) {
368
- continue;
369
- }
370
-
371
- $files[md5($filePath)] = $filePath;
372
-
373
- }
374
- }
375
-
376
  }
377
 
 
 
 
 
 
 
 
 
 
 
 
378
 
379
- $toAdd = array_diff_key($files, $inIndex);
 
 
 
380
 
381
- $resource = Mage::getResourceModel('apptrian_imageoptimizer/file');
 
 
 
 
 
382
 
383
- $resultA = $resource->deleteFiles($toDelete);
384
- $resultB = $resource->updateFilesOptimizedField($toUpdate);
385
- $resultC = $resource->addFiles($toAdd);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
386
 
387
- if ($resultA === true && $resultB === true && $resultC === true) {
388
- return true;
389
- } else {
390
- return false;
391
  }
392
 
 
 
 
393
  }
394
 
395
  /**
@@ -523,8 +577,8 @@ class Apptrian_ImageOptimizer_Helper_Data extends Mage_Core_Helper_Abstract
523
  '/'
524
  );
525
 
526
- $dirs = explode('/', $pathString);
527
- $path = implode(DS, $dirs);
528
 
529
  $this->_utilPath = $this->getBaseDir() . DS . $path . DS . $os;
530
 
@@ -533,4 +587,246 @@ class Apptrian_ImageOptimizer_Helper_Data extends Mage_Core_Helper_Abstract
533
  return $this->_utilPath;
534
  }
535
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
536
  }
31
  protected $_utilPath = null;
32
 
33
  /**
34
+ * Extension (for win binaries)
35
  *
36
  * @var null|string
37
  */
38
  protected $_utilExt = null;
39
 
40
+ /**
41
+ * Index filename.
42
+ *
43
+ * @var string $_indexFilename
44
+ */
45
+ protected $_indexFilename = 'apptrian_imageoptimizer_index.data';
46
+
47
+ /**
48
+ * Index path.
49
+ *
50
+ * @var null|string $_indexPath
51
+ */
52
+ protected $_indexPath = null;
53
+
54
+ /**
55
+ * Index array.
56
+ *
57
+ * @var array $_index
58
+ */
59
+ protected $_index = array();
60
+
61
+ /**
62
+ * Total count of files in index.
63
+ *
64
+ * @var integer $_indexTotalCount
65
+ */
66
+ protected $_indexTotalCount = 0;
67
+
68
+ /**
69
+ * Count of files that are optimized.
70
+ *
71
+ * @var integer $_indexOptimizedCount
72
+ */
73
+ protected $_indexOptimizedCount = 0;
74
+
75
  /**
76
  * Returns extension version.
77
  *
101
  */
102
  public function getBaseDir()
103
  {
104
+
105
  if ($this->_baseDir === null) {
106
 
107
  $this->_baseDir = Mage::getBaseDir();
108
 
109
  }
110
+
111
  return $this->_baseDir;
112
+
113
  }
114
 
115
  /**
270
  */
271
  public function optimize()
272
  {
273
+
274
+ $this->loadIndex();
275
+
276
  // Get Batch Size
277
+ $batchSize = (int) $this->getConfig(
278
  'apptrian_imageoptimizer/general/batch_size'
279
  );
280
 
281
+ // Get array of files for optimization limited by batch size
282
+ $files = $this->getFiles($batchSize);
 
 
 
 
 
283
 
284
+ $id = '';
285
+ $item = array();
286
  $toUpdate = array();
287
+ $encodedPath = '';
288
+ $decodedPath = '';
289
+ $filePath = '';
290
 
291
+ // Optimize batch of files
292
+ foreach ($files as $id => $item) {
 
 
293
 
294
+ $encodedPath = $item['f'];
295
+ $decodedPath = utf8_decode($encodedPath);
296
+ $filePath = realpath($decodedPath);
297
 
298
  // If image exists, optimize else remove it from database
299
  if (file_exists($filePath)) {
300
 
 
 
301
  if ($this->optimizeFile($filePath)) {
302
 
303
+ $toUpdate[$id]['f'] = $encodedPath;
 
 
304
 
305
  }
306
 
307
  } else {
308
 
309
+ // Remove files that do not exist anymore from the index
310
+ unset($this->_index[$id]);
311
 
312
  }
313
 
314
  }
315
 
316
+ $i = '';
317
+ $f = array();
318
+
319
+ // Itereate over $toUpdate array and set modified time
320
+ // (mtime) takes a split second to update
321
  foreach ($toUpdate as $i => $f) {
322
 
323
+ $encodedPath = $f['f'];
324
+ $decodedPath = utf8_decode($encodedPath);
325
+ $filePath = realpath($decodedPath);
326
 
327
  if (file_exists($filePath)) {
328
+
329
+ // Update optimized file information in index
330
+ $this->_index[$i]['t'] = filemtime($filePath);
331
+
332
  }
333
 
334
+ // Free Memory
335
+ unset($toUpdate[$i]);
336
+
337
  }
338
 
339
+ return $this->saveIndex();
 
 
 
 
 
 
 
 
 
340
 
341
  }
342
 
348
  public function scanAndReindex()
349
  {
350
 
351
+ $this->loadIndex();
 
 
 
352
 
353
+ $id = '';
354
+ $item = array();
355
+ $encodedPath = '';
356
+ $decodedPath = '';
357
+ $filePath = '';
 
358
 
359
+ // Check index for files that need to be updated and/or removed
360
+ foreach ($this->_index as $id => $item) {
 
361
 
362
+ $encodedPath = $item['f'];
363
+ $decodedPath = utf8_decode($encodedPath);
364
+ $filePath = realpath($decodedPath);
365
 
366
  if (file_exists($filePath)) {
367
+ if ($item['t'] != 0 && filemtime($filePath) != $item['t']) {
368
+
369
+ // Update time to 0 in index so it can be optimized again
370
+ $this->_index[$id]['t'] = 0;
371
+
372
  }
373
  } else {
374
+
375
+ // Remove files that do not exist anymore from the index
376
+ unset($this->_index[$id]);
377
+
378
  }
379
 
380
  }
381
 
382
+ $paths = $this->getPaths();
383
+ $path = '';
384
 
385
+ // Scan for new files and add them to the index
 
 
386
  foreach ($paths as $path) {
387
 
388
+ $this->scanAndReindexPath($path);
 
 
 
 
 
389
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
390
  }
391
 
392
+ return $this->saveIndex();
393
+
394
+ }
395
+
396
+ /**
397
+ * Scans provided path for images and adds them to index.
398
+ *
399
+ * @param string $path
400
+ */
401
+ public function scanAndReindexPath($path)
402
+ {
403
 
404
+ $id = '';
405
+ $encodedPath = '';
406
+ $filePath = '';
407
+ $file = null;
408
 
409
+ $iterator = new RecursiveIteratorIterator(
410
+ new RecursiveDirectoryIterator(
411
+ $this->getBaseDir() . DS . $path,
412
+ RecursiveDirectoryIterator::FOLLOW_SYMLINKS
413
+ )
414
+ );
415
 
416
+ foreach ($iterator as $file) {
417
+
418
+ if ($file->isFile()
419
+ && preg_match(
420
+ '/^.+\.(jpe?g|gif|png)$/i', $file->getFilename()
421
+ )
422
+ ) {
423
+
424
+ $filePath = $file->getRealPath();
425
+ if (!is_writable($filePath)) {
426
+ continue;
427
+ }
428
+
429
+ $encodedPath = utf8_encode($filePath);
430
+ $id = md5($encodedPath);
431
+
432
+ // Add only if file is not already in the index
433
+ if (!isset($this->_index[$id])) {
434
+ $this->_index[$id] = array('f' => $encodedPath, 't' => 0);
435
+ }
436
+
437
+ }
438
+
439
+ // Free Memory
440
+ $file = null;
441
 
 
 
 
 
442
  }
443
 
444
+ // Free Memory
445
+ $iterator = null;
446
+
447
  }
448
 
449
  /**
577
  '/'
578
  );
579
 
580
+ $dirs = explode('/', $pathString);
581
+ $path = implode(DS, $dirs);
582
 
583
  $this->_utilPath = $this->getBaseDir() . DS . $path . DS . $os;
584
 
587
  return $this->_utilPath;
588
  }
589
 
590
+ /**
591
+ * Returns index path.
592
+ *
593
+ * @return string
594
+ */
595
+ public function getIndexPath()
596
+ {
597
+ if ($this->_indexPath === null) {
598
+
599
+ $this->_indexPath = Mage::getBaseDir('var') . DS
600
+ . $this->_indexFilename;
601
+
602
+ }
603
+
604
+ return $this->_indexPath;
605
+ }
606
+
607
+ /**
608
+ * Returns array of files for optimization limited by $batchSize.
609
+ *
610
+ * @param int $batchSize
611
+ */
612
+ public function getFiles($batchSize)
613
+ {
614
+
615
+ $files = array();
616
+ $counter = 0;
617
+
618
+ foreach ($this->_index as $id => $f) {
619
+
620
+ if ($counter == $batchSize) {
621
+ break;
622
+ }
623
+
624
+ if ($f['t'] == 0) {
625
+ $files[$id] = $f;
626
+ $counter++;
627
+ }
628
+
629
+ }
630
+
631
+ return $files;
632
+
633
+ }
634
+
635
+ /**
636
+ * Returns count of indexed and optmized files.
637
+ *
638
+ * @return array
639
+ */
640
+ public function getFileCount()
641
+ {
642
+
643
+ $this->loadIndex();
644
+
645
+ $r['indexed'] = $this->_indexTotalCount;
646
+ $r['optimized'] = $this->_indexOptimizedCount;
647
+
648
+ // Free memory
649
+ $this->_index = null;
650
+
651
+ return $r;
652
+
653
+ }
654
+
655
+ /**
656
+ * Clear index (Empty index file).
657
+ *
658
+ * @return boolean
659
+ */
660
+ public function clearIndex()
661
+ {
662
+
663
+ $r = file_put_contents($this->getIndexPath(), '', LOCK_EX);
664
+
665
+ if ($r === false) {
666
+ Mage::log('Clear index operation failed.');
667
+ } else {
668
+ $r = true;
669
+ }
670
+
671
+ return $r;
672
+
673
+ }
674
+
675
+ /**
676
+ * Load index from a file.
677
+ *
678
+ */
679
+ public function loadIndex()
680
+ {
681
+
682
+ $filePath = $this->getIndexPath();
683
+
684
+ if (file_exists($filePath)) {
685
+
686
+ $line = '';
687
+ $l = array();
688
+ $id = '';
689
+ $file = array();
690
+
691
+ $str = file_get_contents($filePath);
692
+
693
+ if ($str != '') {
694
+
695
+ $data = explode("\n", $str);
696
+
697
+ // Free Memory
698
+ unset($str);
699
+
700
+ $this->_indexTotalCount = count($data);
701
+
702
+ $i = 0;
703
+
704
+ for ($i = 0; $i < $this->_indexTotalCount; $i++) {
705
+
706
+ $line = $data[$i];
707
+ $l = explode('|', $line);
708
+ $id = (string) $l[0];
709
+ $file['f'] = (string) $l[1];
710
+ $file['t'] = (int) $l[2];
711
+
712
+ $this->_index[$id] = $file;
713
+
714
+ if ($file['t'] > 0) {
715
+ $this->_indexOptimizedCount++;
716
+ }
717
+
718
+ // Free Memory
719
+ unset($data[$i]);
720
+
721
+ }
722
+
723
+ // Free Memory
724
+ $data = null;
725
+
726
+ }
727
+
728
+ if (!$this->_index) {
729
+ $this->_index = array();
730
+ }
731
+
732
+ }
733
+
734
+ }
735
+
736
+ /**
737
+ * Save index to a file.
738
+ *
739
+ * @return boolean
740
+ */
741
+ public function saveIndex()
742
+ {
743
+
744
+ $id = '';
745
+ $f = '';
746
+ $data = array();
747
+ $c = 0;
748
+ $b = 0;
749
+ $r = false;
750
+
751
+ // Truncate existing index file
752
+ $this->clearIndex();
753
+
754
+ foreach ($this->_index as $id => $f) {
755
+
756
+ // str_replace() removes | from filename because | is delimiter
757
+ $data[] = sprintf(
758
+ '%s|%s|%d', $id, str_replace('|', '', $f['f']), $f['t']
759
+ );
760
+
761
+ // Free memory
762
+ unset($this->_index[$id]);
763
+
764
+ if ($c == 100000) {
765
+
766
+ // Save part of the file
767
+ $r = $this->saveToFile($data, $b);
768
+
769
+ // Free memory
770
+ $data = array();
771
+
772
+ // Increment batch
773
+ $b++;
774
+
775
+ // Reset count
776
+ $c = 0;
777
+
778
+ } else {
779
+
780
+ // Increment count
781
+ $c++;
782
+
783
+ }
784
+
785
+ }
786
+
787
+ // Save last part of the file
788
+ $r = $this->saveToFile($data, $b);
789
+
790
+ // Free memory
791
+ $this->_index = null;
792
+
793
+ if ($r === false) {
794
+ Mage::log('Writting index to a file failed.');
795
+ } else {
796
+ $r = true;
797
+ }
798
+
799
+ return $r;
800
+
801
+ }
802
+
803
+ /**
804
+ * Saves batch of data to a file.
805
+ *
806
+ * @param array $data
807
+ * @param int $b
808
+ */
809
+ public function saveToFile($data, $b)
810
+ {
811
+
812
+ $r = true;
813
+
814
+ if (count($data) > 0) {
815
+
816
+ $fh = fopen($this->getIndexPath(), 'a');
817
+
818
+ if ($b != 0) {
819
+ fwrite($fh, "\n");
820
+ }
821
+
822
+ $r = fwrite($fh, implode("\n", $data));
823
+
824
+ fclose($fh);
825
+
826
+ }
827
+
828
+ return $r;
829
+
830
+ }
831
+
832
  }
app/code/community/Apptrian/ImageOptimizer/Model/File.php DELETED
@@ -1,17 +0,0 @@
1
- <?php
2
- /**
3
- * @category Apptrian
4
- * @package Apptrian_ImageOptimizer
5
- * @author Apptrian
6
- * @copyright Copyright (c) 2016 Apptrian (http://www.apptrian.com)
7
- * @license http://opensource.org/licenses/osl-3.0.php Open Software License
8
- */
9
- class Apptrian_ImageOptimizer_Model_File extends Mage_Core_Model_Abstract
10
- {
11
-
12
- protected function _construct()
13
- {
14
- $this->_init('apptrian_imageoptimizer/file');
15
- }
16
-
17
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/code/community/Apptrian/ImageOptimizer/Model/Resource/File.php DELETED
@@ -1,264 +0,0 @@
1
- <?php
2
- /**
3
- * @category Apptrian
4
- * @package Apptrian_ImageOptimizer
5
- * @author Apptrian
6
- * @copyright Copyright (c) 2016 Apptrian (http://www.apptrian.com)
7
- * @license http://opensource.org/licenses/osl-3.0.php Open Software License
8
- */
9
- class Apptrian_ImageOptimizer_Model_Resource_File
10
- extends Mage_Core_Model_Resource_Db_Abstract
11
- {
12
-
13
- protected function _construct()
14
- {
15
- $this->_init('apptrian_imageoptimizer/file', 'id');
16
- }
17
-
18
- /**
19
- * Adds entries to the db with one query.
20
- * Used in scanAndReindex() method.
21
- *
22
- * @param array $files
23
- * @return boolean
24
- */
25
- public function addFiles($files)
26
- {
27
-
28
- if (count($files) > 0) {
29
-
30
- $resource = Mage::getSingleton('core/resource');
31
- $wConn = $resource->getConnection('core_write');
32
- $table = $resource->getTableName('apptrian_imageoptimizer/file');
33
-
34
- $query = 'INSERT INTO ' . $table . ' (`id`, `file_path`) VALUES ';
35
-
36
- $values = '';
37
-
38
- foreach ($files as $id => $path) {
39
- $values .= '(' . $wConn->quote($id) . ', '
40
- . $wConn->quote($path) . '),';
41
- }
42
-
43
- $query .= rtrim($values, ',') . ';';
44
-
45
- try {
46
- $wConn->query($query);
47
- return true;
48
- } catch (Exception $e) {
49
- Mage::log($e);
50
- return false;
51
- }
52
-
53
- } else {
54
-
55
- return true;
56
-
57
- }
58
-
59
- }
60
-
61
- /**
62
- * Updates db entries with new data using only one query.
63
- * Used in optimize() method.
64
- *
65
- * @param array $files
66
- * @return boolean
67
- */
68
- public function updateFiles($files)
69
- {
70
-
71
- if (count($files) > 0) {
72
-
73
- $resource = Mage::getSingleton('core/resource');
74
- $wConn = $resource->getConnection('core_write');
75
- $table = $resource->getTableName('apptrian_imageoptimizer/file');
76
-
77
- $query = 'UPDATE ' . $table . ' SET';
78
-
79
- $optimized = ' optimized = CASE id ';
80
- $optimizationTime = ' optimization_time = CASE id ';
81
- $oldFileSize = ' old_file_size = CASE id ';
82
- $newFileSize = ' new_file_size = CASE id ';
83
-
84
- $where = ' WHERE id IN (';
85
-
86
- foreach ($files as $id => $f) {
87
-
88
- $qId = $wConn->quote($id);
89
-
90
- $optimized .= 'WHEN ' . $qId . ' THEN 1 ';
91
- $optimizationTime .= 'WHEN ' . $qId . ' THEN '
92
- . $f['optimization_time'] . ' ';
93
- $oldFileSize .= 'WHEN ' . $qId . ' THEN '
94
- . $f['old_file_size'] . ' ';
95
- $newFileSize .= 'WHEN ' . $qId . ' THEN '
96
- . $f['new_file_size'] . ' ';
97
-
98
- $where .= $qId . ',';
99
-
100
- }
101
-
102
- $query .= $optimized . 'END,';
103
- $query .= $optimizationTime . 'END,';
104
- $query .= $oldFileSize . 'END,';
105
- $query .= $newFileSize . 'END';
106
-
107
- $query .= rtrim($where, ',') . ');';
108
-
109
- try {
110
- $wConn->query($query);
111
- return true;
112
- } catch (Exception $e) {
113
- Mage::log($e);
114
- return false;
115
- }
116
-
117
- } else {
118
-
119
- return true;
120
-
121
- }
122
-
123
- }
124
-
125
- /**
126
- * Updates "optimized" field in db with one query.
127
- * Used in scanAndReindex() method.
128
- *
129
- * @param array $files
130
- * @return boolean
131
- */
132
- public function updateFilesOptimizedField($files)
133
- {
134
-
135
- if (count($files) > 0) {
136
-
137
- $resource = Mage::getSingleton('core/resource');
138
- $wConn = $resource->getConnection('core_write');
139
- $table = $resource->getTableName('apptrian_imageoptimizer/file');
140
-
141
- $query = 'UPDATE ' . $table . ' SET optimized = 0 WHERE id IN (';
142
-
143
- $values = '';
144
-
145
- foreach ($files as $id) {
146
- $values .= $wConn->quote($id) . ',';
147
- }
148
-
149
- $query .= rtrim($values, ',') . ');';
150
-
151
- try {
152
- $wConn->query($query);
153
- return true;
154
- } catch (Exception $e) {
155
- Mage::log($e);
156
- return false;
157
- }
158
-
159
- } else {
160
-
161
- return true;
162
-
163
- }
164
-
165
- }
166
-
167
- /**
168
- * Deletes entries from db for files that do not exist anymore.
169
- * Used in scanAndReindex() and optimize() methods.
170
- *
171
- * @param array $files
172
- * @return boolean
173
- */
174
- public function deleteFiles($files)
175
- {
176
-
177
- if (count($files) > 0) {
178
-
179
- $resource = Mage::getSingleton('core/resource');
180
- $wConn = $resource->getConnection('core_write');
181
- $table = $resource->getTableName('apptrian_imageoptimizer/file');
182
-
183
- $query = 'DELETE FROM ' . $table . ' WHERE id IN (';
184
-
185
- $values = '';
186
-
187
- foreach ($files as $id) {
188
- $values .= $wConn->quote($id) . ',';
189
- }
190
-
191
- $query .= rtrim($values, ',') . ');';
192
-
193
- try {
194
- $wConn->query($query);
195
- return true;
196
- } catch (Exception $e) {
197
- Mage::log($e);
198
- return false;
199
- }
200
-
201
- } else {
202
-
203
- return true;
204
-
205
- }
206
-
207
- }
208
-
209
- /**
210
- * Returns entry count. If $optimized is provided returns count
211
- * of optimized or not optimized files.
212
- *
213
- * @param int $optimized
214
- * @return boolean
215
- */
216
- public function getFileCount($optimized = null)
217
- {
218
-
219
- $resource = Mage::getSingleton('core/resource');
220
- $rConn = $resource->getConnection('core_read');
221
- $table = $resource->getTableName('apptrian_imageoptimizer/file');
222
-
223
- $query = 'SELECT COUNT(id) FROM ' . $table;
224
-
225
- if ($optimized !== null) {
226
- $query .= ' WHERE optimized = ' . $optimized;
227
- }
228
-
229
- $query .= ';';
230
-
231
- try {
232
- return $rConn->fetchOne($query);
233
- } catch (Exception $e) {
234
- Mage::log($e);
235
- return false;
236
- }
237
-
238
- }
239
-
240
- /**
241
- * Clear index. (Empty db table apptrian_imageoptimizer_files)
242
- *
243
- * @return boolean
244
- */
245
- public function clearIndex()
246
- {
247
-
248
- $resource = Mage::getSingleton('core/resource');
249
- $wConn = $resource->getConnection('core_write');
250
- $table = $resource->getTableName('apptrian_imageoptimizer/file');
251
-
252
- $query = 'TRUNCATE ' . $table . ';';
253
-
254
- try {
255
- $wConn->query($query);
256
- return true;
257
- } catch (Exception $e) {
258
- Mage::log($e);
259
- return false;
260
- }
261
-
262
- }
263
-
264
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/code/community/Apptrian/ImageOptimizer/Model/Resource/File/Collection.php DELETED
@@ -1,18 +0,0 @@
1
- <?php
2
- /**
3
- * @category Apptrian
4
- * @package Apptrian_ImageOptimizer
5
- * @author Apptrian
6
- * @copyright Copyright (c) 2016 Apptrian (http://www.apptrian.com)
7
- * @license http://opensource.org/licenses/osl-3.0.php Open Software License
8
- */
9
- class Apptrian_ImageOptimizer_Model_Resource_File_Collection
10
- extends Mage_Core_Model_Resource_Db_Collection_Abstract
11
- {
12
-
13
- protected function _construct()
14
- {
15
- $this->_init('apptrian_imageoptimizer/file');
16
- }
17
-
18
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/code/community/Apptrian/ImageOptimizer/controllers/Adminhtml/Apptrian/ImgoptController.php CHANGED
@@ -101,11 +101,11 @@ class Apptrian_ImageOptimizer_Adminhtml_Apptrian_ImgoptController
101
  public function clearAction()
102
  {
103
 
104
- $resource = Mage::getResourceModel('apptrian_imageoptimizer/file');
105
 
106
  try {
107
 
108
- $resource->clearIndex();
109
 
110
  $message = $this
111
  ->__('Clear index operation completed successfully.');
101
  public function clearAction()
102
  {
103
 
104
+ $helper = Mage::helper('apptrian_imageoptimizer');
105
 
106
  try {
107
 
108
+ $helper->clearIndex();
109
 
110
  $message = $this
111
  ->__('Clear index operation completed successfully.');
app/code/community/Apptrian/ImageOptimizer/etc/config.xml CHANGED
@@ -11,23 +11,14 @@
11
  <config>
12
  <modules>
13
  <Apptrian_ImageOptimizer>
14
- <version>2.0.0</version>
15
  </Apptrian_ImageOptimizer>
16
  </modules>
17
  <global>
18
  <models>
19
  <apptrian_imageoptimizer>
20
  <class>Apptrian_ImageOptimizer_Model</class>
21
- <resourceModel>apptrian_imageoptimizer_resource</resourceModel>
22
  </apptrian_imageoptimizer>
23
- <apptrian_imageoptimizer_resource>
24
- <class>Apptrian_ImageOptimizer_Model_Resource</class>
25
- <entities>
26
- <file>
27
- <table>apptrian_imageoptimizer_files</table>
28
- </file>
29
- </entities>
30
- </apptrian_imageoptimizer_resource>
31
  </models>
32
  <resources>
33
  <apptrian_imageoptimizer_setup>
@@ -38,16 +29,6 @@
38
  <use>core_setup</use>
39
  </connection>
40
  </apptrian_imageoptimizer_setup>
41
- <apptrian_imageoptimizer_write>
42
- <connection>
43
- <use>core_write</use>
44
- </connection>
45
- </apptrian_imageoptimizer_write>
46
- <apptrian_imageoptimizer_read>
47
- <connection>
48
- <use>core_read</use>
49
- </connection>
50
- </apptrian_imageoptimizer_read>
51
  </resources>
52
  <blocks>
53
  <apptrian_imageoptimizer>
@@ -86,7 +67,7 @@
86
  <jpg_options>-copy none -optimize -progressive -outfile %filepath% %filepath%</jpg_options>
87
  <png>optipng</png>
88
  <png_path></png_path>
89
- <png_options>-o7 -strip all %filepath%</png_options>
90
  </utility>
91
  </apptrian_imageoptimizer>
92
  </default>
11
  <config>
12
  <modules>
13
  <Apptrian_ImageOptimizer>
14
+ <version>2.1.0</version>
15
  </Apptrian_ImageOptimizer>
16
  </modules>
17
  <global>
18
  <models>
19
  <apptrian_imageoptimizer>
20
  <class>Apptrian_ImageOptimizer_Model</class>
 
21
  </apptrian_imageoptimizer>
 
 
 
 
 
 
 
 
22
  </models>
23
  <resources>
24
  <apptrian_imageoptimizer_setup>
29
  <use>core_setup</use>
30
  </connection>
31
  </apptrian_imageoptimizer_setup>
 
 
 
 
 
 
 
 
 
 
32
  </resources>
33
  <blocks>
34
  <apptrian_imageoptimizer>
67
  <jpg_options>-copy none -optimize -progressive -outfile %filepath% %filepath%</jpg_options>
68
  <png>optipng</png>
69
  <png_path></png_path>
70
+ <png_options>-o7 -quiet -strip all %filepath%</png_options>
71
  </utility>
72
  </apptrian_imageoptimizer>
73
  </default>
app/code/community/Apptrian/ImageOptimizer/sql/apptrian_imageoptimizer_setup/install-1.0.0.php DELETED
@@ -1,31 +0,0 @@
1
- <?php
2
- /**
3
- * @category Apptrian
4
- * @package Apptrian_ImageOptimizer
5
- * @author Apptrian
6
- * @copyright Copyright (c) 2016 Apptrian (http://www.apptrian.com)
7
- * @license http://opensource.org/licenses/osl-3.0.php Open Software License
8
- */
9
-
10
- $installer = $this;
11
-
12
- $installer->startSetup();
13
-
14
- $installer->run(
15
- "
16
-
17
- -- DROP TABLE IF EXISTS {$this->getTable('apptrian_imageoptimizer/file')};
18
- CREATE TABLE {$this->getTable('apptrian_imageoptimizer/file')} (
19
- `id` varchar(32) NOT NULL default '',
20
- `file_path` varchar(255) NOT NULL default '',
21
- `optimized` tinyint(1) NOT NULL default '0',
22
- `optimization_time` int(11) unsigned NOT NULL default '0',
23
- `old_file_size` int(11) unsigned NOT NULL default '0',
24
- `new_file_size` int(11) unsigned NOT NULL default '0',
25
- PRIMARY KEY (`id`)
26
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
27
-
28
- "
29
- );
30
-
31
- $installer->endSetup();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
package.xml CHANGED
@@ -1,23 +1,19 @@
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>Apptrian_Image_Optimizer</name>
4
- <version>2.0.0</version>
5
  <stability>stable</stability>
6
  <license uri="http://opensource.org/licenses/osl-3.0.php">Open Software License (OSL 3.0)</license>
7
  <channel>community</channel>
8
  <extends/>
9
  <summary>Optimize your images, reduce their file size without losing image quality and speed up your site.</summary>
10
  <description>Apptrian Image Optimizer will optimize your images (GIF, JPG, PNG) reduce their file size without losing image quality and speed up your site. Extension is very easy to install and use. You can optimize images by clicking a button in Magento Admin or automatically by a configurable cron job. If you are an advanced user you will be pleased to know that extension is fully configurable. You can change optimization options even swap utilities used for optimization with the ones you like. (By default our extension is using optimization utilities recommended by Google PageSpeed Insights.)</description>
11
- <notes>* Complete rewrite from the ground up&#xD;
12
- * Code standards improvements&#xD;
13
- * Fixed few small issues with admin blocks&#xD;
14
- * Empty Index is renamed to Clear Index including all block and methods&#xD;
15
- + Added separate cron jobs, one for scanning one for optimization&#xD;
16
- + Added option to force file permissions after optimization</notes>
17
  <authors><author><name>Apptrian</name><user>apptrian</user><email>apptrian@yahoo.com</email></author></authors>
18
- <date>2016-06-05</date>
19
- <time>15:25:56</time>
20
- <contents><target name="magecommunity"><dir name="Apptrian"><dir name="ImageOptimizer"><dir name="Block"><dir name="Adminhtml"><file name="About.php" hash="eea911933ee3ab8e57430398059828b2"/><dir name="Button"><file name="Clear.php" hash="1ee59b965300d3ca01a7ad51f82d7018"/><file name="Optimize.php" hash="5eab10e4709e7413bb470edb5c290302"/><file name="Scan.php" hash="df9f357ed3f7c27a1c8565a70ca9b74f"/></dir><file name="Info.php" hash="d96973cc7e45776c31ba39b8033159ae"/><file name="Stats.php" hash="6684beb43742aa42e52001e6f88787d8"/></dir></dir><dir name="Helper"><file name="Data.php" hash="0aeeff386d83a7182d110f92e0a0a52d"/></dir><dir name="Model"><dir name="Config"><file name="Batchsize.php" hash="1c72c04544d2444947566ebfa0b0bb4e"/><dir name="Cron"><file name="Optimize.php" hash="a7a1789cf3e8423379d0af4459290380"/><file name="Scan.php" hash="a9c2b3e81fce940a450f953fe19f6da2"/></dir><file name="Exactpath.php" hash="8e5efc5c70d852ee13f600ddd664c301"/><file name="Options.php" hash="7e372a49281ca73c8776aa386562a46e"/><file name="Path.php" hash="a0f04a0b84a6cc0cb455cbc698528bdc"/><file name="Paths.php" hash="85ce5ba99b9cfd253f78fff04e5db54a"/><file name="Permissions.php" hash="e10189c1eb5db46e14a9117582edd7fe"/><file name="Utility.php" hash="df8dbc1337bd53a84edf14acaea749dd"/></dir><file name="Cron.php" hash="ae7e2cf31b16408ffd79226bc1d154a7"/><file name="File.php" hash="aee110649c479fdb2aac2c69b416d07f"/><dir name="Resource"><dir name="File"><file name="Collection.php" hash="71f8258d0ce5c0b312ceb4f27a0aa2fd"/></dir><file name="File.php" hash="d8776a94bc47b8a577b05a0575c84a4e"/></dir></dir><dir name="controllers"><dir name="Adminhtml"><dir name="Apptrian"><file name="ImgoptController.php" hash="19cd9e95165517650f9f3bc64ace712c"/></dir></dir></dir><dir name="etc"><file name="config.xml" hash="7be1811a64c14bacb4e24da25a9aee1f"/><file name="system.xml" hash="251f1c2fbdeb0eccce05e8cf49c581c3"/></dir><dir name="sql"><dir name="apptrian_imageoptimizer_setup"><file name="install-1.0.0.php" hash="9b209f56fbda15ec59c2ef0e8332c2f6"/></dir></dir></dir></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><file name="apptrian_imageoptimizer.xml" hash="19f08ad048141ae01ee915faa655d1dd"/></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Apptrian_ImageOptimizer.xml" hash="d087a739b0b4a182b7efa4f5037b4e48"/></dir></target><target name="magelocale"><dir name="en_US"><file name="Apptrian_ImageOptimizer.csv" hash="14061fbdc4cbdf7c729ce83458dff5b8"/></dir></target><target name="mageskin"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="css"><file name="apptrian_imageoptimizer.css" hash="0f904cb2116423d1dfd626cfa8cfe39a"/></dir></dir></dir></dir></target><target name="magelib"><dir name="apptrian"><dir name="imageoptimizer"><dir name="elf32"><file name="gifsicle" hash="2583e5ceecf67a058fba2858986bb37f"/><file name="jpegoptim" hash="8a035613dd1a9467e5fe47c88a774104"/><file name="jpegtran" hash="fcef276e1f6b99d42d60abe373f37018"/><file name="optipng" hash="fb1334c73c7a91858a1816b05bfa3133"/></dir><dir name="elf64"><file name="gifsicle" hash="13adc57a621501a27a19443cb587ab2b"/><file name="jpegoptim" hash="8a035613dd1a9467e5fe47c88a774104"/><file name="jpegtran" hash="e6da2f02ac13237f7a8d91f0268ecf85"/><file name="optipng" hash="8fbf61c7e24f90128bbc138ddb671201"/></dir><dir name="win32"><file name="gifsicle.exe" hash="574a9274bbd4aec6a905b64b7da79617"/><file name="jpegoptim.exe" hash="cb4fa736e8b60aebfebff583d0ea6f34"/><file name="jpegtran.exe" hash="2ed29cb5dfb19ad21f3ba3d215f2453e"/><file name="libjpeg-62.dll" hash="48c64a6097bfbe8ca8eaa61ad7936aec"/><file name="optipng.exe" hash="e3d154829ea57a0bdd88b080f6851265"/></dir><dir name="win64"><file name="gifsicle.exe" hash="c7fe0fc6744a4e5303f8d924ee08a8d3"/><file name="jpegoptim.exe" hash="cb4fa736e8b60aebfebff583d0ea6f34"/><file name="jpegtran.exe" hash="dd709e653791c5a9ece818440f0ca089"/><file name="libjpeg-62.dll" hash="b4e05a1406a617e14b2ce7f6c28f382e"/><file name="optipng.exe" hash="e3d154829ea57a0bdd88b080f6851265"/></dir></dir></dir></target></contents>
21
  <compatible/>
22
  <dependencies><required><php><min>5.1.0</min><max>8.0.0</max></php></required></dependencies>
23
  </package>
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>Apptrian_Image_Optimizer</name>
4
+ <version>2.1.0</version>
5
  <stability>stable</stability>
6
  <license uri="http://opensource.org/licenses/osl-3.0.php">Open Software License (OSL 3.0)</license>
7
  <channel>community</channel>
8
  <extends/>
9
  <summary>Optimize your images, reduce their file size without losing image quality and speed up your site.</summary>
10
  <description>Apptrian Image Optimizer will optimize your images (GIF, JPG, PNG) reduce their file size without losing image quality and speed up your site. Extension is very easy to install and use. You can optimize images by clicking a button in Magento Admin or automatically by a configurable cron job. If you are an advanced user you will be pleased to know that extension is fully configurable. You can change optimization options even swap utilities used for optimization with the ones you like. (By default our extension is using optimization utilities recommended by Google PageSpeed Insights.)</description>
11
+ <notes>* Index is now saved to a file instead of database&#xD;
12
+ WARNING! If you are upgrading from any previous version of Image Optimizer you will loose old index data. Previously optimized images will still be optimized but you will need to re-index and re-optimize all images again. Optimizing images twice or multiple times will not change quality of images. Image optimization utilities sense if images are optimized and just re-save images without changing them.</notes>
 
 
 
 
13
  <authors><author><name>Apptrian</name><user>apptrian</user><email>apptrian@yahoo.com</email></author></authors>
14
+ <date>2016-06-18</date>
15
+ <time>13:14:42</time>
16
+ <contents><target name="magecommunity"><dir name="Apptrian"><dir name="ImageOptimizer"><dir name="Block"><dir name="Adminhtml"><file name="About.php" hash="eea911933ee3ab8e57430398059828b2"/><dir name="Button"><file name="Clear.php" hash="1ee59b965300d3ca01a7ad51f82d7018"/><file name="Optimize.php" hash="5eab10e4709e7413bb470edb5c290302"/><file name="Scan.php" hash="df9f357ed3f7c27a1c8565a70ca9b74f"/></dir><file name="Info.php" hash="d96973cc7e45776c31ba39b8033159ae"/><file name="Stats.php" hash="c47e232e6843b8be56ec0c2c824b2d52"/></dir></dir><dir name="Helper"><file name="Data.php" hash="2b683656b19c44d96081f92b05638568"/></dir><dir name="Model"><dir name="Config"><file name="Batchsize.php" hash="1c72c04544d2444947566ebfa0b0bb4e"/><dir name="Cron"><file name="Optimize.php" hash="a7a1789cf3e8423379d0af4459290380"/><file name="Scan.php" hash="a9c2b3e81fce940a450f953fe19f6da2"/></dir><file name="Exactpath.php" hash="8e5efc5c70d852ee13f600ddd664c301"/><file name="Options.php" hash="7e372a49281ca73c8776aa386562a46e"/><file name="Path.php" hash="a0f04a0b84a6cc0cb455cbc698528bdc"/><file name="Paths.php" hash="85ce5ba99b9cfd253f78fff04e5db54a"/><file name="Permissions.php" hash="e10189c1eb5db46e14a9117582edd7fe"/><file name="Utility.php" hash="df8dbc1337bd53a84edf14acaea749dd"/></dir><file name="Cron.php" hash="ae7e2cf31b16408ffd79226bc1d154a7"/></dir><dir name="controllers"><dir name="Adminhtml"><dir name="Apptrian"><file name="ImgoptController.php" hash="1aaa610f7274155927e3acccd086496d"/></dir></dir></dir><dir name="etc"><file name="config.xml" hash="cbe005031f5606b803498cc484c57687"/><file name="system.xml" hash="251f1c2fbdeb0eccce05e8cf49c581c3"/></dir></dir></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><file name="apptrian_imageoptimizer.xml" hash="19f08ad048141ae01ee915faa655d1dd"/></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Apptrian_ImageOptimizer.xml" hash="d087a739b0b4a182b7efa4f5037b4e48"/></dir></target><target name="magelocale"><dir name="en_US"><file name="Apptrian_ImageOptimizer.csv" hash="14061fbdc4cbdf7c729ce83458dff5b8"/></dir></target><target name="mageskin"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="css"><file name="apptrian_imageoptimizer.css" hash="0f904cb2116423d1dfd626cfa8cfe39a"/></dir></dir></dir></dir></target><target name="magelib"><dir name="apptrian"><dir name="imageoptimizer"><dir name="elf32"><file name="gifsicle" hash="2583e5ceecf67a058fba2858986bb37f"/><file name="jpegoptim" hash="8a035613dd1a9467e5fe47c88a774104"/><file name="jpegtran" hash="fcef276e1f6b99d42d60abe373f37018"/><file name="optipng" hash="fb1334c73c7a91858a1816b05bfa3133"/></dir><dir name="elf64"><file name="gifsicle" hash="13adc57a621501a27a19443cb587ab2b"/><file name="jpegoptim" hash="8a035613dd1a9467e5fe47c88a774104"/><file name="jpegtran" hash="e6da2f02ac13237f7a8d91f0268ecf85"/><file name="optipng" hash="8fbf61c7e24f90128bbc138ddb671201"/></dir><dir name="win32"><file name="gifsicle.exe" hash="574a9274bbd4aec6a905b64b7da79617"/><file name="jpegoptim.exe" hash="cb4fa736e8b60aebfebff583d0ea6f34"/><file name="jpegtran.exe" hash="2ed29cb5dfb19ad21f3ba3d215f2453e"/><file name="libjpeg-62.dll" hash="48c64a6097bfbe8ca8eaa61ad7936aec"/><file name="optipng.exe" hash="e3d154829ea57a0bdd88b080f6851265"/></dir><dir name="win64"><file name="gifsicle.exe" hash="c7fe0fc6744a4e5303f8d924ee08a8d3"/><file name="jpegoptim.exe" hash="cb4fa736e8b60aebfebff583d0ea6f34"/><file name="jpegtran.exe" hash="dd709e653791c5a9ece818440f0ca089"/><file name="libjpeg-62.dll" hash="b4e05a1406a617e14b2ce7f6c28f382e"/><file name="optipng.exe" hash="e3d154829ea57a0bdd88b080f6851265"/></dir></dir></dir></target></contents>
17
  <compatible/>
18
  <dependencies><required><php><min>5.1.0</min><max>8.0.0</max></php></required></dependencies>
19
  </package>