Tiny_Compresss_Images - Version 2.0.0

Version Notes

==== 2.0.0 ====
Public release - Completely Rebuild code

Download this release

Release Info

Developer Tiny
Extension Tiny_Compresss_Images
Version 2.0.0
Comparing to
See all releases


Code changes from version 1.0.1 to 2.0.0

Files changed (86) hide show
  1. app/code/community/Tiny/CompressImages/Block/Adminhtml/ApiNotification.php +27 -0
  2. app/code/community/Tiny/CompressImages/Block/Adminhtml/System/Config/Form.php +107 -0
  3. app/code/community/Tiny/CompressImages/Block/Adminhtml/System/Config/Form/Field/AccountType.php +17 -0
  4. app/code/community/Tiny/CompressImages/Block/Adminhtml/System/Config/Form/Field/Api.php +111 -0
  5. app/code/community/Tiny/CompressImages/Block/Adminhtml/System/Config/Form/Field/LogFile.php +30 -0
  6. app/code/community/Tiny/CompressImages/Block/Adminhtml/System/Config/Form/Field/LogStatus.php +34 -0
  7. app/code/community/Tiny/CompressImages/Block/Adminhtml/System/Config/Form/Field/Radios.php +81 -0
  8. app/code/community/Tiny/CompressImages/Block/Adminhtml/System/Config/Form/Field/Saved.php +20 -0
  9. app/code/community/Tiny/CompressImages/Block/Adminhtml/System/Config/Form/Field/Status.php +65 -0
  10. app/code/community/Tiny/CompressImages/Block/Adminhtml/System/Config/Form/Field/SupportTab.php +50 -0
  11. app/code/community/Tiny/CompressImages/Exception.php +2 -0
  12. app/code/community/Tiny/CompressImages/Helper/Config.php +184 -0
  13. app/code/community/Tiny/CompressImages/Helper/Data.php +205 -0
  14. app/code/community/Tiny/CompressImages/Helper/Tinify.php +750 -0
  15. app/code/community/Tiny/CompressImages/Model/Image.php +327 -0
  16. app/code/community/Tiny/CompressImages/Model/Observer.php +20 -68
  17. app/code/community/Tiny/CompressImages/Model/Product/Image.php +62 -9
  18. app/code/community/Tiny/CompressImages/Model/Resource/Image.php +13 -0
  19. app/code/community/Tiny/CompressImages/Model/Resource/Image/Collection.php +9 -0
  20. app/code/community/Tiny/CompressImages/Model/Resource/Setup.php +76 -0
  21. app/code/community/Tiny/CompressImages/Model/Resource/Totals.php +13 -0
  22. app/code/community/Tiny/CompressImages/Model/Resource/Totals/Collection.php +9 -0
  23. app/code/community/Tiny/CompressImages/Model/System/Config/Backend/ApiKey.php +33 -0
  24. app/code/community/Tiny/CompressImages/Model/System/Config/Backend/Comment/LoggingMode.php +26 -0
  25. app/code/community/Tiny/CompressImages/Model/System/Config/Source/Cms/ImageTypes.php +30 -0
  26. app/code/community/Tiny/CompressImages/Model/System/Config/Source/Log.php +34 -0
  27. app/code/community/Tiny/CompressImages/Model/System/Config/Source/OnOff.php +26 -0
  28. app/code/community/Tiny/CompressImages/Model/System/Config/Source/Product/ImageTypes.php +34 -0
  29. app/code/community/Tiny/CompressImages/Model/System/Config/Source/Testlive.php +33 -0
  30. app/code/community/Tiny/CompressImages/Model/Totals.php +89 -0
  31. app/code/community/Tiny/CompressImages/Test/Block/Adminhtml/System/Config/Form/Field/LogStatusTest.php +32 -0
  32. app/code/community/Tiny/CompressImages/Test/Framework/Tiny/Test/Config.php +72 -0
  33. app/code/community/Tiny/CompressImages/Test/Framework/Tiny/Test/Http/Response.php +58 -0
  34. app/code/community/Tiny/CompressImages/Test/Framework/Tiny/Test/TestCase.php +244 -0
  35. app/code/community/Tiny/CompressImages/Test/Helper/ConfigTest.php +96 -0
  36. app/code/community/Tiny/CompressImages/Test/Model/ImageTest.php +227 -0
  37. app/code/community/Tiny/CompressImages/Test/Model/Product/ImageTest.php +40 -0
  38. app/code/community/Tiny/CompressImages/Test/Model/System/Config/Backend/Comment/LoggingModeTest.php +34 -0
  39. app/code/community/Tiny/CompressImages/Test/bootstrap.php +10 -0
  40. app/code/community/Tiny/CompressImages/controllers/CompressImagesAdminhtml/ConfigController.php +65 -0
  41. app/code/community/Tiny/CompressImages/controllers/CompressImagesAdminhtml/StatusController.php +46 -0
  42. app/code/community/Tiny/CompressImages/etc/adminhtml.xml +22 -17
  43. app/code/community/Tiny/CompressImages/etc/config.xml +103 -28
  44. app/code/community/Tiny/CompressImages/etc/system.xml +191 -87
  45. app/code/community/Tiny/CompressImages/sql/tiny_compressimages_setup/install-1.0.0.php +250 -0
  46. app/design/adminhtml/default/default/layout/Tiny/CompressImages.xml +16 -0
  47. app/design/adminhtml/default/default/template/Tiny/CompressImages/Api/keyNotification.phtml +9 -0
  48. app/design/adminhtml/default/default/template/Tiny/CompressImages/system/config/form/field/log_file.phtml +21 -0
  49. app/design/adminhtml/default/default/template/Tiny/CompressImages/system/config/form/field/log_status.phtml +164 -0
  50. app/design/adminhtml/default/default/template/Tiny/CompressImages/system/config/form/field/support_tab.phtml +87 -0
  51. app/etc/modules/Tiny_CompressImages.xml +7 -7
  52. app/locale/en_US/Tiny_CompressImages.csv +99 -0
  53. lib/TinyCompress/.gitignore +1 -0
  54. lib/TinyCompress/.travis.yml +25 -0
  55. lib/TinyCompress/LICENSE +21 -0
  56. lib/TinyCompress/README.md +50 -16
  57. lib/TinyCompress/class-tiny-compress-curl.php +0 -77
  58. lib/TinyCompress/class-tiny-compress-fopen.php +0 -85
  59. lib/TinyCompress/class-tiny-compress.php +0 -97
  60. lib/TinyCompress/class-tiny-exception.php +0 -32
  61. lib/TinyCompress/class-tiny-php.php +0 -29
  62. lib/TinyCompress/composer.json +41 -0
  63. lib/TinyCompress/composer.lock +977 -0
  64. lib/TinyCompress/config/tinypng-api.ini +0 -2
  65. lib/TinyCompress/lib/Tinify.php +85 -0
  66. lib/TinyCompress/lib/Tinify/Client.php +105 -0
  67. lib/TinyCompress/lib/Tinify/Exception.php +34 -0
  68. lib/TinyCompress/lib/Tinify/Result.php +36 -0
  69. lib/TinyCompress/lib/Tinify/ResultMeta.php +23 -0
  70. lib/TinyCompress/lib/Tinify/Source.php +69 -0
  71. lib/TinyCompress/{cacert.pem → lib/data/cacert.pem} +307 -213
  72. lib/TinyCompress/phpunit.xml +12 -0
  73. lib/TinyCompress/test/TinifyClientTest.php +176 -0
  74. lib/TinyCompress/test/TinifyResultMetaTest.php +20 -0
  75. lib/TinyCompress/test/TinifyResultTest.php +35 -0
  76. lib/TinyCompress/test/TinifySourceTest.php +314 -0
  77. lib/TinyCompress/test/TinifyTest.php +100 -0
  78. lib/TinyCompress/test/curl_mock.php +160 -0
  79. lib/TinyCompress/test/examples/dummy.png +0 -0
  80. lib/TinyCompress/test/examples/voormedia.png +0 -0
  81. lib/TinyCompress/test/helper.php +14 -0
  82. lib/TinyCompress/test/integration.php +77 -0
  83. package.xml +75 -12
  84. skin/adminhtml/default/default/css/Tiny/CompressImages/config.css +157 -0
  85. skin/adminhtml/default/default/images/Tiny/CompressImages/george-magento@2x_opt.png +0 -0
  86. skin/adminhtml/default/default/images/Tiny/CompressImages/george-menu-icon@2x.png +0 -0
app/code/community/Tiny/CompressImages/Block/Adminhtml/ApiNotification.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Block_Adminhtml_ApiNotification extends Mage_Adminhtml_Block_Abstract
3
+ {
4
+ /**
5
+ * Check if the api key is set.
6
+ *
7
+ * @return bool
8
+ */
9
+ public function isApiKeySet()
10
+ {
11
+ $configHelper = Mage::helper('tiny_compressimages/config');
12
+
13
+ if ($configHelper->getApiKey()) {
14
+ return true;
15
+ }
16
+
17
+ return false;
18
+ }
19
+
20
+ /**
21
+ * @return string
22
+ */
23
+ public function getBackendUrl()
24
+ {
25
+ return Mage::helper('adminhtml')->getUrl('adminhtml/system_config/edit/section/tiny_compressimages/');
26
+ }
27
+ }
app/code/community/Tiny/CompressImages/Block/Adminhtml/System/Config/Form.php ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Block_Adminhtml_System_Config_Form extends Mage_Adminhtml_Block_System_Config_Form
3
+ {
4
+ /**
5
+ * @var array
6
+ */
7
+ protected $_elementTypes = array();
8
+
9
+ /**
10
+ * Add the new form elements
11
+ *
12
+ * @return array
13
+ */
14
+ protected function _getAdditionalElementTypes()
15
+ {
16
+ $this->_elementTypes = parent::_getAdditionalElementTypes();
17
+
18
+ $this
19
+ ->_addRadioButtons()
20
+ ->_addStatusIndicator()
21
+ ->_addSavedIndicator()
22
+ ->_addApiIndicator()
23
+ ->_addAccountType()
24
+ ->_addLogButtonType()
25
+ ;
26
+
27
+ return $this->_elementTypes;
28
+ }
29
+
30
+ /**
31
+ * Add the Off/Live/Test radio button list.
32
+ *
33
+ * @return $this
34
+ */
35
+ protected function _addRadioButtons()
36
+ {
37
+ $this->_elementTypes['compressimages_radios'] = Mage::getConfig()
38
+ ->getBlockClassName('tiny_compressimages/adminhtml_system_config_form_field_radios');
39
+
40
+ return $this;
41
+ }
42
+
43
+ /**
44
+ * Add a field that shows the status indicator.
45
+ *
46
+ * @return $this
47
+ */
48
+ protected function _addStatusIndicator()
49
+ {
50
+ $this->_elementTypes['compressimages_status'] = Mage::getConfig()
51
+ ->getBlockClassName('tiny_compressimages/adminhtml_system_config_form_field_status');
52
+
53
+ return $this;
54
+ }
55
+
56
+ /**
57
+ * Add a field that shows how much has been saved.
58
+ *
59
+ * @return $this
60
+ */
61
+ protected function _addSavedIndicator()
62
+ {
63
+ $this->_elementTypes['compressimages_saved'] = Mage::getConfig()
64
+ ->getBlockClassName('tiny_compressimages/adminhtml_system_config_form_field_saved');
65
+
66
+ return $this;
67
+ }
68
+
69
+ /**
70
+ * Add a field that shows the api status indicator.
71
+ *
72
+ * @return $this
73
+ */
74
+ protected function _addApiIndicator()
75
+ {
76
+ $this->_elementTypes['compressimages_api'] = Mage::getConfig()
77
+ ->getBlockClassName('tiny_compressimages/adminhtml_system_config_form_field_api');
78
+
79
+ return $this;
80
+ }
81
+
82
+ /**
83
+ * Add a field that shows the api status indicator.
84
+ *
85
+ * @return $this
86
+ */
87
+ protected function _addAccountType()
88
+ {
89
+ $this->_elementTypes['compressimages_account_type'] = Mage::getConfig()
90
+ ->getBlockClassName('tiny_compressimages/adminhtml_system_config_form_field_accountType');
91
+
92
+ return $this;
93
+ }
94
+
95
+ /**
96
+ * Add a field that shows the api status indicator.
97
+ *
98
+ * @return $this
99
+ */
100
+ protected function _addLogButtonType()
101
+ {
102
+ $this->_elementTypes['compressimages_log_button'] = Mage::getConfig()
103
+ ->getBlockClassName('tiny_compressimages/adminhtml_system_config_form_field_logFile');
104
+
105
+ return $this;
106
+ }
107
+ }
app/code/community/Tiny/CompressImages/Block/Adminhtml/System/Config/Form/Field/AccountType.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Block_Adminhtml_System_Config_Form_Field_AccountType extends Varien_Data_Form_Element_Abstract
3
+ {
4
+ /**
5
+ * Generate the status for the CompressImages extension.
6
+ *
7
+ * @return string
8
+ */
9
+ public function getElementHtml()
10
+ {
11
+ $button = '<a href="https://tinypng.com/developers/subscription" target="_blank" class="manual-links">';
12
+ $button .= Mage::helper('tiny_compressimages')->__('Credits');
13
+ $button .= '</a>';
14
+
15
+ return Mage::helper('tiny_compressimages')->__('Free (A maximum of 500 images per month)<br>' . $button);
16
+ }
17
+ }
app/code/community/Tiny/CompressImages/Block/Adminhtml/System/Config/Form/Field/Api.php ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Block_Adminhtml_System_Config_Form_Field_Api extends Varien_Data_Form_Element_Abstract
3
+ {
4
+ /**
5
+ * @var Tiny_Compressimages_Helper_Config
6
+ */
7
+ protected $_configHelper = null;
8
+
9
+ /**
10
+ * @var Tiny_Compressimages_Helper_Tinify
11
+ */
12
+ protected $_tinifyHelper = null;
13
+
14
+ /**
15
+ * @var string
16
+ */
17
+ protected $output = '';
18
+
19
+ /**
20
+ * Get the config helper.
21
+ *
22
+ * @return Tiny_CompressImages_Helper_Config
23
+ */
24
+ public function getConfigHelper()
25
+ {
26
+ if ($this->_configHelper === null) {
27
+ $this->_configHelper = Mage::helper('tiny_compressimages/config');
28
+ }
29
+
30
+ return $this->_configHelper;
31
+ }
32
+
33
+ /**
34
+ * Get the Tinify helper.
35
+ *
36
+ * @return Tiny_CompressImages_Helper_Tinify
37
+ */
38
+ public function getTinifyHelper()
39
+ {
40
+ if ($this->_tinifyHelper === null) {
41
+ $this->_tinifyHelper = Mage::helper('tiny_compressimages/tinify');
42
+ }
43
+
44
+ return $this->_tinifyHelper;
45
+ }
46
+
47
+ /**
48
+ * Generate the status for the CompressImages extension.
49
+ *
50
+ * @return string
51
+ */
52
+ public function getElementHtml()
53
+ {
54
+ $this
55
+ ->_getStatusHtml()
56
+ ->_getJavascript()
57
+ ;
58
+
59
+ return $this->output;
60
+ }
61
+
62
+ /**
63
+ * Generate the status message.
64
+ *
65
+ * @return $this
66
+ */
67
+ protected function _getStatusHtml()
68
+ {
69
+ $result = $this->getTinifyHelper()->getApiStatus(true);
70
+
71
+ $this->output .= $result['message'];
72
+
73
+ return $this;
74
+ }
75
+
76
+ /**
77
+ * Generate the javascript to make the Ajax call to check the API.
78
+ *
79
+ * @return $this
80
+ */
81
+ protected function _getJavascript()
82
+ {
83
+ $js = '';
84
+
85
+ if ($this->getConfigHelper()->isEnabled()) {
86
+ $js
87
+ .= '<script type="text/javascript">
88
+ var url = "' . Mage::helper("adminhtml")->getUrl(
89
+ 'adminhtml/CompressImagesAdminhtml_status/getApiStatus'
90
+ ) . '";
91
+
92
+ document.observe("dom:loaded", function() {
93
+ new Ajax.Request(url,
94
+ {
95
+ method: "post",
96
+ onSuccess: function (data) {
97
+ var result = data.responseText.evalJSON(true);
98
+ if (result.status == "success") {
99
+ $("compressimages_api_status").innerHTML = result.message;
100
+ }
101
+ }
102
+ })
103
+ });
104
+ </script>';
105
+ }
106
+
107
+ $this->output .= $js;
108
+
109
+ return $this;
110
+ }
111
+ }
app/code/community/Tiny/CompressImages/Block/Adminhtml/System/Config/Form/Field/LogFile.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Block_Adminhtml_System_Config_Form_Field_LogFile extends Varien_Data_Form_Element_Abstract
3
+ {
4
+ /**
5
+ * Template file used
6
+ *
7
+ * @var string
8
+ */
9
+ protected $_template = 'Tiny/CompressImages/system/config/form/field/log_file.phtml';
10
+
11
+ /**
12
+ * Get the URL where we can download the log file.
13
+ *
14
+ * @return string
15
+ */
16
+ public function getDownloadUrl()
17
+ {
18
+ return Mage::helper('adminhtml')->getUrl('adminhtml/CompressImagesAdminhtml_config/downloadLogs');
19
+ }
20
+
21
+ /**
22
+ * Helper to check if the log file exists.
23
+ *
24
+ * @return bool
25
+ */
26
+ public function logFileExists()
27
+ {
28
+ return Mage::helper('tiny_compressimages')->getLogFileExists();
29
+ }
30
+ }
app/code/community/Tiny/CompressImages/Block/Adminhtml/System/Config/Form/Field/LogStatus.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Block_Adminhtml_System_Config_Form_Field_LogStatus extends Mage_Adminhtml_Block_Abstract implements Varien_Data_Form_Element_Renderer_Interface
3
+ {
4
+ /**
5
+ * Template file used
6
+ *
7
+ * @var string
8
+ */
9
+ protected $_template = 'Tiny/CompressImages/system/config/form/field/log_status.phtml';
10
+
11
+ /**
12
+ * Render template
13
+ *
14
+ * @param Varien_Data_Form_Element_Abstract $element
15
+ *
16
+ * @return string
17
+ */
18
+ public function render(Varien_Data_Form_Element_Abstract $element)
19
+ {
20
+ $this->setElement($element);
21
+
22
+ return $this->toHtml();
23
+ }
24
+
25
+ /**
26
+ * @return string
27
+ */
28
+ public function getCleanImagesUrl()
29
+ {
30
+ $url = Mage::helper("adminhtml")->getUrl('adminhtml/CompressImagesAdminhtml_config/clearCache');
31
+
32
+ return $url;
33
+ }
34
+ }
app/code/community/Tiny/CompressImages/Block/Adminhtml/System/Config/Form/Field/Radios.php ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Block_Adminhtml_System_Config_Form_Field_Radios extends Varien_Data_Form_Element_Radios
3
+ {
4
+ /**
5
+ * Get the html for each individual radio button.
6
+ *
7
+ * @param array|Varien_Object $option
8
+ * @param string $selected
9
+ *
10
+ * @return string
11
+ */
12
+ protected function _optionToHtml($option, $selected)
13
+ {
14
+ $html = '<div class="wrapper-radio">';
15
+ $html .= '<input type="radio"'.$this->serialize(array('name', 'class', 'style', 'disabled'));
16
+ if (is_array($option)) {
17
+ $html.= 'value="'
18
+ . $this->_escape($option['value'])
19
+ . '" id="'
20
+ . $this->getHtmlId()
21
+ . $option['value']
22
+ . '"';
23
+
24
+ if ($option['value'] == $selected) {
25
+ $html .= ' checked="checked"';
26
+ }
27
+
28
+ $html .= ' />';
29
+
30
+ $html .= '<label class="inline" for="'
31
+ . $this->getHtmlId()
32
+ . $option['value']
33
+ . '">'
34
+ . $option['label']
35
+ . '</label>';
36
+ } else if ($option instanceof Varien_Object) {
37
+ $html .= 'id="'
38
+ . $this->getHtmlId()
39
+ . $option->getValue()
40
+ . '"'
41
+ . $option->serialize(
42
+ array(
43
+ 'label',
44
+ 'title',
45
+ 'value',
46
+ 'class',
47
+ 'style',
48
+ )
49
+ );
50
+
51
+ if (in_array($option->getValue(), $selected)) {
52
+ $html .= ' checked="checked"';
53
+ }
54
+
55
+ $html .= ' />';
56
+
57
+ $html .= '<label class="inline" for="'
58
+ . $this->getHtmlId()
59
+ . $option->getValue()
60
+ . '">'
61
+ . $option->getLabel()
62
+ . '</label>';
63
+ }
64
+
65
+ $html.= '</div>';
66
+
67
+ return $html;
68
+ }
69
+
70
+ /**
71
+ * Wrap the output in a container div.
72
+ *
73
+ * @return string
74
+ */
75
+ public function getElementHtml()
76
+ {
77
+ $html = parent::getElementHtml();
78
+
79
+ return '<div class="radio-container">' . $html . '</div>';
80
+ }
81
+ }
app/code/community/Tiny/CompressImages/Block/Adminhtml/System/Config/Form/Field/Saved.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Block_Adminhtml_System_Config_Form_Field_Saved extends Varien_Data_Form_Element_Abstract
3
+ {
4
+ /**
5
+ * Generate the status for the CompressImages extension.
6
+ *
7
+ * @return string
8
+ */
9
+ public function getElementHtml()
10
+ {
11
+ $data = Mage::getModel('tiny_compressimages/totals')->getTotalCompressionInformation();
12
+
13
+ return Mage::helper('tiny_compressimages')->__(
14
+ 'Saved %s%% over a total of %s compressions',
15
+ $data['percentageSaved'],
16
+ $data['totalCompressions']
17
+ );
18
+
19
+ }
20
+ }
app/code/community/Tiny/CompressImages/Block/Adminhtml/System/Config/Form/Field/Status.php ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Block_Adminhtml_System_Config_Form_Field_Status extends Varien_Data_Form_Element_Abstract
3
+ {
4
+ /**
5
+ * @var Tiny_CompressImages_Helper_Data
6
+ */
7
+ protected $_helper = null;
8
+
9
+ /**
10
+ * The constructor
11
+ */
12
+ public function __construct($attributes = array())
13
+ {
14
+ parent::__construct($attributes);
15
+
16
+ $this->_helper = Mage::helper('tiny_compressimages');
17
+ }
18
+
19
+ /**
20
+ * Generate the status for the CompressImages extension.
21
+ *
22
+ * @return string
23
+ */
24
+ public function getElementHtml()
25
+ {
26
+ /** @var Tiny_CompressImages_Helper_Config $configHelper */
27
+ $configHelper = Mage::helper('tiny_compressimages/config');
28
+
29
+ if (!$configHelper->isConfigured()) {
30
+ if (!$configHelper->getApiKey()) {
31
+ return '<span class="compressimages-api-deactivated">'
32
+ . $this->_helper->__('Please enter your api key to check the compression count.')
33
+ . '</span>';
34
+ }
35
+
36
+ if (!$configHelper->isEnabled()) {
37
+ return '<span class="compressimages-api-deactivated">'
38
+ . $this->_helper->__('Please enable the extension to check the compression count.')
39
+ . '</span>';
40
+ }
41
+ }
42
+
43
+ // TODO: Find a method to determine whether to use our or Tinify's compression count
44
+ $compressionCount = Mage::helper('tiny_compressimages/tinify')->compressionCount();
45
+
46
+ if ($configHelper->getApiKey() == '') {
47
+ return $this->_helper->__('Add your TinyPNG API key to check the status');
48
+ }
49
+
50
+ if ($compressionCount == 0 || $compressionCount == 500) {
51
+ $button = '<a href="https://tinypng.com/developers/subscription" target="_blank" id="tinypng_check_status" class="tiny-compressimages-button-orange scalable">';
52
+ $button .= '<span><span><span>Upgrade</span></span></span></a>';
53
+
54
+ $onhold = $this->_helper->__('Compression on hold. 500 free images compressed this month.');
55
+ $upgrade = $this->_helper->__('Upgrade your account to compress more images');
56
+
57
+ return '<span class="compressimages-api-deactivated">' . $onhold . '</span>' . $upgrade . '<br>' . $button;
58
+ }
59
+
60
+ return $this->_helper->__(
61
+ 'There are %s compressions done this month.',
62
+ $compressionCount
63
+ );
64
+ }
65
+ }
app/code/community/Tiny/CompressImages/Block/Adminhtml/System/Config/Form/Field/SupportTab.php ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Block_Adminhtml_System_Config_Form_Field_SupportTab
3
+ extends Mage_Adminhtml_Block_Abstract
4
+ implements Varien_Data_Form_Element_Renderer_Interface
5
+ {
6
+
7
+ /**
8
+ * Template file used
9
+ *
10
+ * @var string
11
+ */
12
+ protected $_template = 'Tiny/CompressImages/system/config/form/field/support_tab.phtml';
13
+
14
+ /**
15
+ * Render fieldset html
16
+ *
17
+ * @param Varien_Data_Form_Element_Abstract $element
18
+ * @return string
19
+ */
20
+ public function render(Varien_Data_Form_Element_Abstract $element)
21
+ {
22
+ $this->setElement($element);
23
+
24
+ return $this->toHtml();
25
+ }
26
+
27
+ /**
28
+ * Get the current version of the PostNL extension's code base.
29
+ *
30
+ * @return string
31
+ */
32
+ public function getModuleVersion()
33
+ {
34
+ $version = (string) Mage::getConfig()->getModuleConfig('Tiny_CompressImages')->version;
35
+
36
+ return $version;
37
+ }
38
+
39
+ /**
40
+ * Get the current stability of the PostNL extension's code base.
41
+ *
42
+ * @return string
43
+ */
44
+ public function getModuleStability()
45
+ {
46
+ $stability = (string) Mage::getConfig()->getModuleConfig('Tiny_CompressImages')->stability;
47
+
48
+ return $stability;
49
+ }
50
+ }
app/code/community/Tiny/CompressImages/Exception.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Exception extends Exception {}
app/code/community/Tiny/CompressImages/Helper/Config.php ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Helper_Config extends Mage_Core_Helper_Abstract
3
+ {
4
+ /**
5
+ * Configuration XPATH
6
+ */
7
+ const XPATH_ENABLED = 'tiny_compressimages/advanced/enabled';
8
+ const XPATH_API_KEY = 'tiny_compressimages/settings/api_key';
9
+ const XPATH_IMAGE_TYPE_BASE = 'tiny_compressimages/image_types/base_images';
10
+ const XPATH_IMAGE_TYPE_SMALL = 'tiny_compressimages/image_types/small_images';
11
+ const XPATH_IMAGE_TYPE_THUMBNAIL = 'tiny_compressimages/image_types/thumbnails';
12
+ const XPATH_IMAGE_TYPE_SWATCHES = 'tiny_compressimages/image_types/swatches';
13
+ const XPATH_LOGGING_MODE = 'tiny_compressimages/advanced/logging_mode';
14
+
15
+ /**
16
+ * Return the enabled modus (off, test or live)
17
+ *
18
+ * @param null $store
19
+ *
20
+ * @return int
21
+ */
22
+ protected function _getEnabled($store = null)
23
+ {
24
+ return Mage::getStoreConfig(self::XPATH_ENABLED, $store);
25
+ }
26
+
27
+ /**
28
+ * Is the extension enabled
29
+ *
30
+ * @param null|int $store
31
+ *
32
+ * @return bool
33
+ */
34
+ public function isEnabled($store = null)
35
+ {
36
+ $enabledValue = $this->_getEnabled($store);
37
+
38
+ if ($enabledValue != 0) {
39
+ return true;
40
+ } else {
41
+ return false;
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Is the extension currently in test mode
47
+ *
48
+ * @param null|int $store
49
+ *
50
+ * @return bool
51
+ */
52
+ public function isTestMode($store = null)
53
+ {
54
+ $enabledValue = $this->_getEnabled($store);
55
+
56
+ if ($enabledValue == 1) {
57
+ return true;
58
+ } else {
59
+ return false;
60
+ }
61
+ }
62
+
63
+ /**
64
+ * @param null $store
65
+ *
66
+ * @return bool
67
+ */
68
+ public function isConfigured($store = null)
69
+ {
70
+ if (!$this->isEnabled($store)) {
71
+ return false;
72
+ }
73
+
74
+ if (!$this->getApiKey($store)) {
75
+ return false;
76
+ }
77
+
78
+ return true;
79
+ }
80
+
81
+ /**
82
+ * Return the API Key
83
+ *
84
+ * @param null|int $store
85
+ *
86
+ * @return string
87
+ */
88
+ public function getApiKey($store = null)
89
+ {
90
+ return Mage::getStoreConfig(self::XPATH_API_KEY, $store);
91
+ }
92
+
93
+ /**
94
+ * Lets you know if base images should be compressed.
95
+ *
96
+ * @param null $store
97
+ *
98
+ * @return mixed
99
+ */
100
+ public function isBaseImageTypeEnabledForCompression($store = null)
101
+ {
102
+ return Mage::getStoreConfig(self::XPATH_IMAGE_TYPE_BASE, $store);
103
+ }
104
+
105
+ /**
106
+ * Lets you know if small images should be compressed.
107
+ *
108
+ * @param null $store
109
+ *
110
+ * @return mixed
111
+ */
112
+ public function isSmallImageTypeEnabledForCompression($store = null)
113
+ {
114
+ return Mage::getStoreConfig(self::XPATH_IMAGE_TYPE_SMALL, $store);
115
+ }
116
+
117
+ /**
118
+ * Lets you know if thumbnail-sized images should be compressed.
119
+ *
120
+ * @param null $store
121
+ *
122
+ * @return mixed
123
+ */
124
+ public function isThumbnailTypeEnabledForCompression($store = null)
125
+ {
126
+ return Mage::getStoreConfig(self::XPATH_IMAGE_TYPE_THUMBNAIL, $store);
127
+ }
128
+
129
+ /**
130
+ * Lets you know if swachtes (small images used to select product attributes) images should be compressed.
131
+ *
132
+ * @param null $store
133
+ *
134
+ * @return mixed
135
+ */
136
+ public function isSwatchTypeEnabledForCompression($store = null)
137
+ {
138
+ return Mage::getStoreConfig(self::XPATH_IMAGE_TYPE_SWATCHES, $store);
139
+ }
140
+
141
+
142
+ /**
143
+ * Returns an array of image types that can be compressed by CompressImages
144
+ *
145
+ * @param null $store
146
+ *
147
+ * @return mixed
148
+ */
149
+ public function getProductImageTypesToCompress($store = null)
150
+ {
151
+ $imageTypes = array();
152
+
153
+ if ($this->isBaseImageTypeEnabledForCompression($store)) {
154
+ $imageTypes[] = 'image';
155
+ }
156
+
157
+ if ($this->isSmallImageTypeEnabledForCompression($store)) {
158
+ $imageTypes[] = 'small_image';
159
+ }
160
+
161
+ if ($this->isThumbnailTypeEnabledForCompression($store)) {
162
+ $imageTypes[] = 'thumbnail';
163
+ $imageTypes[] = 'media_image';
164
+ }
165
+
166
+ if ($this->isSwatchTypeEnabledForCompression($store)) {
167
+ $imageTypes[] = 'swatches';
168
+ }
169
+
170
+ return $imageTypes;
171
+ }
172
+
173
+ /**
174
+ * Returns the logging mode.
175
+ *
176
+ * @param null $store
177
+ *
178
+ * @return mixed
179
+ */
180
+ public function getLoggingMode($store = null)
181
+ {
182
+ return Mage::getStoreConfig(self::XPATH_LOGGING_MODE, $store);
183
+ }
184
+ }
app/code/community/Tiny/CompressImages/Helper/Data.php ADDED
@@ -0,0 +1,205 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Helper_Data extends Mage_Core_Helper_Abstract
3
+ {
4
+ /**
5
+ * The name of the logfile.
6
+ *
7
+ * @var string
8
+ */
9
+ protected $logFile = 'image-optimization.log';
10
+
11
+ /**
12
+ * @var Tiny_CompressImages_Helper_Config
13
+ */
14
+ protected $_configHelper = null;
15
+
16
+ /**
17
+ * Class constructor
18
+ */
19
+ public function __construct()
20
+ {
21
+ $this->_configHelper = Mage::helper('tiny_compressimages/config');
22
+ }
23
+
24
+ /**
25
+ * @param $msg
26
+ * @param $type
27
+ *
28
+ * @return $this;
29
+ */
30
+ public function log($msg, $type = null, $store = null)
31
+ {
32
+ $logginModes = $this->_loggingArray($store);
33
+
34
+ /**
35
+ * Always log exceptions. $msg should be an instanceof Exception!
36
+ */
37
+ if ($msg instanceof Exception) {
38
+ $type = 'exception';
39
+ $msg = $msg->__toString();
40
+ }
41
+
42
+ if (!in_array($type, $logginModes)) {
43
+ return $this;
44
+ }
45
+
46
+ Mage::log($msg, null, $this->logFile, true);
47
+
48
+ return $this;
49
+ }
50
+
51
+ /**
52
+ * @param $store
53
+ *
54
+ * @return array
55
+ */
56
+ protected function _loggingArray($store)
57
+ {
58
+ switch ($this->_configHelper->getLoggingMode($store))
59
+ {
60
+ case 'only_exceptions':
61
+ $logginArray = array('exception');
62
+ break;
63
+ case 'fail_and_exceptions':
64
+ $logginArray = array('error', 'exception');
65
+ break;
66
+ case 'all':
67
+ $logginArray = array('info', 'error', 'exception');
68
+ break;
69
+ case 'off':
70
+ default:
71
+ $logginArray = array('');
72
+ }
73
+
74
+ return $logginArray;
75
+ }
76
+
77
+ /**
78
+ * Returns whether the log file exists or not
79
+ *
80
+ * @return bool
81
+ */
82
+ public function getLogFileExists()
83
+ {
84
+ $filePath = $this->getLogFilePath();
85
+
86
+ if (!@file_exists($filePath)) {
87
+ return false;
88
+ }
89
+
90
+ return true;
91
+ }
92
+
93
+ /**
94
+ * Returns the file path of the log file
95
+ *
96
+ * @return string
97
+ */
98
+ public function getLogFilePath()
99
+ {
100
+ $logDir = Mage::getBaseDir('log');
101
+
102
+ $filePath = $logDir . DS . $this->logFile;
103
+
104
+ return $filePath;
105
+ }
106
+
107
+ /**
108
+ * Get the name of the logfile.
109
+ *
110
+ * @return string
111
+ */
112
+ public function getLogFilename()
113
+ {
114
+ return $this->logFile;
115
+ }
116
+
117
+ /**
118
+ * Copied from https://gist.github.com/jblyberg/1572386
119
+ *
120
+ * @param $datefrom
121
+ * @param int $dateto
122
+ *
123
+ * @return string
124
+ */
125
+ public function timeAgo($datefrom, $dateto = -1) {
126
+ $datefrom = strtotime($datefrom);
127
+ if ($datefrom <= 0) {
128
+ return $this->__('A long time ago');
129
+ }
130
+ if ($dateto == -1) {
131
+ $dateto = time();
132
+ }
133
+ $difference = $dateto - $datefrom;
134
+ if ($difference < 60) {
135
+ $interval = "s";
136
+ } elseif ($difference >= 60 && $difference < 60 * 60) {
137
+ $interval = "n";
138
+ } elseif ($difference >= 60 * 60 && $difference < 60 * 60 * 24) {
139
+ $interval = "h";
140
+ } elseif ($difference >= 60 * 60 * 24 && $difference < 60 * 60 * 24 * 7) {
141
+ $interval = "d";
142
+ } elseif ($difference >= 60 * 60 * 24 * 7 && $difference < 60 * 60 * 24 * 30) {
143
+ $interval = "ww";
144
+ } elseif ($difference >= 60 * 60 * 24 * 30 && $difference < 60 * 60 * 24 * 365) {
145
+ $interval = "m";
146
+ } elseif ($difference >= 60 * 60 * 24 * 365) {
147
+ $interval = "y";
148
+ }
149
+ switch ($interval) {
150
+ case "m":
151
+ $months_difference = floor($difference / 60 / 60 / 24 / 29);
152
+ while (mktime(date("H", $datefrom), date("i", $datefrom), date("s", $datefrom), date("n", $datefrom) + ($months_difference), date("j", $dateto), date("Y", $datefrom)) < $dateto) {
153
+ $months_difference++;
154
+ }
155
+ $datediff = $months_difference;
156
+ if ($datediff == 12) {
157
+ $datediff--;
158
+ }
159
+ $res = ($datediff == 1) ? $this->__('%s month ago', $datediff) : $this->__('%s months ago', $datediff);
160
+ break;
161
+ case "y":
162
+ $datediff = floor($difference / 60 / 60 / 24 / 365);
163
+ $res = ($datediff == 1) ? $this->__('%s year ago', $datediff) : $this->__('%s years ago', $datediff);
164
+ break;
165
+ case "d":
166
+ $datediff = floor($difference / 60 / 60 / 24);
167
+ $res = ($datediff == 1) ? $this->__('%s day ago', $datediff) : $this->__('%s days ago', $datediff);
168
+ break;
169
+ case "ww":
170
+ $datediff = floor($difference / 60 / 60 / 24 / 7);
171
+ $res = ($datediff == 1) ? $this->__('%s week ago', $datediff) : $this->__('%s weeks ago', $datediff);
172
+ break;
173
+ case "h":
174
+ $datediff = floor($difference / 60 / 60);
175
+ $res = ($datediff == 1) ? $this->__('%s hour ago', $datediff) : $this->__('%s hours ago', $datediff);
176
+ break;
177
+ case "n":
178
+ $datediff = floor($difference / 60);
179
+ $res = ($datediff == 1) ? $this->__('%s minute ago', $datediff) : $this->__('%s minutes ago', $datediff);
180
+ break;
181
+ case "s":
182
+ $datediff = $difference;
183
+ $res = ($datediff == 1) ? $this->__('%s second ago', $datediff) : $this->__('%s seconds ago', $datediff);
184
+ break;
185
+ }
186
+
187
+ return $res;
188
+ }
189
+
190
+ /**
191
+ * Retrieve a human readable file size.
192
+ * Copied from http://jeffreysambells.com/2012/10/25/human-readable-filesize-php
193
+ *
194
+ * @param $bytes
195
+ *
196
+ * @return string
197
+ */
198
+ public function fileSize($bytes)
199
+ {
200
+ $size = array('B','kB','MB','GB','TB','PB','EB','ZB','YB');
201
+ $factor = floor((strlen($bytes) - 1) / 3);
202
+
203
+ return sprintf('%.0f ', $bytes / pow(1024, $factor)) . @$size[$factor];
204
+ }
205
+ }
app/code/community/Tiny/CompressImages/Helper/Tinify.php ADDED
@@ -0,0 +1,750 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Helper_Tinify extends Mage_Core_Helper_Abstract
3
+ {
4
+ const TINY_COMPRESSIMAGES_MEDIA_DIRECTORY = '/media/catalog/product/optimized';
5
+
6
+ const CACHE_KEY = 'tiny_compressimages_api_status';
7
+
8
+ /**
9
+ * @var bool $allowCompression
10
+ */
11
+ protected $allowCompression;
12
+
13
+ /**
14
+ * @var bool $isProductTypeAllowed
15
+ */
16
+ protected $isProductTypeAllowed = true;
17
+
18
+ /**
19
+ * @var string $destinationSubdir
20
+ */
21
+ protected $destinationSubdir = '';
22
+
23
+ /**
24
+ * @var SplFileInfo $newFile
25
+ */
26
+ protected $newFile = '';
27
+
28
+ /**
29
+ * @var string $imageWidth
30
+ */
31
+ protected $imageWidth = '';
32
+
33
+ /**
34
+ * @var string $imageHeight
35
+ */
36
+ protected $imageHeight = '';
37
+
38
+ /**
39
+ * @var string $hashBefore
40
+ */
41
+ protected $hashBefore = '';
42
+
43
+ /**
44
+ * @var string $hashAfter
45
+ */
46
+ protected $hashAfter = '';
47
+
48
+ /**
49
+ * @var int $bytesBefore
50
+ */
51
+ protected $bytesBefore = 0;
52
+
53
+ /**
54
+ * @var int $bytesAfter
55
+ */
56
+ protected $bytesAfter = 0;
57
+
58
+ /**
59
+ * @var null|int $parentId
60
+ */
61
+ protected $parentId = null;
62
+
63
+ /**
64
+ * @var bool $isCompressedBefore
65
+ */
66
+ protected $isCompressedBefore = false;
67
+
68
+ /**
69
+ * @var int $isUsedAsSource
70
+ */
71
+ protected $isUsedAsSource = 1;
72
+
73
+ /**
74
+ * @var Tiny_CompressImages_Helper_Data
75
+ */
76
+ protected $helper;
77
+
78
+ /**
79
+ * @var int $storeId
80
+ */
81
+ protected $storeId = 0;
82
+
83
+ /**
84
+ * @var Tiny_CompressImages_Helper_Config
85
+ */
86
+ protected $configHelper;
87
+
88
+ /**
89
+ * @var null|Tiny_CompressImages_Model_Image
90
+ */
91
+ protected $_model = null;
92
+
93
+ /**
94
+ * Constructor
95
+ */
96
+ public function __construct() {
97
+ $this->_registerAutoloader();
98
+ $this->_setIdentifier();
99
+
100
+ $this->helper = Mage::helper('tiny_compressimages');
101
+ $this->configHelper = Mage::helper('tiny_compressimages/config');
102
+
103
+ $apiKey = $this->configHelper->getApiKey($this->storeId);
104
+ $this->allowCompression = $this->validate($apiKey);
105
+ }
106
+
107
+ /**
108
+ * Register our custom autoloader, this is needed because Magento can't handle PHP's namespaces.
109
+ *
110
+ * @return $this
111
+ */
112
+ protected function _registerAutoloader()
113
+ {
114
+ require_once(Mage::getBaseDir('lib') . '/TinyCompress/lib/Tinify.php');
115
+
116
+ spl_autoload_register( array($this, 'load'), true, true );
117
+
118
+ return $this;
119
+ }
120
+
121
+ /**
122
+ * Set the app identifier
123
+ *
124
+ * @return $this
125
+ */
126
+ protected function _setIdentifier()
127
+ {
128
+ $version = Mage::getVersion();
129
+ $edition = Mage::getEdition();
130
+
131
+ Tinify\setAppIdentifier('Magento ' . $edition . ' ' . $version);
132
+
133
+ return $this;
134
+ }
135
+
136
+ /**
137
+ * This function autoloads Tinify classes
138
+ *
139
+ * @param string $class
140
+ */
141
+ protected static function load($class)
142
+ {
143
+ /**
144
+ * Project-specific namespace prefix
145
+ */
146
+ $prefix = 'Tinify';
147
+
148
+ /**
149
+ * Base directory for the namespace prefix
150
+ */
151
+ $base_dir = Mage::getBaseDir('lib') . '/TinyCompress/lib/';
152
+
153
+ if (strpos($class, $prefix) !== 0) {
154
+ /**
155
+ * No, move to the next registered autoloader
156
+ */
157
+ return;
158
+ }
159
+
160
+ /**
161
+ * Get the relative class name
162
+ */
163
+ $class_directory = str_replace('\\', '/', $class);
164
+
165
+ /**
166
+ * Tinify has all its exceptions in one file, so take that in account
167
+ */
168
+ if (substr($class_directory, -9) == 'Exception') {
169
+ $class_array = explode('/', $class_directory);
170
+ $class_array[count($class_array) - 1] = 'Exception';
171
+
172
+ $class_directory = implode('/', $class_array);
173
+ }
174
+
175
+ /**
176
+ * Replace the namespace prefix with the base directory, replace namespace
177
+ * separators with directory separators in the relative class name, append
178
+ * with .php
179
+ */
180
+ $file = $base_dir . $class_directory . '.php';
181
+
182
+ /**
183
+ * if the file exists, require it
184
+ */
185
+ if (file_exists($file)) {
186
+ require $file;
187
+ }
188
+ }
189
+
190
+ /**
191
+ * Validate the Tinify Api Key.
192
+ *
193
+ * @param $apiKey
194
+ *
195
+ * @return bool
196
+ */
197
+ public function validate($apiKey) {
198
+ if (empty($apiKey)) {
199
+ return false;
200
+ }
201
+
202
+ \Tinify\setKey($apiKey);
203
+
204
+ try {
205
+ \Tinify\validate();
206
+ } catch (\Tinify\Exception $e) {
207
+ $this->helper->log($e->getMessage(), null, $this->storeId);
208
+ return false;
209
+ }
210
+
211
+ return true;
212
+ }
213
+
214
+ /**
215
+ * Compress the image.
216
+ *
217
+ * @return bool
218
+ * @throws Tiny_CompressImages_Exception
219
+ */
220
+ public function compress()
221
+ {
222
+ if (!$this->configHelper->isEnabled($this->storeId)) {
223
+ $this->helper->log('The TinyPNG module is disabled, not compressing ' . $this->newFile->getPathname(), 'info', $this->storeId);
224
+
225
+ return false;
226
+ }
227
+
228
+ if (!$this->_isCompressionAllowed()) {
229
+ $this->helper->log('Compression is not allowed at this moment.', 'info', $this->storeId);
230
+
231
+ return false;
232
+ }
233
+
234
+ $this->_prepareCompression();
235
+
236
+ if ($this->_isInOptimizedMediaDirectory()) {
237
+ $this->helper->log(
238
+ $this->newFile->getPathname(). ' is propably compressed before and can be found in the compression folder'
239
+ );
240
+ $this
241
+ ->_SetCompressionAsPreviously()
242
+ ->_saveCompression();
243
+ return true;
244
+ }
245
+
246
+ /**
247
+ * Check if this file is compressed before. If that is the case, copy it to this location.
248
+ */
249
+ if ($this->_isAlreadyCompressed()) {
250
+ return true;
251
+ }
252
+
253
+ try {
254
+ $message = '';
255
+ $input = \Tinify\fromFile($this->newFile->getPathname());
256
+
257
+ if ($this->configHelper->isTestMode($this->storeId)) {
258
+ $message .= 'TESTMODE - ';
259
+
260
+ if (function_exists('mb_strlen')) {
261
+ $this->bytesAfter = mb_strlen($input->toBuffer(), '8bit');
262
+ } else {
263
+ $this->bytesAfter = strlen($input->toBuffer());
264
+ }
265
+
266
+ if (!is_writable($this->newFile->getPathname())) {
267
+ throw new Tiny_CompressImages_Exception('The file ' . $this->newFile->getPathname() . ' is not writable!');
268
+ }
269
+ } else {
270
+ $input->toFile($this->newFile->getPathname());
271
+ $this->bytesAfter = $this->_getFileSize($this->newFile);
272
+ }
273
+
274
+ $this->_model->createPath();
275
+
276
+ $compressionFile = $this->_model->getFilepathOptimized();
277
+ $this->helper->log('Write to compression Folder : '. $compressionFile, 'info', $this->storeId);
278
+ file_put_contents($compressionFile, $input->toBuffer());
279
+
280
+ $message .=
281
+ 'Compressed: ' . $this->newFile->getFilename() . ' - ' .
282
+ 'Variant: '. $this->destinationSubdir . ' - ' .
283
+ 'Size (WxH): ' . $this->imageWidth . 'x' . $this->imageHeight . ' - ' .
284
+ 'Bytes saved: ' . ($this->bytesBefore - $this->bytesAfter) . ' - ' .
285
+ 'Compressed Before'. $this->isCompressedBefore . ' - '.
286
+ 'Path: ' . $compressionFile;
287
+
288
+ $this->helper->log($message, 'info', $this->storeId);
289
+ } catch (\Tinify\Exception $e) {
290
+ $this->helper->log($e, null, $this->storeId);
291
+ return false;
292
+ }
293
+
294
+ $this->_saveCompression();
295
+
296
+ return true;
297
+ }
298
+
299
+ /**
300
+ * Calculates the hash and checks if the file was processed before. If so, it will copy the base file if it still
301
+ * exists. Otherwise it will delete the record from the database.
302
+ *
303
+ * @return bool
304
+ */
305
+ protected function _isAlreadyCompressed()
306
+ {
307
+ $hash = $this->_getFileHash($this->newFile);
308
+
309
+ /** @var Tiny_CompressImages_Model_Image|null $model */
310
+ $model = Mage::getModel('tiny_compressimages/image')->getByHash($hash);
311
+
312
+ if ($model !== null) {
313
+ return $this->_copyExistingFile($model);
314
+ } else {
315
+ $this->helper->log('No existing file found with hash ' . $hash, 'info', $this->storeId);
316
+
317
+ return false;
318
+ }
319
+ }
320
+
321
+ /**
322
+ * Check if the Optimized media direcotory already contains the images.
323
+ *
324
+ * @return bool
325
+ */
326
+ protected function _isInOptimizedMediaDirectory()
327
+ {
328
+ $path = $this->_model->getPathOptimized();
329
+ $file = new SplFileInfo($path);
330
+
331
+ if ($file->isFile()) {
332
+ $this->isCompressedBefore = true;
333
+ return true;
334
+ }
335
+
336
+ return false;
337
+ }
338
+
339
+ /**
340
+ * Check if the file exists. If so, copy it to the new location to prevent duplicate compressions. If does not
341
+ * exists anymore, delete the model.
342
+ *
343
+ * @param Tiny_CompressImages_Model_Image $model
344
+ *
345
+ * @return bool
346
+ */
347
+ protected function _copyExistingFile($model)
348
+ {
349
+ $sourceFile = new SplFileInfo(Mage::getBaseDir() . $model->getPathOptimized());
350
+
351
+ if (!$sourceFile->isFile()) {
352
+ $message = 'Failed: Copying the source file ' . $sourceFile->getPathname() . '. The file does not exists ' .
353
+ 'anymore. Deleting the model (ID: ' . $model->getId() . ').';
354
+ $this->helper->log($message, 'info', $this->storeId);
355
+
356
+ $model->delete();
357
+
358
+ return false;
359
+ } else {
360
+ $model->addUsedAsSource()->save();
361
+
362
+ $this->helper->log('Copying the source file from ' . $sourceFile->getPathname() .
363
+ ' to ' . $this->newFile->getPathname(), 'info', $this->storeId);
364
+
365
+ if ($this->configHelper->isTestMode($this->storeId)) {
366
+ $this->helper->log('Testmode is enabled, no image is copied');
367
+
368
+ return true;
369
+ }
370
+
371
+ $this->hashBefore = $this->_getFileHash($this->newFile);
372
+ $this->hashAfter = $model->getHashAfter();
373
+ $this->bytesAfter = $this->_getFileSize($this->newFile);
374
+ $this->bytesBefore = $model->getBytesBefore();
375
+ $this->isUsedAsSource = $model->getUsedAsSource();
376
+ $this->parentId = $model->getId();
377
+ $this->isCompressedBefore = false;
378
+
379
+ $this->_saveCompression();
380
+
381
+ // Reset parent id and used at source.
382
+ $this->parentId = null;
383
+ $this->isUsedAsSource = 1;
384
+
385
+ return copy($sourceFile->getPathname(), $this->newFile->getPathname());
386
+ }
387
+ }
388
+
389
+ /**
390
+ * @param Mage_Catalog_Model_Product_Image $image
391
+ * @param $storeId
392
+ *
393
+ * @return $this
394
+ */
395
+ public function setProductImage($image, $storeId = null)
396
+ {
397
+ $this->newFile = new SplFileInfo($image->getNewFile());
398
+ $this->hashBefore = $this->_getFileHash($this->newFile);
399
+ $this->bytesBefore = $this->_getFileSize($this->newFile);
400
+
401
+ if ($storeId !== null) {
402
+ $this->storeId = $storeId;
403
+ }
404
+
405
+ if (!$this->configHelper->isEnabled($this->storeId)) {
406
+ return $this;
407
+ }
408
+
409
+ if (!$this->_isProductImageAllowed($image->getDestinationSubdir())) {
410
+ $this->isProductTypeAllowed = false;
411
+ $this->helper->log(
412
+ 'Product ' . $image->getDestinationSubdir() . ' image type is not selected for optimization',
413
+ 'error',
414
+ $this->storeId
415
+ );
416
+
417
+ return $this;
418
+ }
419
+
420
+ $this->destinationSubdir = $image->getDestinationSubdir();
421
+ $this->imageWidth = $image->getWidth();
422
+ $this->imageHeight = $image->getHeight();
423
+
424
+ if (!$this->newFile->isFile()) {
425
+ $this->helper->log('Could not load the core image data', 'info', $this->storeId);
426
+
427
+ return $this;
428
+ }
429
+
430
+ return $this;
431
+ }
432
+
433
+ /**
434
+ * Prepare the compression. This way the optimized path can be calculated.
435
+ *
436
+ * @return $this
437
+ */
438
+ protected function _prepareCompression()
439
+ {
440
+ $path = str_replace(Mage::getBaseDir(), '', $this->newFile->getPathname());
441
+
442
+ /** @var Tiny_CompressImages_Model_Image */
443
+ $this->_model = Mage::getModel('tiny_compressimages/image');
444
+ $this->_model->setPath($path);
445
+ $this->_model->setImageType($this->destinationSubdir);
446
+ $this->_model->setHashBefore($this->hashBefore);
447
+ $this->_model->setBytesBefore($this->bytesBefore);
448
+
449
+ return $this;
450
+ }
451
+
452
+ /**
453
+ * Save the file meta info to the database. This way we can prevent duplicate compressions.
454
+ *
455
+ * @return $this
456
+ */
457
+ protected function _saveCompression()
458
+ {
459
+ $this->hashAfter = $this->_getFileHash($this->newFile);
460
+
461
+ $this->_model->setHashAfter($this->hashAfter);
462
+ $this->_model->setBytesAfter($this->bytesAfter);
463
+ $this->_model->setProcessedAt(Varien_Date::now());
464
+ $this->_model->setUsedAsSource($this->isUsedAsSource);
465
+
466
+ if ($this->configHelper->isTestMode($this->storeId)) {
467
+ $this->_model->setIsTest(1);
468
+ }
469
+
470
+ $this->_model->setParentId($this->parentId);
471
+ $this->_model->setCompressedBefore($this->isCompressedBefore);
472
+
473
+ $this->_model->save();
474
+
475
+ $this->setTotalSavings();
476
+
477
+ return $this;
478
+ }
479
+
480
+ /**
481
+ * @return $this
482
+ */
483
+ protected function _SetCompressionAsPreviously()
484
+ {
485
+ $compressedFile = new SplFileInfo($this->_getOptimizedMediaPath($this->newFile->getPathname()));
486
+
487
+ $this->isCompressedBefore = true;
488
+
489
+ $this->bytesAfter = $this->_getFileSize($compressedFile);
490
+ $this->hashAfter = $this->_getFileHash($compressedFile);
491
+
492
+ return $this;
493
+ }
494
+
495
+ /**
496
+ * Save the file meta for the total month savings.
497
+ *
498
+ * @return $this
499
+ */
500
+ public function setTotalSavings()
501
+ {
502
+ $model = Mage::getModel('tiny_compressimages/totals');
503
+ $collection = $model->getCollection()->setOrder('entity_id', 'DESC');
504
+
505
+ /** @var Tiny_CompressImages_Model_Totals $latest */
506
+ $latest = $collection->getFirstItem();
507
+
508
+ $bytesBefore = $this->bytesBefore;
509
+ $bytesAfter = $this->bytesAfter;
510
+ $totalCompression = 1;
511
+
512
+ if ($this->isBetweenDates($latest->getDateFrom(),$latest->getDateTo())) {
513
+ $bytesBefore = $bytesBefore + $latest->getTotalBytesBefore();
514
+ $bytesAfter = $bytesAfter + $latest->getTotalBytesAfter();
515
+ $totalCompression = $totalCompression + $latest->getTotalCompressions();
516
+ $dateFrom = $latest->getDateFrom();
517
+ $dateTo = $latest->getDateTo();
518
+
519
+ // Load the latest record for updates.
520
+ $model->load($latest->getEntityId());
521
+
522
+ } else {
523
+ $dateFrom = Mage::getModel('core/date')->date('Y-m-01');
524
+ $dateTo = Mage::getModel('core/date')->date('Y-m-t');
525
+ }
526
+
527
+ $model->setTotalBytesBefore($bytesBefore);
528
+ $model->setTotalBytesAfter($bytesAfter);
529
+ $model->setTotalCompressions($totalCompression);
530
+ $model->setDateFrom($dateFrom);
531
+ $model->setDateTo($dateTo);
532
+ $model->setUpdatedAt(Varien_Date::now());
533
+
534
+ $model->save();
535
+
536
+ return $this;
537
+ }
538
+
539
+ /**
540
+ * @param $from
541
+ * @param $to
542
+ *
543
+ * @return bool
544
+ */
545
+ public function isBetweenDates($from, $to)
546
+ {
547
+ $between = false;
548
+
549
+ if ((Varien_Date::now() > $from)
550
+ && (Varien_Date::now() < $to)
551
+ ) {
552
+ $between = true;
553
+ }
554
+
555
+ return $between;
556
+ }
557
+
558
+ /**
559
+ * Check if we are allowed to compress images.
560
+ *
561
+ * @return bool
562
+ */
563
+ protected function _isCompressionAllowed()
564
+ {
565
+ if (!$this->allowCompression) {
566
+ return false;
567
+ }
568
+
569
+ if (!$this->isProductTypeAllowed) {
570
+ return false;
571
+ }
572
+
573
+ return true;
574
+ }
575
+
576
+ /**
577
+ * @param $imageDestination
578
+ *
579
+ * @return bool
580
+ */
581
+ protected function _isProductImageAllowed($imageDestination)
582
+ {
583
+ if (!$this->allowCompression) {
584
+ return false;
585
+ }
586
+
587
+ $typesAllowed = $this->configHelper->getProductImageTypesToCompress($this->storeId);
588
+
589
+ if (in_array($imageDestination, $typesAllowed)) {
590
+ return true;
591
+ }
592
+
593
+ return false;
594
+ }
595
+
596
+ /**
597
+ * Check how many images have been compressed this month
598
+ *
599
+ * @param null $store
600
+ *
601
+ * @return int|null
602
+ */
603
+ public function compressionCount($store = null) {
604
+ if(!$this->configHelper->isConfigured($store)) {
605
+ return 0;
606
+ }
607
+
608
+ $apiKey = $this->configHelper->getApiKey($store);
609
+ $validated = $this->validate($apiKey);
610
+
611
+ if (!$validated) {
612
+ return 0;
613
+ }
614
+
615
+ return \Tinify\compressionCount();
616
+ }
617
+
618
+ /**
619
+ * Get all the compressions
620
+ *
621
+ * @return Tiny_CompressImages_Model_Resource_Image_Collection
622
+ */
623
+ public function getCompressionStatus()
624
+ {
625
+ $collection = Mage::getModel('tiny_compressimages/image')->getCollection();
626
+ $select = $collection->getSelect();
627
+ $select->limit(50);
628
+
629
+ $fromDate = Mage::getModel('core/date')->date('Y-m-01');
630
+ $toDate = Mage::getModel('core/date')->date('Y-m-t');
631
+
632
+ $select->where(
633
+ 'processed_at',
634
+ array(
635
+ 'from' => $fromDate,
636
+ 'to' => $toDate,
637
+ 'date' => true
638
+ )
639
+ );
640
+
641
+ $collection->setOrder('processed_at', Varien_Data_Collection_Db::SORT_ORDER_DESC);
642
+
643
+ return $collection;
644
+ }
645
+
646
+ /**
647
+ * Check the API status.
648
+ *
649
+ * @return array
650
+ */
651
+ public function getApiStatus($useCache = false)
652
+ {
653
+ $apiStatusCache = Mage::app()->loadCache(static::CACHE_KEY);
654
+ if ($useCache && $apiStatusCache !== false) {
655
+ return json_decode($apiStatusCache, true);
656
+ }
657
+
658
+ /** @var Tiny_CompressImages_Helper_Config $configHelper */
659
+ $configHelper = Mage::helper('tiny_compressimages/config');
660
+ $apiKey = $configHelper->getApiKey();
661
+ $isValidated = Mage::helper('tiny_compressimages/tinify')->validate($apiKey);
662
+
663
+ $cacheData = array();
664
+ if (!$apiKey || $isValidated) {
665
+ $message = '<span class="compressimages_status_success">'
666
+ . '<span class="indicator"><img src="' . Mage::getDesign()->getSkinUrl('images/fam_bullet_success.gif') . '"></span>'
667
+ . Mage::helper('tiny_compressimages')->__('API connection successful')
668
+ . '</span>';
669
+
670
+ $cacheData['status'] = 'operational';
671
+ } else {
672
+ $message = '<span class="compressimages_status_failure">'
673
+ . '<span class="indicator"><img src="' . Mage::getDesign()->getSkinUrl('images/error_msg_icon.gif') . '"></span>'
674
+ . Mage::helper('tiny_compressimages')->__('Non-operational')
675
+ . '</span>';
676
+
677
+ $cacheData['status'] = 'nonoperational';
678
+ }
679
+
680
+ $result = array();
681
+ $result['status'] = 'success';
682
+ $result['message'] = $message;
683
+
684
+ /**
685
+ * Only cache the results if the api is up.
686
+ */
687
+ if ($cacheData['status'] == 'operational') {
688
+ Mage::app()->saveCache(json_encode($result), static::CACHE_KEY);
689
+ }
690
+
691
+ return $result;
692
+ }
693
+
694
+ /**
695
+ * @param $file
696
+ *
697
+ * @return string
698
+ */
699
+ protected function _getOptimizedMediaPath($file)
700
+ {
701
+ $baseDir = Mage::getBaseDir('media');
702
+ $tinyPath = substr(Tiny_CompressImages_Helper_Tinify::TINY_COMPRESSIMAGES_MEDIA_DIRECTORY.DS, 1);
703
+
704
+ $path = str_replace(
705
+ $baseDir . DS,
706
+ $tinyPath,
707
+ $file
708
+ );
709
+
710
+ return Mage::getBaseDir(). '/' .str_replace(DS, '/', $path);
711
+ }
712
+
713
+ /**
714
+ * Generic function so we can change the hash function easily.
715
+ *
716
+ * @param SplFileInfo $file
717
+ *
718
+ * @return string
719
+ */
720
+ protected function _getFileHash(SplFileInfo $file)
721
+ {
722
+ if (!$file->isFile()) {
723
+ return false;
724
+ }
725
+
726
+ return md5_file($file->getPathname());
727
+ }
728
+
729
+ /**
730
+ * Get the filesize for the specified file.
731
+ *
732
+ * @param SplFileInfo $file
733
+ *
734
+ * @return bool|int
735
+ */
736
+ protected function _getFileSize(SplFileInfo $file)
737
+ {
738
+ if (!$file->isFile())
739
+ {
740
+ return false;
741
+ }
742
+
743
+ /**
744
+ * Flush PHP's internal cache so we always have use a fresh copy of the file.
745
+ */
746
+ clearstatcache();
747
+
748
+ return $file->getSize();
749
+ }
750
+ }
app/code/community/Tiny/CompressImages/Model/Image.php ADDED
@@ -0,0 +1,327 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @method string|null getPath();
4
+ * @method $this setPathOptimized(String $path);
5
+ * @method string|null getPathOptimized();
6
+ * @method $this setImageType(String $type);
7
+ * @method $this setHashBefore(String $hash);
8
+ * @method string|null getHashBefore();
9
+ * @method $this setHashAfter(String $hash);
10
+ * @method string|null getHashAfter();
11
+ * @method $this setBytesBefore(int $bytes);
12
+ * @method int|null getBytesBefore();
13
+ * @method $this setBytesAfter(int $bytes);
14
+ * @method int|null getBytesAfter();
15
+ * @method $this setUsedAsSource(int $times);
16
+ * @method int|null getUsedAsSource();
17
+ * @method $this setProcessedAt(String $date);
18
+ * @method string|null getProcessedAt();
19
+ * @method $this setIsTest(int $testMode);
20
+ * @method string|null getIsTest();
21
+ * @method $this setCompressedBefore(int $compressedBefore);
22
+ * @method int|null getCompressedBefore();
23
+ * @method $this setParentId(int $parentId);
24
+ * @method int|null getParentId();
25
+ */
26
+ class Tiny_CompressImages_Model_Image extends Mage_Core_Model_Abstract
27
+ {
28
+ /**
29
+ * @var Tiny_CompressImages_Helper_Data
30
+ */
31
+ protected $_helper = null;
32
+
33
+ /**
34
+ * The constructer. Loads the helper.
35
+ */
36
+ public function __construct()
37
+ {
38
+ parent::__construct();
39
+
40
+ $this->_helper = Mage::helper('tiny_compressimages');
41
+ }
42
+
43
+ /**
44
+ * Class constructor.
45
+ */
46
+ public function _construct()
47
+ {
48
+ $this->_init('tiny_compressimages/image');
49
+ }
50
+
51
+ /**
52
+ * Set the path and also calculate the optimized path.
53
+ *
54
+ * @param $path
55
+ *
56
+ * @return $this
57
+ */
58
+ public function setPath($path)
59
+ {
60
+ $this->setData('path', $path);
61
+
62
+ $filename = basename($path);
63
+ $newPath = str_replace($filename, '', $path);
64
+ $hash = md5($newPath);
65
+
66
+ $optimizedPath = Tiny_CompressImages_Helper_Tinify::TINY_COMPRESSIMAGES_MEDIA_DIRECTORY;
67
+ $optimizedPath .= '/' . $hash[0] . '/' . $hash[1] . '/' . $hash . '/' . $filename;
68
+
69
+ $this->setPathOptimized($optimizedPath);
70
+
71
+ return $this;
72
+ }
73
+
74
+ /**
75
+ * Creates the path where the image will be saved.
76
+ *
77
+ * @return $this
78
+ */
79
+ public function createPath()
80
+ {
81
+ $path = dirname($this->getPathOptimized());
82
+ $fullpath = Mage::getBaseDir('media') . str_replace('/media', '', $path);
83
+
84
+ if (!is_dir($fullpath)) {
85
+ mkdir($fullpath, 0777, true);
86
+ }
87
+
88
+ return $this;
89
+ }
90
+
91
+ /**
92
+ * The full path where the image will be saved.
93
+ *
94
+ * @return string
95
+ */
96
+ public function getFilepathOptimized()
97
+ {
98
+ $path = $this->getPathOptimized();
99
+ return Mage::getBaseDir('media') . str_replace('/media', '', $path);
100
+ }
101
+
102
+ /**
103
+ * Retrieve the url to the image.
104
+ *
105
+ * @return string
106
+ */
107
+ public function getUrl()
108
+ {
109
+ return Mage::getBaseUrl('media') . str_replace('/media/', '', $this->getPathOptimized());
110
+ }
111
+
112
+ /**
113
+ * Get the statistics for the CompressImages module.
114
+ *
115
+ * $options:
116
+ * - current_month: defaults to true
117
+ *
118
+ * @param array $options
119
+ *
120
+ * @return Varien_Object
121
+ */
122
+ public function getStatistics($options = array())
123
+ {
124
+ $collection = $this->getCollection();
125
+
126
+ /**
127
+ * Filter by the current month.
128
+ */
129
+ if (
130
+ !isset($options['current_month']) ||
131
+ (
132
+ isset($options['current_month']) &&
133
+ $options['current_month']
134
+ )
135
+ ) {
136
+ $dateFrom = Mage::getModel('core/date')->date('Y-m-01');
137
+ $dateTo = Mage::getModel('core/date')->date('Y-m-t');
138
+
139
+ $collection->addFieldToFilter(
140
+ 'processed_at',
141
+ array(
142
+ 'from' => $dateFrom,
143
+ 'to' => $dateTo,
144
+ 'date' => true
145
+ )
146
+ );
147
+ }
148
+
149
+ $collection
150
+ ->getSelect()
151
+ ->reset(Zend_Db_Select::COLUMNS)
152
+ ->columns('count(image_id) as images_count')
153
+ ->columns('sum(bytes_before) as bytes_before')
154
+ ->columns('sum(bytes_after) as bytes_after')
155
+ ->columns('max(((bytes_before - bytes_after) / bytes_before) * 100) as greatest_saving')
156
+ ;
157
+
158
+ $data = $collection->getFirstItem();
159
+
160
+ if ($data->images_count > 0) {
161
+ $data->setData('percentage_saved', (($data->bytes_before - $data->bytes_after) / $data->bytes_before) * 100);
162
+ } else {
163
+ $data->setData('percentage_saved', 0);
164
+ }
165
+
166
+ return $data;
167
+ }
168
+
169
+ /**
170
+ * Retrieve a model by the hash.
171
+ *
172
+ * @param $hash
173
+ *
174
+ * @return Tiny_CompressImages_Model_Image|null
175
+ */
176
+ public function getByHash($hash)
177
+ {
178
+ /** @var Tiny_CompressImages_Model_Resource_Image_Collection $model */
179
+ $model = $this->getCollection();
180
+ $model->addFieldToFilter(
181
+ array(
182
+ 'hash_before',
183
+ 'hash_after',
184
+ ),
185
+ array(
186
+ array('eq' => $hash),
187
+ array('eq' => $hash),
188
+ )
189
+ );
190
+
191
+ $item = $model->getFirstItem();
192
+ if ($item->getId() !== null) {
193
+ return $item;
194
+ } else {
195
+ return null;
196
+ }
197
+ }
198
+
199
+ /**
200
+ * Simple function to add 1 to the used_as_source column.
201
+ *
202
+ * @return $this
203
+ */
204
+ public function addUsedAsSource()
205
+ {
206
+ $this->setUsedAsSource($this->getUsedAsSource() + 1);
207
+
208
+ return $this;
209
+ }
210
+
211
+ /**
212
+ * Get the url for this image.
213
+ *
214
+ * @return string
215
+ */
216
+ public function getImageUrl()
217
+ {
218
+ // If it is a duplicate image, then there will be a link to his parent.
219
+ if ($this->getParentId()) {
220
+ /** @var Tiny_CompressImages_Model_Image $parent */
221
+ $parent = Mage::getModel('tiny_compressimages/image')->load($this->getParentId());
222
+
223
+ return $parent->getUrl();
224
+ }
225
+
226
+ return $this->getUrl();
227
+ }
228
+
229
+ /**
230
+ * Calculate the bytes saved.
231
+ *
232
+ * @return null|string
233
+ */
234
+ public function getBytesSaved()
235
+ {
236
+ return $this->getBytesBefore() - $this->getBytesAfter();
237
+ }
238
+
239
+ /**
240
+ * Show the correct image type.
241
+ *
242
+ * @return string
243
+ */
244
+ public function getImageType()
245
+ {
246
+ $data = $this->getData('image_type');
247
+
248
+ switch($data) {
249
+ case 'image':
250
+ $data = 'Base image';
251
+ break;
252
+
253
+ case 'small_image':
254
+ $data = 'Small image';
255
+ break;
256
+
257
+ case 'thumbnail':
258
+ $data = 'Thumbnail';
259
+ break;
260
+
261
+ case 'media_image':
262
+ $data = 'Swatches';
263
+ break;
264
+ }
265
+
266
+ return $data;
267
+ }
268
+
269
+ /**
270
+ * Calculate the percentage saved.
271
+ *
272
+ * @return null|string
273
+ */
274
+ public function getPercentageSaved()
275
+ {
276
+ $bytesSaved = $this->getBytesSaved();
277
+
278
+ if ($bytesSaved == 0) {
279
+ return '0 %';
280
+ } else {
281
+ return round(($bytesSaved / $this->getBytesBefore()) * 100) . ' %';
282
+ }
283
+ }
284
+
285
+ /**
286
+ * Shows the time ago in human readable format when this image was processed.
287
+ *
288
+ * @return string
289
+ */
290
+ public function getTimeAgo()
291
+ {
292
+ return $this->_helper->timeAgo($this->getProcessedAt());
293
+ }
294
+
295
+ /**
296
+ * Delete all models
297
+ *
298
+ * @return $this
299
+ */
300
+ public function deleteAll()
301
+ {
302
+ $collection = $this->getCollection();
303
+
304
+ Mage::getSingleton('core/resource_iterator')->walk($collection->getSelect(), array( function ($args) {
305
+ Mage::getModel('tiny_compressimages/image')->load($args['row']['image_id'])->delete();
306
+ }));
307
+
308
+ return $this;
309
+ }
310
+
311
+ /**
312
+ * Delete all models
313
+ *
314
+ * @return $this
315
+ */
316
+ public function deleteTest()
317
+ {
318
+ $collection = $this->getCollection();
319
+ $collection->addFieldToFilter('is_test', '1');
320
+
321
+ Mage::getSingleton('core/resource_iterator')->walk($collection->getSelect(), array( function ($args) {
322
+ Mage::getModel('tiny_compressimages/image')->load($args['row']['image_id'])->delete();
323
+ }));
324
+
325
+ return $this;
326
+ }
327
+ }
app/code/community/Tiny/CompressImages/Model/Observer.php CHANGED
@@ -1,75 +1,27 @@
1
  <?php
2
-
3
- /*
4
- * Tiny Compress Images - Magento Extension.
5
- * Copyright (C) 2015 Voormedia B.V.
6
- *
7
- * This program is free software; you can redistribute it and/or modify it
8
- * under the terms of the GNU General Public License as published by the Free
9
- * Software Foundation; either version 2 of the License, or (at your option)
10
- * any later version.
11
- *
12
- * This program is distributed in the hope that it will be useful, but WITHOUT
13
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15
- * more details.
16
- *
17
- * You should have received a copy of the GNU General Public License along
18
- * with this program; if not, write to the Free Software Foundation, Inc., 51
19
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
- */
21
-
22
- require('TinyCompress' . DIRECTORY_SEPARATOR . 'class-tiny-exception.php');
23
- require('TinyCompress' . DIRECTORY_SEPARATOR . 'class-tiny-php.php');
24
- require('TinyCompress' . DIRECTORY_SEPARATOR . 'class-tiny-compress.php');
25
- require('TinyCompress' . DIRECTORY_SEPARATOR . 'class-tiny-compress-curl.php');
26
- require('TinyCompress' . DIRECTORY_SEPARATOR . 'class-tiny-compress-fopen.php');
27
-
28
  class Tiny_CompressImages_Model_Observer
29
  {
30
- public function compress(Varien_Event_Observer $observer)
 
 
 
 
 
 
 
 
 
 
 
 
31
  {
32
- $imageObject = $observer->getEvent()->getObject();
33
- $destinationSubdir = $imageObject->getDestinationSubdir();
34
- switch ($destinationSubdir) {
35
- case "image" :
36
- $allowCompression = Mage::getStoreConfig('compress_images/image_sizes/compress_image');
37
- break;
38
- case "small_image" :
39
- $allowCompression = Mage::getStoreConfig('compress_images/image_sizes/compress_small_image');
40
- break;
41
- case "thumbnail" :
42
- $allowCompression = Mage::getStoreConfig('compress_images/image_sizes/compress_thumbnail');
43
- break;
44
- default :
45
- $allowCompression = Mage::getStoreConfig('compress_images/image_sizes/compress_other_images');
46
- break;
47
  }
48
- if ($allowCompression) {
49
- $apiKey = Mage::getStoreConfig('compress_images/settings/api_key');
50
- if (!empty($apiKey)) {
51
- $newFile = $imageObject->getNewFile();
52
- $width = $imageObject->getWidth();
53
- $height = $imageObject->getHeight();
54
- $compressor = Tiny_Compress::get_compressor($apiKey);
55
- try {
56
- $details = $compressor->compress_file($newFile);
57
- $logDescription =
58
- "Variant " . $destinationSubdir .
59
- " allowed " . $allowCompression .
60
- " width " . $width .
61
- " height " . $height .
62
- " API " . $apiKey .
63
- " JSON response " . json_encode($details);
64
- } catch (Tiny_Exception $e) {
65
- $logDescription = $e->get_error() . ': ' . $e->getMessage();
66
- }
67
- } else {
68
- $logDescription = "No API key found for compression.";
69
- }
70
- } else {
71
- $logDescription = "Variant {$destinationSubdir} not selected for compression.";
72
- }
73
- Mage::log($logDescription, null, 'image-compression.log');
74
  }
75
  }
1
  <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  class Tiny_CompressImages_Model_Observer
3
  {
4
+ /**
5
+ * @var null|Tiny_CompressImages_Helper_Tinify
6
+ */
7
+ protected $_tinifyHelper = null;
8
+
9
+ /**
10
+ * Compress product images
11
+ *
12
+ * @param $observer
13
+ *
14
+ * @return $this
15
+ */
16
+ public function catalogProductImageSaveAfter($observer)
17
  {
18
+ if ($this->_tinifyHelper === null) {
19
+ $this->_tinifyHelper = Mage::helper('tiny_compressimages/tinify');
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  }
21
+
22
+ $storeId = Mage::app()->getStore()->getStoreId();
23
+ $this->_tinifyHelper->setProductImage($observer->getObject(), $storeId)->compress();
24
+
25
+ return $this;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  }
27
  }
app/code/community/Tiny/CompressImages/Model/Product/Image.php CHANGED
@@ -1,24 +1,77 @@
1
  <?php
2
-
3
  class Tiny_CompressImages_Model_Product_Image extends Mage_Catalog_Model_Product_Image
4
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
- /* Changed for TinyPNG image compression */
7
- protected $_quality = 95;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
 
9
  /**
10
- * @return Mage_Catalog_Model_Product_Image
11
  */
12
  public function saveFile()
13
  {
14
- $filename = $this->getNewFile();
15
- $this->getImageProcessor()->save($filename);
16
- Mage::helper('core/file_storage_database')->saveFile($filename);
17
 
18
- /* Added for TinyPNG image compression */
19
  Mage::dispatchEvent('catalog_product_image_save_after', array($this->_eventObject => $this));
20
 
21
  return $this;
22
  }
23
-
24
  }
1
  <?php
 
2
  class Tiny_CompressImages_Model_Product_Image extends Mage_Catalog_Model_Product_Image
3
  {
4
+ /**
5
+ * Set the minimun required quality for CompressImages which is 95
6
+ *
7
+ * @var int
8
+ */
9
+ protected $_quality = 85;
10
+
11
+ /**
12
+ * @var Tiny_CompressImages_Helper_Config|null
13
+ */
14
+ protected $_configHelper = null;
15
+
16
+ /**
17
+ * @var Tiny_CompressImages_Helper_Tinify|null
18
+ */
19
+ protected $_dataHelper = null;
20
+
21
+ /**
22
+ * @return Tiny_CompressImages_Helper_Config
23
+ */
24
+ public function getConfigHelper()
25
+ {
26
+ if ($this->_configHelper === null) {
27
+ $this->_configHelper = Mage::helper('tiny_compressimages/config');
28
+ }
29
+
30
+ return $this->_configHelper;
31
+ }
32
+
33
+ /**
34
+ * @return Tiny_CompressImages_Helper_Data
35
+ */
36
+ public function getDataHelper()
37
+ {
38
+ if ($this->_dataHelper === null) {
39
+ $this->_dataHelper = Mage::helper('tiny_compressimages');
40
+ }
41
+
42
+ return $this->_dataHelper;
43
+ }
44
 
45
+ /**
46
+ * @return string
47
+ */
48
+ public function getUrl()
49
+ {
50
+ /** @var Tiny_CompressImages_Helper_Config $helper */
51
+ $helper = $this->getConfigHelper();
52
+ if ($helper->isTestMode(Mage::app()->getStore()->getStoreId())) {
53
+ return parent::getUrl();
54
+ }
55
+
56
+ /** @var Tiny_Compressimages_Model_Image $model */
57
+ $path = substr($this->_newFile, strlen(Mage::getBaseDir('media')) - 6);
58
+ $model = Mage::getModel('tiny_compressimages/image')->load($path, 'path');
59
+ if (!$model->getId() || !file_exists($model->getFilepathOptimized())) {
60
+ return parent::getUrl();
61
+ }
62
+
63
+ return $model->getUrl();
64
+ }
65
 
66
  /**
67
+ * @return Mage_Catalog_Model_Product_Image $this
68
  */
69
  public function saveFile()
70
  {
71
+ parent::saveFile();
 
 
72
 
 
73
  Mage::dispatchEvent('catalog_product_image_save_after', array($this->_eventObject => $this));
74
 
75
  return $this;
76
  }
 
77
  }
app/code/community/Tiny/CompressImages/Model/Resource/Image.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Model_Resource_Image extends Mage_Core_Model_Resource_Db_Abstract
3
+ {
4
+ /**
5
+ * Define main table and id field name.
6
+ *
7
+ * @return void
8
+ */
9
+ protected function _construct()
10
+ {
11
+ $this->_init('tiny_compressimages/image', 'image_id');
12
+ }
13
+ }
app/code/community/Tiny/CompressImages/Model/Resource/Image/Collection.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Model_Resource_Image_Collection extends Mage_Core_Model_Resource_Db_Collection_Abstract
3
+ {
4
+ public function _construct()
5
+ {
6
+ parent::_construct();
7
+ $this->_init('tiny_compressimages/image');
8
+ }
9
+ }
app/code/community/Tiny/CompressImages/Model/Resource/Setup.php ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Model_Resource_Setup extends Mage_Core_Model_Resource_Setup
3
+ {
4
+ /**
5
+ * Copy a config setting from an old xpath to a new xpath directly in the database, rather than using Magento config
6
+ * entities.
7
+ *
8
+ * @param string $fromXpath
9
+ * @param string $toXpath
10
+ *
11
+ * @return $this
12
+ */
13
+ public function moveConfigSettingInDb($fromXpath, $toXpath)
14
+ {
15
+ $conn = $this->getConnection();
16
+
17
+ try {
18
+ $select = $conn->select()
19
+ ->from($this->getTable('core/config_data'))
20
+ ->where('path = ?', $fromXpath);
21
+
22
+ $result = $conn->fetchAll($select);
23
+ foreach ($result as $row) {
24
+ try {
25
+ /**
26
+ * Copy the old setting to the new setting.
27
+ *
28
+ * @todo Check if the row already exists.
29
+ */
30
+ $conn->insert(
31
+ $this->getTable('core/config_data'),
32
+ array(
33
+ 'scope' => $row['scope'],
34
+ 'scope_id' => $row['scope_id'],
35
+ 'value' => $row['value'],
36
+ 'path' => $toXpath
37
+ )
38
+ );
39
+ } catch (Exception $e) {
40
+ Mage::helper('tiny_compressimages')->log($e);
41
+ }
42
+ }
43
+ } catch (Exception $e) {
44
+ Mage::helper('tiny_compressimages')->log($e);
45
+ }
46
+
47
+ return $this;
48
+ }
49
+
50
+ /**
51
+ * Check if the specified xpath exists.
52
+ *
53
+ * @param $xpath
54
+ *
55
+ * @return bool
56
+ */
57
+ public function configExists($xpath)
58
+ {
59
+ $conn = $this->getConnection();
60
+
61
+ try {
62
+ $select = $conn->select()
63
+ ->from($this->getTable('core/config_data'))
64
+ ->where('path = ?', $xpath);
65
+
66
+ $result = $conn->fetchAll($select);
67
+ foreach ($result as $row) {
68
+ return true;
69
+ }
70
+ } catch (Exception $e) {
71
+ Mage::helper('tiny_compressimages')->log($e);
72
+ }
73
+
74
+ return false;
75
+ }
76
+ }
app/code/community/Tiny/CompressImages/Model/Resource/Totals.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Model_Resource_Totals extends Mage_Core_Model_Resource_Db_Abstract
3
+ {
4
+ /**
5
+ * Define main table and id field name.
6
+ *
7
+ * @return void
8
+ */
9
+ protected function _construct()
10
+ {
11
+ $this->_init('tiny_compressimages/totals', 'entity_id');
12
+ }
13
+ }
app/code/community/Tiny/CompressImages/Model/Resource/Totals/Collection.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Model_Resource_Totals_Collection extends Mage_Core_Model_Resource_Db_Collection_Abstract
3
+ {
4
+ public function _construct()
5
+ {
6
+ parent::_construct();
7
+ $this->_init('tiny_compressimages/totals');
8
+ }
9
+ }
app/code/community/Tiny/CompressImages/Model/System/Config/Backend/ApiKey.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Model_System_Config_Backend_ApiKey extends Mage_Core_Model_Config_Data
3
+ {
4
+ /**
5
+ * Validate the value before saving.
6
+ *
7
+ * @return Mage_Core_Model_Abstract
8
+ * @throws Mage_Exception
9
+ */
10
+ protected function _beforeSave()
11
+ {
12
+ $apiKeyValue = $this->getValue();
13
+ $oldApiKeyValue = $this->getOldValue();
14
+ $helper = Mage::helper('tiny_compressimages/tinify');
15
+
16
+ if (strlen($apiKeyValue) > 0) {
17
+ $validateResult = $helper->validate($apiKeyValue);
18
+
19
+ if (!$validateResult) {
20
+ throw new Mage_Exception($helper->__('The Api Key is invalid'));
21
+ }
22
+ }
23
+
24
+ /**
25
+ * Remove the cached items.
26
+ */
27
+ if ($apiKeyValue != $oldApiKeyValue) {
28
+ Mage::app()->removeCache(Tiny_CompressImages_Helper_Tinify::CACHE_KEY);
29
+ }
30
+
31
+ return parent::_beforeSave();
32
+ }
33
+ }
app/code/community/Tiny/CompressImages/Model/System/Config/Backend/Comment/LoggingMode.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Model_System_Config_Backend_Comment_LoggingMode
3
+ {
4
+ /**
5
+ * Make the /var/log/image-optimization.log file clickable.
6
+ *
7
+ * @return string
8
+ */
9
+ public function getCommentText()
10
+ {
11
+ $text = Mage::helper('tiny_compressimages')->__('Any error messages will be saved to %s');
12
+ $downloadUrl = Mage::helper("adminhtml")->getUrl('adminhtml/CompressImagesAdminhtml_config/downloadLogs');
13
+ $logPath = Mage::helper('tiny_compressimages')->getLogFilePath();
14
+ $basePath = Mage::getBaseDir();
15
+
16
+ $nicePath = str_replace($basePath, '', $logPath);
17
+
18
+ if (Mage::helper('tiny_compressimages')->getLogFileExists()) {
19
+ $text = sprintf($text, '<a href="' . $downloadUrl . '">' . $nicePath . '</a>');
20
+ } else {
21
+ $text = sprintf($text, $nicePath);
22
+ }
23
+
24
+ return $text;
25
+ }
26
+ }
app/code/community/Tiny/CompressImages/Model/System/Config/Source/Cms/ImageTypes.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Model_System_Config_Source_Cms_ImageTypes
3
+ {
4
+ /**
5
+ * Source cms model for collecting the image types.
6
+ *
7
+ * @return array
8
+ */
9
+ public function toOptionArray()
10
+ {
11
+ $helper = Mage::helper('tiny_compressimages');
12
+
13
+ $array = array(
14
+ array(
15
+ 'value' => 'category_images',
16
+ 'label' => $helper->__('Category images')
17
+ ),
18
+ array(
19
+ 'value' => 'block_images',
20
+ 'label' => $helper->__('Block images')
21
+ ),
22
+ array(
23
+ 'value' => 'cms_images',
24
+ 'label' => $helper->__('CMS page images')
25
+ ),
26
+ );
27
+
28
+ return $array;
29
+ }
30
+ }
app/code/community/Tiny/CompressImages/Model/System/Config/Source/Log.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Model_System_Config_Source_Log
3
+ {
4
+ /**
5
+ * Get the select list for logging mode.
6
+ *
7
+ * @return array
8
+ */
9
+ public function toOptionArray()
10
+ {
11
+ $helper = Mage::helper('tiny_compressimages');
12
+
13
+ $array = array(
14
+ array(
15
+ 'value' => 'off',
16
+ 'label' => $helper->__('Logging disabled')
17
+ ),
18
+ array(
19
+ 'value' => 'only_exceptions',
20
+ 'label' => $helper->__('Exceptions only')
21
+ ),
22
+ array(
23
+ 'value' => 'fail_and_exceptions',
24
+ 'label' => $helper->__('Errors and Exceptions')
25
+ ),
26
+ array(
27
+ 'value' => 'all',
28
+ 'label' => $helper->__('All logging information')
29
+ ),
30
+ );
31
+
32
+ return $array;
33
+ }
34
+ }
app/code/community/Tiny/CompressImages/Model/System/Config/Source/OnOff.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Model_System_Config_Source_OnOff
3
+ {
4
+ /**
5
+ * Source model for on / off selection
6
+ *
7
+ * @return array
8
+ */
9
+ public function toOptionArray()
10
+ {
11
+ $helper = Mage::helper('tiny_compressimages');
12
+
13
+ $array = array(
14
+ array(
15
+ 'value' => 0,
16
+ 'label' => $helper->__('Off')
17
+ ),
18
+ array(
19
+ 'value' => 1,
20
+ 'label' => $helper->__('On')
21
+ ),
22
+ );
23
+
24
+ return $array;
25
+ }
26
+ }
app/code/community/Tiny/CompressImages/Model/System/Config/Source/Product/ImageTypes.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Model_System_Config_Source_Product_ImageTypes
3
+ {
4
+ /**
5
+ * Source product model for collecting the image types.
6
+ *
7
+ * @return array
8
+ */
9
+ public function toOptionArray()
10
+ {
11
+ $helper = Mage::helper('tiny_compressimages');
12
+
13
+ $array = array(
14
+ array(
15
+ 'value' => 'thumbnail',
16
+ 'label' => $helper->__('Thumbnail')
17
+ ),
18
+ array(
19
+ 'value' => 'small_image',
20
+ 'label' => $helper->__('Small Image')
21
+ ),
22
+ array(
23
+ 'value' => 'image',
24
+ 'label' => $helper->__('Base Image')
25
+ ),
26
+ array(
27
+ 'value' => 'media_image',
28
+ 'label' => $helper->__('Media Image')
29
+ ),
30
+ );
31
+
32
+ return $array;
33
+ }
34
+ }
app/code/community/Tiny/CompressImages/Model/System/Config/Source/Testlive.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Model_System_Config_Source_Testlive
3
+ {
4
+ /**
5
+ * Source model for test / live setting.
6
+ *
7
+ * @return array
8
+ */
9
+ public function toOptionArray()
10
+ {
11
+ $helper = Mage::helper('tiny_compressimages');
12
+
13
+ /**
14
+ * Used 0, 1 and 2 as values so that Mage::getStoreConfigFlag() would still function for checking if the
15
+ * extension is active. You still need to check if the value is 2 to see if it's in live or test mode.
16
+ */
17
+ $array = array(
18
+ array(
19
+ 'value' => '2',
20
+ 'label' => $helper->__('Live')
21
+ ),
22
+ array(
23
+ 'value' => '1',
24
+ 'label' => $helper->__('Test')
25
+ ),
26
+ array(
27
+ 'value' => '0',
28
+ 'label' => $helper->__('Disabled')
29
+ ),
30
+ );
31
+ return $array;
32
+ }
33
+ }
app/code/community/Tiny/CompressImages/Model/Totals.php ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @method string|null getEntityId();
4
+ * @method $this setDateFrom(String $date);
5
+ * @method string|null getDateFrom();
6
+ * @method $this setDateTo(String $date);
7
+ * @method string|null getDateTo();
8
+ * @method $this setTotalBytesBefore(int $bytes);
9
+ * @method int|null getTotalBytesBefore();
10
+ * @method $this setTotalBytesAfter(int $bytes);
11
+ * @method int|null getTotalBytesAfter();
12
+ * @method $this setTotalCompressions(int $compressions);
13
+ * @method string|null getTotalCompressions();
14
+ * @method $this setUpdatedAt(String $date);
15
+ * @method string|null getUpdatedAt();
16
+ */
17
+ class Tiny_CompressImages_Model_Totals extends Mage_Core_Model_Abstract
18
+ {
19
+ /**
20
+ * Constructor load his parent.
21
+ */
22
+ public function __construct()
23
+ {
24
+ parent::__construct();
25
+ }
26
+
27
+ /**
28
+ * Class constructor.
29
+ */
30
+ public function _construct()
31
+ {
32
+ $this->_init('tiny_compressimages/totals');
33
+ }
34
+
35
+ /**
36
+ * Gets the compression information over the total data.
37
+ *
38
+ * @return array
39
+ */
40
+ public function getTotalCompressionInformation()
41
+ {
42
+ $collection = $this->getCollection();
43
+
44
+ $totalCompressions = 0;
45
+ $totalBytesBefore = 0;
46
+ $totalBytesAfter = 0;
47
+
48
+ /** @var Tiny_CompressImages_Model_Totals $record */
49
+ foreach ($collection as $record) {
50
+ $totalCompressions = $record->getTotalCompressions() + $totalCompressions;
51
+ $totalBytesBefore = $record->getTotalBytesBefore() + $totalBytesBefore;
52
+ $totalBytesAfter = $record->getTotalBytesAfter() + $totalBytesAfter;
53
+ }
54
+
55
+ $bytesSaved = $totalBytesBefore - $totalBytesAfter;
56
+ $percantageSaved = 0;
57
+
58
+ if ($bytesSaved !== 0) {
59
+ $percantageSaved = round(($bytesSaved / $totalBytesBefore) * 100);
60
+ }
61
+
62
+ return array(
63
+ 'percentageSaved' => $percantageSaved,
64
+ 'totalCompressions' => $totalCompressions,
65
+ 'bytesBefore' => $this->formatBytes($totalBytesBefore),
66
+ 'bytesAfter' => $this->formatBytes($totalBytesAfter),
67
+ );
68
+ }
69
+
70
+ /**
71
+ * @param $bytes
72
+ * @param int $precision
73
+ *
74
+ * @return string
75
+ */
76
+ function formatBytes($bytes, $precision = 2) {
77
+ if ($bytes <= 0) {
78
+ return '0 KB';
79
+ }
80
+
81
+ $units = array('B', 'KB', 'MB', 'GB', 'TB');
82
+
83
+ $i = floor(log($bytes, 1024));
84
+ $sum = round($bytes / pow(1024, $i), $precision);
85
+
86
+ return $sum . ' ' . $units[$i];
87
+
88
+ }
89
+ }
app/code/community/Tiny/CompressImages/Test/Block/Adminhtml/System/Config/Form/Field/LogStatusTest.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Test_Block_Adminhtml_System_Config_Form_Field_LogStatusTest
3
+ extends Tiny_CompressImages_Test_Framework_Tiny_Test_TestCase
4
+ {
5
+ /**
6
+ * @var Tiny_CompressImages_Block_Adminhtml_System_Config_Form_Field_LogStatus
7
+ */
8
+ protected $_instance = null;
9
+
10
+ protected function setUp()
11
+ {
12
+ $this->_instance = new Tiny_CompressImages_Block_Adminhtml_System_Config_Form_Field_LogStatus;
13
+ $this->_instance->setArea('adminhtml');
14
+
15
+ Mage::getModel('tiny_compressimages/image')->deleteAll();
16
+ }
17
+
18
+ public function testImagesLimit()
19
+ {
20
+ $html = $this->_instance->toHtml();
21
+ $this->assertNotContains('id="show_all"', $html);
22
+
23
+ for ($i = 0; $i < 11; $i++) {
24
+ $model = Mage::getModel('tiny_compressimages/image');
25
+ $model->setProcessedAt(Varien_Date::now());
26
+ $model->save();
27
+ }
28
+
29
+ $html = $this->_instance->toHtml();
30
+ $this->assertContains('id="show_all"', $html);
31
+ }
32
+ }
app/code/community/Tiny/CompressImages/Test/Framework/Tiny/Test/Config.php ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Test_Framework_Tiny_Test_Config extends Mage_Core_Model_Config
3
+ {
4
+ /**
5
+ * @var array
6
+ */
7
+ protected $_mockModels = array();
8
+
9
+ /**
10
+ * @var array
11
+ */
12
+ protected $_mockResourceModels = array();
13
+
14
+ /**
15
+ * @param string $modelClass
16
+ * @param object $mock
17
+ *
18
+ * @return $this
19
+ */
20
+ public function setModelMock($modelClass, $mock)
21
+ {
22
+ $this->_mockModels[$modelClass] = $mock;
23
+ return $this;
24
+ }
25
+
26
+ /**
27
+ * @param string $modelClass
28
+ * @param object $mock
29
+ *
30
+ * @return $this
31
+ */
32
+ public function setResourceModelMock($modelClass, $mock)
33
+ {
34
+ $this->_mockResourceModels[$modelClass] = $mock;
35
+ return $this;
36
+ }
37
+
38
+ /**
39
+ * @param string $modelClass
40
+ * @param array $constructArguments
41
+ *
42
+ * @return false|Mage_Core_Model_Abstract
43
+ */
44
+ public function getModelInstance($modelClass = '', $constructArguments = array())
45
+ {
46
+ $modelClass = (string) $modelClass;
47
+
48
+ if (array_key_exists($modelClass, $this->_mockModels)) {
49
+ return $this->_mockModels[$modelClass];
50
+ }
51
+
52
+ return parent::getModelInstance($modelClass, $constructArguments);
53
+ }
54
+
55
+ /**
56
+ * Get resource model object by alias
57
+ *
58
+ * @param string $modelClass
59
+ * @param array $constructArguments
60
+ * @return object
61
+ */
62
+ public function getResourceModelInstance($modelClass='', $constructArguments = array())
63
+ {
64
+ $modelClass = (string) $modelClass;
65
+
66
+ if (array_key_exists($modelClass, $this->_mockResourceModels)) {
67
+ return $this->_mockResourceModels[$modelClass];
68
+ }
69
+
70
+ return parent::getResourceModelInstance($modelClass, $constructArguments);
71
+ }
72
+ }
app/code/community/Tiny/CompressImages/Test/Framework/Tiny/Test/Http/Response.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Test_Framework_Tiny_Test_Http_Response extends Mage_Core_Controller_Response_Http
3
+ {
4
+ /**
5
+ * @var bool
6
+ */
7
+ protected $_headersSent = false;
8
+
9
+ /**
10
+ * @param boolean $headersSent
11
+ *
12
+ * @return Tiny_CompressImages_Test_Framework_Tiny_Test_Http_Response
13
+ */
14
+ public function setHeadersSent($headersSent)
15
+ {
16
+ $this->_headersSent = $headersSent;
17
+
18
+ return $this;
19
+ }
20
+
21
+ /**
22
+ * @return boolean
23
+ */
24
+ public function getHeadersSent()
25
+ {
26
+ return $this->_headersSent;
27
+ }
28
+
29
+ /**
30
+ * @param bool $throw
31
+ *
32
+ * @return bool
33
+ */
34
+ public function canSendHeaders($throw = false)
35
+ {
36
+ $canSendHeaders = !$this->getHeadersSent();
37
+ return $canSendHeaders;
38
+ }
39
+
40
+ /**
41
+ * @return Mage_Core_Controller_Response_Http
42
+ */
43
+ public function sendHeaders()
44
+ {
45
+ $this->setHeadersSent(true);
46
+
47
+ return $this;
48
+ }
49
+
50
+ /**
51
+ * @return $this
52
+ */
53
+ public function sendResponse()
54
+ {
55
+ return $this;
56
+ }
57
+
58
+ }
app/code/community/Tiny/CompressImages/Test/Framework/Tiny/Test/TestCase.php ADDED
@@ -0,0 +1,244 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Test_Framework_Tiny_Test_TestCase extends PHPUnit_Framework_TestCase
3
+ {
4
+ /**
5
+ * @var null
6
+ */
7
+ protected $_instance = null;
8
+
9
+ /**
10
+ * Resets and restarts Magento.
11
+ */
12
+ public static function resetMagento()
13
+ {
14
+ Mage::reset();
15
+
16
+ Mage::setIsDeveloperMode(false);
17
+ Mage::app(
18
+ 'admin',
19
+ 'store',
20
+ array(
21
+ 'config_model' => 'Tiny_CompressImages_Test_Framework_Tiny_Test_Config'
22
+ )
23
+ )->setResponse(new Tiny_CompressImages_Test_Framework_Tiny_Test_Http_Response());
24
+
25
+ $handler = set_error_handler(function() {});
26
+
27
+ set_error_handler(function($errno, $errstr, $errfile, $errline) use ($handler) {
28
+ if (E_WARNING === $errno
29
+ && 0 === strpos($errstr, 'include(')
30
+ && substr($errfile, -19) == 'Varien/Autoload.php'
31
+ ) {
32
+ return null;
33
+ }
34
+ return call_user_func(
35
+ $handler, $errno, $errstr, $errfile, $errline
36
+ );
37
+ });
38
+ }
39
+
40
+ public function prepareFrontendDispatch()
41
+ {
42
+ $store = Mage::app()->getDefaultStoreView();
43
+ $store->setConfig('web/url/redirect_to_base', false);
44
+ $store->setConfig('web/url/use_store', false);
45
+ $store->setConfig('advanced/modules_disable_output/Enterprise_Banner', true);
46
+
47
+ Mage::app()->setCurrentStore($store->getCode());
48
+
49
+ $this->registerMockSessions();
50
+ }
51
+
52
+ public function registerMockSessions($modules = null)
53
+ {
54
+ if (!is_array($modules)) {
55
+ $modules = array('core', 'customer', 'checkout', 'catalog', 'reports');
56
+ }
57
+
58
+ foreach ($modules as $module) {
59
+ $class = "$module/session";
60
+ $sessionMock = $this->getMockBuilder(
61
+ Mage::getConfig()->getModelClassName($class)
62
+ )->disableOriginalConstructor()
63
+ ->getMock();
64
+ $sessionMock->expects($this->any())
65
+ ->method('start')
66
+ ->will($this->returnSelf());
67
+ $sessionMock->expects($this->any())
68
+ ->method('init')
69
+ ->will($this->returnSelf());
70
+ $sessionMock->expects($this->any())
71
+ ->method('getMessages')
72
+ ->will($this->returnValue(
73
+ Mage::getModel('core/message_collection')
74
+ ));
75
+ $sessionMock->expects($this->any())
76
+ ->method('getSessionIdQueryParam')
77
+ ->will($this->returnValue(
78
+ Mage_Core_Model_Session_Abstract::SESSION_ID_QUERY_PARAM
79
+ ));
80
+ $sessionMock->expects($this->any())
81
+ ->method('getCookieShouldBeReceived')
82
+ ->will($this->returnValue(false));
83
+ $this->setSingletonMock($class, $sessionMock);
84
+ $this->setModelMock($class, $sessionMock);
85
+ }
86
+
87
+ $cookieMock = $this->getMock('Mage_Core_Model_Cookie');
88
+ $cookieMock->expects($this->any())
89
+ ->method('get')
90
+ ->will($this->returnValue(serialize('dummy')));
91
+ Mage::unregister('_singleton/core/cookie');
92
+ Mage::register('_singleton/core/cookie', $cookieMock);
93
+
94
+ // mock visitor log observer
95
+ $logVisitorMock = $this->getMock('Mage_Log_Model_Visitor');
96
+ $this->setModelMock('log/visitor', $logVisitorMock);
97
+
98
+ /**
99
+ * Fix enterprise catalog permissions issue
100
+ */
101
+ $factoryName = 'enterprise_catalogpermissions/permission_index';
102
+ $className = Mage::getConfig()->getModelClassName($factoryName);
103
+ if (class_exists($className)) {
104
+ $mockPermissions = $this->getMock($className);
105
+ $mockPermissions->expects($this->any())
106
+ ->method('getIndexForCategory')
107
+ ->withAnyParameters()
108
+ ->will($this->returnValue(array()));
109
+
110
+ $this->setSingletonMock($factoryName, $mockPermissions);
111
+ }
112
+ }
113
+
114
+ /**
115
+ * @param string $modelClass
116
+ * @param object $mock
117
+ *
118
+ * @return $this
119
+ */
120
+ public function setModelMock($modelClass, $mock)
121
+ {
122
+ $this->getConfig()->setModelMock($modelClass, $mock);
123
+
124
+ return $this;
125
+ }
126
+ /**
127
+ * @param string $modelClass
128
+ * @param object $mock
129
+ *
130
+ * @return $this
131
+ */
132
+ public function setResourceModelMock($modelClass, $mock)
133
+ {
134
+ $this->getConfig()->setResourceModelMock($modelClass, $mock);
135
+
136
+ return $this;
137
+ }
138
+
139
+ /**
140
+ * @param string $modelClass
141
+ * @param object $mock
142
+ *
143
+ * @return $this
144
+ */
145
+ public function setSingletonMock($modelClass, $mock)
146
+ {
147
+ $registryKey = '_singleton/' . $modelClass;
148
+
149
+ Mage::unregister($registryKey);
150
+ Mage::register($registryKey, $mock);
151
+
152
+ return $this;
153
+ }
154
+
155
+ /**
156
+ * @param $modelClass
157
+ *
158
+ * @return mixed
159
+ */
160
+ public function getSingletonMock($modelClass)
161
+ {
162
+ $registryKey = '_singleton/' . $modelClass;
163
+
164
+ return Mage::registry($registryKey);
165
+ }
166
+
167
+ /**
168
+ * @param string $resourceModelClass
169
+ * @param object $mock
170
+ *
171
+ * @return $this
172
+ */
173
+ public function setResourceSingletonMock($resourceModelClass, $mock)
174
+ {
175
+ $registryKey = '_resource_singleton/' . $resourceModelClass;
176
+
177
+ Mage::unregister($registryKey);
178
+ Mage::register($registryKey, $mock);
179
+
180
+ return $this;
181
+ }
182
+
183
+ /**
184
+ * @param string $helperClass
185
+ * @param object $mock
186
+ *
187
+ * @return $this
188
+ */
189
+ public function setHelperMock($helperClass, $mock)
190
+ {
191
+ $registryKey = '_helper/' . $helperClass;
192
+
193
+ Mage::unregister($registryKey);
194
+ Mage::register($registryKey, $mock);
195
+
196
+ return $this;
197
+ }
198
+
199
+ /**
200
+ * @return Tiny_CompressImages_Test_Framework_Tiny_Test_Config
201
+ */
202
+ public function getConfig()
203
+ {
204
+ return Mage::getConfig();
205
+ }
206
+
207
+ /**
208
+ * Create the models with the provided data.
209
+ *
210
+ * @param $modelName
211
+ * @param $data
212
+ */
213
+ public function createModels($modelName, $data)
214
+ {
215
+ foreach ($data as $row) {
216
+ $model = Mage::getModel($modelName);
217
+ $model->setData($row);
218
+ $model->save();
219
+ }
220
+ }
221
+
222
+ /**
223
+ * Sets a protected property to the provided value.
224
+ *
225
+ * @param $property
226
+ * @param $value
227
+ * @param null $instance
228
+ *
229
+ * @return $this
230
+ */
231
+ public function setProperty($property, $value, $instance = null)
232
+ {
233
+ if ($instance === null) {
234
+ $instance = $this->_instance;
235
+ }
236
+
237
+ $reflection = new ReflectionObject($instance);
238
+ $property = $reflection->getProperty($property);
239
+ $property->setAccessible(true);
240
+ $property->setValue($instance, $value);
241
+
242
+ return $this;
243
+ }
244
+ }
app/code/community/Tiny/CompressImages/Test/Helper/ConfigTest.php ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Test_Helper_DataTest extends Tiny_CompressImages_Test_Framework_Tiny_Test_TestCase
3
+ {
4
+ /**
5
+ * @var Tiny_CompressImages_Helper_Config
6
+ */
7
+ protected $_instance = null;
8
+
9
+ public function setUp()
10
+ {
11
+ $this->_instance = Mage::helper('tiny_compressimages/config');
12
+ }
13
+
14
+ public function getProductImageTypesToCompressDataProvider()
15
+ {
16
+ return array(
17
+ array(
18
+ array(
19
+ Tiny_CompressImages_Helper_Config::XPATH_IMAGE_TYPE_BASE => 1,
20
+ Tiny_CompressImages_Helper_Config::XPATH_IMAGE_TYPE_SMALL => 1,
21
+ Tiny_CompressImages_Helper_Config::XPATH_IMAGE_TYPE_THUMBNAIL => 1,
22
+ Tiny_CompressImages_Helper_Config::XPATH_IMAGE_TYPE_SWATCHES => 1,
23
+ ),
24
+ array(
25
+ 'image',
26
+ 'small_image',
27
+ 'thumbnail',
28
+ 'media_image',
29
+ 'swatches',
30
+ ),
31
+ ),
32
+ array(
33
+ array(
34
+ Tiny_CompressImages_Helper_Config::XPATH_IMAGE_TYPE_BASE => 0,
35
+ Tiny_CompressImages_Helper_Config::XPATH_IMAGE_TYPE_SMALL => 1,
36
+ Tiny_CompressImages_Helper_Config::XPATH_IMAGE_TYPE_THUMBNAIL => 1,
37
+ Tiny_CompressImages_Helper_Config::XPATH_IMAGE_TYPE_SWATCHES => 1,
38
+ ),
39
+ array(
40
+ 'small_image',
41
+ 'thumbnail',
42
+ 'media_image',
43
+ 'swatches',
44
+ ),
45
+ ),
46
+ array(
47
+ array(
48
+ Tiny_CompressImages_Helper_Config::XPATH_IMAGE_TYPE_BASE => 0,
49
+ Tiny_CompressImages_Helper_Config::XPATH_IMAGE_TYPE_SMALL => 0,
50
+ Tiny_CompressImages_Helper_Config::XPATH_IMAGE_TYPE_THUMBNAIL => 1,
51
+ Tiny_CompressImages_Helper_Config::XPATH_IMAGE_TYPE_SWATCHES => 1,
52
+ ),
53
+ array(
54
+ 'thumbnail',
55
+ 'media_image',
56
+ 'swatches',
57
+ ),
58
+ ),
59
+ array(
60
+ array(
61
+ Tiny_CompressImages_Helper_Config::XPATH_IMAGE_TYPE_BASE => 0,
62
+ Tiny_CompressImages_Helper_Config::XPATH_IMAGE_TYPE_SMALL => 0,
63
+ Tiny_CompressImages_Helper_Config::XPATH_IMAGE_TYPE_THUMBNAIL => 0,
64
+ Tiny_CompressImages_Helper_Config::XPATH_IMAGE_TYPE_SWATCHES => 1,
65
+ ),
66
+ array(
67
+ 'swatches',
68
+ ),
69
+ ),
70
+ array(
71
+ array(
72
+ Tiny_CompressImages_Helper_Config::XPATH_IMAGE_TYPE_BASE => 0,
73
+ Tiny_CompressImages_Helper_Config::XPATH_IMAGE_TYPE_SMALL => 0,
74
+ Tiny_CompressImages_Helper_Config::XPATH_IMAGE_TYPE_THUMBNAIL => 0,
75
+ Tiny_CompressImages_Helper_Config::XPATH_IMAGE_TYPE_SWATCHES => 0,
76
+ ),
77
+ array(
78
+ ),
79
+ ),
80
+ );
81
+ }
82
+
83
+ /**
84
+ * @dataProvider getProductImageTypesToCompressDataProvider
85
+ */
86
+ public function testGetProductImageTypesToCompress($config, $shouldHave)
87
+ {
88
+ foreach ($config as $path => $value) {
89
+ Mage::app()->getStore()->setConfig($path, $value);
90
+ }
91
+
92
+ $result = $this->_instance->getProductImageTypesToCompress();
93
+
94
+ $this->assertEquals($shouldHave, $result);
95
+ }
96
+ }
app/code/community/Tiny/CompressImages/Test/Model/ImageTest.php ADDED
@@ -0,0 +1,227 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class ImageTest extends Tiny_CompressImages_Test_Framework_Tiny_Test_TestCase
3
+ {
4
+ /**
5
+ * @var Tiny_CompressImages_Model_Image
6
+ */
7
+ protected $_instance = null;
8
+
9
+ /**
10
+ * Delete all models before testing.
11
+ */
12
+ public function setup()
13
+ {
14
+ Mage::getModel('tiny_compressimages/image')->deleteAll();
15
+
16
+ $this->_instance = Mage::getModel('tiny_compressimages/image');
17
+ }
18
+
19
+ /**
20
+ * Test data.
21
+ *
22
+ * @return array
23
+ */
24
+ public function testGetStatisticsDataProvider()
25
+ {
26
+ $now = Zend_Date::now();
27
+
28
+ return array(
29
+ array(
30
+ array(
31
+ array(
32
+ 'path' => '/media/catalog/product/cache/1/image/c96a280f94e22e3ee3823dd0a1a87606/a/c/acj003_2.jpg',
33
+ 'hash_before' => md5(uniqid()),
34
+ 'hash_after' => md5(uniqid()),
35
+ 'bytes_before' => 100,
36
+ 'bytes_after' => 50,
37
+ 'used_as_source' => 3,
38
+ 'processed_at' => $now->subMonth(1),
39
+ ),
40
+ array(
41
+ 'path' => '/media/catalog/product/cache/1/image/c96a280f94e22e3ee3823dd0a1a87606/a/c/acj003_2.jpg',
42
+ 'hash_before' => md5(uniqid()),
43
+ 'hash_after' => md5(uniqid()),
44
+ 'bytes_before' => 100,
45
+ 'bytes_after' => 75,
46
+ 'used_as_source' => 3,
47
+ 'processed_at' => Varien_Date::now(),
48
+ ),
49
+ ),
50
+ array(
51
+ 'percentage' => '25 %',
52
+ 'percentage_all_year' => '38 %',
53
+ 'greatest_saving' => '25',
54
+ 'greatest_saving_all_year' => '50',
55
+ 'bytes_saved' => 25,
56
+ 'bytes_saved_all_year' => 75,
57
+ 'images_count' => 1,
58
+ 'images_count_all_year' => 2,
59
+ )
60
+ ),
61
+ array(
62
+ array(
63
+ array(
64
+ 'path' => '/media/catalog/product/cache/1/image/c96a280f94e22e3ee3823dd0a1a87606/d/e/dec001_1.jpg',
65
+ 'hash_before' => md5(uniqid()),
66
+ 'hash_after' => md5(uniqid()),
67
+ 'bytes_before' => 500,
68
+ 'bytes_after' => 400,
69
+ 'used_as_source' => 1,
70
+ 'processed_at' => Varien_Date::now(),
71
+ ),
72
+ ),
73
+ array(
74
+ 'percentage' => '20 %',
75
+ 'percentage_all_year' => '20 %',
76
+ 'greatest_saving' => '20',
77
+ 'greatest_saving_all_year' => '20',
78
+ 'bytes_saved' => 100,
79
+ 'bytes_saved_all_year' => 100,
80
+ 'images_count' => 1,
81
+ 'images_count_all_year' => 1,
82
+ )
83
+ ),
84
+ array(
85
+ array(
86
+ array(
87
+ 'path' => '/media/catalog/product/cache/1/image/c96a280f94e22e3ee3823dd0a1a87606/t/r/troe008.jpg',
88
+ 'hash_before' => md5(uniqid()),
89
+ 'hash_after' => md5(uniqid()),
90
+ 'bytes_before' => 200,
91
+ 'bytes_after' => 150,
92
+ 'used_as_source' => 1,
93
+ 'processed_at' => Varien_Date::now(),
94
+ ),
95
+ ),
96
+ array(
97
+ 'percentage' => '25 %',
98
+ 'percentage_all_year' => '25 %',
99
+ 'greatest_saving' => '25',
100
+ 'greatest_saving_all_year' => '25',
101
+ 'bytes_saved' => 50,
102
+ 'bytes_saved_all_year' => 50,
103
+ 'images_count' => 1,
104
+ 'images_count_all_year' => 1,
105
+ )
106
+ ),
107
+ );
108
+ }
109
+
110
+ /**
111
+ * Test the results provided by the getStatistics method.
112
+ *
113
+ * @dataProvider testGetStatisticsDataProvider
114
+ */
115
+ public function testGetStatistics($models, $results)
116
+ {
117
+ $this->createModels('tiny_compressimages/image', $models);
118
+
119
+ $stats = $this->_instance->getStatistics();
120
+ $this->assertEquals($results['percentage'], $stats->getPercentageSaved());
121
+ $this->assertEquals($results['bytes_saved'], $stats->getBytesSaved());
122
+ $this->assertEquals($results['images_count'], $stats->getImagesCount());
123
+ $this->assertEquals($results['greatest_saving'], $stats->getGreatestSaving());
124
+
125
+ $stats = $this->_instance->getStatistics(['current_month' => false]);
126
+ $this->assertEquals($results['percentage_all_year'], $stats->getPercentageSaved());
127
+ $this->assertEquals($results['bytes_saved_all_year'], $stats->getBytesSaved());
128
+ $this->assertEquals($results['images_count_all_year'], $stats->getImagesCount());
129
+ $this->assertEquals($results['greatest_saving_all_year'], $stats->getGreatestSaving());
130
+ }
131
+
132
+ /**
133
+ * Test the fetching of a model by a hash.
134
+ */
135
+ public function testGetByHash()
136
+ {
137
+ $this->createModels('tiny_compressimages/image', array(
138
+ array(
139
+ 'path' => '1.jpg',
140
+ 'hash_before' => '54eab696c5c868b669076216ede66a9f',
141
+ 'hash_after' => '636734773941b236c82c9285b11d7f6c',
142
+ 'processed_at' => Varien_Date::now(),
143
+ ),
144
+ array(
145
+ 'path' => '2.jpg',
146
+ 'hash_before' => 'e79f197d28bebd30ba1bc571c2cc075a',
147
+ 'hash_after' => 'df72ed8dbbdca9c440ff6d3182fb0070',
148
+ 'processed_at' => Varien_Date::now(),
149
+ ),
150
+ array(
151
+ 'path' => '3.jpg',
152
+ 'hash_before' => '59c50fe6455c85fe00b169bde7cb1962',
153
+ 'hash_after' => '8e160a4f7fa67e9126269bedcc81c640',
154
+ 'processed_at' => Varien_Date::now(),
155
+ ),
156
+ ));
157
+
158
+ $model = $this->_instance->getByHash('54eab696c5c868b669076216ede66a9f');
159
+ $this->assertEquals('1.jpg', $model->getPath());
160
+
161
+ $model = $this->_instance->getByHash('df72ed8dbbdca9c440ff6d3182fb0070');
162
+ $this->assertEquals('2.jpg', $model->getPath());
163
+
164
+ $model = $this->_instance->getByHash('foobar');
165
+ $this->assertNull($model);
166
+ }
167
+
168
+ /**
169
+ * Test if the addUsedAsSource works properly.
170
+ */
171
+ public function testAddUsedAsSource()
172
+ {
173
+ for ($i = 1; $i <= 3; $i++) {
174
+ $this->_instance->addUsedAsSource();
175
+ $this->assertEquals($i, $this->_instance->getUsedAsSource());
176
+ }
177
+ }
178
+
179
+ /**
180
+ * Test the getBytesSaved method.
181
+ */
182
+ public function testGetBytesSaved()
183
+ {
184
+ $this->_instance->setBytesBefore(500);
185
+ $this->_instance->setBytesAfter(300);
186
+
187
+ $this->assertEquals(200, $this->_instance->getBytesSaved());
188
+ }
189
+
190
+ /**
191
+ * Test the getPercentageSaved method.
192
+ */
193
+ public function testGetPercentageSaved()
194
+ {
195
+ $this->_instance->setBytesBefore(500);
196
+ $this->_instance->setBytesAfter(400);
197
+
198
+ $this->assertEquals('20 %', $this->_instance->getPercentageSaved());
199
+
200
+ $this->_instance->setBytesBefore(500);
201
+ $this->_instance->setBytesAfter(500);
202
+
203
+ $this->assertEquals('0 %', $this->_instance->getPercentageSaved());
204
+ }
205
+
206
+ /**
207
+ * Test the deleteTest method.
208
+ */
209
+ public function testDeleteAll()
210
+ {
211
+ $models = array();
212
+ for ($i = 0; $i < 10; $i++) {
213
+ $models[] = array(
214
+ 'hash_before' => md5(uniqid()),
215
+ 'hash_after' => md5(uniqid()),
216
+ );
217
+ }
218
+
219
+ $this->createModels('tiny_compressimages/image', $models);
220
+
221
+ $this->assertEquals(10, $this->_instance->getCollection()->getSize());
222
+
223
+ $this->_instance->deleteAll();
224
+
225
+ $this->assertEquals(0, $this->_instance->getCollection()->getSize());
226
+ }
227
+ }
app/code/community/Tiny/CompressImages/Test/Model/Product/ImageTest.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Model_Product_ImageTest extends Tiny_CompressImages_Test_Framework_Tiny_Test_TestCase
3
+ {
4
+ /**
5
+ * @var null|Tiny_CompressImages_Helper_Config
6
+ */
7
+ protected $_helper = null;
8
+
9
+ /**
10
+ * @var Mage_Catalog_Model_Product_Image
11
+ */
12
+ protected $_instance = null;
13
+
14
+ public function setUp()
15
+ {
16
+ $this->_instance = Mage::getModel('catalog/product_image');
17
+ $this->_helper = $this->getMock('Tiny_CompressImages_Helper_Config');
18
+
19
+ $this->setProperty('_configHelper', $this->_helper);
20
+ }
21
+
22
+ public function testGetUrl()
23
+ {
24
+ $this->_helper
25
+ ->expects($this->once())
26
+ ->method('isTestMode')
27
+ ->willReturn('false');
28
+
29
+ $this->setProperty('_newFile', 'test.jpg');
30
+
31
+ $url = Mage::getBaseUrl('web');
32
+ $result = $this->_instance->getUrl();
33
+
34
+ $this->assertEquals('http://magento.local/media/test.jpg', str_replace($url, 'http://magento.local/', $result));
35
+
36
+ Mage::app()->getStore()->setConfig('web/seo/', 1);
37
+
38
+ $this->assertEquals('http://magento.local/media/test.jpg', str_replace($url, 'http://magento.local/', $result));
39
+ }
40
+ }
app/code/community/Tiny/CompressImages/Test/Model/System/Config/Backend/Comment/LoggingModeTest.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_Test_Model_System_Config_Backend_Comment_LoggingModeTest
3
+ extends Tiny_CompressImages_Test_Framework_Tiny_Test_TestCase
4
+ {
5
+ /**
6
+ * @var null|Tiny_CompressImages_Model_System_Config_Backend_Comment_LoggingMode
7
+ */
8
+ protected $_instance = null;
9
+
10
+ /**
11
+ * @var null|string
12
+ */
13
+ protected $_logPath = null;
14
+
15
+ public function setUp()
16
+ {
17
+ $this->_logPath = Mage::helper('tiny_compressimages')->getLogFilePath();
18
+ $this->_instance = new Tiny_CompressImages_Model_System_Config_Backend_Comment_LoggingMode;
19
+
20
+ if (file_exists($this->_logPath)) {
21
+ unlink($this->_logPath);
22
+ }
23
+ }
24
+
25
+ public function testCommentReturnsLink()
26
+ {
27
+ $text = $this->_instance->getCommentText();
28
+ $this->assertNotContains('<a href', $text);
29
+
30
+ touch($this->_logPath);
31
+ $text = $this->_instance->getCommentText();
32
+ $this->assertContains('<a href', $text);
33
+ }
34
+ }
app/code/community/Tiny/CompressImages/Test/bootstrap.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (strpos(__DIR__, '.modman') !== false) {
3
+ require_once(dirname(__DIR__) . '/../../../../../../../app/Mage.php');
4
+ } else {
5
+ require_once(__DIR__ . '/../../../../../../Mage.php');
6
+ }
7
+
8
+ ini_set('display_errors', true);
9
+ error_reporting(-1);
10
+ Tiny_CompressImages_Test_Framework_Tiny_Test_TestCase::resetMagento();
app/code/community/Tiny/CompressImages/controllers/CompressImagesAdminhtml/ConfigController.php ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_CompressImagesAdminhtml_ConfigController extends Mage_Adminhtml_Controller_Action
3
+ {
4
+ /**
5
+ * @return bool
6
+ */
7
+ protected function _isAllowed()
8
+ {
9
+ /** @var Mage_Admin_Model_Session $session */
10
+ $session = Mage::getSingleton('admin/session');
11
+
12
+ return $session->isAllowed('admin/compressimages');
13
+ }
14
+
15
+ /**
16
+ * Download CompressImages log file
17
+ *
18
+ * @return $this
19
+ */
20
+ public function downloadLogsAction()
21
+ {
22
+ /** @var Tiny_CompressImages_Helper_Data $helper */
23
+ $helper = Mage::helper('tiny_compressimages');
24
+ $filePath = $helper->getLogFilePath();
25
+
26
+ if (!$helper->getLogFileExists()) {
27
+ return $this;
28
+ }
29
+
30
+ $content = array(
31
+ 'type' => 'filename',
32
+ 'value' => $filePath,
33
+ 'rm' => false,
34
+ );
35
+
36
+ $this->postDispatch();
37
+ $this->_prepareDownloadResponse($helper->getLogFilename(), $content);
38
+
39
+ return $this;
40
+ }
41
+
42
+ /**
43
+ * @return bool
44
+ */
45
+ public function clearCacheAction()
46
+ {
47
+ try {
48
+ Mage::getModel('catalog/product_image')->clearCache();
49
+ Mage::dispatchEvent('clean_catalog_images_cache_after');
50
+ $this->_getSession()->addSuccess(
51
+ Mage::helper('adminhtml')->__('The image cache was cleaned.')
52
+ );
53
+ }
54
+ catch (Mage_Core_Exception $e) {
55
+ $this->_getSession()->addError($e->getMessage());
56
+ }
57
+ catch (Exception $e) {
58
+ $this->_getSession()->addException(
59
+ $e,
60
+ Mage::helper('adminhtml')->__('An error occurred while clearing the image cache.')
61
+ );
62
+ }
63
+ $this->_redirect('adminhtml/system_config/edit/section/tiny_compressimages');
64
+ }
65
+ }
app/code/community/Tiny/CompressImages/controllers/CompressImagesAdminhtml/StatusController.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Tiny_CompressImages_CompressImagesAdminhtml_StatusController extends Mage_Adminhtml_Controller_Action
3
+ {
4
+ /**
5
+ * @var Tiny_Compressimages_Helper_Tinify
6
+ */
7
+ protected $_helper = null;
8
+
9
+ /**
10
+ * @return bool
11
+ */
12
+ protected function _isAllowed()
13
+ {
14
+ /** @var Mage_Admin_Model_Session $session */
15
+ $session = Mage::getSingleton('admin/session');
16
+
17
+ return $session->isAllowed('admin/compressimages');
18
+ }
19
+
20
+ /**
21
+ * Get the Tinify helper.
22
+ *
23
+ * @return Tiny_CompressImages_Helper_Tinify
24
+ */
25
+ public function getHelper()
26
+ {
27
+ if ($this->_helper === null) {
28
+ $this->_helper = Mage::helper('tiny_compressimages/tinify');
29
+ }
30
+
31
+ return $this->_helper;
32
+ }
33
+
34
+ public function getApiStatusAction()
35
+ {
36
+ if (!$this->_validateFormKey()) {
37
+ return;
38
+ }
39
+
40
+ $result = $this->getHelper()->getApiStatus();
41
+
42
+ /** @var Mage_Core_Helper_Data $coreHelper */
43
+ $coreHelper = Mage::helper('core');
44
+ $this->getResponse()->setBody($coreHelper->jsonEncode($result));
45
+ }
46
+ }
app/code/community/Tiny/CompressImages/etc/adminhtml.xml CHANGED
@@ -1,21 +1,26 @@
 
1
  <config>
2
- <acl>
3
- <resources>
4
- <admin>
5
- <children>
6
- <system>
7
- <children>
8
- <config>
9
  <children>
10
- <compress_images>
11
- <title>Image Compression Section</title>
12
- </compress_images>
 
 
 
 
 
 
 
 
 
13
  </children>
14
- </config>
15
- </children>
16
- </system>
17
- </children>
18
- </admin>
19
- </resources>
20
- </acl>
21
  </config>
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
  <config>
3
+ <acl>
4
+ <resources>
5
+ <all>
6
+ <title>Allow everything</title>
7
+ </all>
8
+ <admin>
 
9
  <children>
10
+ <system>
11
+ <children>
12
+ <config>
13
+ <children>
14
+ <tiny_compressimages translate="title">
15
+ <title>Tiny CompressImages</title>
16
+ <sort_order>500</sort_order>
17
+ </tiny_compressimages>
18
+ </children>
19
+ </config>
20
+ </children>
21
+ </system>
22
  </children>
23
+ </admin>
24
+ </resources>
25
+ </acl>
 
 
 
 
26
  </config>
app/code/community/Tiny/CompressImages/etc/config.xml CHANGED
@@ -1,30 +1,105 @@
 
1
  <config>
2
- <modules>
3
- <Tiny_CompressImages>
4
- <version>1.0.0</version>
5
- </Tiny_CompressImages>
6
- </modules>
7
- <global>
8
- <models>
9
- <tiny_compressimages>
10
- <class>Tiny_CompressImages_Model</class>
11
- </tiny_compressimages>
12
- <catalog>
13
- <rewrite>
14
- <product_image>Tiny_CompressImages_Model_Product_Image</product_image>
15
- </rewrite>
16
- </catalog>
17
- </models>
18
- <events>
19
- <catalog_product_image_save_after>
20
- <observers>
21
- <tiny_compressimages>
22
- <class>tiny_compressimages/observer</class>
23
- <method>compress</method>
24
- <type>singleton</type>
25
- </tiny_compressimages>
26
- </observers>
27
- </catalog_product_image_save_after>
28
- </events>
29
- </global>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  </config>
1
+ <?xml version="1.0"?>
2
  <config>
3
+ <modules>
4
+ <Tiny_CompressImages>
5
+ <version>2.0.0</version>
6
+ <stability>stable</stability>
7
+ </Tiny_CompressImages>
8
+ </modules>
9
+ <global>
10
+ <blocks>
11
+ <tiny_compressimages>
12
+ <class>Tiny_CompressImages_Block</class>
13
+ </tiny_compressimages>
14
+ </blocks>
15
+ <helpers>
16
+ <tiny_compressimages>
17
+ <class>Tiny_CompressImages_Helper</class>
18
+ </tiny_compressimages>
19
+ </helpers>
20
+ <models>
21
+ <tiny_compressimages>
22
+ <class>Tiny_CompressImages_Model</class>
23
+ <resourceModel>tiny_compressimages_resource</resourceModel>
24
+ </tiny_compressimages>
25
+ <tiny_compressimages_resource>
26
+ <class>Tiny_CompressImages_Model_Resource</class>
27
+ <entities>
28
+ <image>
29
+ <table>tiny_compressimages_image</table>
30
+ </image>
31
+ <totals>
32
+ <table>tiny_compressimages_totals</table>
33
+ </totals>
34
+ </entities>
35
+ </tiny_compressimages_resource>
36
+ <catalog>
37
+ <rewrite>
38
+ <product_image>Tiny_CompressImages_Model_Product_Image</product_image>
39
+ </rewrite>
40
+ </catalog>
41
+ </models>
42
+ <resources>
43
+ <tiny_compressimages_setup>
44
+ <setup>
45
+ <class>Tiny_CompressImages_Model_Resource_Setup</class>
46
+ <module>Tiny_CompressImages</module>
47
+ </setup>
48
+ </tiny_compressimages_setup>
49
+ </resources>
50
+ <events>
51
+ <catalog_product_image_save_after>
52
+ <observers>
53
+ <tiny_compressimages_compress_product_image>
54
+ <type>singleton</type>
55
+ <class>Tiny_CompressImages_Model_Observer</class>
56
+ <method>catalogProductImageSaveAfter</method>
57
+ </tiny_compressimages_compress_product_image>
58
+ </observers>
59
+ </catalog_product_image_save_after>
60
+ </events>
61
+ </global>
62
+ <admin>
63
+ <routers>
64
+ <adminhtml>
65
+ <args>
66
+ <modules>
67
+ <tiny_compressimages after="Mage_Adminhtml">Tiny_CompressImages</tiny_compressimages>
68
+ </modules>
69
+ </args>
70
+ </adminhtml>
71
+ </routers>
72
+ </admin>
73
+ <adminhtml>
74
+ <layout>
75
+ <updates>
76
+ <tiny_compressimages>
77
+ <file>Tiny/CompressImages.xml</file>
78
+ </tiny_compressimages>
79
+ </updates>
80
+ </layout>
81
+ <translate>
82
+ <modules>
83
+ <Tiny_CompressImages>
84
+ <files>
85
+ <default>Tiny_CompressImages.csv</default>
86
+ </files>
87
+ </Tiny_CompressImages>
88
+ </modules>
89
+ </translate>
90
+ </adminhtml>
91
+ <default>
92
+ <tiny_compressimages>
93
+ <image_types>
94
+ <base_images>1</base_images>
95
+ <small_images>1</small_images>
96
+ <thumbnails>1</thumbnails>
97
+ <swatches>1</swatches>
98
+ </image_types>
99
+ <advanced>
100
+ <logging_mode>all</logging_mode>
101
+ <enabled>2</enabled>
102
+ </advanced>
103
+ </tiny_compressimages>
104
+ </default>
105
  </config>
app/code/community/Tiny/CompressImages/etc/system.xml CHANGED
@@ -1,89 +1,193 @@
 
1
  <config>
2
- <sections>
3
- <compress_images translate="label">
4
- <class>separator-top</class>
5
- <label>JPG &amp; PNG compression</label>
6
- <tab>catalog</tab>
7
- <frontend_type>text</frontend_type>
8
- <sort_order>41</sort_order>
9
- <show_in_default>1</show_in_default>
10
- <show_in_website>1</show_in_website>
11
- <show_in_store>1</show_in_store>
12
- <groups>
13
- <settings translate="label">
14
- <label>API Key</label>
15
- <frontend_type>text</frontend_type>
16
- <sort_order>10</sort_order>
17
- <show_in_default>1</show_in_default>
18
- <show_in_website>1</show_in_website>
19
- <show_in_store>1</show_in_store>
20
- <expanded>1</expanded>
21
- <fields>
22
- <api_key translate="label comment">
23
- <label>TinyPNG API Key</label>
24
- <frontend_type>text</frontend_type>
25
- <comment>Visit https://tinypng.com/developer to obtain a free key</comment>
26
- <sort_order>10</sort_order>
27
- <show_in_default>1</show_in_default>
28
- <show_in_website>1</show_in_website>
29
- <show_in_store>1</show_in_store>
30
- </api_key>
31
- </fields>
32
- </settings>
33
-
34
- <image_sizes translate="label">
35
- <label>Compressed Image Sizes</label>
36
- <frontend_type>text</frontend_type>
37
- <comment>Choose which image types generated by Magento and stored in the image cache are compressed by TinyPNG. Each selected image size counts as one compression in your compression total.</comment>
38
- <sort_order>20</sort_order>
39
- <show_in_default>1</show_in_default>
40
- <show_in_website>1</show_in_website>
41
- <show_in_store>1</show_in_store>
42
- <expanded>1</expanded>
43
- <fields>
44
- <compress_image translate="label">
45
- <label>Compress Base Images</label>
46
- <frontend_type>select</frontend_type>
47
- <tooltip>Compress the general product images</tooltip>
48
- <source_model>adminhtml/system_config_source_enabledisable</source_model>
49
- <sort_order>30</sort_order>
50
- <show_in_default>1</show_in_default>
51
- <show_in_website>1</show_in_website>
52
- <show_in_store>1</show_in_store>
53
- </compress_image>
54
- <compress_small_image translate="label">
55
- <label>Compress Small Images</label>
56
- <frontend_type>select</frontend_type>
57
- <tooltip>Compress the small product images</tooltip>
58
- <source_model>adminhtml/system_config_source_enabledisable</source_model>
59
- <sort_order>40</sort_order>
60
- <show_in_default>1</show_in_default>
61
- <show_in_website>1</show_in_website>
62
- <show_in_store>1</show_in_store>
63
- </compress_small_image>
64
- <compress_thumbnail translate="label">
65
- <label>Compress Thumbnails</label>
66
- <frontend_type>select</frontend_type>
67
- <tooltip>Compress the product thumbnails</tooltip>
68
- <source_model>adminhtml/system_config_source_enabledisable</source_model>
69
- <sort_order>50</sort_order>
70
- <show_in_default>1</show_in_default>
71
- <show_in_website>1</show_in_website>
72
- <show_in_store>1</show_in_store>
73
- </compress_thumbnail>
74
- <compress_other_images translate="label">
75
- <label>Compress Other Sizes</label>
76
- <frontend_type>select</frontend_type>
77
- <tooltip>Compress the unresized product images</tooltip>
78
- <source_model>adminhtml/system_config_source_enabledisable</source_model>
79
- <sort_order>60</sort_order>
80
- <show_in_default>1</show_in_default>
81
- <show_in_website>1</show_in_website>
82
- <show_in_store>1</show_in_store>
83
- </compress_other_images>
84
- </fields>
85
- </image_sizes>
86
- </groups>
87
- </compress_images>
88
- </sections>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  </config>
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
  <config>
3
+ <sections>
4
+ <tiny_compressimages translate="label" module="tiny_compressimages">
5
+ <label>Image Optimization</label>
6
+ <tab>general</tab>
7
+ <frontend_model>tiny_compressimages/adminhtml_system_config_form</frontend_model>
8
+ <class>tiny-compressimages-section</class>
9
+ <frontend_type>text</frontend_type>
10
+ <sort_order>1200</sort_order>
11
+ <show_in_default>1</show_in_default>
12
+ <show_in_website>1</show_in_website>
13
+ <show_in_store>1</show_in_store>
14
+ <groups>
15
+ <support translate="label" module="tiny_compressimages">
16
+ <label>Version &amp; Support</label>
17
+ <sort_order>10</sort_order> <!-- This should always be the first tab -->
18
+ <show_in_default>1</show_in_default>
19
+ <show_in_website>1</show_in_website>
20
+ <show_in_store>1</show_in_store>
21
+ <fields>
22
+ <support>
23
+ <sort_order>0</sort_order>
24
+ <frontend_model>tiny_compressimages/adminhtml_system_config_form_field_supportTab</frontend_model>
25
+ <show_in_default>1</show_in_default>
26
+ <show_in_website>1</show_in_website>
27
+ <show_in_store>1</show_in_store>
28
+ </support>
29
+ </fields>
30
+ </support>
31
+ <settings translate="label">
32
+ <label>Connection Settings</label>
33
+ <sort_order>20</sort_order>
34
+ <show_in_default>1</show_in_default>
35
+ <show_in_website>1</show_in_website>
36
+ <show_in_store>1</show_in_store>
37
+ <class>active</class>
38
+ <fields>
39
+ <api_key tranaslate="label comment">
40
+ <label>API Key</label>
41
+ <frontend_type>text</frontend_type>
42
+ <backend_model>tiny_compressimages/system_config_backend_apiKey</backend_model>
43
+ <comment><![CDATA[Visit <a href="https://tinypng.com/developers/subscription" target="_BLANK">TinyPNG Developer section</a> to get an API key.]]></comment>
44
+ <sort_order>10</sort_order>
45
+ <show_in_default>1</show_in_default>
46
+ <show_in_website>1</show_in_website>
47
+ <show_in_store>1</show_in_store>
48
+ </api_key>
49
+ <api>
50
+ <label>TinyPNG API Status</label>
51
+ <sort_order>20</sort_order>
52
+ <frontend_type>compressimages_api</frontend_type>
53
+ <show_in_default>1</show_in_default>
54
+ <show_in_website>1</show_in_website>
55
+ <show_in_store>1</show_in_store>
56
+ </api>
57
+ <usage translate="label comment">
58
+ <label> </label>
59
+ <sort_order>30</sort_order>
60
+ <frontend_type>compressimages_status</frontend_type>
61
+ <show_in_default>1</show_in_default>
62
+ <show_in_website>0</show_in_website>
63
+ <show_in_store>0</show_in_store>
64
+ </usage>
65
+ </fields>
66
+ </settings>
67
+ <image_types translate="label">
68
+ <label>Image Types to Optimize</label>
69
+ <comment>Choose which generated image types should be optimized with TinyPNG or TinyJPG. Each selected image size counts as one compression in your compression total.</comment>
70
+ <sort_order>25</sort_order>
71
+ <show_in_default>1</show_in_default>
72
+ <show_in_website>1</show_in_website>
73
+ <show_in_store>1</show_in_store>
74
+ <class>active</class>
75
+ <fields>
76
+ <base_images translate="label comment tooltip">
77
+ <label>Base Images</label>
78
+ <frontend_type>select</frontend_type>
79
+ <comment>Large images on product pages.</comment>
80
+ <source_model>adminhtml/system_config_source_yesno</source_model>
81
+ <sort_order>10</sort_order>
82
+ <show_in_default>1</show_in_default>
83
+ <show_in_website>1</show_in_website>
84
+ <show_in_store>1</show_in_store>
85
+ </base_images>
86
+ <small_images translate="label comment tooltip">
87
+ <label>Small Images</label>
88
+ <comment>Smaller images on category pages, in list of recently viewed product, new product lists, upsells, wish lists, etc.</comment>
89
+ <frontend_type>select</frontend_type>
90
+ <source_model>adminhtml/system_config_source_yesno</source_model>
91
+ <sort_order>20</sort_order>
92
+ <show_in_default>1</show_in_default>
93
+ <show_in_website>1</show_in_website>
94
+ <show_in_store>1</show_in_store>
95
+ </small_images>
96
+ <thumbnails translate="label comment tooltip">
97
+ <label>Thumbnails</label>
98
+ <comment>Thumbnail-sized images in product image galleries, sidebars, widgets, RSS feeds, etc.</comment>
99
+ <frontend_type>select</frontend_type>
100
+ <source_model>adminhtml/system_config_source_yesno</source_model>
101
+ <sort_order>30</sort_order>
102
+ <show_in_default>1</show_in_default>
103
+ <show_in_website>1</show_in_website>
104
+ <show_in_store>1</show_in_store>
105
+ </thumbnails>
106
+ <swatches>
107
+ <label>Swatches</label>
108
+ <comment>Small images used to select product attributes.</comment>
109
+ <frontend_type>select</frontend_type>
110
+ <source_model>adminhtml/system_config_source_yesno</source_model>
111
+ <sort_order>40</sort_order>
112
+ <show_in_default>1</show_in_default>
113
+ <show_in_website>1</show_in_website>
114
+ <show_in_store>1</show_in_store>
115
+ </swatches>
116
+ </fields>
117
+ </image_types>
118
+ <status translate="label">
119
+ <label>Latest Optimizations</label>
120
+ <sort_order>30</sort_order>
121
+ <show_in_default>1</show_in_default>
122
+ <show_in_website>1</show_in_website>
123
+ <show_in_store>1</show_in_store>
124
+ <class>active</class>
125
+ <fields>
126
+ <log_status>
127
+ <sort_order>40</sort_order>
128
+ <frontend_model>tiny_compressimages/adminhtml_system_config_form_field_logStatus</frontend_model>
129
+ <show_in_default>1</show_in_default>
130
+ <show_in_website>1</show_in_website>
131
+ <show_in_store>1</show_in_store>
132
+ </log_status>
133
+ </fields>
134
+ </status>
135
+ <advanced translate="label">
136
+ <label>Advanced</label>
137
+ <sort_order>40</sort_order>
138
+ <show_in_default>1</show_in_default>
139
+ <show_in_website>1</show_in_website>
140
+ <show_in_store>1</show_in_store>
141
+ <fields>
142
+ <enabled translate="label comment tooltip">
143
+ <label>Mode</label>
144
+ <frontend_type>select</frontend_type>
145
+ <sort_order>10</sort_order>
146
+ <source_model>tiny_compressimages/system_config_source_testlive</source_model>
147
+ <comment><![CDATA[
148
+ Live: Extension works normally (default)
149
+ <br>
150
+ <br>
151
+ Test: New product images will be optimized and saved so you can
152
+ test if everything works as expected. However, the optimized
153
+ images will not be shown in your store. After testing and switching
154
+ to live mode, your store will show the optimized images.
155
+ <br>
156
+ <br>
157
+ Disabled: The extension is switched off and no new product
158
+ images will be optimized.
159
+ <br>
160
+ <br>
161
+ ]]>
162
+ </comment>
163
+ <tooltip>If test mode is activated, the extension will do real compressions. The result won't be saved.</tooltip>
164
+ <show_in_default>1</show_in_default>
165
+ <show_in_website>1</show_in_website>
166
+ <show_in_store>1</show_in_store>
167
+ </enabled>
168
+ <logging_mode translate="label comment">
169
+ <label>Messages that should be logged</label>
170
+ <sort_order>20</sort_order>
171
+ <source_model>tiny_compressimages/system_config_source_log</source_model>
172
+ <frontend_type>select</frontend_type>
173
+ <comment>
174
+ <model>tiny_compressimages/system_config_backend_comment_loggingMode</model>
175
+ </comment>
176
+ <show_in_default>1</show_in_default>
177
+ <show_in_website>1</show_in_website>
178
+ <show_in_store>1</show_in_store>
179
+ </logging_mode>
180
+ <log_file translate="label comment">
181
+ <label>Download the logfile</label>
182
+ <sort_order>30</sort_order>
183
+ <frontend_type>compressimages_log_button</frontend_type>
184
+ <show_in_default>1</show_in_default>
185
+ <show_in_website>1</show_in_website>
186
+ <show_in_store>1</show_in_store>
187
+ </log_file>
188
+ </fields>
189
+ </advanced>
190
+ </groups>
191
+ </tiny_compressimages>
192
+ </sections>
193
  </config>
app/code/community/Tiny/CompressImages/sql/tiny_compressimages_setup/install-1.0.0.php ADDED
@@ -0,0 +1,250 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @var Tiny_CompressImages_Model_Resource_Setup $installer
4
+ */
5
+ $installer = $this;
6
+
7
+ $installer->startSetup();
8
+
9
+ /** @var Varien_Db_Adapter_Interface $connection */
10
+ $connection = $installer->getConnection();
11
+
12
+ $tableName = $installer->getTable('tiny_compressimages/image');
13
+ if (!$connection->isTableExists($tableName)) {
14
+ $table = $connection
15
+ ->newTable($tableName)
16
+ ->addColumn(
17
+ 'image_id',
18
+ Varien_Db_Ddl_Table::TYPE_INTEGER,
19
+ null,
20
+ array(
21
+ 'identity' => true,
22
+ 'unsigned' => true,
23
+ 'nullable' => false,
24
+ 'primary' => true,
25
+ ),
26
+ 'ID'
27
+ )
28
+ ->addColumn(
29
+ 'path',
30
+ Varien_Db_Ddl_Table::TYPE_VARCHAR,
31
+ 255,
32
+ array(
33
+ 'nullable' => false,
34
+ ),
35
+ 'The path of this image'
36
+ )
37
+ ->addColumn(
38
+ 'path_optimized',
39
+ Varien_Db_Ddl_Table::TYPE_VARCHAR,
40
+ 255,
41
+ array(
42
+ 'nullable' => false,
43
+ ),
44
+ 'The optimized path of this image'
45
+ )
46
+ ->addColumn(
47
+ 'image_type',
48
+ Varien_Db_Ddl_Table::TYPE_VARCHAR,
49
+ 255,
50
+ array(
51
+ 'nullable' => false,
52
+ ),
53
+ 'The type of this image'
54
+ )
55
+ ->addColumn(
56
+ 'hash_before',
57
+ Varien_Db_Ddl_Table::TYPE_VARCHAR,
58
+ 255,
59
+ array(
60
+ 'nullable' => false,
61
+ ),
62
+ 'The hash of the image before processing'
63
+ )
64
+ ->addColumn(
65
+ 'hash_after',
66
+ Varien_Db_Ddl_Table::TYPE_VARCHAR,
67
+ 255,
68
+ array(
69
+ 'nullable' => false,
70
+ ),
71
+ 'The hash of the image after processing'
72
+ )
73
+ ->addColumn(
74
+ 'bytes_before',
75
+ Varien_Db_Ddl_Table::TYPE_INTEGER,
76
+ null,
77
+ array(
78
+ 'nullable' => false,
79
+ ),
80
+ 'The number of bytes before processing'
81
+ )
82
+ ->addColumn(
83
+ 'bytes_after',
84
+ Varien_Db_Ddl_Table::TYPE_INTEGER,
85
+ null,
86
+ array(
87
+ 'nullable' => false,
88
+ ),
89
+ 'The number of bytes after processing'
90
+ )
91
+ ->addColumn(
92
+ 'used_as_source',
93
+ Varien_Db_Ddl_Table::TYPE_INTEGER,
94
+ null,
95
+ array(
96
+ 'nullable' => false,
97
+ ),
98
+ 'How many times is this file used as source'
99
+ )
100
+ ->addColumn(
101
+ 'is_test',
102
+ Varien_Db_Ddl_Table::TYPE_INTEGER,
103
+ null,
104
+ array(
105
+ 'nullable' => false,
106
+ ),
107
+ 'Is this image processed in test mode?'
108
+ )
109
+ ->addColumn(
110
+ 'parent_id',
111
+ Varien_Db_Ddl_Table::TYPE_INTEGER,
112
+ null,
113
+ array(),
114
+ 'Has parent image and therefore its copied'
115
+ )
116
+ ->addColumn(
117
+ 'compressed_before',
118
+ Varien_Db_Ddl_Table::TYPE_INTEGER,
119
+ null,
120
+ array(),
121
+ 'Is copressed before and therefore not compressed again'
122
+ )
123
+ ->addColumn(
124
+ 'processed_at',
125
+ Varien_Db_Ddl_Table::TYPE_DATETIME,
126
+ null,
127
+ array(
128
+ 'nullable' => false,
129
+ ),
130
+ 'Processed At'
131
+ );
132
+
133
+ $connection->createTable($table);
134
+ }
135
+
136
+ $tableName = $installer->getTable('tiny_compressimages/totals');
137
+ if (!$connection->isTableExists($tableName)) {
138
+ $table = $connection
139
+ ->newTable($tableName)
140
+ ->addColumn(
141
+ 'entity_id',
142
+ Varien_Db_Ddl_Table::TYPE_INTEGER,
143
+ null,
144
+ array(
145
+ 'identity' => true,
146
+ 'unsigned' => true,
147
+ 'nullable' => false,
148
+ 'primary' => true,
149
+ ),
150
+ 'ID'
151
+ )
152
+ ->addColumn(
153
+ 'total_bytes_before',
154
+ Varien_Db_Ddl_Table::TYPE_INTEGER,
155
+ null,
156
+ array(
157
+ 'nullable' => false,
158
+ ),
159
+ 'The number of bytes before processing'
160
+ )
161
+ ->addColumn(
162
+ 'total_bytes_after',
163
+ Varien_Db_Ddl_Table::TYPE_INTEGER,
164
+ null,
165
+ array(
166
+ 'nullable' => false,
167
+ ),
168
+ 'The number of bytes after processing'
169
+ )
170
+ ->addColumn(
171
+ 'total_compressions',
172
+ Varien_Db_Ddl_Table::TYPE_INTEGER,
173
+ null,
174
+ array(
175
+ 'nullable' => false,
176
+ ),
177
+ 'The number of compressions'
178
+ )
179
+ ->addColumn(
180
+ 'date_from',
181
+ Varien_Db_Ddl_Table::TYPE_DATETIME,
182
+ null,
183
+ array(
184
+ 'nullable' => false,
185
+ ),
186
+ 'First day of the month'
187
+ )
188
+ ->addColumn(
189
+ 'date_to',
190
+ Varien_Db_Ddl_Table::TYPE_DATETIME,
191
+ null,
192
+ array(
193
+ 'nullable' => false,
194
+ ),
195
+ 'Last day of the month'
196
+ )
197
+ ->addColumn(
198
+ 'updated_at',
199
+ Varien_Db_Ddl_Table::TYPE_DATETIME,
200
+ null,
201
+ array(
202
+ 'nullable' => false,
203
+ ),
204
+ 'Processed At'
205
+ );
206
+
207
+ $connection->createTable($table);
208
+ }
209
+
210
+ /**
211
+ * Move the api_key setting to it's new location
212
+ */
213
+ $installer->moveConfigSettingInDb('compress_images/settings/api_key', 'tiny_compressimages/settings/api_key');
214
+
215
+ /**
216
+ * In the old module the different image types are 4 different options, in the new module this is only 1 option
217
+ */
218
+ $images = array(
219
+ 'compress_image' => 'image',
220
+ 'compress_small_image' => 'small_image',
221
+ 'compress_thumbnail' => 'thumbnail',
222
+ 'compress_other_images' => 'media',
223
+ );
224
+
225
+ $allowedTypes = array();
226
+ foreach ($images as $from => $to) {
227
+ $value = Mage::getConfig('compress_images/image_sizes/' . $from);
228
+
229
+ if ($value) {
230
+ $allowedTypes[] = $to;
231
+ }
232
+ }
233
+
234
+ if (count($allowedTypes)) {
235
+ try {
236
+ $connection->insert(
237
+ $installer->getTable('core/config_data'),
238
+ array(
239
+ 'scope' => 'default',
240
+ 'scope_id' => '0',
241
+ 'value' => implode(',', $allowedTypes),
242
+ 'path' => 'tiny_compressimages/settings/product_compression',
243
+ )
244
+ );
245
+ } catch (Exception $e) {
246
+ Mage::helper('tiny_compressimages')->log($e);
247
+ }
248
+ }
249
+
250
+ $installer->endSetup();
app/design/adminhtml/default/default/layout/Tiny/CompressImages.xml ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <layout>
3
+ <default>
4
+ <reference name="notifications">
5
+ <block type="tiny_compressimages/adminhtml_apiNotification" name="tiny_compressimages_api_key_notification" template="Tiny/CompressImages/Api/keyNotification.phtml"/>
6
+ </reference>
7
+ </default>
8
+ <adminhtml_system_config_edit>
9
+ <reference name="head">
10
+ <action method="addItem">
11
+ <type>skin_css</type>
12
+ <name>css/Tiny/CompressImages/config.css</name>
13
+ </action>
14
+ </reference>
15
+ </adminhtml_system_config_edit>
16
+ </layout>
app/design/adminhtml/default/default/template/Tiny/CompressImages/Api/keyNotification.phtml ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php $helper = Mage::helper('tiny_compressimages'); ?>
2
+ <?php if (!$this->isApiKeySet()) : ?>
3
+ <div class="notification-global">
4
+ <?php echo $helper->__('Add your TinyPNG API key to start compressing images.'); ?>
5
+ <a href="<?php echo $this->getBackendUrl(); ?>">
6
+ <?php echo $helper->__('Go to Image Optimization Settings and add your key.'); ?>
7
+ </a>
8
+ </div>
9
+ <?php endif; ?>
app/design/adminhtml/default/default/template/Tiny/CompressImages/system/config/form/field/log_file.phtml ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Tiny_CompressImages_Block_Adminhtml_System_Config_Form_Field_LogFile $this */
3
+ ?>
4
+ <tr id="row_tiny_compressimages_advanced_log_file">
5
+ <td class="label">
6
+ <label for="tiny_compressimages_advanced_log_file"> Log file</label>
7
+ </td>
8
+ <td class="value">
9
+ <?php if ($this->logFileExists()): ?>
10
+ <button onclick="setLocation('<?php echo $this->getDownloadUrl(); ?>')" type="button" class="scalable">
11
+ <span><span><span><?php echo $this->__('Download log file'); ?></span></span></span>
12
+ </button>
13
+ <?php else: ?>
14
+ <button type="button" class="scalable disabled">
15
+ <span><span><span><?php echo $this->__('Download log file'); ?></span></span></span>
16
+ </button>
17
+ <?php endif; ?>
18
+ </td>
19
+ </tr>
20
+
21
+
app/design/adminhtml/default/default/template/Tiny/CompressImages/system/config/form/field/log_status.phtml ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @var Tiny_CompressImages_Block_Adminhtml_System_Config_Form_Field_LogStatus $this
4
+ */
5
+
6
+ /** @var Tiny_CompressImages_Helper_Tinify $_tinify */
7
+ $_tinify = Mage::helper('tiny_compressimages/tinify');
8
+
9
+ /** @var Tiny_CompressImages_Helper_Data $_helper */
10
+ $_helper = Mage::helper('tiny_compressimages');
11
+ $_data = Mage::getModel('tiny_compressimages/totals')->getTotalCompressionInformation();
12
+
13
+ /** @var Tiny_CompressImages_Model_Image $image */
14
+ $_images = $_tinify->getCompressionStatus();
15
+
16
+ $_imagesLimit = 10;
17
+ ?>
18
+
19
+ <tr>
20
+ <td colspan="4">
21
+ <table cellspacing="5" class="form-list">
22
+ <tr>
23
+ <td>
24
+ <h5><?php echo $this->__('Images are optimized each time Magento generates new product images in the image cache folder')?></h5>
25
+ <?php if ($_data['totalCompressions'] < 1) :?>
26
+ <p><?php
27
+ echo $this->__(
28
+ 'If you have never used the extension before you should flush the product images cache. Magento will
29
+ generate new product images that will be automatically optimized. You will only need to flush the cache
30
+ once, any new products will be automatically optimized in future.'
31
+ );
32
+ ?></p>
33
+
34
+ <button onclick="setLocation('<?php echo $this->getCleanImagesUrl()?>')" type="button" class="scalable">
35
+ <span><span><span><?php echo Mage::helper('adminhtml')->__('Flush Catalog Images Cache') ?></span></span></span>
36
+ </button>
37
+ <?php endif; ?>
38
+ </td>
39
+ </tr>
40
+ </table>
41
+ </td>
42
+ </tr>
43
+
44
+
45
+ <?php if ($_data['totalCompressions'] > 0) :?>
46
+ <tr>
47
+ <td class="log-details-td">
48
+ <?php echo Mage::helper('tiny_compressimages')->__(
49
+ 'Total of %s optimized product images. Original size : %s. New size : %s. Average savings %s%%.',
50
+ $_data['totalCompressions'],
51
+ $_data['bytesBefore'],
52
+ $_data['bytesAfter'],
53
+ $_data['percentageSaved']
54
+ ); ?>
55
+ </td>
56
+ </tr>
57
+ <?php endif; ?>
58
+
59
+ <?php $i = 0; ?>
60
+ <?php if ($_images->count()): ?>
61
+ <tr>
62
+ <td colspan="4">
63
+ <table id="tiny_compressimages_compression" cellspacing="5">
64
+ <?php /** Tiny_CompressImages_Model_Image $image */?>
65
+ <?php foreach ($_images as $image): ?>
66
+ <?php $i++; ?>
67
+ <?php if ($i > $_imagesLimit): ?>
68
+ <tr class="tiny_compressimages_log log_hidden">
69
+ <?php else : ?>
70
+ <tr class="tiny_compressimages_log">
71
+ <?php endif;?>
72
+ <td class="image_path">
73
+ <a href="<?php echo $image->getImageUrl(); ?>" target="_BLANK">
74
+ <img src="<?php echo $image->getImageUrl(); ?>">
75
+ </a>
76
+ </td>
77
+ <td class="info_box"><?php echo $image->getImageType(); ?></td>
78
+ <td class="info_box tiny_compressimages_width">
79
+ <?php echo $image->getPercentageSaved(); ?> saved (<?php echo $_helper->fileSize($image->getBytesBefore()). ' / '. $_helper->fileSize($image->getBytesAfter()); ?>)
80
+ </td>
81
+ <td class="info_box tiny_compressimages_width">
82
+ <?php if ($image->getCompressedBefore()) : ?>
83
+ <?php echo $this->__('Optimized previously'); ?>
84
+ <?php elseif ($image->getParentId()) :?>
85
+ <?php echo $this->__('Duplicate image'); ?>
86
+ <?php else: ?>
87
+ <?php echo $this->__('Optimized'); ?>
88
+ <?php endif; ?>
89
+ </td>
90
+ <td class="info_box tiny_compressimages_width"><?php echo $image->getTimeAgo(); ?></td>
91
+ </tr>
92
+ <?php endforeach; ?>
93
+
94
+ <?php if ($_images->getSize() > $_images->count()): ?>
95
+ <tr class="tiny_compressimages_log log_hidden">
96
+ <td colspan="5"><?php echo $_helper->__('...and %d more images', $_images->getSize() - $_images->count()); ?></td>
97
+ </tr>
98
+ <?php endif; ?>
99
+
100
+ <?php if ($i > $_imagesLimit): ?>
101
+ <tr>
102
+ <td colspan="5"><a id="show_all" href="#"><?php echo $this->__('Show more'); ?></a></td>
103
+ </tr>
104
+ <tr>
105
+ <td colspan="5"><a id="show_less" href="#"><?php echo $this->__('Show less'); ?></a></td>
106
+ </tr>
107
+ <?php endif; ?>
108
+ </table>
109
+ </td>
110
+ </tr>
111
+ <?php else: ?>
112
+ <tr>
113
+ <td class="tiny_compressimages-no-images">
114
+ <?php echo $_helper->__('There are no saved compressions available yet.'); ?><br>
115
+ </td>
116
+ </tr>
117
+ <?php endif; ?>
118
+
119
+ <tr>
120
+ <td class="log-details-td">
121
+ <?php $url = "<a href=".$this->getCleanImagesUrl()."/>".$this->__('flush the Magento image cache')."</a>"; ?>
122
+ <?php echo $_helper->__('If an image does not appear you may need to %s and visit the product page
123
+ again so images will be regenerated and optimized.', $url
124
+ ); ?>
125
+ </td>
126
+ </tr>
127
+
128
+
129
+ <script type="application/javascript">
130
+ document.observe('dom:loaded', function() {
131
+
132
+ var show_less = $('show_less');
133
+ var show_all = $('show_all');
134
+
135
+ $$('.log_hidden').each(function(element) {
136
+ element.hide();
137
+ });
138
+
139
+ if (show_all !== null) {
140
+ show_all.observe('click', function (e) {
141
+ Event.stop(e);
142
+
143
+ $$('.log_hidden').each(function (element) {
144
+ element.show();
145
+ });
146
+ show_all.hide();
147
+ show_less.show();
148
+ });
149
+ }
150
+
151
+ if (show_less !== null) {
152
+ show_less.hide();
153
+ show_less.observe('click', function (e) {
154
+ Event.stop(e);
155
+
156
+ $$('.log_hidden').each(function (element) {
157
+ element.hide();
158
+ });
159
+ show_less.hide();
160
+ show_all.show();
161
+ });
162
+ }
163
+ });
164
+ </script>
app/design/adminhtml/default/default/template/Tiny/CompressImages/system/config/form/field/support_tab.phtml ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Tiny_CompressImages_Block_Adminhtml_System_Config_Form_Field_SupportTab $this */
3
+ ?>
4
+
5
+ <?php $_tigHomepage = 'https://tig.nl/image-optimization-magento-extension-community-edition'; ?>
6
+ <?php $_kbUrl = 'http://servicedesk.tig.nl/hc/nl/categories/202720888-TinyPNG'; ?>
7
+ <?php $_kbTicketUrl = 'mailto:servicedesk@tig.nl'; ?>
8
+ <?php $_changelogUrl = 'https://tig.nl'; ?>
9
+ <?php $_installationManualUrl = 'http://servicedesk.tig.nl/hc/nl/articles/219422177-TinyPNG-handleiding'; ?>
10
+ <?php $_userGuideUrl = 'https://tig.nl'; ?>
11
+ <?php $_version = $this->getModuleVersion(); ?>
12
+ <?php $_stability = $this->getModuleStability(); ?>
13
+
14
+ <tr id="tiny_compressimages_support">
15
+ <td>
16
+ <h2 class="content-heading">
17
+ <?php echo $this->__('Image Optimization %s', $_version);?>
18
+ <?php if (!empty($_stability) && $_stability != 'stable'): ?>
19
+ - <?php echo $_stability; ?>
20
+ <?php endif; ?>
21
+ </h2>
22
+ <table id="supportWrap" cellpadding="0" cellspacing="0">
23
+ <tr>
24
+ <td colspan="2">
25
+
26
+ <div class="">
27
+ <div class="col-set">
28
+ <div class="col-1">
29
+ <p>
30
+ <?php echo $this->__('Make your store faster by optimizing your JPEG and PNG product images. This extension automatically optimizes the images by integrating with the popular image compression services TinyJPG and TinyPNG.'); ?>
31
+ </p>
32
+
33
+ <!-- Magento CE -->
34
+ <?php if (Mage::getEdition() === 'Community'): ?>
35
+ <p>
36
+ <?php echo $this->__('In case you need help or assistance with the extension or your account please contact'); ?> <a href="mailto:support@tinypng.com">support@tinypng.com</a>.
37
+ </p>
38
+ <?php else: ?>
39
+ <!-- Magento EE -->
40
+ <p>
41
+ <?php echo $this->__('For general questions and help with your account please contact') ?> <a href="mailto:support@tinypng.com">support@tinypng.com</a>.
42
+ </p>
43
+ <?php endif; ?>
44
+
45
+ <p>
46
+ <?php echo $this->__('This extension is developed by <a href="%s" target="_BLANK">TIG</a>. Please <a href="%s" target="_BLANK">contact them</a> for technical support.', $_tigHomepage, $_kbTicketUrl); ?>
47
+ </p>
48
+
49
+ </div>
50
+ <div class="col-2">
51
+ <img class="tiny-logo-bear" alt="CompressImages" src="<?php echo $this->getSkinUrl('images/Tiny/CompressImages/george-magento@2x_opt.png'); ?>" />
52
+ </div>
53
+ </div>
54
+ </div>
55
+ </td>
56
+ </tr>
57
+ </table>
58
+ </td>
59
+ </tr>
60
+
61
+ <script>
62
+ //<![CDATA[
63
+ document.observe('dom:loaded', function() {
64
+ var elem;
65
+
66
+ // Set tabs open.
67
+ [
68
+ 'tiny_compressimages_support-head',
69
+ 'tiny_compressimages_image_types-head',
70
+ 'tiny_compressimages_status-head',
71
+ 'tiny_compressimages_settings-head'
72
+ ].each( function (name) {
73
+ elem = $(name);
74
+
75
+ if (!elem.hasClassName('open')) {
76
+ elem.click();
77
+ }
78
+ });
79
+
80
+ // Remove default onclick value
81
+ $('tiny_compressimages_support-head').setAttribute('onclick', '');
82
+
83
+ // Get and remove the first head on the page (ours)
84
+ $$('.entry-edit-head')[0].remove();
85
+ });
86
+ //]]>
87
+ </script>
app/etc/modules/Tiny_CompressImages.xml CHANGED
@@ -1,9 +1,9 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
  <config>
3
- <modules>
4
- <Tiny_CompressImages>
5
- <active>true</active>
6
- <codePool>community</codePool>
7
- </Tiny_CompressImages>
8
- </modules>
9
  </config>
1
+ <?xml version="1.0"?>
2
  <config>
3
+ <modules>
4
+ <Tiny_CompressImages>
5
+ <active>true</active>
6
+ <codePool>community</codePool>
7
+ </Tiny_CompressImages>
8
+ </modules>
9
  </config>
app/locale/en_US/Tiny_CompressImages.csv ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "Tiny_CompressImages::TinyPNG","TinyPNG"
2
+ "Tiny_CompressImages::Version &amp; Support","Version &amp; Support"
3
+ "Tiny_CompressImages::Enable TinyPNG","Enable TinyPNG"
4
+ "Tiny_CompressImages::Logging disabled","Logging disabled"
5
+ "Tiny_CompressImages::Exceptions only","Exceptions only"
6
+ "Tiny_CompressImages::Errors and Exceptions","Errors and Exceptions"
7
+ "Tiny_CompressImages::All logging information","All logging information"
8
+ "Tiny_CompressImages::A long time ago","A long time ago"
9
+ "Tiny_CompressImages::%s month ago","%s month ago"
10
+ "Tiny_CompressImages::%s months ago","%s months ago"
11
+ "Tiny_CompressImages::%s year ago","%s year ago"
12
+ "Tiny_CompressImages::%s years ago","%s years ago"
13
+ "Tiny_CompressImages::%s day ago","%s days ago"
14
+ "Tiny_CompressImages::%s week ago","%s weeks ago"
15
+ "Tiny_CompressImages::%s hour ago","%s hours ago"
16
+ "Tiny_CompressImages::%s minute ago","%s minutes ago"
17
+ "Tiny_CompressImages::%s second ago","%s seconds ago"
18
+ "Tiny_CompressImages::...and %d more images","...and %d more images"
19
+ "Tiny_CompressImages::There are no saved compressions available yet.","There are no saved compressions available yet."
20
+ "Tiny_CompressImages::Warning: Flushing the image cache will cause the TinyPNG module to recompress all images. When having a big catalog this can lead to high costs.\n\nAre you sure you want to continue?","Warning: Flushing the image cache will cause the TinyPNG module to recompress all images. When having a big catalog this can lead to high costs.\n\nAre you sure you want to continue?"
21
+ "Tiny_CompressImages::TIG Tinypng %s","TIG Tinypng %s"
22
+ "Tiny_CompressImages::Information about the TinyPNG extension","Information about the TinyPNG extension"
23
+ "Tiny_CompressImages::Magento & 3rd party version compatibility","Magento & 3rd party version compatibility"
24
+ "Tiny_CompressImages::Magento Community Edition version","Magento Community Edition version"
25
+ "Tiny_CompressImages::Magento Enterprise Edition version","Magento Enterprise Edition version"
26
+ "Tiny_CompressImages::Support","Support"
27
+ "Tiny_CompressImages::The extension is developed by TIG.","The extension is developed by TIG."
28
+ "Tiny_CompressImages::Website:","Website:"
29
+ "Tiny_CompressImages::Support website:","Support website:"
30
+ "Tiny_CompressImages::Extension support and configuration questions","Extension support and configuration questions"
31
+ "Tiny_CompressImages::For questions about installing and configuring the extension please consult the relevant documentation:","For questions about installing and configuring the extension please consult the relevant documentation:"
32
+ "Tiny_CompressImages::Frequently asked questions","Frequently asked questions"
33
+ "Tiny_CompressImages::FAQ","FAQ"
34
+ "Tiny_CompressImages::Installation Manual","Installation Manual"
35
+ "Tiny_CompressImages::Do you have any additional questions?","Do you have any additional questions?"
36
+ "Tiny_CompressImages::Please contact the TIG servicedesk for additional questions.","Please contact the TIG servicedesk for additional questions."
37
+ "Tiny_CompressImages::Ask your question","Ask your question"
38
+ "Tiny_CompressImages::TIG.nl","TIG.nl"
39
+ "Tiny_CompressImages::TIG Knowledgebase","TIG Knowledgebase"
40
+ "Tiny_CompressImages::Operational","Operational"
41
+ "Tiny_CompressImages::Non-operational","Non-operational"
42
+ "Tiny_CompressImages::Click the button to check the API status.","Click the button to check the API status."
43
+ "Tiny_CompressImages::Check status","Check status"
44
+ "Tiny_CompressImages::TinyPNG API Status","TinyPNG API Status"
45
+ "Tiny_CompressImages::We saved %s%% this month! The greatest image compression was %s%%.","We saved %s%% this month! The greatest image compression was %s%%."
46
+ "Tiny_CompressImages::There are %s compressions done this month.","There are %s compressions done this month."
47
+ "Tiny_CompressImages::TinyPNG Settings","TinyPNG Settings"
48
+ "Tiny_CompressImages::On","On"
49
+ "Tiny_CompressImages::Off","Off"
50
+ "Tiny_CompressImages::Test","Test"
51
+ "Tiny_CompressImages::Live","Live"
52
+ "Tiny_CompressImages::If this is set to Off, TinyPNG will no longer compress images","If this is set to Off, TinyPNG will no longer compress images"
53
+ "Tiny_CompressImages::If test mode is activated, the extension will do real compressions. The result won't be saved.","If test mode is activated, the extension will do real compressions. The result won't be saved."
54
+ "Tiny_CompressImages::API Key","API Key"
55
+ "Tiny_CompressImages::You can fetch the API Key from the <a href=""https://tinypng.com/developers/subscription"" target=""_BLANK"">TinyPNG website</a>.","You can fetch the API Key from the <a href=""https://tinypng.com/developers/subscription"" target=""_BLANK"">TinyPNG website</a>."
56
+ "Tiny_CompressImages::Product images to be compressed","Product images to be compressed"
57
+ "Tiny_CompressImages::Messages that should be logged","Messages that should be logged"
58
+ "Tiny_CompressImages::TinyPNG Status","TinyPNG Status"
59
+ "Tiny_CompressImages::Status","Status"
60
+ "Tiny_CompressImages::Saved","Saved"
61
+ "Tiny_CompressImages::The Api Key is invalid","The Api Key is invalid"
62
+ "Tiny_CompressImages::Category images","Category images"
63
+ "Tiny_CompressImages::Block images","Block images"
64
+ "Tiny_CompressImages::CMS page images","CMS page images"
65
+ "Tiny_CompressImages::Thumbnail","Thumbnail"
66
+ "Tiny_CompressImages::Small Image","Small Image"
67
+ "Tiny_CompressImages::Base Image","Base Image"
68
+ "Tiny_CompressImages::Media Image","Media Image"
69
+ "Tiny_CompressImages::File","File"
70
+ "Tiny_CompressImages::File size","File size"
71
+ "Tiny_CompressImages::Bytes Saved","Bytes Saved"
72
+ "Tiny_CompressImages::Percentage saved","Percentage saved"
73
+ "Tiny_CompressImages::Time","Time"
74
+ "Tiny_CompressImages::Show more","Show more"
75
+ "Tiny_CompressImages::Show less","Show less"
76
+ "Tiny_CompressImages::Saved %s%% over a total of %s compressions", "Saved %s%% over a total of %s compressions"
77
+ "Tiny_CompressImages::When set to all, the log file can become huge. Recommended setting for production servers is Errors and Exceptions.","When set to all, the log file can become huge. Recommended setting for production servers is Errors and Exceptions."
78
+ "Tiny_CompressImages::Account type","Account type"
79
+ "Tiny_CompressImages::TinyPNG Log","TinyPNG Log"
80
+ "Tiny_CompressImages::Note: When flushing the image cache, the TinyPNG extension will re-optimize all product images that are shown on the store view(s).","Note: When flushing the image cache, the TinyPNG extension will re-optimize all product images that are shown on the store view(s)."
81
+ "Tiny_CompressImages::File","File"
82
+ "Tiny_CompressImages::Original","Original"
83
+ "Tiny_CompressImages::Now","Now"
84
+ "Tiny_CompressImages::Saved","Saved"
85
+ "Tiny_CompressImages::Time","Time"
86
+ "Tiny_CompressImages::Download log file","Download log file"
87
+ "Tiny_CompressImages::Download TinyPNG log file","Download TinyPNG log file"
88
+ "Tiny_CompressImages::Information about the TinyPNG extension","Information about the TinyPNG extension"
89
+ "Tiny_CompressImages::What does TinyPNG do?","What does TinyPNG do?"
90
+ "Tiny_CompressImages::TinyPNG uses smart lossy compression techniques to reduce the file size of your PNG files. By selectively decreasing the number of colors in the image, fewer bytes are required to store the data. The effect is nearly invisible but it makes a very large difference in file size!","TinyPNG uses smart lossy compression techniques to reduce the file size of your PNG files. By selectively decreasing the number of colors in the image, fewer bytes are required to store the data. The effect is nearly invisible but it makes a very large difference in file size!"
91
+ "Tiny_CompressImages::Why should I use TinyPNG?","Why should I use TinyPNG?"
92
+ "Tiny_CompressImages::PNG is useful because it's the only widely supported format that can store partially transparent images. The format uses compression, but the files can still be large. Use TinyPNG to shrink images for your apps and sites. It will use less bandwidth and load faster.","PNG is useful because it's the only widely supported format that can store partially transparent images. The format uses compression, but the files can still be large. Use TinyPNG to shrink images for your apps and sites. It will use less bandwidth and load faster."
93
+ "Tiny_CompressImages::How does the extension work?","How does the extension work?"
94
+ "Tiny_CompressImages::When a users visits the store view, the TinyPNG will automatically compress the images on the fly. This only applies for images that are not already cached. So in order to optimize all images, <a target=\"_blank\" href=\"%s\">flush your entire images cache</a> so your whole images database will be optimized. When test mode is enabled, the images will also be compressed on the fly, however, compressed images will not be saved to disk. The result can be found in the status log, which can be downloaded in the <a href=\"#tiny_compressimages_logging-head\">Log section</a> tab of this extension.","When a users visits the store view, the TinyPNG will automatically compress the images on the fly. This only applies for images that are not already cached. So in order to optimize all images, <a target=\"_blank\" href=\"%s\">flush your entire images cache</a> so your whole images database will be optimized. When test mode is enabled, the images will also be compressed on the fly, however, compressed images will not be saved to disk. The result can be found in the status log, which can be downloaded in the <a href=\"#tiny_compressimages_logging-head\">Log section</a> tab of this extension."
95
+ "Tiny_CompressImages::General settings and accountdata","General settings and accountdata"
96
+ "Tiny_CompressImages::Please contact TinyPNG for assistance in setting up your account data:","Please contact TinyPNG for assistance in setting up your account data:"
97
+ "Tiny_CompressImages::Optimized,Optimized"
98
+ "Tiny_CompressImages::Please enable the extension to check the compression count.,Please enable the extension to check the compression count."
99
+ "Tiny_CompressImages::Please enter your api key to check the compression count.,Please enter your api key to check the compression count."
lib/TinyCompress/.gitignore ADDED
@@ -0,0 +1 @@
 
1
+ vendor
lib/TinyCompress/.travis.yml ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ language: php
2
+ php:
3
+ - 5.3
4
+ - 5.4
5
+ - 5.5
6
+ - 5.6
7
+ - 7.0
8
+ - hhvm
9
+ - nightly
10
+ env:
11
+ global:
12
+ secure: BFdcLqU/07l3/NGaSZA5+VSB5FSVSwTL9wAyrJSD1N7jN2HzFTE4xxxmcVrAqq6t+jhZqajXcSf8/DTUKyLcmWXGw3JkseHx3ofHw5p2E4Mp+dUvNMh+3KgAABCPm5zEBUgnhNGwFqL+WA/cgXIJY1/sv87u/mg63ojvf3orKJ3KMxFFsVbGo553XYVsiSUXfzvV3foqPdcV9D0SZ0v7IiLcsuwtDRtfJ/udgSZ2C2LFiOek1dLwbjM3inMBPkfLcpuvC2l8Z1CyW5ptxYRrHHJqCMbdRmmwGH04hxRju54EJKX5PGTyDhfG9Kyiu8/hQCtDL4jNQlVNAKbvHrRTnLogoMKhHMRaAIDMNI+lcQB9OHHuureYAqL7gJvRmE2sfN/OAbzizYJ2z+yXvjaKJsd2htrHff8hgvl0M3guhP+mA5C9ubibzGiCD66kdeqS5tJi3EH7wk9GO75lFm3tlZEWZ4FJCwgyFQRZGMGSRJC5cWvW4QlGLHeVnWwnf9CM9/B2oD21LraccgCZhpIbib5/XJ2vTQO0V2ke3kXT1D9E3P8E2eClxnge1aShUSy+d5kMTNeLxkfalgGEviWqA236XLzS8+MjWzNWy3+roBb63Vh0OPp4GyTO810U16Y5lwCMegVrxusnz9bCo1HbK1w2k8D7Ueb/O7LEFYaZSD4=
13
+ matrix:
14
+ allow_failures:
15
+ - php: nightly
16
+ include:
17
+ - php: 5.6
18
+ env: INTEGRATION_TESTS=true
19
+ script: "if [ \"$TRAVIS_PULL_REQUEST\" == \"false\" ]; then vendor/bin/phpunit --no-configuration test/integration.php; fi"
20
+ before_script: composer install
21
+ script: vendor/bin/phpunit
22
+ notifications:
23
+ email: false
24
+ slack:
25
+ secure: W1cEp+ctAD+in3hA/gansbUYrFZsR3EMd7s/XiK2mfAxRRXPCPgCvv0PWpYelJ5F2AnHXkmBP3USKFDhKN+JLmOOxrZpjzh4ve9QSNs4IPgcrU4meQYSgJ3uovS7h4fqAmqhQKL+FpAnrXAmXWGXVPCPtneySsMTyU6kNdmVfulxXRMJ+kLHtFQlT+U7cPYG0f8FkKR2u5CbRsdjUvoZHwbK7jmWpUcCi2O0A1vvMMEMEOG+iuayWW/RbfSfKIgM/SZG0pGYpoAB7I8XfYns7IyLhkJAw18jIWnowF4DuBusNRdr3zIfwC7bSlLKMFYJYpEsiLFCaeGZgp1NbYJ77DvqpwNp9xmoPz9rFGNe7Re+i13pjNWhEnwc5N3St7x8DYNhUC3L0upQ2FWZSomMM7ghlc6GIVtlXYrRJ5AnxIjSWyLRcTRU5Pf/PPRckOTiuLnVgUZNMVIlAHlRV7c/pUVDjbPvjcOajdXnpcd3+5cuKyzCYpXugIfJ9Hzsozq0yCHDKjo8ssAU+5H3mEfB7M25Rtd2awObb3zqOyUPm+J3M/dzql95cF+zj2SWQsBF/ViwkHo+9SoAr/FYqCZveiS0w9vzoKzbGXVDYCfFD+GlEMJ2b8zw4d2sqmIbw24jGq1ZPgczrpD5fcbI2TaheKBkgWvsBJFFO5KbGWqzHIM=
lib/TinyCompress/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ The MIT License
2
+
3
+ Copyright (c) 2013-2016 Voormedia
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
lib/TinyCompress/README.md CHANGED
@@ -1,24 +1,58 @@
1
- # Compress JPEG & PNG Images with Magento
2
 
3
- This extension automatically compresses your Magento images that are generated
4
- in the cache folder.
5
 
6
- ## Advantages
7
 
8
- - Your site will load faster
9
- - You will save bandwidth and hosting costs
10
- - Compression happens on-the-fly in the background
11
- - The extension is compatible with serving images through a CDN
12
- - No cron jobs or scheduled tasks needed
13
 
14
- ## Extended Magento Product Catalog Image from core with extra code
15
 
16
- Right now we have extended Mage_Catalog_Model_Product_Image method from
17
- Magento version 1.9.1.0 with the new Dispatch Event and changed the default JPEG
18
- quality to 95%.
19
 
20
- ## Magento core feature request
21
 
22
- We have asked Magento to include the extra line of code so the function rewrite
23
- can be removed again. But we have not recieved any response yet.
 
 
 
 
 
24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [<img src="https://travis-ci.org/tinify/tinify-php.svg?branch=master" alt="Build Status">](https://travis-ci.org/tinify/tinify-php)
2
 
3
+ # Tinify API client for PHP
 
4
 
5
+ PHP client for the Tinify API, used for [TinyPNG](https://tinypng.com) and [TinyJPG](https://tinyjpg.com). Tinify compresses your images intelligently. Read more at [http://tinify.com](http://tinify.com).
6
 
7
+ ## Documentation
 
 
 
 
8
 
9
+ [Go to the documentation for the PHP client](https://tinypng.com/developers/reference/php).
10
 
11
+ ## Installation
 
 
12
 
13
+ Install the API client with Composer. Add this to your `composer.json`:
14
 
15
+ ```json
16
+ {
17
+ "require": {
18
+ "tinify/tinify": "*"
19
+ }
20
+ }
21
+ ```
22
 
23
+ Then install with:
24
+
25
+ ```
26
+ composer install
27
+ ```
28
+
29
+ Use autoloading to make the client available in PHP:
30
+
31
+ ```php
32
+ require_once("vendor/autoload.php");
33
+ ```
34
+
35
+ ## Usage
36
+
37
+ ```php
38
+ Tinify\setKey("YOUR_API_KEY");
39
+ Tinify\fromFile("unoptimized.png")->toFile("optimized.png");
40
+ ```
41
+
42
+ ## Running tests
43
+
44
+ ```
45
+ composer install
46
+ vendor/bin/phpunit
47
+ ```
48
+
49
+ ### Integration tests
50
+
51
+ ```
52
+ composer install
53
+ TINIFY_KEY=$YOUR_API_KEY vendor/bin/phpunit --no-configuration test/integration.php
54
+ ```
55
+
56
+ ## License
57
+
58
+ This software is licensed under the MIT License. [View the license](LICENSE).
lib/TinyCompress/class-tiny-compress-curl.php DELETED
@@ -1,77 +0,0 @@
1
- <?php
2
- /*
3
- * Tiny Compress Images - WordPress plugin.
4
- * Copyright (C) 2015 Voormedia B.V.
5
- *
6
- * This program is free software; you can redistribute it and/or modify it
7
- * under the terms of the GNU General Public License as published by the Free
8
- * Software Foundation; either version 2 of the License, or (at your option)
9
- * any later version.
10
- *
11
- * This program is distributed in the hope that it will be useful, but WITHOUT
12
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14
- * more details.
15
- *
16
- * You should have received a copy of the GNU General Public License along
17
- * with this program; if not, write to the Free Software Foundation, Inc., 51
18
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
- */
20
-
21
- class Tiny_Compress_Curl extends Tiny_Compress {
22
- protected function shrink_options($input) {
23
- return array(
24
- CURLOPT_URL => $this->config['api']['url'],
25
- CURLOPT_USERPWD => 'api:' . $this->api_key,
26
- CURLOPT_POSTFIELDS => $input,
27
- CURLOPT_BINARYTRANSFER => true,
28
- CURLOPT_RETURNTRANSFER => true,
29
- CURLOPT_HEADER => true,
30
- CURLOPT_CAINFO => self::get_ca_file(),
31
- CURLOPT_SSL_VERIFYPEER => true,
32
- CURLOPT_USERAGENT => Tiny_Compress::identification() . ' cURL'
33
- );
34
- }
35
-
36
- protected function shrink($input) {
37
- $request = curl_init();
38
- curl_setopt_array($request, $this->shrink_options($input));
39
-
40
- $output_url = null;
41
- $response = curl_exec($request);
42
- if ($response === false) {
43
- return array(array(
44
- 'error' => 'CurlError',
45
- 'message' => curl_error($request)
46
- ), null
47
- );
48
- }
49
-
50
- $header_size = curl_getinfo($request, CURLINFO_HEADER_SIZE);
51
- if (curl_getinfo($request, CURLINFO_HTTP_CODE) === 201) {
52
- $output_url = self::parse_location_header(substr($response, 0, $header_size));
53
- }
54
- curl_close($request);
55
-
56
- return array(self::decode(substr($response, $header_size)), $output_url);
57
- }
58
-
59
- protected function output_options($url) {
60
- return array(
61
- CURLOPT_URL => $url,
62
- CURLOPT_RETURNTRANSFER => true,
63
- CURLOPT_CAINFO => self::get_ca_file(),
64
- CURLOPT_SSL_VERIFYPEER => true
65
- );
66
- }
67
-
68
- protected function output($url) {
69
- $request = curl_init();
70
- curl_setopt_array($request, $this->output_options($url));
71
-
72
- $response = curl_exec($request);
73
- curl_close($request);
74
-
75
- return $response;
76
- }
77
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/TinyCompress/class-tiny-compress-fopen.php DELETED
@@ -1,85 +0,0 @@
1
- <?php
2
- /*
3
- * Tiny Compress Images - WordPress plugin.
4
- * Copyright (C) 2015 Voormedia B.V.
5
- *
6
- * This program is free software; you can redistribute it and/or modify it
7
- * under the terms of the GNU General Public License as published by the Free
8
- * Software Foundation; either version 2 of the License, or (at your option)
9
- * any later version.
10
- *
11
- * This program is distributed in the hope that it will be useful, but WITHOUT
12
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14
- * more details.
15
- *
16
- * You should have received a copy of the GNU General Public License along
17
- * with this program; if not, write to the Free Software Foundation, Inc., 51
18
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
- */
20
-
21
- class Tiny_Compress_Fopen extends Tiny_Compress {
22
- protected function shrink_options($input) {
23
- return array(
24
- 'http' => array(
25
- 'method' => 'POST',
26
- 'header' => array(
27
- 'Content-type: image/png',
28
- 'Authorization: Basic ' . base64_encode('api:' . $this->api_key),
29
- 'User-Agent: ' . Tiny_Compress::identification() . ' fopen',
30
- ),
31
- 'content' => $input
32
- ),
33
- 'ssl' => array(
34
- 'cafile' => self::get_ca_file(),
35
- 'verify_peer' => true
36
- )
37
- );
38
- }
39
-
40
- protected function shrink($input) {
41
- $context = stream_context_create($this->shrink_options($input));
42
- $request = @fopen($this->config['api']['url'], 'r', false, $context);
43
-
44
- if (!$request) {
45
- return array(array(
46
- 'error' => 'FopenError',
47
- 'message' => 'Could not compress, enable cURL for detailed error'
48
- ), null
49
- );
50
- }
51
-
52
- $response = stream_get_contents($request);
53
- $meta_data = stream_get_meta_data($request);
54
- $output_url = self::parse_location_header($meta_data['wrapper_data']);
55
- fclose($request);
56
-
57
- return array(self::decode($response), $output_url);
58
- }
59
-
60
- protected function output_options() {
61
- return array(
62
- 'http' => array(
63
- 'method' => 'GET',
64
- ),
65
- 'ssl' => array(
66
- 'cafile' => self::get_ca_file(),
67
- 'verify_peer' => true
68
- )
69
- );
70
- }
71
-
72
- protected function output($url) {
73
- $context = stream_context_create($this->output_options());
74
- $request = @fopen($url, 'rb', false, $context);
75
-
76
- if ($request) {
77
- $response = stream_get_contents($request);
78
- fclose($request);
79
- } else {
80
- $response = '';
81
- }
82
-
83
- return $response;
84
- }
85
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/TinyCompress/class-tiny-compress.php DELETED
@@ -1,97 +0,0 @@
1
- <?php
2
- /*
3
- * Tiny Compress Images - WordPress plugin.
4
- * Copyright (C) 2015 Voormedia B.V.
5
- *
6
- * This program is free software; you can redistribute it and/or modify it
7
- * under the terms of the GNU General Public License as published by the Free
8
- * Software Foundation; either version 2 of the License, or (at your option)
9
- * any later version.
10
- *
11
- * This program is distributed in the hope that it will be useful, but WITHOUT
12
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14
- * more details.
15
- *
16
- * You should have received a copy of the GNU General Public License along
17
- * with this program; if not, write to the Free Software Foundation, Inc., 51
18
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
- */
20
-
21
- abstract class Tiny_Compress {
22
- protected $api_key;
23
- protected $config;
24
-
25
- public static function identification() {
26
- return "Tiny Compress Magento v1.0";
27
- }
28
-
29
- public static function get_ca_file() {
30
- return dirname(__FILE__) . '/cacert.pem';
31
- }
32
-
33
- public static function get_config() {
34
- return parse_ini_file(dirname(__FILE__) . '/config/tinypng-api.ini', true);
35
- }
36
-
37
- public static function get_compressor($api_key) {
38
- if (Tiny_PHP::is_curl_available()) {
39
- return new Tiny_Compress_Curl($api_key, self::get_config());
40
- } elseif (Tiny_PHP::is_fopen_available()) {
41
- return new Tiny_Compress_Fopen($api_key, self::get_config());
42
- }
43
- throw new Tiny_Exception('No HTTP client is available (cURL or fopen)', 'NoHttpClient');
44
- }
45
-
46
- protected function __construct($api_key, $config) {
47
- $this->api_key = $api_key;
48
- $this->config = $config;
49
- }
50
-
51
- abstract protected function shrink($input);
52
- abstract protected function output($url);
53
-
54
- public function compress($input) {
55
- list($details, $outputUrl) = $this->shrink($input);
56
- if (isset($details['error']) && $details['error']) {
57
- throw new Tiny_Exception($details['message'], $details['error']);
58
- } else if ($outputUrl === null) {
59
- throw new Tiny_Exception('Could not find output url', 'OutputNotFound');
60
- }
61
- $output = $this->output($outputUrl);
62
- if (strlen($output) == 0) {
63
- throw new Tiny_Exception('Could not download output', 'OutputError');
64
- }
65
- return array($output, $details);
66
- }
67
-
68
- public function compress_file($file) {
69
- if (!file_exists($file)) {
70
- throw new Tiny_Exception('File does not exists', 'FileError');
71
- }
72
- list($output, $details) = $this->compress(file_get_contents($file));
73
- file_put_contents($file, $output);
74
- return $details;
75
- }
76
-
77
- protected static function parse_location_header($headers) {
78
- if (!is_array($headers)) {
79
- $headers = explode("\r\n", $headers);
80
- }
81
- foreach ($headers as $header) {
82
- if (strtolower(substr($header, 0, 10)) === "location: ") {
83
- return substr($header, 10);
84
- }
85
- }
86
- return null;
87
- }
88
-
89
- protected static function decode($text) {
90
- $result = json_decode($text, true);
91
- if ($result === null) {
92
- throw new Tiny_Exception('Could not decode JSON', 'JsonError');
93
- }
94
- return $result;
95
- }
96
- }
97
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/TinyCompress/class-tiny-exception.php DELETED
@@ -1,32 +0,0 @@
1
- <?php
2
- /*
3
- * Tiny Compress Images - WordPress plugin.
4
- * Copyright (C) 2015 Voormedia B.V.
5
- *
6
- * This program is free software; you can redistribute it and/or modify it
7
- * under the terms of the GNU General Public License as published by the Free
8
- * Software Foundation; either version 2 of the License, or (at your option)
9
- * any later version.
10
- *
11
- * This program is distributed in the hope that it will be useful, but WITHOUT
12
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14
- * more details.
15
- *
16
- * You should have received a copy of the GNU General Public License along
17
- * with this program; if not, write to the Free Software Foundation, Inc., 51
18
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
- */
20
-
21
- class Tiny_Exception extends Exception {
22
- private $error;
23
-
24
- public function __construct($message, $error=null) {
25
- parent::__construct($message);
26
- $this->error = $error;
27
- }
28
-
29
- public function get_error() {
30
- return $this->error;
31
- }
32
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/TinyCompress/class-tiny-php.php DELETED
@@ -1,29 +0,0 @@
1
- <?php
2
- /*
3
- * Tiny Compress Images - WordPress plugin.
4
- * Copyright (C) 2015 Voormedia B.V.
5
- *
6
- * This program is free software; you can redistribute it and/or modify it
7
- * under the terms of the GNU General Public License as published by the Free
8
- * Software Foundation; either version 2 of the License, or (at your option)
9
- * any later version.
10
- *
11
- * This program is distributed in the hope that it will be useful, but WITHOUT
12
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14
- * more details.
15
- *
16
- * You should have received a copy of the GNU General Public License along
17
- * with this program; if not, write to the Free Software Foundation, Inc., 51
18
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
- */
20
-
21
- class Tiny_PHP {
22
- public static function is_curl_available() {
23
- return extension_loaded('curl');
24
- }
25
-
26
- public static function is_fopen_available() {
27
- return ini_get('allow_url_fopen');
28
- }
29
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/TinyCompress/composer.json ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "tinify/tinify",
3
+ "description": "PHP client for the Tinify API. Tinify compresses your images intelligently. Read more at https://tinify.com.",
4
+ "keywords": [
5
+ "tinify",
6
+ "tinypng",
7
+ "tinyjpg",
8
+ "compress",
9
+ "images",
10
+ "api"
11
+ ],
12
+
13
+ "homepage": "https://tinify.com/developers",
14
+ "license": "MIT",
15
+
16
+ "support": {
17
+ "email": "support@tinify.com"
18
+ },
19
+
20
+ "authors": [{
21
+ "name": "Rolf Timmermans",
22
+ "email": "rolftimmermans@voormedia.com"
23
+ }],
24
+
25
+ "require": {
26
+ "php": ">=5.3.0",
27
+ "ext-curl": "*",
28
+ "ext-json": "*",
29
+ "lib-curl": ">=7.20.0"
30
+ },
31
+
32
+ "require-dev": {
33
+ "symfony/yaml": "~2.0",
34
+ "phpunit/phpunit": "~4.0"
35
+ },
36
+
37
+ "autoload": {
38
+ "files": ["lib/Tinify.php", "lib/Tinify/Exception.php"],
39
+ "psr-4": {"Tinify\\": "lib/Tinify/"}
40
+ }
41
+ }
lib/TinyCompress/composer.lock ADDED
@@ -0,0 +1,977 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_readme": [
3
+ "This file locks the dependencies of your project to a known state",
4
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
5
+ "This file is @generated automatically"
6
+ ],
7
+ "hash": "24129bff61e8cfa8b2a82efee5c7069a",
8
+ "content-hash": "6251dc24eeaff94cb037569e414a6195",
9
+ "packages": [],
10
+ "packages-dev": [
11
+ {
12
+ "name": "doctrine/instantiator",
13
+ "version": "1.0.5",
14
+ "source": {
15
+ "type": "git",
16
+ "url": "https://github.com/doctrine/instantiator.git",
17
+ "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d"
18
+ },
19
+ "dist": {
20
+ "type": "zip",
21
+ "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d",
22
+ "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d",
23
+ "shasum": ""
24
+ },
25
+ "require": {
26
+ "php": ">=5.3,<8.0-DEV"
27
+ },
28
+ "require-dev": {
29
+ "athletic/athletic": "~0.1.8",
30
+ "ext-pdo": "*",
31
+ "ext-phar": "*",
32
+ "phpunit/phpunit": "~4.0",
33
+ "squizlabs/php_codesniffer": "~2.0"
34
+ },
35
+ "type": "library",
36
+ "extra": {
37
+ "branch-alias": {
38
+ "dev-master": "1.0.x-dev"
39
+ }
40
+ },
41
+ "autoload": {
42
+ "psr-4": {
43
+ "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
44
+ }
45
+ },
46
+ "notification-url": "https://packagist.org/downloads/",
47
+ "license": [
48
+ "MIT"
49
+ ],
50
+ "authors": [
51
+ {
52
+ "name": "Marco Pivetta",
53
+ "email": "ocramius@gmail.com",
54
+ "homepage": "http://ocramius.github.com/"
55
+ }
56
+ ],
57
+ "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
58
+ "homepage": "https://github.com/doctrine/instantiator",
59
+ "keywords": [
60
+ "constructor",
61
+ "instantiate"
62
+ ],
63
+ "time": "2015-06-14 21:17:01"
64
+ },
65
+ {
66
+ "name": "phpdocumentor/reflection-docblock",
67
+ "version": "2.0.4",
68
+ "source": {
69
+ "type": "git",
70
+ "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
71
+ "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8"
72
+ },
73
+ "dist": {
74
+ "type": "zip",
75
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8",
76
+ "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8",
77
+ "shasum": ""
78
+ },
79
+ "require": {
80
+ "php": ">=5.3.3"
81
+ },
82
+ "require-dev": {
83
+ "phpunit/phpunit": "~4.0"
84
+ },
85
+ "suggest": {
86
+ "dflydev/markdown": "~1.0",
87
+ "erusev/parsedown": "~1.0"
88
+ },
89
+ "type": "library",
90
+ "extra": {
91
+ "branch-alias": {
92
+ "dev-master": "2.0.x-dev"
93
+ }
94
+ },
95
+ "autoload": {
96
+ "psr-0": {
97
+ "phpDocumentor": [
98
+ "src/"
99
+ ]
100
+ }
101
+ },
102
+ "notification-url": "https://packagist.org/downloads/",
103
+ "license": [
104
+ "MIT"
105
+ ],
106
+ "authors": [
107
+ {
108
+ "name": "Mike van Riel",
109
+ "email": "mike.vanriel@naenius.com"
110
+ }
111
+ ],
112
+ "time": "2015-02-03 12:10:50"
113
+ },
114
+ {
115
+ "name": "phpspec/prophecy",
116
+ "version": "v1.6.0",
117
+ "source": {
118
+ "type": "git",
119
+ "url": "https://github.com/phpspec/prophecy.git",
120
+ "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972"
121
+ },
122
+ "dist": {
123
+ "type": "zip",
124
+ "url": "https://api.github.com/repos/phpspec/prophecy/zipball/3c91bdf81797d725b14cb62906f9a4ce44235972",
125
+ "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972",
126
+ "shasum": ""
127
+ },
128
+ "require": {
129
+ "doctrine/instantiator": "^1.0.2",
130
+ "php": "^5.3|^7.0",
131
+ "phpdocumentor/reflection-docblock": "~2.0",
132
+ "sebastian/comparator": "~1.1",
133
+ "sebastian/recursion-context": "~1.0"
134
+ },
135
+ "require-dev": {
136
+ "phpspec/phpspec": "~2.0"
137
+ },
138
+ "type": "library",
139
+ "extra": {
140
+ "branch-alias": {
141
+ "dev-master": "1.5.x-dev"
142
+ }
143
+ },
144
+ "autoload": {
145
+ "psr-0": {
146
+ "Prophecy\\": "src/"
147
+ }
148
+ },
149
+ "notification-url": "https://packagist.org/downloads/",
150
+ "license": [
151
+ "MIT"
152
+ ],
153
+ "authors": [
154
+ {
155
+ "name": "Konstantin Kudryashov",
156
+ "email": "ever.zet@gmail.com",
157
+ "homepage": "http://everzet.com"
158
+ },
159
+ {
160
+ "name": "Marcello Duarte",
161
+ "email": "marcello.duarte@gmail.com"
162
+ }
163
+ ],
164
+ "description": "Highly opinionated mocking framework for PHP 5.3+",
165
+ "homepage": "https://github.com/phpspec/prophecy",
166
+ "keywords": [
167
+ "Double",
168
+ "Dummy",
169
+ "fake",
170
+ "mock",
171
+ "spy",
172
+ "stub"
173
+ ],
174
+ "time": "2016-02-15 07:46:21"
175
+ },
176
+ {
177
+ "name": "phpunit/php-code-coverage",
178
+ "version": "2.2.4",
179
+ "source": {
180
+ "type": "git",
181
+ "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
182
+ "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979"
183
+ },
184
+ "dist": {
185
+ "type": "zip",
186
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979",
187
+ "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979",
188
+ "shasum": ""
189
+ },
190
+ "require": {
191
+ "php": ">=5.3.3",
192
+ "phpunit/php-file-iterator": "~1.3",
193
+ "phpunit/php-text-template": "~1.2",
194
+ "phpunit/php-token-stream": "~1.3",
195
+ "sebastian/environment": "^1.3.2",
196
+ "sebastian/version": "~1.0"
197
+ },
198
+ "require-dev": {
199
+ "ext-xdebug": ">=2.1.4",
200
+ "phpunit/phpunit": "~4"
201
+ },
202
+ "suggest": {
203
+ "ext-dom": "*",
204
+ "ext-xdebug": ">=2.2.1",
205
+ "ext-xmlwriter": "*"
206
+ },
207
+ "type": "library",
208
+ "extra": {
209
+ "branch-alias": {
210
+ "dev-master": "2.2.x-dev"
211
+ }
212
+ },
213
+ "autoload": {
214
+ "classmap": [
215
+ "src/"
216
+ ]
217
+ },
218
+ "notification-url": "https://packagist.org/downloads/",
219
+ "license": [
220
+ "BSD-3-Clause"
221
+ ],
222
+ "authors": [
223
+ {
224
+ "name": "Sebastian Bergmann",
225
+ "email": "sb@sebastian-bergmann.de",
226
+ "role": "lead"
227
+ }
228
+ ],
229
+ "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
230
+ "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
231
+ "keywords": [
232
+ "coverage",
233
+ "testing",
234
+ "xunit"
235
+ ],
236
+ "time": "2015-10-06 15:47:00"
237
+ },
238
+ {
239
+ "name": "phpunit/php-file-iterator",
240
+ "version": "1.4.1",
241
+ "source": {
242
+ "type": "git",
243
+ "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
244
+ "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0"
245
+ },
246
+ "dist": {
247
+ "type": "zip",
248
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0",
249
+ "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0",
250
+ "shasum": ""
251
+ },
252
+ "require": {
253
+ "php": ">=5.3.3"
254
+ },
255
+ "type": "library",
256
+ "extra": {
257
+ "branch-alias": {
258
+ "dev-master": "1.4.x-dev"
259
+ }
260
+ },
261
+ "autoload": {
262
+ "classmap": [
263
+ "src/"
264
+ ]
265
+ },
266
+ "notification-url": "https://packagist.org/downloads/",
267
+ "license": [
268
+ "BSD-3-Clause"
269
+ ],
270
+ "authors": [
271
+ {
272
+ "name": "Sebastian Bergmann",
273
+ "email": "sb@sebastian-bergmann.de",
274
+ "role": "lead"
275
+ }
276
+ ],
277
+ "description": "FilterIterator implementation that filters files based on a list of suffixes.",
278
+ "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
279
+ "keywords": [
280
+ "filesystem",
281
+ "iterator"
282
+ ],
283
+ "time": "2015-06-21 13:08:43"
284
+ },
285
+ {
286
+ "name": "phpunit/php-text-template",
287
+ "version": "1.2.1",
288
+ "source": {
289
+ "type": "git",
290
+ "url": "https://github.com/sebastianbergmann/php-text-template.git",
291
+ "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
292
+ },
293
+ "dist": {
294
+ "type": "zip",
295
+ "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
296
+ "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
297
+ "shasum": ""
298
+ },
299
+ "require": {
300
+ "php": ">=5.3.3"
301
+ },
302
+ "type": "library",
303
+ "autoload": {
304
+ "classmap": [
305
+ "src/"
306
+ ]
307
+ },
308
+ "notification-url": "https://packagist.org/downloads/",
309
+ "license": [
310
+ "BSD-3-Clause"
311
+ ],
312
+ "authors": [
313
+ {
314
+ "name": "Sebastian Bergmann",
315
+ "email": "sebastian@phpunit.de",
316
+ "role": "lead"
317
+ }
318
+ ],
319
+ "description": "Simple template engine.",
320
+ "homepage": "https://github.com/sebastianbergmann/php-text-template/",
321
+ "keywords": [
322
+ "template"
323
+ ],
324
+ "time": "2015-06-21 13:50:34"
325
+ },
326
+ {
327
+ "name": "phpunit/php-timer",
328
+ "version": "1.0.7",
329
+ "source": {
330
+ "type": "git",
331
+ "url": "https://github.com/sebastianbergmann/php-timer.git",
332
+ "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b"
333
+ },
334
+ "dist": {
335
+ "type": "zip",
336
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3e82f4e9fc92665fafd9157568e4dcb01d014e5b",
337
+ "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b",
338
+ "shasum": ""
339
+ },
340
+ "require": {
341
+ "php": ">=5.3.3"
342
+ },
343
+ "type": "library",
344
+ "autoload": {
345
+ "classmap": [
346
+ "src/"
347
+ ]
348
+ },
349
+ "notification-url": "https://packagist.org/downloads/",
350
+ "license": [
351
+ "BSD-3-Clause"
352
+ ],
353
+ "authors": [
354
+ {
355
+ "name": "Sebastian Bergmann",
356
+ "email": "sb@sebastian-bergmann.de",
357
+ "role": "lead"
358
+ }
359
+ ],
360
+ "description": "Utility class for timing",
361
+ "homepage": "https://github.com/sebastianbergmann/php-timer/",
362
+ "keywords": [
363
+ "timer"
364
+ ],
365
+ "time": "2015-06-21 08:01:12"
366
+ },
367
+ {
368
+ "name": "phpunit/php-token-stream",
369
+ "version": "1.4.8",
370
+ "source": {
371
+ "type": "git",
372
+ "url": "https://github.com/sebastianbergmann/php-token-stream.git",
373
+ "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da"
374
+ },
375
+ "dist": {
376
+ "type": "zip",
377
+ "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da",
378
+ "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da",
379
+ "shasum": ""
380
+ },
381
+ "require": {
382
+ "ext-tokenizer": "*",
383
+ "php": ">=5.3.3"
384
+ },
385
+ "require-dev": {
386
+ "phpunit/phpunit": "~4.2"
387
+ },
388
+ "type": "library",
389
+ "extra": {
390
+ "branch-alias": {
391
+ "dev-master": "1.4-dev"
392
+ }
393
+ },
394
+ "autoload": {
395
+ "classmap": [
396
+ "src/"
397
+ ]
398
+ },
399
+ "notification-url": "https://packagist.org/downloads/",
400
+ "license": [
401
+ "BSD-3-Clause"
402
+ ],
403
+ "authors": [
404
+ {
405
+ "name": "Sebastian Bergmann",
406
+ "email": "sebastian@phpunit.de"
407
+ }
408
+ ],
409
+ "description": "Wrapper around PHP's tokenizer extension.",
410
+ "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
411
+ "keywords": [
412
+ "tokenizer"
413
+ ],
414
+ "time": "2015-09-15 10:49:45"
415
+ },
416
+ {
417
+ "name": "phpunit/phpunit",
418
+ "version": "4.8.24",
419
+ "source": {
420
+ "type": "git",
421
+ "url": "https://github.com/sebastianbergmann/phpunit.git",
422
+ "reference": "a1066c562c52900a142a0e2bbf0582994671385e"
423
+ },
424
+ "dist": {
425
+ "type": "zip",
426
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a1066c562c52900a142a0e2bbf0582994671385e",
427
+ "reference": "a1066c562c52900a142a0e2bbf0582994671385e",
428
+ "shasum": ""
429
+ },
430
+ "require": {
431
+ "ext-dom": "*",
432
+ "ext-json": "*",
433
+ "ext-pcre": "*",
434
+ "ext-reflection": "*",
435
+ "ext-spl": "*",
436
+ "php": ">=5.3.3",
437
+ "phpspec/prophecy": "^1.3.1",
438
+ "phpunit/php-code-coverage": "~2.1",
439
+ "phpunit/php-file-iterator": "~1.4",
440
+ "phpunit/php-text-template": "~1.2",
441
+ "phpunit/php-timer": ">=1.0.6",
442
+ "phpunit/phpunit-mock-objects": "~2.3",
443
+ "sebastian/comparator": "~1.1",
444
+ "sebastian/diff": "~1.2",
445
+ "sebastian/environment": "~1.3",
446
+ "sebastian/exporter": "~1.2",
447
+ "sebastian/global-state": "~1.0",
448
+ "sebastian/version": "~1.0",
449
+ "symfony/yaml": "~2.1|~3.0"
450
+ },
451
+ "suggest": {
452
+ "phpunit/php-invoker": "~1.1"
453
+ },
454
+ "bin": [
455
+ "phpunit"
456
+ ],
457
+ "type": "library",
458
+ "extra": {
459
+ "branch-alias": {
460
+ "dev-master": "4.8.x-dev"
461
+ }
462
+ },
463
+ "autoload": {
464
+ "classmap": [
465
+ "src/"
466
+ ]
467
+ },
468
+ "notification-url": "https://packagist.org/downloads/",
469
+ "license": [
470
+ "BSD-3-Clause"
471
+ ],
472
+ "authors": [
473
+ {
474
+ "name": "Sebastian Bergmann",
475
+ "email": "sebastian@phpunit.de",
476
+ "role": "lead"
477
+ }
478
+ ],
479
+ "description": "The PHP Unit Testing framework.",
480
+ "homepage": "https://phpunit.de/",
481
+ "keywords": [
482
+ "phpunit",
483
+ "testing",
484
+ "xunit"
485
+ ],
486
+ "time": "2016-03-14 06:16:08"
487
+ },
488
+ {
489
+ "name": "phpunit/phpunit-mock-objects",
490
+ "version": "2.3.8",
491
+ "source": {
492
+ "type": "git",
493
+ "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
494
+ "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983"
495
+ },
496
+ "dist": {
497
+ "type": "zip",
498
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983",
499
+ "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983",
500
+ "shasum": ""
501
+ },
502
+ "require": {
503
+ "doctrine/instantiator": "^1.0.2",
504
+ "php": ">=5.3.3",
505
+ "phpunit/php-text-template": "~1.2",
506
+ "sebastian/exporter": "~1.2"
507
+ },
508
+ "require-dev": {
509
+ "phpunit/phpunit": "~4.4"
510
+ },
511
+ "suggest": {
512
+ "ext-soap": "*"
513
+ },
514
+ "type": "library",
515
+ "extra": {
516
+ "branch-alias": {
517
+ "dev-master": "2.3.x-dev"
518
+ }
519
+ },
520
+ "autoload": {
521
+ "classmap": [
522
+ "src/"
523
+ ]
524
+ },
525
+ "notification-url": "https://packagist.org/downloads/",
526
+ "license": [
527
+ "BSD-3-Clause"
528
+ ],
529
+ "authors": [
530
+ {
531
+ "name": "Sebastian Bergmann",
532
+ "email": "sb@sebastian-bergmann.de",
533
+ "role": "lead"
534
+ }
535
+ ],
536
+ "description": "Mock Object library for PHPUnit",
537
+ "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
538
+ "keywords": [
539
+ "mock",
540
+ "xunit"
541
+ ],
542
+ "time": "2015-10-02 06:51:40"
543
+ },
544
+ {
545
+ "name": "sebastian/comparator",
546
+ "version": "1.2.0",
547
+ "source": {
548
+ "type": "git",
549
+ "url": "https://github.com/sebastianbergmann/comparator.git",
550
+ "reference": "937efb279bd37a375bcadf584dec0726f84dbf22"
551
+ },
552
+ "dist": {
553
+ "type": "zip",
554
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22",
555
+ "reference": "937efb279bd37a375bcadf584dec0726f84dbf22",
556
+ "shasum": ""
557
+ },
558
+ "require": {
559
+ "php": ">=5.3.3",
560
+ "sebastian/diff": "~1.2",
561
+ "sebastian/exporter": "~1.2"
562
+ },
563
+ "require-dev": {
564
+ "phpunit/phpunit": "~4.4"
565
+ },
566
+ "type": "library",
567
+ "extra": {
568
+ "branch-alias": {
569
+ "dev-master": "1.2.x-dev"
570
+ }
571
+ },
572
+ "autoload": {
573
+ "classmap": [
574
+ "src/"
575
+ ]
576
+ },
577
+ "notification-url": "https://packagist.org/downloads/",
578
+ "license": [
579
+ "BSD-3-Clause"
580
+ ],
581
+ "authors": [
582
+ {
583
+ "name": "Jeff Welch",
584
+ "email": "whatthejeff@gmail.com"
585
+ },
586
+ {
587
+ "name": "Volker Dusch",
588
+ "email": "github@wallbash.com"
589
+ },
590
+ {
591
+ "name": "Bernhard Schussek",
592
+ "email": "bschussek@2bepublished.at"
593
+ },
594
+ {
595
+ "name": "Sebastian Bergmann",
596
+ "email": "sebastian@phpunit.de"
597
+ }
598
+ ],
599
+ "description": "Provides the functionality to compare PHP values for equality",
600
+ "homepage": "http://www.github.com/sebastianbergmann/comparator",
601
+ "keywords": [
602
+ "comparator",
603
+ "compare",
604
+ "equality"
605
+ ],
606
+ "time": "2015-07-26 15:48:44"
607
+ },
608
+ {
609
+ "name": "sebastian/diff",
610
+ "version": "1.4.1",
611
+ "source": {
612
+ "type": "git",
613
+ "url": "https://github.com/sebastianbergmann/diff.git",
614
+ "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e"
615
+ },
616
+ "dist": {
617
+ "type": "zip",
618
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e",
619
+ "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e",
620
+ "shasum": ""
621
+ },
622
+ "require": {
623
+ "php": ">=5.3.3"
624
+ },
625
+ "require-dev": {
626
+ "phpunit/phpunit": "~4.8"
627
+ },
628
+ "type": "library",
629
+ "extra": {
630
+ "branch-alias": {
631
+ "dev-master": "1.4-dev"
632
+ }
633
+ },
634
+ "autoload": {
635
+ "classmap": [
636
+ "src/"
637
+ ]
638
+ },
639
+ "notification-url": "https://packagist.org/downloads/",
640
+ "license": [
641
+ "BSD-3-Clause"
642
+ ],
643
+ "authors": [
644
+ {
645
+ "name": "Kore Nordmann",
646
+ "email": "mail@kore-nordmann.de"
647
+ },
648
+ {
649
+ "name": "Sebastian Bergmann",
650
+ "email": "sebastian@phpunit.de"
651
+ }
652
+ ],
653
+ "description": "Diff implementation",
654
+ "homepage": "https://github.com/sebastianbergmann/diff",
655
+ "keywords": [
656
+ "diff"
657
+ ],
658
+ "time": "2015-12-08 07:14:41"
659
+ },
660
+ {
661
+ "name": "sebastian/environment",
662
+ "version": "1.3.5",
663
+ "source": {
664
+ "type": "git",
665
+ "url": "https://github.com/sebastianbergmann/environment.git",
666
+ "reference": "dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf"
667
+ },
668
+ "dist": {
669
+ "type": "zip",
670
+ "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf",
671
+ "reference": "dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf",
672
+ "shasum": ""
673
+ },
674
+ "require": {
675
+ "php": ">=5.3.3"
676
+ },
677
+ "require-dev": {
678
+ "phpunit/phpunit": "~4.4"
679
+ },
680
+ "type": "library",
681
+ "extra": {
682
+ "branch-alias": {
683
+ "dev-master": "1.3.x-dev"
684
+ }
685
+ },
686
+ "autoload": {
687
+ "classmap": [
688
+ "src/"
689
+ ]
690
+ },
691
+ "notification-url": "https://packagist.org/downloads/",
692
+ "license": [
693
+ "BSD-3-Clause"
694
+ ],
695
+ "authors": [
696
+ {
697
+ "name": "Sebastian Bergmann",
698
+ "email": "sebastian@phpunit.de"
699
+ }
700
+ ],
701
+ "description": "Provides functionality to handle HHVM/PHP environments",
702
+ "homepage": "http://www.github.com/sebastianbergmann/environment",
703
+ "keywords": [
704
+ "Xdebug",
705
+ "environment",
706
+ "hhvm"
707
+ ],
708
+ "time": "2016-02-26 18:40:46"
709
+ },
710
+ {
711
+ "name": "sebastian/exporter",
712
+ "version": "1.2.1",
713
+ "source": {
714
+ "type": "git",
715
+ "url": "https://github.com/sebastianbergmann/exporter.git",
716
+ "reference": "7ae5513327cb536431847bcc0c10edba2701064e"
717
+ },
718
+ "dist": {
719
+ "type": "zip",
720
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/7ae5513327cb536431847bcc0c10edba2701064e",
721
+ "reference": "7ae5513327cb536431847bcc0c10edba2701064e",
722
+ "shasum": ""
723
+ },
724
+ "require": {
725
+ "php": ">=5.3.3",
726
+ "sebastian/recursion-context": "~1.0"
727
+ },
728
+ "require-dev": {
729
+ "phpunit/phpunit": "~4.4"
730
+ },
731
+ "type": "library",
732
+ "extra": {
733
+ "branch-alias": {
734
+ "dev-master": "1.2.x-dev"
735
+ }
736
+ },
737
+ "autoload": {
738
+ "classmap": [
739
+ "src/"
740
+ ]
741
+ },
742
+ "notification-url": "https://packagist.org/downloads/",
743
+ "license": [
744
+ "BSD-3-Clause"
745
+ ],
746
+ "authors": [
747
+ {
748
+ "name": "Jeff Welch",
749
+ "email": "whatthejeff@gmail.com"
750
+ },
751
+ {
752
+ "name": "Volker Dusch",
753
+ "email": "github@wallbash.com"
754
+ },
755
+ {
756
+ "name": "Bernhard Schussek",
757
+ "email": "bschussek@2bepublished.at"
758
+ },
759
+ {
760
+ "name": "Sebastian Bergmann",
761
+ "email": "sebastian@phpunit.de"
762
+ },
763
+ {
764
+ "name": "Adam Harvey",
765
+ "email": "aharvey@php.net"
766
+ }
767
+ ],
768
+ "description": "Provides the functionality to export PHP variables for visualization",
769
+ "homepage": "http://www.github.com/sebastianbergmann/exporter",
770
+ "keywords": [
771
+ "export",
772
+ "exporter"
773
+ ],
774
+ "time": "2015-06-21 07:55:53"
775
+ },
776
+ {
777
+ "name": "sebastian/global-state",
778
+ "version": "1.1.1",
779
+ "source": {
780
+ "type": "git",
781
+ "url": "https://github.com/sebastianbergmann/global-state.git",
782
+ "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4"
783
+ },
784
+ "dist": {
785
+ "type": "zip",
786
+ "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4",
787
+ "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4",
788
+ "shasum": ""
789
+ },
790
+ "require": {
791
+ "php": ">=5.3.3"
792
+ },
793
+ "require-dev": {
794
+ "phpunit/phpunit": "~4.2"
795
+ },
796
+ "suggest": {
797
+ "ext-uopz": "*"
798
+ },
799
+ "type": "library",
800
+ "extra": {
801
+ "branch-alias": {
802
+ "dev-master": "1.0-dev"
803
+ }
804
+ },
805
+ "autoload": {
806
+ "classmap": [
807
+ "src/"
808
+ ]
809
+ },
810
+ "notification-url": "https://packagist.org/downloads/",
811
+ "license": [
812
+ "BSD-3-Clause"
813
+ ],
814
+ "authors": [
815
+ {
816
+ "name": "Sebastian Bergmann",
817
+ "email": "sebastian@phpunit.de"
818
+ }
819
+ ],
820
+ "description": "Snapshotting of global state",
821
+ "homepage": "http://www.github.com/sebastianbergmann/global-state",
822
+ "keywords": [
823
+ "global state"
824
+ ],
825
+ "time": "2015-10-12 03:26:01"
826
+ },
827
+ {
828
+ "name": "sebastian/recursion-context",
829
+ "version": "1.0.2",
830
+ "source": {
831
+ "type": "git",
832
+ "url": "https://github.com/sebastianbergmann/recursion-context.git",
833
+ "reference": "913401df809e99e4f47b27cdd781f4a258d58791"
834
+ },
835
+ "dist": {
836
+ "type": "zip",
837
+ "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791",
838
+ "reference": "913401df809e99e4f47b27cdd781f4a258d58791",
839
+ "shasum": ""
840
+ },
841
+ "require": {
842
+ "php": ">=5.3.3"
843
+ },
844
+ "require-dev": {
845
+ "phpunit/phpunit": "~4.4"
846
+ },
847
+ "type": "library",
848
+ "extra": {
849
+ "branch-alias": {
850
+ "dev-master": "1.0.x-dev"
851
+ }
852
+ },
853
+ "autoload": {
854
+ "classmap": [
855
+ "src/"
856
+ ]
857
+ },
858
+ "notification-url": "https://packagist.org/downloads/",
859
+ "license": [
860
+ "BSD-3-Clause"
861
+ ],
862
+ "authors": [
863
+ {
864
+ "name": "Jeff Welch",
865
+ "email": "whatthejeff@gmail.com"
866
+ },
867
+ {
868
+ "name": "Sebastian Bergmann",
869
+ "email": "sebastian@phpunit.de"
870
+ },
871
+ {
872
+ "name": "Adam Harvey",
873
+ "email": "aharvey@php.net"
874
+ }
875
+ ],
876
+ "description": "Provides functionality to recursively process PHP variables",
877
+ "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
878
+ "time": "2015-11-11 19:50:13"
879
+ },
880
+ {
881
+ "name": "sebastian/version",
882
+ "version": "1.0.6",
883
+ "source": {
884
+ "type": "git",
885
+ "url": "https://github.com/sebastianbergmann/version.git",
886
+ "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6"
887
+ },
888
+ "dist": {
889
+ "type": "zip",
890
+ "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
891
+ "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
892
+ "shasum": ""
893
+ },
894
+ "type": "library",
895
+ "autoload": {
896
+ "classmap": [
897
+ "src/"
898
+ ]
899
+ },
900
+ "notification-url": "https://packagist.org/downloads/",
901
+ "license": [
902
+ "BSD-3-Clause"
903
+ ],
904
+ "authors": [
905
+ {
906
+ "name": "Sebastian Bergmann",
907
+ "email": "sebastian@phpunit.de",
908
+ "role": "lead"
909
+ }
910
+ ],
911
+ "description": "Library that helps with managing the version number of Git-hosted PHP projects",
912
+ "homepage": "https://github.com/sebastianbergmann/version",
913
+ "time": "2015-06-21 13:59:46"
914
+ },
915
+ {
916
+ "name": "symfony/yaml",
917
+ "version": "v2.8.4",
918
+ "source": {
919
+ "type": "git",
920
+ "url": "https://github.com/symfony/yaml.git",
921
+ "reference": "584e52cb8f788a887553ba82db6caacb1d6260bb"
922
+ },
923
+ "dist": {
924
+ "type": "zip",
925
+ "url": "https://api.github.com/repos/symfony/yaml/zipball/584e52cb8f788a887553ba82db6caacb1d6260bb",
926
+ "reference": "584e52cb8f788a887553ba82db6caacb1d6260bb",
927
+ "shasum": ""
928
+ },
929
+ "require": {
930
+ "php": ">=5.3.9"
931
+ },
932
+ "type": "library",
933
+ "extra": {
934
+ "branch-alias": {
935
+ "dev-master": "2.8-dev"
936
+ }
937
+ },
938
+ "autoload": {
939
+ "psr-4": {
940
+ "Symfony\\Component\\Yaml\\": ""
941
+ },
942
+ "exclude-from-classmap": [
943
+ "/Tests/"
944
+ ]
945
+ },
946
+ "notification-url": "https://packagist.org/downloads/",
947
+ "license": [
948
+ "MIT"
949
+ ],
950
+ "authors": [
951
+ {
952
+ "name": "Fabien Potencier",
953
+ "email": "fabien@symfony.com"
954
+ },
955
+ {
956
+ "name": "Symfony Community",
957
+ "homepage": "https://symfony.com/contributors"
958
+ }
959
+ ],
960
+ "description": "Symfony Yaml Component",
961
+ "homepage": "https://symfony.com",
962
+ "time": "2016-03-04 07:54:35"
963
+ }
964
+ ],
965
+ "aliases": [],
966
+ "minimum-stability": "stable",
967
+ "stability-flags": [],
968
+ "prefer-stable": false,
969
+ "prefer-lowest": false,
970
+ "platform": {
971
+ "php": ">=5.3.0",
972
+ "ext-curl": "*",
973
+ "ext-json": "*",
974
+ "lib-curl": ">=7.20.0"
975
+ },
976
+ "platform-dev": []
977
+ }
lib/TinyCompress/config/tinypng-api.ini DELETED
@@ -1,2 +0,0 @@
1
- [api]
2
- url = "https://api.tinypng.com/shrink"
 
 
lib/TinyCompress/lib/Tinify.php ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Tinify;
4
+
5
+ const VERSION = "1.3.0";
6
+
7
+ class Tinify {
8
+ private static $key = NULL;
9
+ private static $appIdentifier = NULL;
10
+ private static $compressionCount = NULL;
11
+ private static $client = NULL;
12
+
13
+ public static function setKey($key) {
14
+ self::$key = $key;
15
+ self::$client = NULL;
16
+ }
17
+
18
+ public static function setAppIdentifier($appIdentifier) {
19
+ self::$appIdentifier = $appIdentifier;
20
+ self::$client = NULL;
21
+ }
22
+
23
+ public static function getCompressionCount() {
24
+ return self::$compressionCount;
25
+ }
26
+
27
+ public static function setCompressionCount($compressionCount) {
28
+ self::$compressionCount = $compressionCount;
29
+ }
30
+
31
+ public static function getClient() {
32
+ if (!self::$key) {
33
+ throw new AccountException("Provide an API key with Tinify\setKey(...)");
34
+ }
35
+
36
+ if (!self::$client) {
37
+ self::$client = new Client(self::$key, self::$appIdentifier);
38
+ }
39
+
40
+ return self::$client;
41
+ }
42
+
43
+ public static function setClient($client) {
44
+ self::$client = $client;
45
+ }
46
+ }
47
+
48
+ function setKey($key) {
49
+ return Tinify::setKey($key);
50
+ }
51
+
52
+ function setAppIdentifier($appIdentifier) {
53
+ return Tinify::setAppIdentifier($appIdentifier);
54
+ }
55
+
56
+ function getCompressionCount() {
57
+ return Tinify::getCompressionCount();
58
+ }
59
+
60
+ function compressionCount() {
61
+ return Tinify::getCompressionCount();
62
+ }
63
+
64
+ function fromFile($path) {
65
+ return Source::fromFile($path);
66
+ }
67
+
68
+ function fromBuffer($string) {
69
+ return Source::fromBuffer($string);
70
+ }
71
+
72
+ function fromUrl($string) {
73
+ return Source::fromUrl($string);
74
+ }
75
+
76
+ function validate() {
77
+ try {
78
+ Tinify::getClient()->request("post", "/shrink");
79
+ } catch (AccountException $err) {
80
+ if ($err->status == 429) return true;
81
+ throw $err;
82
+ } catch (ClientException $err) {
83
+ return true;
84
+ }
85
+ }
lib/TinyCompress/lib/Tinify/Client.php ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Tinify;
4
+
5
+ class Client {
6
+ const API_ENDPOINT = "https://api.tinify.com";
7
+
8
+ private $options;
9
+
10
+ public static function userAgent() {
11
+ $curl = curl_version();
12
+ return "Tinify/" . VERSION . " PHP/" . PHP_VERSION . " curl/" . $curl["version"];
13
+ }
14
+
15
+ private static function caBundle() {
16
+ return __DIR__ . "/../data/cacert.pem";
17
+ }
18
+
19
+ function __construct($key, $app_identifier = NULL) {
20
+ $this->options = array(
21
+ CURLOPT_BINARYTRANSFER => true,
22
+ CURLOPT_RETURNTRANSFER => true,
23
+ CURLOPT_HEADER => true,
24
+ CURLOPT_USERPWD => "api:" . $key,
25
+ CURLOPT_CAINFO => self::caBundle(),
26
+ CURLOPT_SSL_VERIFYPEER => true,
27
+ CURLOPT_USERAGENT => join(" ", array_filter(array(self::userAgent(), $app_identifier))),
28
+ );
29
+ }
30
+
31
+ function request($method, $url, $body = NULL, $header = array()) {
32
+ if (is_array($body)) {
33
+ if (!empty($body)) {
34
+ $body = json_encode($body);
35
+ array_push($header, "Content-Type: application/json");
36
+ } else {
37
+ $body = NULL;
38
+ }
39
+ }
40
+
41
+ $request = curl_init();
42
+ curl_setopt_array($request, $this->options);
43
+
44
+ $url = strtolower(substr($url, 0, 6)) == "https:" ? $url : Client::API_ENDPOINT . $url;
45
+ curl_setopt($request, CURLOPT_URL, $url);
46
+ curl_setopt($request, CURLOPT_HTTPHEADER, $header);
47
+ curl_setopt($request, CURLOPT_CUSTOMREQUEST, strtoupper($method));
48
+
49
+ if ($body) {
50
+ curl_setopt($request, CURLOPT_POSTFIELDS, $body);
51
+ }
52
+
53
+ $response = curl_exec($request);
54
+
55
+ if (is_string($response)) {
56
+ $status = curl_getinfo($request, CURLINFO_HTTP_CODE);
57
+ $headerSize = curl_getinfo($request, CURLINFO_HEADER_SIZE);
58
+ curl_close($request);
59
+
60
+ $headers = self::parseHeaders(substr($response, 0, $headerSize));
61
+ $body = substr($response, $headerSize);
62
+
63
+ if (isset($headers["compression-count"])) {
64
+ Tinify::setCompressionCount(intval($headers["compression-count"]));
65
+ }
66
+
67
+ if ($status >= 200 && $status <= 299) {
68
+ return array("body" => $body, "headers" => $headers);
69
+ }
70
+
71
+ $details = json_decode($body);
72
+ if (!$details) {
73
+ $message = sprintf("Error while parsing response: %s (#%d)",
74
+ PHP_VERSION_ID >= 50500 ? json_last_error_msg() : "Error",
75
+ json_last_error());
76
+ $details = (object) array(
77
+ "message" => $message,
78
+ "error" => "ParseError"
79
+ );
80
+ }
81
+
82
+ throw Exception::create($details->message, $details->error, $status);
83
+ } else {
84
+ $message = sprintf("%s (#%d)", curl_error($request), curl_errno($request));
85
+ curl_close($request);
86
+ throw new ConnectionException("Error while connecting: " . $message);
87
+ }
88
+ }
89
+
90
+ protected static function parseHeaders($headers) {
91
+ if (!is_array($headers)) {
92
+ $headers = explode("\r\n", $headers);
93
+ }
94
+
95
+ $res = array();
96
+ foreach ($headers as $header) {
97
+ if (empty($header)) continue;
98
+ $split = explode(":", $header, 2);
99
+ if (count($split) === 2) {
100
+ $res[strtolower($split[0])] = trim($split[1]);
101
+ }
102
+ }
103
+ return $res;
104
+ }
105
+ }
lib/TinyCompress/lib/Tinify/Exception.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Tinify;
4
+
5
+ class Exception extends \Exception {
6
+ public static function create($message, $type, $status) {
7
+ if ($status == 401 || $status == 429) {
8
+ $klass = "Tinify\AccountException";
9
+ } else if($status >= 400 && $status <= 499) {
10
+ $klass = "Tinify\ClientException";
11
+ } else if($status >= 500 && $status <= 599) {
12
+ $klass = "Tinify\ServerException";
13
+ } else {
14
+ $klass = "Tinify\Exception";
15
+ }
16
+
17
+ if (empty($message)) $message = "No message was provided";
18
+ return new $klass($message, $type, $status);
19
+ }
20
+
21
+ function __construct($message, $type = NULL, $status = NULL) {
22
+ if ($status) {
23
+ $this->status = $status;
24
+ parent::__construct($message . " (HTTP " . $status . "/" . $type . ")");
25
+ } else {
26
+ parent::__construct($message);
27
+ }
28
+ }
29
+ }
30
+
31
+ class AccountException extends Exception {}
32
+ class ClientException extends Exception {}
33
+ class ServerException extends Exception {}
34
+ class ConnectionException extends Exception {}
lib/TinyCompress/lib/Tinify/Result.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Tinify;
4
+
5
+ class Result extends ResultMeta {
6
+ protected $data;
7
+
8
+ public function __construct($meta, $data) {
9
+ $this->meta = $meta;
10
+ $this->data = $data;
11
+ }
12
+
13
+ public function data() {
14
+ return $this->data;
15
+ }
16
+
17
+ public function toBuffer() {
18
+ return $this->data;
19
+ }
20
+
21
+ public function toFile($path) {
22
+ return file_put_contents($path, $this->toBuffer());
23
+ }
24
+
25
+ public function size() {
26
+ return intval($this->meta["content-length"]);
27
+ }
28
+
29
+ public function mediaType() {
30
+ return $this->meta["content-type"];
31
+ }
32
+
33
+ public function contentType() {
34
+ return $this->mediaType();
35
+ }
36
+ }
lib/TinyCompress/lib/Tinify/ResultMeta.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Tinify;
4
+
5
+ class ResultMeta {
6
+ protected $meta;
7
+
8
+ public function __construct($meta) {
9
+ $this->meta = $meta;
10
+ }
11
+
12
+ public function width() {
13
+ return intval($this->meta["image-width"]);
14
+ }
15
+
16
+ public function height() {
17
+ return intval($this->meta["image-height"]);
18
+ }
19
+
20
+ public function location() {
21
+ return isset($this->meta["location"]) ? $this->meta["location"] : null;
22
+ }
23
+ }
lib/TinyCompress/lib/Tinify/Source.php ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Tinify;
4
+
5
+ class Source {
6
+ private $url, $commands;
7
+
8
+ public static function fromFile($path) {
9
+ return self::fromBuffer(file_get_contents($path));
10
+ }
11
+
12
+ public static function fromBuffer($string) {
13
+ $response = Tinify::getClient()->request("post", "/shrink", $string);
14
+ return new self($response["headers"]["location"]);
15
+ }
16
+
17
+ public static function fromUrl($url) {
18
+ $body = array("source" => array("url" => $url));
19
+ $response = Tinify::getClient()->request("post", "/shrink", $body);
20
+ return new self($response["headers"]["location"]);
21
+ }
22
+
23
+ public function __construct($url, $commands = array()) {
24
+ $this->url = $url;
25
+ $this->commands = $commands;
26
+ }
27
+
28
+ public function preserve() {
29
+ $options = $this->flatten(func_get_args());
30
+ $commands = array_merge($this->commands, array("preserve" => $options));
31
+ return new self($this->url, $commands);
32
+ }
33
+
34
+ public function resize($options) {
35
+ $commands = array_merge($this->commands, array("resize" => $options));
36
+ return new self($this->url, $commands);
37
+ }
38
+
39
+ public function store($options) {
40
+ $response = Tinify::getClient()->request("post", $this->url,
41
+ array_merge($this->commands, array("store" => $options)));
42
+ return new Result($response["headers"], $response["body"]);
43
+ }
44
+
45
+ public function result() {
46
+ $response = Tinify::getClient()->request("get", $this->url, $this->commands);
47
+ return new Result($response["headers"], $response["body"]);
48
+ }
49
+
50
+ public function toFile($path) {
51
+ return $this->result()->toFile($path);
52
+ }
53
+
54
+ public function toBuffer() {
55
+ return $this->result()->toBuffer();
56
+ }
57
+
58
+ private static function flatten($options) {
59
+ $flattened = array();
60
+ foreach ($options as $option) {
61
+ if (is_array($option)) {
62
+ $flattened = array_merge($flattened, $option);
63
+ } else {
64
+ array_push($flattened, $option);
65
+ }
66
+ }
67
+ return $flattened;
68
+ }
69
+ }
lib/TinyCompress/{cacert.pem → lib/data/cacert.pem} RENAMED
@@ -1,7 +1,7 @@
1
  ##
2
  ## Bundle of CA Root Certificates
3
  ##
4
- ## Certificate data from Mozilla downloaded on: Wed Sep 3 03:12:03 2014
5
  ##
6
  ## This is a bundle of X.509 certificates of public Certificate Authorities
7
  ## (CA). These were automatically extracted from Mozilla's root certificates
@@ -13,66 +13,11 @@
13
  ## an Apache+mod_ssl webserver for SSL client authentication.
14
  ## Just configure this file as the SSLCACertificateFile.
15
  ##
16
- ## Conversion done with mk-ca-bundle.pl verison 1.22.
17
- ## SHA1: c4540021427a6fa29e5f50db9f12d48c97d33889
18
  ##
19
 
20
 
21
- GTE CyberTrust Global Root
22
- ==========================
23
- -----BEGIN CERTIFICATE-----
24
- MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9HVEUg
25
- Q29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNvbHV0aW9ucywgSW5jLjEjMCEG
26
- A1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJvb3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEz
27
- MjM1OTAwWjB1MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQL
28
- Ex5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0
29
- IEdsb2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4u
30
- sJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcql
31
- HHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8FLztimQID
32
- AQABMA0GCSqGSIb3DQEBBAUAA4GBAG3rGwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMW
33
- M4ETCJ57NE7fQMh017l93PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OF
34
- NMQkpw0PlZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/
35
- -----END CERTIFICATE-----
36
-
37
- Thawte Server CA
38
- ================
39
- -----BEGIN CERTIFICATE-----
40
- MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT
41
- DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs
42
- dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UE
43
- AxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5j
44
- b20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNV
45
- BAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29u
46
- c3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcG
47
- A1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0
48
- ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl
49
- /Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg7
50
- 1CcEJRCXL+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzAR
51
- MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWDTSEwjsrZqG9J
52
- GubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6eQNuozDJ0uW8NxuOzRAvZim+aKZuZ
53
- GCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc=
54
- -----END CERTIFICATE-----
55
-
56
- Thawte Premium Server CA
57
- ========================
58
- -----BEGIN CERTIFICATE-----
59
- MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkExFTATBgNVBAgT
60
- DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs
61
- dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UE
62
- AxMYVGhhd3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZl
63
- ckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYT
64
- AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMU
65
- VGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2
66
- aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3DQEJARYZ
67
- cHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2
68
- aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIh
69
- Udib0GfQug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/
70
- qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQAm
71
- SCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUIhfzJATj/Tb7yFkJD57taRvvBxhEf
72
- 8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7t
73
- UCemDaYj+bvLpgcUQg==
74
- -----END CERTIFICATE-----
75
-
76
  Equifax Secure CA
77
  =================
78
  -----BEGIN CERTIFICATE-----
@@ -93,25 +38,6 @@ BIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee95
93
  70+sB3c4
94
  -----END CERTIFICATE-----
95
 
96
- Verisign Class 3 Public Primary Certification Authority - G2
97
- ============================================================
98
- -----BEGIN CERTIFICATE-----
99
- MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJBgNVBAYTAlVT
100
- MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy
101
- eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln
102
- biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz
103
- dCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVT
104
- MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy
105
- eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln
106
- biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz
107
- dCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCO
108
- FoUgRm1HP9SFIIThbbP4pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71
109
- lSk8UOg013gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwIDAQAB
110
- MA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSkU01UbSuvDV1Ai2TT
111
- 1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7iF6YM40AIOw7n60RzKprxaZLvcRTD
112
- Oaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpYoJ2daZH9
113
- -----END CERTIFICATE-----
114
-
115
  GlobalSign Root CA
116
  ==================
117
  -----BEGIN CERTIFICATE-----
@@ -248,40 +174,6 @@ Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H
248
  RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
249
  -----END CERTIFICATE-----
250
 
251
- Equifax Secure Global eBusiness CA
252
- ==================================
253
- -----BEGIN CERTIFICATE-----
254
- MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT
255
- RXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBTZWN1cmUgR2xvYmFsIGVCdXNp
256
- bmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIwMDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMx
257
- HDAaBgNVBAoTE0VxdWlmYXggU2VjdXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEds
258
- b2JhbCBlQnVzaW5lc3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRV
259
- PEnCUdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc58O/gGzN
260
- qfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/o5brhTMhHD4ePmBudpxn
261
- hcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAHMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j
262
- BBgwFoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hs
263
- MA0GCSqGSIb3DQEBBAUAA4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okEN
264
- I7SS+RkAZ70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv8qIY
265
- NMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV
266
- -----END CERTIFICATE-----
267
-
268
- Equifax Secure eBusiness CA 1
269
- =============================
270
- -----BEGIN CERTIFICATE-----
271
- MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT
272
- RXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENB
273
- LTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQwMDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UE
274
- ChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNz
275
- IENBLTEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ
276
- 1MRoRvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBuWqDZQu4a
277
- IZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKwEnv+j6YDAgMBAAGjZjBk
278
- MBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEp4MlIR21kW
279
- Nl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRKeDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQF
280
- AAOBgQB1W6ibAxHm6VZMzfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5
281
- lSE/9dR+WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN/Bf+
282
- KpYrtWKmpj29f5JZzVoqgrI3eQ==
283
- -----END CERTIFICATE-----
284
-
285
  AddTrust Low-Value Services Root
286
  ================================
287
  -----BEGIN CERTIFICATE-----
@@ -527,59 +419,6 @@ gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm
527
  X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS
528
  -----END CERTIFICATE-----
529
 
530
- America Online Root Certification Authority 1
531
- =============================================
532
- -----BEGIN CERTIFICATE-----
533
- MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT
534
- QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp
535
- Y2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkG
536
- A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg
537
- T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQAD
538
- ggEPADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lkhsmj76CG
539
- v2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym1BW32J/X3HGrfpq/m44z
540
- DyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsWOqMFf6Dch9Wc/HKpoH145LcxVR5lu9Rh
541
- sCFg7RAycsWSJR74kEoYeEfffjA3PlAb2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP
542
- 8c9GsEsPPt2IYriMqQkoO3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0T
543
- AQH/BAUwAwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAUAK3Z
544
- o/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQB8itEf
545
- GDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkFZu90821fnZmv9ov761KyBZiibyrF
546
- VL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAbLjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft
547
- 3OJvx8Fi8eNy1gTIdGcL+oiroQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43g
548
- Kd8hdIaC2y+CMMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds
549
- sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7
550
- -----END CERTIFICATE-----
551
-
552
- America Online Root Certification Authority 2
553
- =============================================
554
- -----BEGIN CERTIFICATE-----
555
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- +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
- 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
- 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
- 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
- 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
- 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
- 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
580
- cX/9XhmgD0uRuMRUvAawRY8mkaKO/qk=
581
- -----END CERTIFICATE-----
582
-
583
  Visa eCommerce Root
584
  ===================
585
  -----BEGIN CERTIFICATE-----
@@ -1777,33 +1616,6 @@ JOzHdiEoZa5X6AeIdUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfk
1777
  vQ==
1778
  -----END CERTIFICATE-----
1779
 
1780
- TC TrustCenter Class 3 CA II
1781
- ============================
1782
- -----BEGIN CERTIFICATE-----
1783
- MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC
1784
- REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy
1785
- IENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYw
1786
- MTEyMTQ0MTU3WhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1
1787
- c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UE
1788
- AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
1789
- AQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJWHt4bNwcwIi9v8Qbxq63W
1790
- yKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+QVl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo
1791
- 6SI7dYnWRBpl8huXJh0obazovVkdKyT21oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZ
1792
- uV3bOx4a+9P/FRQI2AlqukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk
1793
- 2ZyqBwi1Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1UdEwEB
1794
- /wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NXXAek0CSnwPIA1DCB
1795
- 7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90
1796
- Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU
1797
- cnVzdENlbnRlciUyMENsYXNzJTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i
1798
- SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u
1799
- TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlNirTzwppVMXzE
1800
- O2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8TtXqluJucsG7Kv5sbviRmEb8
1801
- yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9
1802
- IJqDnxrcOfHFcqMRA/07QlIp2+gB95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal
1803
- 092Y+tTmBvTwtiBjS+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc
1804
- 5A==
1805
- -----END CERTIFICATE-----
1806
-
1807
  TC TrustCenter Universal CA I
1808
  =============================
1809
  -----BEGIN CERTIFICATE-----
@@ -2421,28 +2233,6 @@ yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi
2421
  LXpUq3DDfSJlgnCW
2422
  -----END CERTIFICATE-----
2423
 
2424
- E-Guven Kok Elektronik Sertifika Hizmet Saglayicisi
2425
- ===================================================
2426
- -----BEGIN CERTIFICATE-----
2427
- MIIDtjCCAp6gAwIBAgIQRJmNPMADJ72cdpW56tustTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG
2428
- EwJUUjEoMCYGA1UEChMfRWxla3Ryb25payBCaWxnaSBHdXZlbmxpZ2kgQS5TLjE8MDoGA1UEAxMz
2429
- ZS1HdXZlbiBLb2sgRWxla3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhZ2xheWljaXNpMB4XDTA3
2430
- MDEwNDExMzI0OFoXDTE3MDEwNDExMzI0OFowdTELMAkGA1UEBhMCVFIxKDAmBgNVBAoTH0VsZWt0
2431
- cm9uaWsgQmlsZ2kgR3V2ZW5saWdpIEEuUy4xPDA6BgNVBAMTM2UtR3V2ZW4gS29rIEVsZWt0cm9u
2432
- aWsgU2VydGlmaWthIEhpem1ldCBTYWdsYXlpY2lzaTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
2433
- AQoCggEBAMMSIJ6wXgBljU5Gu4Bc6SwGl9XzcslwuedLZYDBS75+PNdUMZTe1RK6UxYC6lhj71vY
2434
- 8+0qGqpxSKPcEC1fX+tcS5yWCEIlKBHMilpiAVDV6wlTL/jDj/6z/P2douNffb7tC+Bg62nsM+3Y
2435
- jfsSSYMAyYuXjDtzKjKzEve5TfL0TW3H5tYmNwjy2f1rXKPlSFxYvEK+A1qBuhw1DADT9SN+cTAI
2436
- JjjcJRFHLfO6IxClv7wC90Nex/6wN1CZew+TzuZDLMN+DfIcQ2Zgy2ExR4ejT669VmxMvLz4Bcpk
2437
- 9Ok0oSy1c+HCPujIyTQlCFzz7abHlJ+tiEMl1+E5YP6sOVkCAwEAAaNCMEAwDgYDVR0PAQH/BAQD
2438
- AgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJ/uRLOU1fqRTy7ZVZoEVtstxNulMA0GCSqG
2439
- SIb3DQEBBQUAA4IBAQB/X7lTW2M9dTLn+sR0GstG30ZpHFLPqk/CaOv/gKlR6D1id4k9CnU58W5d
2440
- F4dvaAXBlGzZXd/aslnLpRCKysw5zZ/rTt5S/wzw9JKp8mxTq5vSR6AfdPebmvEvFZ96ZDAYBzwq
2441
- D2fK/A+JYZ1lpTzlvBNbCNvj/+27BrtqBrF6T2XGgv0enIu1De5Iu7i9qgi0+6N8y5/NkHZchpZ4
2442
- Vwpm+Vganf2XKWDeEaaQHBkc7gGWIjQ0LpH5t8Qn0Xvmv/uARFoW5evg1Ao4vOSR49XrXMGs3xtq
2443
- fJ7lddK2l4fbzIcrQzqECK+rPNv3PGYxhrCdU3nt+CPeQuMtgvEP5fqX
2444
- -----END CERTIFICATE-----
2445
-
2446
  GlobalSign Root CA - R3
2447
  =======================
2448
  -----BEGIN CERTIFICATE-----
@@ -3892,3 +3682,307 @@ ONFLAzkopR6RctR9q5czxNM+4Gm2KHmgCY0c0f9BckgG/Jou5yD5m6Leie2uPAmvylezkolwQOQv
3892
  T8Jwg0DXJCxr5wkf09XHwQj02w47HAcLQxGEIYbpgNR12KvxAmLBsX5VYc8T1yaw15zLKYs4SgsO
3893
  kI26oQ==
3894
  -----END CERTIFICATE-----
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ##
2
  ## Bundle of CA Root Certificates
3
  ##
4
+ ## Certificate data from Mozilla as of: Wed Apr 22 03:12:04 2015
5
  ##
6
  ## This is a bundle of X.509 certificates of public Certificate Authorities
7
  ## (CA). These were automatically extracted from Mozilla's root certificates
13
  ## an Apache+mod_ssl webserver for SSL client authentication.
14
  ## Just configure this file as the SSLCACertificateFile.
15
  ##
16
+ ## Conversion done with mk-ca-bundle.pl version 1.25.
17
+ ## SHA1: ed3c0bbfb7912bcc00cd2033b0cb85c98d10559c
18
  ##
19
 
20
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  Equifax Secure CA
22
  =================
23
  -----BEGIN CERTIFICATE-----
38
  70+sB3c4
39
  -----END CERTIFICATE-----
40
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  GlobalSign Root CA
42
  ==================
43
  -----BEGIN CERTIFICATE-----
174
  RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
175
  -----END CERTIFICATE-----
176
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
  AddTrust Low-Value Services Root
178
  ================================
179
  -----BEGIN CERTIFICATE-----
419
  X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS
420
  -----END CERTIFICATE-----
421
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
422
  Visa eCommerce Root
423
  ===================
424
  -----BEGIN CERTIFICATE-----
1616
  vQ==
1617
  -----END CERTIFICATE-----
1618
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1619
  TC TrustCenter Universal CA I
1620
  =============================
1621
  -----BEGIN CERTIFICATE-----
2233
  LXpUq3DDfSJlgnCW
2234
  -----END CERTIFICATE-----
2235
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2236
  GlobalSign Root CA - R3
2237
  =======================
2238
  -----BEGIN CERTIFICATE-----
3682
  T8Jwg0DXJCxr5wkf09XHwQj02w47HAcLQxGEIYbpgNR12KvxAmLBsX5VYc8T1yaw15zLKYs4SgsO
3683
  kI26oQ==
3684
  -----END CERTIFICATE-----
3685
+
3686
+ COMODO RSA Certification Authority
3687
+ ==================================
3688
+ -----BEGIN CERTIFICATE-----
3689
+ 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
3715
+ LaZRfyHBNVOFBkpdn627G190
3716
+ -----END CERTIFICATE-----
3717
+
3718
+ USERTrust RSA Certification Authority
3719
+ =====================================
3720
+ -----BEGIN CERTIFICATE-----
3721
+ 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
3747
+ Q+6IHdfGjjxDah2nGN59PRbxYvnKkKj9
3748
+ -----END CERTIFICATE-----
3749
+
3750
+ USERTrust ECC Certification Authority
3751
+ =====================================
3752
+ -----BEGIN CERTIFICATE-----
3753
+ MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDELMAkGA1UEBhMC
3754
+ VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
3755
+ aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv
3756
+ biBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMC
3757
+ VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
3758
+ aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv
3759
+ biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqfloI+d61SRvU8Za2EurxtW2
3760
+ 0eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinngo4N+LZfQYcTxmdwlkWOrfzCjtHDix6Ez
3761
+ nPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0GA1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNV
3762
+ HQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBB
3763
+ HU6+4WMBzzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbWRNZu
3764
+ 9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg=
3765
+ -----END CERTIFICATE-----
3766
+
3767
+ GlobalSign ECC Root CA - R4
3768
+ ===========================
3769
+ -----BEGIN CERTIFICATE-----
3770
+ MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEkMCIGA1UECxMb
3771
+ R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
3772
+ EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb
3773
+ R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
3774
+ EwpHbG9iYWxTaWduMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprl
3775
+ OQcJFspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAwDgYDVR0P
3776
+ AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61FuOJAf/sKbvu+M8k8o4TV
3777
+ MAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGXkPoUVy0D7O48027KqGx2vKLeuwIgJ6iF
3778
+ JzWbVsaj8kfSt24bAgAXqmemFZHe+pTsewv4n4Q=
3779
+ -----END CERTIFICATE-----
3780
+
3781
+ GlobalSign ECC Root CA - R5
3782
+ ===========================
3783
+ -----BEGIN CERTIFICATE-----
3784
+ MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEkMCIGA1UECxMb
3785
+ R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
3786
+ EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb
3787
+ R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
3788
+ EwpHbG9iYWxTaWduMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6
3789
+ SFkc8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8kehOvRnkmS
3790
+ h5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd
3791
+ BgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYIKoZIzj0EAwMDaAAwZQIxAOVpEslu28Yx
3792
+ uglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7
3793
+ yFz9SO8NdCKoCOJuxUnOxwy8p2Fp8fc74SrL+SvzZpA3
3794
+ -----END CERTIFICATE-----
3795
+
3796
+ Staat der Nederlanden Root CA - G3
3797
+ ==================================
3798
+ -----BEGIN CERTIFICATE-----
3799
+ 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
3824
+ -----END CERTIFICATE-----
3825
+
3826
+ Staat der Nederlanden EV Root CA
3827
+ ================================
3828
+ -----BEGIN CERTIFICATE-----
3829
+ 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
3853
+ eUN51q1veieQA6TqJIc/2b3Z6fJfUEkc7uzXLg==
3854
+ -----END CERTIFICATE-----
3855
+
3856
+ IdenTrust Commercial Root CA 1
3857
+ ==============================
3858
+ -----BEGIN CERTIFICATE-----
3859
+ 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
3883
+ cGzM7vRX+Bi6hG6H
3884
+ -----END CERTIFICATE-----
3885
+
3886
+ IdenTrust Public Sector Root CA 1
3887
+ =================================
3888
+ -----BEGIN CERTIFICATE-----
3889
+ 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
3913
+ 3Wl9af0AVqW3rLatt8o+Ae+c
3914
+ -----END CERTIFICATE-----
3915
+
3916
+ Entrust Root Certification Authority - G2
3917
+ =========================================
3918
+ -----BEGIN CERTIFICATE-----
3919
+ MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMCVVMxFjAUBgNV
3920
+ BAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVy
3921
+ bXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ug
3922
+ b25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIw
3923
+ HhcNMDkwNzA3MTcyNTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoT
3924
+ DUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMx
3925
+ OTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25s
3926
+ eTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwggEi
3927
+ MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP
3928
+ /vaCeb9zYQYKpSfYs1/TRU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXz
3929
+ HHfV1IWNcCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hWwcKU
3930
+ s/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1U1+cPvQXLOZprE4y
3931
+ TGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0jaWvYkxN4FisZDQSA/i2jZRjJKRx
3932
+ AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ6
3933
+ 0B7vfec7aVHUbI2fkBJmqzANBgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5Z
3934
+ iXMRrEPR9RP/jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ
3935
+ Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v1fN2D807iDgi
3936
+ nWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4RnAuknZoh8/CbCzB428Hch0P+
3937
+ vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmHVHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xO
3938
+ e4pIb4tF9g==
3939
+ -----END CERTIFICATE-----
3940
+
3941
+ Entrust Root Certification Authority - EC1
3942
+ ==========================================
3943
+ -----BEGIN CERTIFICATE-----
3944
+ MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkGA1UEBhMCVVMx
3945
+ FjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVn
3946
+ YWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXpl
3947
+ ZCB1c2Ugb25seTEzMDEGA1UEAxMqRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5
3948
+ IC0gRUMxMB4XDTEyMTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYw
3949
+ FAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2Fs
3950
+ LXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQg
3951
+ dXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt
3952
+ IEVDMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHy
3953
+ AsWfoPZb1YsGGYZPUxBtByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef
3954
+ 9eNi1KlHBz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
3955
+ FLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVCR98crlOZF7ZvHH3h
3956
+ vxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nXhTcGtXsI/esni0qU+eH6p44mCOh8
3957
+ kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G
3958
+ -----END CERTIFICATE-----
3959
+
3960
+ CFCA EV ROOT
3961
+ ============
3962
+ -----BEGIN CERTIFICATE-----
3963
+ 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
3988
+ -----END CERTIFICATE-----
lib/TinyCompress/phpunit.xml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <phpunit bootstrap="test/helper.php" colors="true">
2
+ <testsuites>
3
+ <testsuite name="Tinify PHP Test Suite">
4
+ <directory suffix="Test.php">test</directory>
5
+ </testsuite>
6
+ </testsuites>
7
+ <filter>
8
+ <whitelist>
9
+ <directory>lib</directory>
10
+ </whitelist>
11
+ </filter>
12
+ </phpunit>
lib/TinyCompress/test/TinifyClientTest.php ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use Tinify\CurlMock;
4
+
5
+ class TinifyClientTest extends TestCase {
6
+ public function testRequestWhenValidShouldIssueRequest() {
7
+ CurlMock::register("https://api.tinify.com/", array("status" => 200));
8
+ $client = new Tinify\Client("key");
9
+ $client->request("get", "/");
10
+
11
+ $this->assertSame("https://api.tinify.com/", CurlMock::last(CURLOPT_URL));
12
+ $this->assertSame("api:key", CurlMock::last(CURLOPT_USERPWD));
13
+ }
14
+
15
+ public function testRequestWhenValidShouldIssueRequestWithoutBodyWhenOptionsAreEmpty() {
16
+ CurlMock::register("https://api.tinify.com/", array("status" => 200));
17
+ $client = new Tinify\Client("key");
18
+ $client->request("get", "/", array());
19
+
20
+ $this->assertFalse(CurlMock::last_has(CURLOPT_POSTFIELDS));
21
+ }
22
+
23
+ public function testRequestWhenValidShouldIssueRequestWithoutContentTypeWhenOptionsAreEmpty() {
24
+ CurlMock::register("https://api.tinify.com/", array("status" => 200));
25
+ $client = new Tinify\Client("key");
26
+ $client->request("get", "/", array());
27
+
28
+ $this->assertSame(array(), CurlMock::last(CURLOPT_HTTPHEADER));
29
+ }
30
+
31
+ public function testRequestWhenValidShouldIssueRequestWithJSONBody() {
32
+ CurlMock::register("https://api.tinify.com/", array("status" => 200));
33
+ $client = new Tinify\Client("key");
34
+ $client->request("get", "/", array("hello" => "world"));
35
+
36
+ $this->assertSame(array("Content-Type: application/json"), CurlMock::last(CURLOPT_HTTPHEADER));
37
+ $this->assertSame('{"hello":"world"}', CurlMock::last(CURLOPT_POSTFIELDS));
38
+ }
39
+
40
+ public function testRequestWhenValidShouldIssueRequestWithUserAgent() {
41
+ CurlMock::register("https://api.tinify.com/", array("status" => 200));
42
+ $client = new Tinify\Client("key");
43
+ $client->request("get", "/");
44
+
45
+ $curl = curl_version();
46
+ $this->assertSame(Tinify\Client::userAgent(), CurlMock::last(CURLOPT_USERAGENT));
47
+ }
48
+
49
+ public function testRequestWhenValidShouldUpdateCompressionCount() {
50
+ CurlMock::register("https://api.tinify.com/", array(
51
+ "status" => 200, "headers" => array("Compression-Count" => "12")
52
+ ));
53
+ $client = new Tinify\Client("key");
54
+ $client->request("get", "/");
55
+
56
+ $this->assertSame(12, Tinify\getCompressionCount());
57
+ }
58
+
59
+ public function testRequestWhenValidWithAppIdShouldIssueRequestWithUserAgent() {
60
+ CurlMock::register("https://api.tinify.com/", array("status" => 200));
61
+ $client = new Tinify\Client("key", "TestApp/0.1");
62
+ $client->request("get", "/");
63
+
64
+ $curl = curl_version();
65
+ $this->assertSame(Tinify\Client::userAgent() . " TestApp/0.1", CurlMock::last(CURLOPT_USERAGENT));
66
+ }
67
+
68
+ public function testRequestWithUnexpectedErrorShouldThrowConnectionException() {
69
+ CurlMock::register("https://api.tinify.com/", array(
70
+ "error" => "Failed!", "errno" => 2
71
+ ));
72
+ $this->setExpectedException("Tinify\ConnectionException");
73
+ $client = new Tinify\Client("key");
74
+ $client->request("get", "/");
75
+ }
76
+
77
+ public function testRequestWithUnexpectedErrorShouldThrowExceptionWithMessage() {
78
+ CurlMock::register("https://api.tinify.com/", array(
79
+ "error" => "Failed!", "errno" => 2
80
+ ));
81
+ $this->setExpectedExceptionRegExp("Tinify\ConnectionException",
82
+ "/Error while connecting: Failed! \(#2\)/");
83
+ $client = new Tinify\Client("key");
84
+ $client->request("get", "/");
85
+ }
86
+
87
+ public function testRequestWithCurlErrorShouldThrowConnectionError() {
88
+ CurlMock::register("https://api.tinify.com/", array(
89
+ "errno" => 0, "error" => "", "return" => null
90
+ ));
91
+ $this->setExpectedException("Tinify\ConnectionException");
92
+ $client = new Tinify\Client("key");
93
+ $client->request("get", "/");
94
+ }
95
+
96
+ public function testRequestWithServerErrorShouldThrowServerException() {
97
+ CurlMock::register("https://api.tinify.com/", array(
98
+ "status" => 584, "body" => '{"error":"InternalServerError","message":"Oops!"}'
99
+ ));
100
+ $this->setExpectedException("Tinify\ServerException");
101
+ $client = new Tinify\Client("key");
102
+ $client->request("get", "/");
103
+ }
104
+
105
+ public function testRequestWithServerErrorShouldThrowExceptionWithMessage() {
106
+ CurlMock::register("https://api.tinify.com/", array(
107
+ "status" => 584, "body" => '{"error":"InternalServerError","message":"Oops!"}'
108
+ ));
109
+ $this->setExpectedExceptionRegExp("Tinify\ServerException",
110
+ "/Oops! \(HTTP 584\/InternalServerError\)/");
111
+ $client = new Tinify\Client("key");
112
+ $client->request("get", "/");
113
+ }
114
+
115
+ public function testRequestWithBadServerResponseShouldThrowServerException() {
116
+ CurlMock::register("https://api.tinify.com/", array(
117
+ "status" => 543, "body" => '<!-- this is not json -->'
118
+ ));
119
+ $this->setExpectedException("Tinify\ServerException");
120
+ $client = new Tinify\Client("key");
121
+ $client->request("get", "/");
122
+ }
123
+
124
+ public function testRequestWithBadServerResponseShouldThrowExceptionWithMessage() {
125
+ CurlMock::register("https://api.tinify.com/", array(
126
+ "status" => 543, "body" => '<!-- this is not json -->'
127
+ ));
128
+ if (PHP_VERSION_ID >= 50500) {
129
+ $this->setExpectedExceptionRegExp("Tinify\ServerException",
130
+ "/Error while parsing response: Syntax error \(#4\) \(HTTP 543\/ParseError\)/");
131
+ } else {
132
+ $this->setExpectedExceptionRegExp("Tinify\ServerException",
133
+ "/Error while parsing response: Error \(#4\) \(HTTP 543\/ParseError\)/");
134
+ }
135
+ $client = new Tinify\Client("key");
136
+ $client->request("get", "/");
137
+ }
138
+
139
+ public function testRequestWithClientErrorShouldThrowClientException() {
140
+ CurlMock::register("https://api.tinify.com/", array(
141
+ "status" => 492, "body" => '{"error":"BadRequest","message":"Oops!"}')
142
+ );
143
+ $this->setExpectedException("Tinify\ClientException");
144
+ $client = new Tinify\Client("key");
145
+ $client->request("get", "/");
146
+ }
147
+
148
+ public function testRequestWithClientErrorShouldThrowExceptionWithMessage() {
149
+ CurlMock::register("https://api.tinify.com/", array(
150
+ "status" => 492, "body" => '{"error":"BadRequest","message":"Oops!"}'
151
+ ));
152
+ $this->setExpectedExceptionRegExp("Tinify\ClientException",
153
+ "/Oops! \(HTTP 492\/BadRequest\)/");
154
+ $client = new Tinify\Client("key");
155
+ $client->request("get", "/");
156
+ }
157
+
158
+ public function testRequestWithBadCredentialsShouldThrowAccountException() {
159
+ CurlMock::register("https://api.tinify.com/", array(
160
+ "status" => 401, "body" => '{"error":"Unauthorized","message":"Oops!"}'
161
+ ));
162
+ $this->setExpectedException("Tinify\AccountException");
163
+ $client = new Tinify\Client("key");
164
+ $client->request("get", "/");
165
+ }
166
+
167
+ public function testRequestWithBadCredentialsShouldThrowExceptionWithMessage() {
168
+ CurlMock::register("https://api.tinify.com/", array(
169
+ "status" => 401, "body" => '{"error":"Unauthorized","message":"Oops!"}'
170
+ ));
171
+ $this->setExpectedExceptionRegExp("Tinify\AccountException",
172
+ "/Oops! \(HTTP 401\/Unauthorized\)/");
173
+ $client = new Tinify\Client("key");
174
+ $client->request("get", "/");
175
+ }
176
+ }
lib/TinyCompress/test/TinifyResultMetaTest.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use Tinify\CurlMock;
4
+
5
+ class TinifyResultMetaTest extends TestCase {
6
+ public function testWithMetadataWidthShouldReturnImageWidth() {
7
+ $result = new Tinify\ResultMeta(array("image-width" => "100"));
8
+ $this->assertSame(100, $result->width());
9
+ }
10
+
11
+ public function testWithMetadataHeightShouldReturnImageHeight() {
12
+ $result = new Tinify\ResultMeta(array("image-height" => "60"));
13
+ $this->assertSame(60, $result->height());
14
+ }
15
+
16
+ public function testWithMetadataLocationShouldReturnImageLocation() {
17
+ $result = new Tinify\ResultMeta(array("location" => "https://example.com/image.png"));
18
+ $this->assertSame("https://example.com/image.png", $result->location());
19
+ }
20
+ }
lib/TinyCompress/test/TinifyResultTest.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use Tinify\CurlMock;
4
+
5
+ class TinifyResultTest extends TestCase {
6
+ public function testWithMetaAndDataWidthShouldReturnImageWidth() {
7
+ $result = new Tinify\Result(array("image-width" => "100"), "image data");
8
+ $this->assertSame(100, $result->width());
9
+ }
10
+
11
+ public function testWithMetaAndDataHeightShouldReturnImageHeight() {
12
+ $result = new Tinify\Result(array("image-height" => "60"), "image data");
13
+ $this->assertSame(60, $result->height());
14
+ }
15
+
16
+ public function testWithMetaAndDataLocationShouldReturnNull() {
17
+ $result = new Tinify\ResultMeta(array(), "image data");
18
+ $this->assertSame(null, $result->location());
19
+ }
20
+
21
+ public function testWithMetaAndDataSizeShouldReturnContentLength() {
22
+ $result = new Tinify\Result(array("content-length" => "450"), "image data");
23
+ $this->assertSame(450, $result->size());
24
+ }
25
+
26
+ public function testWithMetaAndDataContentTypeShouldReturnMimeType() {
27
+ $result = new Tinify\Result(array("content-type" => "image/png"), "image data");
28
+ $this->assertSame("image/png", $result->contentType());
29
+ }
30
+
31
+ public function testWithMetaAndDataToBufferShouldReturnImageData() {
32
+ $result = new Tinify\Result(array(), "image data");
33
+ $this->assertSame("image data", $result->toBuffer());
34
+ }
35
+ }
lib/TinyCompress/test/TinifySourceTest.php ADDED
@@ -0,0 +1,314 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use Tinify\CurlMock;
4
+
5
+ class TinifySourceTest extends TestCase {
6
+ private $dummyFile;
7
+
8
+ public function setUp() {
9
+ parent::setUp();
10
+ $this->dummyFile = __DIR__ . "/examples/dummy.png";
11
+ }
12
+
13
+ public function testWithInvalidApiKeyFromFileShouldThrowAccountException() {
14
+ Tinify\setKey("invalid");
15
+
16
+ CurlMock::register("https://api.tinify.com/shrink", array(
17
+ "status" => 401, "body" => '{"error":"Unauthorized","message":"Credentials are invalid"}'
18
+ ));
19
+
20
+ $this->setExpectedException("Tinify\AccountException");
21
+ Tinify\Source::fromFile($this->dummyFile);
22
+ }
23
+
24
+ public function testWithInvalidApiKeyFromBufferShouldThrowAccountException() {
25
+ Tinify\setKey("invalid");
26
+
27
+ CurlMock::register("https://api.tinify.com/shrink", array(
28
+ "status" => 401, "body" => '{"error":"Unauthorized","message":"Credentials are invalid"}'
29
+ ));
30
+
31
+ $this->setExpectedException("Tinify\AccountException");
32
+ Tinify\Source::fromBuffer("png file");
33
+ }
34
+
35
+ public function testWithInvalidApiKeyFromUrlShouldThrowAccountException() {
36
+ Tinify\setKey("invalid");
37
+
38
+ CurlMock::register("https://api.tinify.com/shrink", array(
39
+ "status" => 401, "body" => '{"error":"Unauthorized","message":"Credentials are invalid"}'
40
+ ));
41
+
42
+ $this->setExpectedException("Tinify\AccountException");
43
+ Tinify\Source::fromUrl("http://example.com/test.jpg");
44
+ }
45
+
46
+ public function testWithValidApiKeyFromFileShouldReturnSource() {
47
+ Tinify\setKey("valid");
48
+
49
+ CurlMock::register("https://api.tinify.com/shrink", array(
50
+ "status" => 201, "headers" => array("Location" => "https://api.tinify.com/some/location")
51
+ ));
52
+
53
+ $this->assertInstanceOf("Tinify\Source", Tinify\Source::fromFile($this->dummyFile));
54
+ }
55
+
56
+ public function testWithValidApiKeyFromFileShouldReturnSourceWithData() {
57
+ Tinify\setKey("valid");
58
+
59
+ CurlMock::register("https://api.tinify.com/shrink", array(
60
+ "status" => 201, "headers" => array("Location" => "https://api.tinify.com/some/location")
61
+ ));
62
+
63
+ CurlMock::register("https://api.tinify.com/some/location", array(
64
+ "status" => 200, "body" => "compressed file"
65
+ ));
66
+
67
+ $this->assertSame("compressed file", Tinify\Source::fromFile($this->dummyFile)->toBuffer());
68
+ }
69
+
70
+ public function testWithValidApiKeyFromBufferShouldReturnSource() {
71
+ Tinify\setKey("valid");
72
+
73
+ CurlMock::register("https://api.tinify.com/shrink", array(
74
+ "status" => 201, "headers" => array("Location" => "https://api.tinify.com/some/location")
75
+ ));
76
+
77
+ $this->assertInstanceOf("Tinify\Source", Tinify\Source::fromBuffer("png file"));
78
+ }
79
+
80
+ public function testWithValidApiKeyFromBufferShouldReturnSourceWithData() {
81
+ Tinify\setKey("valid");
82
+
83
+ CurlMock::register("https://api.tinify.com/shrink", array(
84
+ "status" => 201, "headers" => array("Location" => "https://api.tinify.com/some/location")
85
+ ));
86
+
87
+ CurlMock::register("https://api.tinify.com/some/location", array(
88
+ "status" => 200, "body" => "compressed file"
89
+ ));
90
+
91
+ $this->assertSame("compressed file", Tinify\Source::fromBuffer("png file")->toBuffer());
92
+ }
93
+
94
+ public function testWithValidApiKeyFromUrlShouldReturnSource() {
95
+ Tinify\setKey("valid");
96
+
97
+ CurlMock::register("https://api.tinify.com/shrink", array(
98
+ "status" => 201, "headers" => array("Location" => "https://api.tinify.com/some/location")
99
+ ));
100
+
101
+ $this->assertInstanceOf("Tinify\Source", Tinify\Source::fromUrl("http://example.com/testWithValidApiKey.jpg"));
102
+ }
103
+
104
+ public function testWithValidApiKeyFromUrlShouldReturnSourceWithData() {
105
+ Tinify\setKey("valid");
106
+
107
+ CurlMock::register("https://api.tinify.com/shrink", array(
108
+ "status" => 201, "headers" => array("Location" => "https://api.tinify.com/some/location")
109
+ ));
110
+
111
+ CurlMock::register("https://api.tinify.com/some/location", array(
112
+ "status" => 200, "body" => "compressed file"
113
+ ));
114
+
115
+ $this->assertSame("compressed file", Tinify\Source::fromUrl("http://example.com/testWithValidApiKey.jpg")->toBuffer());
116
+ }
117
+
118
+ public function testWithValidApiKeyFromUrlShouldThrowExceptionIfRequestIsNotOK() {
119
+ Tinify\setKey("valid");
120
+
121
+ CurlMock::register("https://api.tinify.com/shrink", array(
122
+ "status" => 400, "body" => '{"error":"Source not found","message":"Cannot parse URL"}'
123
+ ));
124
+
125
+ $this->setExpectedException("Tinify\ClientException");
126
+ Tinify\Source::fromUrl("file://wrong");
127
+ }
128
+
129
+ public function testWithValidApiKeyResultShouldReturnResult() {
130
+ Tinify\setKey("valid");
131
+
132
+ CurlMock::register("https://api.tinify.com/shrink", array(
133
+ "status" => 201,
134
+ "headers" => array("Location" => "https://api.tinify.com/some/location"),
135
+ ));
136
+
137
+ $this->assertInstanceOf("Tinify\Result", Tinify\Source::fromBuffer("png file")->result());
138
+ }
139
+
140
+ public function testWithValidApiKeyPreserveShouldReturnSource() {
141
+ Tinify\setKey("valid");
142
+
143
+ CurlMock::register("https://api.tinify.com/shrink", array(
144
+ "status" => 201, "headers" => array("Location" => "https://api.tinify.com/some/location")
145
+ ));
146
+
147
+ CurlMock::register("https://api.tinify.com/some/location", array(
148
+ "status" => 200, "body" => "copyrighted file"
149
+ ));
150
+
151
+ $this->assertInstanceOf("Tinify\Source", Tinify\Source::fromBuffer("png file")->preserve("copyright", "location"));
152
+ $this->assertSame("png file", CurlMock::last(CURLOPT_POSTFIELDS));
153
+ }
154
+
155
+ public function testWithValidApiKeyPreserveShouldReturnSourceWithData() {
156
+ Tinify\setKey("valid");
157
+
158
+ CurlMock::register("https://api.tinify.com/shrink", array(
159
+ "status" => 201, "headers" => array("Location" => "https://api.tinify.com/some/location")
160
+ ));
161
+
162
+ CurlMock::register("https://api.tinify.com/some/location", array(
163
+ "status" => 200, "body" => "copyrighted file"
164
+ ));
165
+
166
+ $this->assertSame("copyrighted file", Tinify\Source::fromBuffer("png file")->preserve("copyright", "location")->toBuffer());
167
+ $this->assertSame("{\"preserve\":[\"copyright\",\"location\"]}", CurlMock::last(CURLOPT_POSTFIELDS));
168
+ }
169
+
170
+ public function testWithValidApiKeyPreserveShouldReturnSourceWithDataForArray() {
171
+ Tinify\setKey("valid");
172
+
173
+ CurlMock::register("https://api.tinify.com/shrink", array(
174
+ "status" => 201, "headers" => array("Location" => "https://api.tinify.com/some/location")
175
+ ));
176
+
177
+ CurlMock::register("https://api.tinify.com/some/location", array(
178
+ "status" => 200, "body" => "copyrighted file"
179
+ ));
180
+
181
+ $this->assertSame("copyrighted file", Tinify\Source::fromBuffer("png file")->preserve(array("copyright", "location"))->toBuffer());
182
+ $this->assertSame("{\"preserve\":[\"copyright\",\"location\"]}", CurlMock::last(CURLOPT_POSTFIELDS));
183
+ }
184
+
185
+ public function testWithValidApiKeyPreserveShouldIncludeOtherOptionsIfSet() {
186
+ Tinify\setKey("valid");
187
+
188
+ CurlMock::register("https://api.tinify.com/shrink", array(
189
+ "status" => 201, "headers" => array("Location" => "https://api.tinify.com/some/location")
190
+ ));
191
+
192
+ CurlMock::register("https://api.tinify.com/some/location", array(
193
+ "status" => 200, "body" => "copyrighted resized file"
194
+ ));
195
+
196
+ $source = Tinify\Source::fromBuffer("png file")->resize(array("width" => 400))->preserve(array("copyright", "location"));
197
+
198
+ $this->assertSame("copyrighted resized file", $source->toBuffer());
199
+ $this->assertSame("{\"resize\":{\"width\":400},\"preserve\":[\"copyright\",\"location\"]}", CurlMock::last(CURLOPT_POSTFIELDS));
200
+ }
201
+
202
+ public function testWithValidApiKeyResizeShouldReturnSource() {
203
+ Tinify\setKey("valid");
204
+
205
+ CurlMock::register("https://api.tinify.com/shrink", array(
206
+ "status" => 201, "headers" => array("Location" => "https://api.tinify.com/some/location")
207
+ ));
208
+
209
+ CurlMock::register("https://api.tinify.com/some/location", array(
210
+ "status" => 200, "body" => "small file"
211
+ ));
212
+
213
+ $this->assertInstanceOf("Tinify\Source", Tinify\Source::fromBuffer("png file")->resize(array("width" => 400)));
214
+ $this->assertSame("png file", CurlMock::last(CURLOPT_POSTFIELDS));
215
+ }
216
+
217
+ public function testWithValidApiKeyResizeShouldReturnSourceWithData() {
218
+ Tinify\setKey("valid");
219
+
220
+ CurlMock::register("https://api.tinify.com/shrink", array(
221
+ "status" => 201, "headers" => array("Location" => "https://api.tinify.com/some/location")
222
+ ));
223
+
224
+ CurlMock::register("https://api.tinify.com/some/location", array(
225
+ "status" => 200, "body" => "small file"
226
+ ));
227
+
228
+ $this->assertSame("small file", Tinify\Source::fromBuffer("png file")->resize(array("width" => 400))->toBuffer());
229
+ $this->assertSame("{\"resize\":{\"width\":400}}", CurlMock::last(CURLOPT_POSTFIELDS));
230
+ }
231
+
232
+ public function testWithValidApiKeyStoreShouldReturnResultMeta() {
233
+ Tinify\setKey("valid");
234
+
235
+ CurlMock::register("https://api.tinify.com/shrink", array(
236
+ "status" => 201,
237
+ "headers" => array("Location" => "https://api.tinify.com/some/location"),
238
+ ));
239
+
240
+ CurlMock::register("https://api.tinify.com/some/location", array(
241
+ "body" => '{"store":{"service":"s3","aws_secret_access_key":"abcde"}}'
242
+ ), array("status" => 200));
243
+
244
+ $options = array("service" => "s3", "aws_secret_access_key" => "abcde");
245
+ $this->assertInstanceOf("Tinify\Result", Tinify\Source::fromBuffer("png file")->store($options));
246
+ $this->assertSame("{\"store\":{\"service\":\"s3\",\"aws_secret_access_key\":\"abcde\"}}", CurlMock::last(CURLOPT_POSTFIELDS));
247
+ }
248
+
249
+ public function testWithValidApiKeyStoreShouldReturnResultMetaWithLocation() {
250
+ Tinify\setKey("valid");
251
+
252
+ CurlMock::register("https://api.tinify.com/shrink", array(
253
+ "status" => 201,
254
+ "headers" => array("Location" => "https://api.tinify.com/some/location"),
255
+ ));
256
+
257
+ CurlMock::register("https://api.tinify.com/some/location", array(
258
+ "body" => '{"store":{"service":"s3"}}'
259
+ ), array(
260
+ "status" => 201,
261
+ "headers" => array("Location" => "https://bucket.s3.amazonaws.com/example"),
262
+ ));
263
+
264
+ $location = Tinify\Source::fromBuffer("png file")->store(array("service" => "s3"))->location();
265
+ $this->assertSame("https://bucket.s3.amazonaws.com/example", $location);
266
+ $this->assertSame("{\"store\":{\"service\":\"s3\"}}", CurlMock::last(CURLOPT_POSTFIELDS));
267
+ }
268
+
269
+ public function testWithValidApiKeyStoreShouldIncludeOtherOptionsIfSet() {
270
+ Tinify\setKey("valid");
271
+
272
+ CurlMock::register("https://api.tinify.com/shrink", array(
273
+ "status" => 201,
274
+ "headers" => array("Location" => "https://api.tinify.com/some/location"),
275
+ ));
276
+
277
+ CurlMock::register("https://api.tinify.com/some/location", array(
278
+ "body" => '{"resize":{"width":300},"store":{"service":"s3","aws_secret_access_key":"abcde"}}'
279
+ ), array("status" => 200));
280
+
281
+ $options = array("service" => "s3", "aws_secret_access_key" => "abcde");
282
+ $this->assertInstanceOf("Tinify\Result", Tinify\Source::fromBuffer("png file")->resize(array("width" => 300))->store($options));
283
+ $this->assertSame("{\"resize\":{\"width\":300},\"store\":{\"service\":\"s3\",\"aws_secret_access_key\":\"abcde\"}}", CurlMock::last(CURLOPT_POSTFIELDS));
284
+ }
285
+
286
+ public function testWithValidApiKeyToBufferShouldReturnImageData() {
287
+ Tinify\setKey("valid");
288
+
289
+ CurlMock::register("https://api.tinify.com/shrink", array(
290
+ "status" => 201, "headers" => array("Location" => "https://api.tinify.com/some/location")
291
+ ));
292
+ CurlMock::register("https://api.tinify.com/some/location", array(
293
+ "status" => 200, "body" => "compressed file"
294
+ ));
295
+
296
+ $this->assertSame("compressed file", Tinify\Source::fromBuffer("png file")->toBuffer());
297
+ }
298
+
299
+ public function testWithValidApiKeyToFileShouldStoreImageData() {
300
+ Tinify\setKey("valid");
301
+
302
+ CurlMock::register("https://api.tinify.com/shrink", array(
303
+ "status" => 201, "headers" => array("Location" => "https://api.tinify.com/some/location")
304
+ ));
305
+
306
+ CurlMock::register("https://api.tinify.com/some/location", array(
307
+ "status" => 200, "body" => "compressed file"
308
+ ));
309
+
310
+ $path = tempnam(sys_get_temp_dir(), "tinify-php");
311
+ Tinify\Source::fromBuffer("png file")->toFile($path);
312
+ $this->assertSame("compressed file", file_get_contents($path));
313
+ }
314
+ }
lib/TinyCompress/test/TinifyTest.php ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use Tinify\CurlMock;
4
+
5
+ class ClientTest extends TestCase {
6
+ private $dummyFile;
7
+
8
+ public function setUp() {
9
+ parent::setUp();
10
+ $this->dummyFile = __DIR__ . "/examples/dummy.png";
11
+ }
12
+
13
+ public function testKeyShouldResetClientWithNewKey() {
14
+ CurlMock::register("https://api.tinify.com/", array("status" => 200));
15
+ Tinify\setKey("abcde");
16
+ Tinify\Tinify::getClient();
17
+ Tinify\setKey("fghij");
18
+ $client = Tinify\Tinify::getClient();
19
+ $client->request("get", "/");
20
+
21
+ $this->assertSame("api:fghij", CurlMock::last(CURLOPT_USERPWD));
22
+ }
23
+
24
+ public function testAppIdentifierShouldResetClientWithNewAppIdentifier() {
25
+ CurlMock::register("https://api.tinify.com/", array("status" => 200));
26
+ Tinify\setKey("abcde");
27
+ Tinify\setAppIdentifier("MyApp/1.0");
28
+ Tinify\Tinify::getClient();
29
+ Tinify\setAppIdentifier("MyApp/2.0");
30
+ $client = Tinify\Tinify::getClient();
31
+ $client->request("get", "/");
32
+
33
+ $this->assertSame(Tinify\Client::userAgent() . " MyApp/2.0", CurlMock::last(CURLOPT_USERAGENT));
34
+ }
35
+
36
+ public function testClientWithKeyShouldReturnClient() {
37
+ Tinify\setKey("abcde");
38
+ $this->assertInstanceOf("Tinify\Client", Tinify\Tinify::getClient());
39
+ }
40
+
41
+ public function testClientWithoutKeyShouldThrowException() {
42
+ $this->setExpectedException("Tinify\AccountException");
43
+ $this->assertInstanceOf("Tinify\Client", Tinify\Tinify::getClient());
44
+ }
45
+
46
+ public function testSetClientShouldReplaceClient() {
47
+ Tinify\setKey("abcde");
48
+ Tinify\Tinify::setClient("foo");
49
+ $this->assertSame("foo", Tinify\Tinify::getClient());
50
+ }
51
+
52
+ public function testValidateWithValidKeyShouldReturnTrue() {
53
+ Tinify\setKey("valid");
54
+ CurlMock::register("https://api.tinify.com/shrink", array(
55
+ "status" => 400, "body" => '{"error":"Input missing","message":"No input"}'
56
+ ));
57
+ $this->assertTrue(Tinify\validate());
58
+ }
59
+
60
+ public function testValidateWithLimitedKeyShouldReturnTrue() {
61
+ Tinify\setKey("invalid");
62
+ CurlMock::register("https://api.tinify.com/shrink", array(
63
+ "status" => 429, "body" => '{"error":"Too many requests","message":"Your monthly limit has been exceeded"}'
64
+ ));
65
+ $this->assertTrue(Tinify\validate());
66
+ }
67
+
68
+ public function testValidateWithErrorShouldThrowException() {
69
+ Tinify\setKey("invalid");
70
+ CurlMock::register("https://api.tinify.com/shrink", array(
71
+ "status" => 401, "body" => '{"error":"Unauthorized","message":"Credentials are invalid"}'
72
+ ));
73
+ $this->setExpectedException("Tinify\AccountException");
74
+ Tinify\validate();
75
+ }
76
+
77
+ public function testFromFileShouldReturnSource() {
78
+ CurlMock::register("https://api.tinify.com/shrink", array(
79
+ "status" => 201, "headers" => array("Location" => "https://api.tinify.com/some/location")
80
+ ));
81
+ Tinify\setKey("valid");
82
+ $this->assertInstanceOf("Tinify\Source", Tinify\fromFile($this->dummyFile));
83
+ }
84
+
85
+ public function testFromBufferShouldReturnSource() {
86
+ CurlMock::register("https://api.tinify.com/shrink", array(
87
+ "status" => 201, "headers" => array("Location" => "https://api.tinify.com/some/location")
88
+ ));
89
+ Tinify\setKey("valid");
90
+ $this->assertInstanceOf("Tinify\Source", Tinify\fromBuffer("png file"));
91
+ }
92
+
93
+ public function testFromUrlShouldReturnSource() {
94
+ CurlMock::register("https://api.tinify.com/shrink", array(
95
+ "status" => 201, "headers" => array("Location" => "https://api.tinify.com/some/location")
96
+ ));
97
+ Tinify\setKey("valid");
98
+ $this->assertInstanceOf("Tinify\Source", Tinify\fromUrl("http://example.com/test.jpg"));
99
+ }
100
+ }
lib/TinyCompress/test/curl_mock.php ADDED
@@ -0,0 +1,160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Tinify;
4
+
5
+ class CurlMockException extends Exception {
6
+ }
7
+
8
+ class CurlMock {
9
+ private static $urls = array();
10
+ private static $requests = array();
11
+
12
+ public $options = array();
13
+ public $response;
14
+ public $closed = false;
15
+
16
+ public static function register($url, $request, $response = NULL) {
17
+ if (!$response) {
18
+ $response = $request;
19
+ $request = NULL;
20
+ }
21
+ self::$urls[$url] = array($request, $response);
22
+ }
23
+
24
+ public static function reset() {
25
+ self::$requests = array();
26
+ }
27
+
28
+ public static function last_has($key) {
29
+ $lastReq = self::$requests[count(self::$requests) - 1];
30
+ return array_key_exists($key, $lastReq->options);
31
+ }
32
+
33
+ public static function last($key = null) {
34
+ $lastReq = self::$requests[count(self::$requests) - 1];
35
+ if ($key) {
36
+ return $lastReq->options[$key];
37
+ } else {
38
+ return $lastReq;
39
+ }
40
+ }
41
+
42
+ public function close() {
43
+ $this->closed = true;
44
+ }
45
+
46
+ public function exec() {
47
+ if ($this->closed) {
48
+ throw new CurlMockException("Curl already closed");
49
+ }
50
+ array_push(self::$requests, $this);
51
+
52
+ list($this->request, $this->response) = self::$urls[$this->options[CURLOPT_URL]];
53
+ if ($this->request) {
54
+ if ($this->request["body"]) {
55
+ if ($this->options[CURLOPT_POSTFIELDS] != $this->request["body"]) {
56
+ throw new Exception("Body '" . $this->options[CURLOPT_POSTFIELDS] .
57
+ "' does not match expected '" . $this->request["body"] . "'");
58
+ }
59
+ }
60
+ }
61
+
62
+ if (isset($this->response["headers"])) {
63
+ $headers = "";
64
+ foreach ($this->response["headers"] as $header => $value) {
65
+ $headers .= $header . ": " . $value . "\r\n";
66
+ }
67
+ $this->response["headers"] = $headers . "\r\n";
68
+ } else {
69
+ $this->response["headers"] = "\r\n";
70
+ }
71
+
72
+ if (!isset($this->response["body"])) {
73
+ $this->response["body"] = "";
74
+ }
75
+
76
+ if (array_key_exists("return", $this->response)) {
77
+ return $this->response["return"];
78
+ } else if (isset($this->response["status"])) {
79
+ return $this->response["headers"] . $this->response["body"];
80
+ } else {
81
+ return false;
82
+ }
83
+ }
84
+
85
+ public function setopt_array($array) {
86
+ if ($this->closed) {
87
+ throw new CurlMockException("Curl already closed");
88
+ }
89
+ foreach ($array as $key => $value) {
90
+ $this->options[$key] = $value;
91
+ }
92
+ }
93
+
94
+ public function setopt($key, $value) {
95
+ if ($this->closed) {
96
+ throw new CurlMockException("Curl already closed");
97
+ }
98
+ $this->options[$key] = $value;
99
+ }
100
+
101
+ public function getinfo($key) {
102
+ if ($this->closed) {
103
+ throw new CurlMockException("Curl already closed");
104
+ }
105
+ switch ($key) {
106
+ case CURLINFO_HTTP_CODE:
107
+ return isset($this->response["status"]) ? $this->response["status"] : 0;
108
+ case CURLINFO_HEADER_SIZE:
109
+ return strlen($this->response["headers"]);
110
+ default:
111
+ throw new Exception("Bad key $key");
112
+ }
113
+ }
114
+
115
+ public function error() {
116
+ if ($this->closed) {
117
+ throw new CurlMockException("Curl already closed");
118
+ }
119
+ return $this->response["error"];
120
+ }
121
+
122
+ public function errno() {
123
+ if ($this->closed) {
124
+ throw new CurlMockException("Curl already closed");
125
+ }
126
+ return $this->response["errno"];
127
+ }
128
+ }
129
+
130
+ function curl_init() {
131
+ return new CurlMock();
132
+ }
133
+
134
+ function curl_exec($mock) {
135
+ return $mock->exec();
136
+ }
137
+
138
+ function curl_close($mock) {
139
+ $mock->close();
140
+ }
141
+
142
+ function curl_setopt_array($mock, $array) {
143
+ return $mock->setopt_array($array);
144
+ }
145
+
146
+ function curl_setopt($mock, $key, $value) {
147
+ return $mock->setopt($key, $value);
148
+ }
149
+
150
+ function curl_getinfo($mock, $key) {
151
+ return $mock->getinfo($key);
152
+ }
153
+
154
+ function curl_error($mock) {
155
+ return $mock->error();
156
+ }
157
+
158
+ function curl_errno($mock) {
159
+ return $mock->errno();
160
+ }
lib/TinyCompress/test/examples/dummy.png ADDED
File without changes
lib/TinyCompress/test/examples/voormedia.png ADDED
Binary file
lib/TinyCompress/test/helper.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once("curl_mock.php");
4
+ require_once("vendor/autoload.php");
5
+
6
+ class TestCase extends \PHPUnit_Framework_TestCase {
7
+ function setUp() {
8
+ Tinify\setKey(NULL);
9
+ }
10
+
11
+ function tearDown() {
12
+ Tinify\CurlMock::reset();
13
+ }
14
+ }
lib/TinyCompress/test/integration.php ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if (!getenv("TINIFY_KEY")) {
4
+ exit("Set the TINIFY_KEY environment variable.\n");
5
+ }
6
+
7
+ class ClientIntegrationTest extends PHPUnit_Framework_TestCase {
8
+ static private $optimized;
9
+
10
+ static public function setUpBeforeClass() {
11
+ \Tinify\setKey(getenv("TINIFY_KEY"));
12
+
13
+ $unoptimizedPath = __DIR__ . "/examples/voormedia.png";
14
+ self::$optimized = \Tinify\fromFile($unoptimizedPath);
15
+ }
16
+
17
+ public function testShouldCompressFromFile() {
18
+ $path = tempnam(sys_get_temp_dir(), "tinify-php");
19
+ self::$optimized->toFile($path);
20
+
21
+ $size = filesize($path);
22
+ $contents = fread(fopen($path, "rb"), $size);
23
+
24
+ $this->assertGreaterThan(1000, $size);
25
+ $this->assertLessThan(1500, $size);
26
+
27
+ /* width == 137 */
28
+ $this->assertContains("\0\0\0\x89", $contents);
29
+ $this->assertNotContains("Copyright Voormedia", $contents);
30
+ }
31
+
32
+ public function testShouldCompressFromUrl() {
33
+ $path = tempnam(sys_get_temp_dir(), "tinify-php");
34
+ $source = \Tinify\fromUrl("https://raw.githubusercontent.com/tinify/tinify-php/master/test/examples/voormedia.png");
35
+ $source->toFile($path);
36
+
37
+ $size = filesize($path);
38
+ $contents = fread(fopen($path, "rb"), $size);
39
+
40
+ $this->assertGreaterThan(1000, $size);
41
+ $this->assertLessThan(1500, $size);
42
+
43
+ /* width == 137 */
44
+ $this->assertContains("\0\0\0\x89", $contents);
45
+ $this->assertNotContains("Copyright Voormedia", $contents);
46
+ }
47
+
48
+ public function testShouldResize() {
49
+ $path = tempnam(sys_get_temp_dir(), "tinify-php");
50
+ self::$optimized->resize(array("method" => "fit", "width" => 50, "height" => 20))->toFile($path);
51
+
52
+ $size = filesize($path);
53
+ $contents = fread(fopen($path, "rb"), $size);
54
+
55
+ $this->assertGreaterThan(500, $size);
56
+ $this->assertLessThan(1000, $size);
57
+
58
+ /* width == 50 */
59
+ $this->assertContains("\0\0\0\x32", $contents);
60
+ $this->assertNotContains("Copyright Voormedia", $contents);
61
+ }
62
+
63
+ public function testShouldPreserveMetadata() {
64
+ $path = tempnam(sys_get_temp_dir(), "tinify-php");
65
+ self::$optimized->preserve("copyright", "creation")->toFile($path);
66
+
67
+ $size = filesize($path);
68
+ $contents = fread(fopen($path, "rb"), $size);
69
+
70
+ $this->assertGreaterThan(1000, $size);
71
+ $this->assertLessThan(2000, $size);
72
+
73
+ /* width == 137 */
74
+ $this->assertContains("\0\0\0\x89", $contents);
75
+ $this->assertContains("Copyright Voormedia", $contents);
76
+ }
77
+ }
package.xml CHANGED
@@ -1,20 +1,83 @@
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>Tiny_Compresss_Images</name>
4
- <version>1.0.1</version>
5
  <stability>stable</stability>
6
- <license uri="https://www.gnu.org/licenses/gpl-2.0.html">GPL v2 or later</license>
7
  <channel>community</channel>
8
  <extends/>
9
- <summary>Speed up your webshop. Optimize your JPEG and PNG images automatically with TinyPNG. </summary>
10
- <description>Make your webshop faster by compressing your JPEG and PNG images.&#xD;
11
- &#xD;
12
- This plugin automatically optimizes your images by integrating with the popular image compression services TinyJPG and TinyPNG.</description>
13
- <notes>Handle errors from service</notes>
14
- <authors><author><name>TinyPNG</name><user>TinyPNG</user><email>info@tinypng.com</email></author></authors>
15
- <date>2015-05-15</date>
16
- <time>13:56:57</time>
17
- <contents><target name="mageetc"><dir name="modules"><file name="Tiny_CompressImages.xml" hash="13fbe2b1d6381daadcf798266785a451"/></dir></target><target name="magelib"><dir name="TinyCompress"><file name="README.md" hash="4ae1886316de0c8dea5d1990b9649cd4"/><file name="cacert.pem" hash="d7f7dd7e3ede3e323fc0e09381f16caf"/><file name="class-tiny-compress-curl.php" hash="7ecabcea793ae179063c1dc93a2509a9"/><file name="class-tiny-compress-fopen.php" hash="ade5462599afcb9d7b49aca1982a148c"/><file name="class-tiny-compress.php" hash="e74709f18b1efd623e5c3945b8cbcf47"/><file name="class-tiny-exception.php" hash="9a9ae877854ee523d68c1ad9c875c319"/><file name="class-tiny-php.php" hash="7ab90f953a98a6ff2becc0d5aaea3f66"/><dir name="config"><file name="tinypng-api.ini" hash="c876771cfd9609aa517fc6a677f0d329"/></dir></dir></target><target name="magecommunity"><dir name="Tiny"><dir name="CompressImages"><dir name="Model"><file name="Observer.php" hash="890f0300645e8002bc28715a7b514bd3"/><dir name="Product"><file name="Image.php" hash="d022a2c075571e90919716b49602aefc"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="ec3a27c4fca2924c2bcace7cf2a33fb4"/><file name="config.xml" hash="af64144c88706151e633a178475a46fd"/><file name="system.xml" hash="77bf25c48a20ea171b11776beaa7165b"/></dir></dir></dir></target></contents>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  <compatible/>
19
- <dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php></required></dependencies>
20
  </package>
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>Tiny_Compresss_Images</name>
4
+ <version>2.0.0</version>
5
  <stability>stable</stability>
6
+ <license>MIT License</license>
7
  <channel>community</channel>
8
  <extends/>
9
+ <summary>Compress JPEG &amp; PNG images</summary>
10
+ <description># Compress JPEG &amp; PNG images for Magento 1&#xD;
11
+ &#xD;
12
+ Make your Magento 1 store faster by compressing your JPEG and PNG images.&#xD;
13
+ &#xD;
14
+ This plugin automatically optimizes your images by integrating with the&#xD;
15
+ popular image compression services TinyJPG and TinyPNG.&#xD;
16
+ &#xD;
17
+ Learn more about TinyJPG and TinyPNG at https://tinypng.com/.&#xD;
18
+ &#xD;
19
+ Do you use Magento 2? Install our Magento 2 plugin instead:&#xD;
20
+ https://packagist.org/packages/tinify/magento2&#xD;
21
+ &#xD;
22
+ ## How doest it work?&#xD;
23
+ &#xD;
24
+ When you view a product in your webshop, Magento creates different image sizes&#xD;
25
+ in its cache folders. This extension will compress these images for you&#xD;
26
+ automatically. Any image sizes that are exact duplicates of each other will&#xD;
27
+ only be compressed once.&#xD;
28
+ &#xD;
29
+ Your product images are uploaded to the TinyJPG or TinyPNG service and&#xD;
30
+ analyzed to apply the best possible compression. Based on the content of the&#xD;
31
+ image an optimal strategy is chosen. The result is sent back to your Magento&#xD;
32
+ webshop and saved in your public media folder.&#xD;
33
+ &#xD;
34
+ On average JPEG images are compressed by 40-60% and PNG images by 50-80%&#xD;
35
+ without visible loss in quality. Your webshop will load faster for your&#xD;
36
+ visitors, and you&#x2019;ll save storage space and bandwidth!&#xD;
37
+ &#xD;
38
+ ## Getting started&#xD;
39
+ &#xD;
40
+ Obtain your free API key from https://tinypng.com/developers. The first 500&#xD;
41
+ compressions per month are completely free, no strings attached! As each&#xD;
42
+ product will be shown in different sizes, between 50 and 100 products can be&#xD;
43
+ uploaded to your Magento webshop and compressed for free. You can also change&#xD;
44
+ which of types of image sizes should be compressed.&#xD;
45
+ &#xD;
46
+ If you&#x2019;re a heavy user, you can compress additional images for a small&#xD;
47
+ additional fee per image by upgrading your account. You can keep track of the&#xD;
48
+ amount of compressions in the Magento 1 configuration section.&#xD;
49
+ &#xD;
50
+ ## Installation&#xD;
51
+ &#xD;
52
+ Copy the extension key from Magento Connect. Login on your webshop backend&#xD;
53
+ and open *System -&gt; Magento Connect -&gt; Magento Connect Manager*.&#xD;
54
+ Paste the extension key to install the extension.&#xD;
55
+ &#xD;
56
+ After installation, go to *System -&gt; Configuration -&gt; Image Optimization*, and &#xD;
57
+ enter your TinyPNG API Key. Flush the images cache to start compressing.&#xD;
58
+ &#xD;
59
+ ## Contact us&#xD;
60
+ &#xD;
61
+ Got questions or feedback? Let us know! Contact us at support@tinypng.com.&#xD;
62
+ &#xD;
63
+ ## Information for plugin contributors&#xD;
64
+ &#xD;
65
+ * PHP 5.4 or newer.&#xD;
66
+ * MySQL 5.4 or newer (integration tests).&#xD;
67
+ * Magento 1.8.0.0 or newer.&#xD;
68
+ * phpunit 4.8 or newer.&#xD;
69
+ &#xD;
70
+ ### Running the unit tests&#xD;
71
+ &#xD;
72
+ From the .modman/Tiny_CompressImages directory:&#xD;
73
+ &#xD;
74
+ phpunit</description>
75
+ <notes>==== 2.0.0 ====&#xD;
76
+ Public release - Completely Rebuild code</notes>
77
+ <authors><author><name>Tiny</name><user>TinyPNG</user><email>support@tinypng.com</email></author></authors>
78
+ <date>2016-07-20</date>
79
+ <time>11:02:06</time>
80
+ <contents><target name="magecommunity"><dir name="Tiny"><dir name="CompressImages"><dir name="Block"><dir name="Adminhtml"><file name="ApiNotification.php" hash="6426312d49088e23b6ee1f627929adbb"/><dir name="System"><dir name="Config"><dir name="Form"><dir name="Field"><file name="AccountType.php" hash="380f33d6963230c46fab8e57866dc1f8"/><file name="Api.php" hash="8ceb591180cf579793f05924a043dc9c"/><file name="LogFile.php" hash="4e25c761671651b6553d562d3741dcd1"/><file name="LogStatus.php" hash="8146245e4a4a31d9e2286c933026cca4"/><file name="Radios.php" hash="4c7ece1b54c42297f6045b045fcb84e0"/><file name="Saved.php" hash="f0542c956a2a8679e1391c24dc3485ab"/><file name="Status.php" hash="3a6e9353a54936a98d7fbc63fc0ef3ed"/><file name="SupportTab.php" hash="d507bd32b83a8b14aaf52461d9b63f66"/></dir></dir><file name="Form.php" hash="6dcad3be2f0234a6afdb5a74fb4fe5fe"/></dir></dir></dir></dir><file name="Exception.php" hash="232327ae8c91c77b8ce4f2ea7e945b5d"/><dir name="Helper"><file name="Config.php" hash="b4f5af580d639c4c97eaa3dfb77a5f32"/><file name="Data.php" hash="c13a81a9520be131e7536a30541d0762"/><file name="Tinify.php" hash="1e7ff414f2624343728c6d970673cff7"/></dir><dir name="Model"><file name="Image.php" hash="0cb0d880bf82fa05777bd3742332726f"/><file name="Observer.php" hash="c8a474b20d0430cfd63d4feee5534261"/><dir name="Product"><file name="Image.php" hash="a2e4186d060aa9069fade4d4ebcc518e"/></dir><dir name="Resource"><dir name="Image"><file name="Collection.php" hash="d9d16df3b1b6440e3076251aa81f8780"/></dir><file name="Image.php" hash="2eb4265ecbf7458f804c62b61e80e734"/><file name="Setup.php" hash="e283458ac9c153678a3a6c719cdbfb91"/><dir name="Totals"><file name="Collection.php" hash="fdcdc1ca85ac337fab31252864eb941d"/></dir><file name="Totals.php" hash="70e729f767002c31faae7ded152eb911"/></dir><dir name="System"><dir name="Config"><dir name="Backend"><file name="ApiKey.php" hash="22499692a62df9ee8860e2df09e4bbd2"/><dir name="Comment"><file name="LoggingMode.php" hash="8d62d2a43629522bdd6acceb54016d74"/></dir></dir><dir name="Source"><dir name="Cms"><file name="ImageTypes.php" hash="f4ff83b2a25d152df5e425815a1b9ac7"/></dir><file name="Log.php" hash="fdfad3559c14ebab9f5990f489a78ce8"/><file name="OnOff.php" hash="460040d33b3a2522532b60673f749e57"/><dir name="Product"><file name="ImageTypes.php" hash="841b9ccd4f6bbe449074cfd5aadb0d70"/></dir><file name="Testlive.php" hash="d1cb53fdb8278202c04351c6e525aad3"/></dir></dir></dir><file name="Totals.php" hash="eee19b6e18ea8fa326ccd5957443281a"/></dir><dir name="Test"><dir name="Block"><dir name="Adminhtml"><dir name="System"><dir name="Config"><dir name="Form"><dir name="Field"><file name="LogStatusTest.php" hash="4c89257172518a55e930d7f2f0683ae8"/></dir></dir></dir></dir></dir></dir><dir name="Framework"><dir name="Tiny"><dir name="Test"><file name="Config.php" hash="9220264aabacd8ca1f63b62a7527cad6"/><dir name="Http"><file name="Response.php" hash="a7c31bcd031b8ae7e895b1a48602fc62"/></dir><file name="TestCase.php" hash="32556035e6eb7d9d9a13187a3f33f911"/></dir></dir></dir><dir name="Helper"><file name="ConfigTest.php" hash="c361ed44073e7f03bbdf285a929e175c"/></dir><dir name="Model"><file name="ImageTest.php" hash="5567d1208225d1aa98814ce26c4a3c66"/><dir name="Product"><file name="ImageTest.php" hash="4552bc02eb244fd04f02b06f56e5474a"/></dir><dir name="System"><dir name="Config"><dir name="Backend"><dir name="Comment"><file name="LoggingModeTest.php" hash="99c46dc66ba10db9a5cf2ab1aa88904f"/></dir></dir></dir></dir></dir><file name="bootstrap.php" hash="29ef0d78bdb07399a148609f70ebe6de"/></dir><dir name="controllers"><dir name="CompressImagesAdminhtml"><file name="ConfigController.php" hash="4ded82dc68dae8e14eeaa60d66698c3d"/><file name="StatusController.php" hash="7e9eb303e31a28b75a6bf0af940b9866"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="61c1da0f235d4fb616fd0e2e5a6a78a7"/><file name="config.xml" hash="eecdde03b3be7c4ede1dfb12c1b125f4"/><file name="system.xml" hash="a34f6d2381366f5001a03a314e157c3c"/></dir><dir name="sql"><dir name="tiny_compressimages_setup"><file name="install-1.0.0.php" hash="333d08c5949c91ac6ae098e15c64054d"/></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Tiny_CompressImages.xml" hash="598a989aeda17423c8b9f9ab11c341bb"/></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><dir name="Tiny"><file name="CompressImages.xml" hash="63d02f84f40722cd69ddaa234900e811"/></dir></dir><dir name="template"><dir name="Tiny"><dir name="CompressImages"><dir name="Api"><file name="keyNotification.phtml" hash="f202d40d56e5657493de5edb67906504"/></dir><dir name="system"><dir name="config"><dir name="form"><dir name="field"><file name="log_file.phtml" hash="f6ad229ffe35bc1cdbc3a2ee58e05b88"/><file name="log_status.phtml" hash="c3539e506c59059b3ea9137585c78dd0"/><file name="support_tab.phtml" hash="82d7ee5b4a782dc9dcfabb0fa5b843ae"/></dir></dir></dir></dir></dir></dir></dir></dir></dir></dir></target><target name="mageskin"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="css"><dir name="Tiny"><dir name="CompressImages"><file name="config.css" hash="61b1a856e391d6a3fffbd1703f11509e"/></dir></dir></dir><dir name="images"><dir name="Tiny"><dir name="CompressImages"><file name="george-magento@2x_opt.png" hash="13554407009301f1f62b212d67f5ae5e"/><file name="george-menu-icon@2x.png" hash="b1417eacc5320ad2741b8fd76ee60d56"/></dir></dir></dir></dir></dir></dir></target><target name="magelocale"><dir name="en_US"><file name="Tiny_CompressImages.csv" hash="a734673d17763c1334561e7e43d5f65f"/></dir></target><target name="magelib"><dir name="TinyCompress"><file name="LICENSE" hash="83cea2ac6da126d2dc6bcb26e740bac4"/><file name="README.md" hash="bd0c9f693fb84769a64c0b8721ecb394"/><file name="composer.json" hash="24129bff61e8cfa8b2a82efee5c7069a"/><file name="composer.lock" hash="faf46a8bba90ecc3a886f94f3cf922f4"/><dir name="lib"><dir name="Tinify"><file name="Client.php" hash="2c6d298a95c17762bf4e18a4b6343faa"/><file name="Exception.php" hash="ef195fc4ac81e45a7a52053d094da53f"/><file name="Result.php" hash="d6e0474e180cb17d0dc383ab974c0062"/><file name="ResultMeta.php" hash="4ec72ae5736f7fc91d7cb2b4bb55d3b9"/><file name="Source.php" hash="4c105bacaef6d6e69aa85da603c0378e"/></dir><file name="Tinify.php" hash="c3938730013e0a8237c3232b3ff8dc80"/><dir name="data"><file name="cacert.pem" hash="380df856e8f789c1af97d0da9a243769"/></dir></dir><file name="phpunit.xml" hash="73458f69fc3467a5d6ed3b1e5cd160cf"/><dir name="test"><file name="TinifyClientTest.php" hash="65160c2eed8aff5da38a0690575bfdfd"/><file name="TinifyResultMetaTest.php" hash="6c7e18d7ad946c7ac61a638cc92df8df"/><file name="TinifyResultTest.php" hash="0b574d4fd3b16d2cf7afb09a9f3e6e3a"/><file name="TinifySourceTest.php" hash="0db178b560fb4e59ec8ea31541ca3a98"/><file name="TinifyTest.php" hash="c018f154445101ec12fc0a5d493de09d"/><file name="curl_mock.php" hash="6b28a44ab36b3b53fcccbbad060fae05"/><dir name="examples"><file name="dummy.png" hash="d41d8cd98f00b204e9800998ecf8427e"/><file name="voormedia.png" hash="2824dd3c804309be2d275dbc2f16c788"/></dir><file name="helper.php" hash="7a7d4ddf6f771260cc74c8e18145a1bd"/><file name="integration.php" hash="43dbc9d7dc2f6b9be72c6a0d5036e9ce"/></dir><file name=".gitignore" hash="e8a346051f935e6cb104e1dc40998a91"/><file name=".travis.yml" hash="dbe91093178a614d31b4ac430659b81a"/></dir></target></contents>
81
  <compatible/>
82
+ <dependencies><required><php><min>5.4.0</min><max>7.0.0</max></php></required></dependencies>
83
  </package>
skin/adminhtml/default/default/css/Tiny/CompressImages/config.css ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Default Magento Override */
2
+
3
+ .content-header h3 {
4
+ color:#253033;
5
+ }
6
+
7
+ /* Modus radios */
8
+ .wrapper-radio { margin-bottom: 3px; }
9
+ .wrapper-radio input { margin-right: 5px; }
10
+ #row_tiny_compressimages_status_usage .label { vertical-align: middle; }
11
+ .radio-container { display: inline-block; }
12
+ .radio-container + .field-tooltip { float:right; }
13
+
14
+ /* ======== Logo / Identity ======== */
15
+
16
+ /* logo in title bar */
17
+ #tiny_compressimages_support .content-heading { background: url('../../../images/Tiny/CompressImages/george-menu-icon@2x.png') no-repeat 0 0px !important;
18
+ background-size: auto 40px !important;
19
+ line-height: 40px;
20
+ padding-left: 50px;
21
+ padding-bottom: 5px;
22
+ }
23
+
24
+ /* logo in left column */
25
+ .tiny-compressimages-section { position: relative; line-height: 24px; }
26
+ .tiny-compressimages-section span { padding-left: 50px !important; }
27
+ .tiny-compressimages-section:after { content: '';
28
+ display: block;
29
+ position: absolute;
30
+ top: 3px;
31
+ left: 18px;
32
+ height: 40px;
33
+ width: 54px;
34
+ background: url('../../../images/Tiny/CompressImages/george-menu-icon@2x.png') no-repeat 0 0px !important;
35
+ background-size: auto 25px !important;
36
+ }
37
+ /* ======== Support Tab General ====== */
38
+
39
+ #tiny_compressimages_support { position :relative;}
40
+ #tiny_compressimages_support p,
41
+ #tiny_compressimages_support ul,
42
+ #tiny_compressimages_support ol { padding: 6px 0 10px 0; }
43
+
44
+ #tiny_compressimages_support ol { list-style: decimal inside; }
45
+ #tiny_compressimages_support ol ol { list-style: lower-alpha inside; padding: 0 0 10px 12px; }
46
+ #tiny_compressimages_support ul ul { list-style:none; padding: 0 0 10px 12px; }
47
+ #tiny_compressimages_support h2.content-heading { border-bottom: 4px solid #dfdfdf; }
48
+ #tiny_compressimages_support h2.content-heading .content-heading-logo { height: 24px; }
49
+
50
+ #tiny_compressimages_support h4,
51
+ #tiny_compressimages_support p { margin: 0; }
52
+
53
+ /* ======== Support Tab ====== */
54
+
55
+ .tiny-logo-bear {
56
+ position: absolute;
57
+ bottom: 0px;
58
+ right: 0;
59
+ width: auto;
60
+ max-width: 20%;
61
+ height: auto;
62
+ max-height: 180px; }
63
+
64
+ #tiny_compressimages_support a:hover { text-decoration:none; }
65
+ #tiny_compressimages_support img { max-width: 100%; }
66
+
67
+ #tiny_compressimages_support .col-set { float:left; width: 100%; }
68
+ #tiny_compressimages_support .col-set .col-1 { float:left; width: 75%; box-sizing:border-box; padding-right: 10px; }
69
+ #tiny_compressimages_support .col-set .col-2 { float:left; width: 25%; box-sizing:border-box; padding-left: 10px;}
70
+
71
+ #tiny_compressimages_support .tig_branding { float:left; width: 100%; }
72
+ #tiny_compressimages_support .tig_branding .image { float:left; width: 50px; margin-top: 3px; }
73
+ #tiny_compressimages_support .tig_branding .signature{ float:left; width: calc(100% - 50px); }
74
+
75
+ /* ======== Connection Settings ======== */
76
+
77
+ #compressimages_api_status { color: #009f3e;float: left; padding-bottom: 5px; clear: both; }
78
+ .compressimages-api-deactivated { color: #cc0000; }
79
+
80
+ .compressimages_status_success .indicator,
81
+ .compressimages_status_failure .indicator {
82
+ vertical-align: top;
83
+ display: inline-block;
84
+ margin-right: 3px;
85
+ }
86
+
87
+ .compressimages_status_failure { color: #cc0000; }
88
+
89
+ #row_tiny_compressimages_settings_api_key a:hover { text-decoration:none; }
90
+ #compressimages_check_status { margin-left: 0 !important; float:left; clear:both; }
91
+
92
+ /* ======== Image types to optimize ======== */
93
+
94
+
95
+
96
+
97
+ /* ======== Latest Optimizations ======== */
98
+
99
+ #tiny_compressimages_status tr td .scalable{ margin: 10px 0; }
100
+
101
+ #tiny_compressimages_compression { padding: 9px 0; }
102
+ #tiny_compressimages_compression td { padding-top:2px; padding-bottom:2px; margin:0; vertical-align:middle; overflow:hidden; }
103
+ #tiny_compressimages_compression tr.tiny_compressimages_log { border-bottom: 1px solid #ececec; width: 100%; }
104
+
105
+ #tiny_compressimages_compression .image_path { padding-left: 10px; }
106
+
107
+ #tiny_compressimages_compression .image_path img { display: inline-block; max-width: 30px; max-height: 30px; vertical-align: middle; border: 1px solid #d6d6d6; }
108
+
109
+ #tiny_compressimages_compression .info_box { padding: 0 0 0 20px; }
110
+
111
+ #tiny_compressimages_compression .centered td,
112
+ #tiny_compressimages_compression .show_less td,
113
+ #tiny_compressimages_compression .show_more td { text-align:center; }
114
+
115
+ .tiny_compressimages_width { box-sizing: border-box; min-width: 180px;}
116
+ .tiny_compressimages-no-images {padding: 0 0 10px 4px; font-weight: bold;}
117
+ .log-details-td {padding-left: 4px;}
118
+
119
+ .title-file { width: 45px; }
120
+ .title-original { width: 65px; }
121
+ .title-now { width: 50px; }
122
+
123
+ /* ======== Advanced options ======== */
124
+
125
+
126
+
127
+
128
+
129
+
130
+
131
+
132
+
133
+
134
+
135
+
136
+
137
+
138
+
139
+
140
+
141
+
142
+
143
+
144
+
145
+
146
+
147
+
148
+
149
+
150
+
151
+
152
+
153
+
154
+
155
+
156
+
157
+
skin/adminhtml/default/default/images/Tiny/CompressImages/george-magento@2x_opt.png ADDED
Binary file
skin/adminhtml/default/default/images/Tiny/CompressImages/george-menu-icon@2x.png ADDED
Binary file