Gallery – Photo Gallery and Images Gallery - Version 2.7.0

Version Description

  • New super gallery cache function
Download this release

Release Info

Developer robosoft
Plugin Icon 128x128 Gallery – Photo Gallery and Images Gallery
Version 2.7.0
Comparing to
See all releases

Code changes from version 2.6.22 to 2.7.0

Files changed (36) hide show
  1. includes/cache.php +33 -0
  2. includes/extensions/categoryPage/category.class.php +246 -0
  3. includes/extensions/categoryPage/category.init.php +23 -0
  4. includes/extensions/categoryPage/css/index.html +0 -0
  5. includes/extensions/categoryPage/css/style.css +161 -0
  6. includes/extensions/categoryPage/index.html +0 -0
  7. includes/extensions/categoryPage/js/index.html +0 -0
  8. includes/extensions/categoryPage/js/jquery.nestable.js +484 -0
  9. includes/extensions/categoryPage/js/script.js +92 -0
  10. includes/extensions/zip/Core/AbstractException.php +14 -0
  11. includes/extensions/zip/Core/AbstractZipArchive.php +1046 -0
  12. includes/extensions/zip/Core/ZipUtils.php +125 -0
  13. includes/extensions/zip/Core/index.html +0 -0
  14. includes/extensions/zip/Exception/BufferNotEmpty.php +46 -0
  15. includes/extensions/zip/Exception/HeaderPositionError.php +52 -0
  16. includes/extensions/zip/Exception/HeadersSent.php +52 -0
  17. includes/extensions/zip/Exception/IncompatiblePhpVersion.php +54 -0
  18. includes/extensions/zip/Exception/InvalidPhpConfiguration.php +58 -0
  19. includes/extensions/zip/Exception/LengthMismatch.php +51 -0
  20. includes/extensions/zip/Exception/index.html +0 -0
  21. includes/extensions/zip/File/Zip.php +187 -0
  22. includes/extensions/zip/File/index.html +0 -0
  23. includes/extensions/zip/Listener/ZipArchiveListener.php +29 -0
  24. includes/extensions/zip/Listener/index.html +0 -0
  25. includes/extensions/zip/Stream/ZipStream.php +204 -0
  26. includes/extensions/zip/Stream/index.html +0 -0
  27. includes/extensions/zip/index.html +0 -0
  28. includes/frontend/rbs_gallery_class.php +59 -12
  29. includes/options/cache.php +48 -0
  30. includes/options/rbs_gallery_options_images.php +7 -0
  31. includes/options/rbs_gallery_options_tools.php +3 -1
  32. includes/rbs_gallery_edit.php +2 -0
  33. includes/rbs_gallery_init.php +5 -1
  34. includes/rbs_gallery_settings.php +2 -4
  35. readme.txt +10 -2
  36. robogallery.php +4 -4
includes/cache.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * Robo Gallery By Robosoft
4
+ * Contact: https://robosoft.co/robogallery/
5
+ * Copyright (c) 2014-2017, Robosoft. All rights reserved.
6
+ */
7
+
8
+ if ( ! defined( 'ABSPATH' ) ) exit;
9
+
10
+
11
+ function robo_gallery_save_gallery( $post_id, $post, $update ) {
12
+
13
+ $post_type = get_post_type($post_id);
14
+
15
+ if ( ROBO_GALLERY_TYPE_POST != $post_type ) return;
16
+
17
+ delete_transient( 'robo_gallery_cached_id'. $post_id ) ;
18
+ }
19
+ add_action( 'save_post', 'robo_gallery_save_gallery', 10, 3 );
20
+
21
+
22
+ function robo_gallery_new_gallery( $post_id, $post, $update ) {
23
+
24
+ if( wp_is_post_revision( $post_id ) ) return;
25
+
26
+ $post_type = get_post_type($post_id);
27
+ if ( ROBO_GALLERY_TYPE_POST != $post_type ) return;
28
+
29
+ /*add_post_meta($post_id, 'robo_gallery_cache', uniqid() );*/
30
+
31
+ }
32
+ add_action( 'wp_insert_post', 'robo_gallery_new_gallery', 10, 3 );
33
+
includes/extensions/categoryPage/category.class.php ADDED
@@ -0,0 +1,246 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * Robo Gallery
4
+ * Version: 1.0
5
+ * By Robosoft
6
+ *
7
+ * Contact: https://robosoft.co/robogallery/
8
+ * Created: 2015
9
+ * Licensed under the GPLv2 license - http://opensource.org/licenses/gpl-2.0.php
10
+ *
11
+ * Copyright (c) 2014-2016, Robosoft. All rights reserved.
12
+ * Available only in https://robosoft.co/robogallery/
13
+ */
14
+
15
+ if ( ! defined( 'ABSPATH' ) ) exit;
16
+
17
+ class ROBO_GALLERY_CATEGORY_PAGE{
18
+
19
+ protected $postType;
20
+
21
+ protected $postTypeParams;
22
+
23
+ protected $assetsUri;
24
+
25
+ protected $currentPostOrder;
26
+
27
+ public function __construct($postType){ //, array $postTypeParams
28
+
29
+ $this->postType = $postType;
30
+ $this->postTypeParams = array();
31
+ //$this->postTypeParams = $postTypeParams;
32
+ $this->assetsUri = plugin_dir_url(__FILE__);
33
+
34
+
35
+ $this->enqueueScripts();
36
+ // add_action("wp_ajax_hierarchy_{$this->postType}_meta_box", array($this, 'ajaxMetaBoxAttributes'));
37
+
38
+ //add_action("wp_ajax_hierarchy_{$this->postType}_dialog", array($this, 'ajaxDialog'));
39
+
40
+ $this->ajaxDialog ();
41
+
42
+ add_action("wp_ajax_hierarchy_{$this->postType}_dialog_save", array($this, 'ajaxDialogSave'));
43
+
44
+ }
45
+
46
+
47
+
48
+
49
+ public function enqueueScripts(){
50
+ wp_enqueue_style('wp-jquery-ui-dialog');
51
+ wp_enqueue_style(
52
+ 'hierarchy-post-attributes-style',
53
+ $this->assetsUri . 'css/style.css',
54
+ array('wp-jquery-ui-dialog')
55
+ );
56
+
57
+ wp_enqueue_script('jquery-ui-dialog');
58
+ wp_enqueue_script(
59
+ 'hierarchy-post-attributes-nestable-js',
60
+ $this->assetsUri . 'js/jquery.nestable.js',
61
+ array('jquery-ui-dialog'),
62
+ false,
63
+ true
64
+ );
65
+ wp_enqueue_script(
66
+ 'hierarchy-post-attributes-js',
67
+ $this->assetsUri . 'js/script.js',
68
+ array('jquery-ui-dialog', 'hierarchy-post-attributes-nestable-js'),
69
+ false,
70
+ true
71
+ );
72
+
73
+ $postTypeObject = get_post_type_object($this->postType);
74
+ wp_localize_script(
75
+ 'hierarchy-post-attributes-js',
76
+ 'hierarchyPostAttributes',
77
+ array(
78
+ 'ajaxUrl' => admin_url('admin-ajax.php'),
79
+ 'metaBox' => array(
80
+ 'action' => array(
81
+ 'get' => "hierarchy_{$this->postType}_meta_box"
82
+ )
83
+ ),
84
+ 'dialog' => array(
85
+ 'title' => __(sprintf('Edit hierarchy of %s', $postTypeObject->labels->name)),
86
+ 'button' => array(
87
+ 'save' => array(
88
+ 'label' => __('Save')
89
+ ),
90
+ 'cancel' => array(
91
+ 'label' => __('Cancel')
92
+ )
93
+ ),
94
+ 'action' => array(
95
+ 'get' => "hierarchy_{$this->postType}_dialog",
96
+ 'save' => "hierarchy_{$this->postType}_dialog_save",
97
+ ),
98
+ ),
99
+ 'error' => array(
100
+ 'title' => __('Error'),
101
+ 'button' => array(
102
+ 'ok' => array(
103
+ 'label' => __('OK')
104
+ ),
105
+ )
106
+ )
107
+ )
108
+ );
109
+ }
110
+
111
+
112
+
113
+
114
+
115
+
116
+ public function ajaxDialog() {
117
+ $this->checkPermission();
118
+
119
+ $postTree = $this->getPostTree(ROBO_GALLERY_TYPE_POST);
120
+ ?>
121
+ <p>
122
+ <button class="save_category button button-primary"> Save</button>
123
+ </p>
124
+ <div class="wrapper-nestable-list" >
125
+ <div class="nestable-list dd">
126
+ <?php $this->theNestableList($postTree); ?>
127
+ </div>
128
+ <div class="nestable-list-spinner">
129
+ <img src="<?php echo admin_url('/images/spinner-2x.gif') ?>" />
130
+ </div>
131
+ </div>
132
+ <button class="save_category button button-primary"> Save</button>
133
+ <?php
134
+
135
+ //wp_die();
136
+ }
137
+
138
+ public function ajaxDialogSave() {
139
+ $this->checkPermission();
140
+
141
+ if (!isset($_POST['hierarchy_posts'])) {
142
+ header('HTTP/1.0 403 Forbidden');
143
+ echo 'Empty posts hierarchy data for saving';
144
+ die();
145
+ }
146
+ if (!is_array($_POST['hierarchy_posts'])) {
147
+ header('HTTP/1.0 403 Forbidden');
148
+ echo 'Wrong posts hierarchy data for saving';
149
+ die();
150
+ }
151
+
152
+ $hierarchyPosts = $_POST['hierarchy_posts'];
153
+ $this->currentPostOrder = 0;
154
+ foreach ($hierarchyPosts as $order => $postData) {
155
+ $this->updatePostHierarchy($postData);
156
+ }
157
+ }
158
+
159
+
160
+ protected function getPostTree($postType){
161
+ $args = array(
162
+ 'post_type' => $postType,
163
+ 'post_status' => 'publish',
164
+ 'posts_per_page' => -1,
165
+ 'orderby' => 'menu_order',
166
+ 'order' => 'ASC'
167
+ );
168
+ $postMap = array();
169
+ $postTree = array();
170
+
171
+ foreach (get_posts($args) as $post) {
172
+ if (isset($postMap[$post->ID])) {
173
+ $postMap[$post->ID]['post'] = $post;
174
+ $postData = &$postMap[$post->ID];
175
+ } else {
176
+ $postData = array('post' => $post, 'children' => array());
177
+ $postMap[$post->ID] = &$postData;
178
+ }
179
+ if (0 == $post->post_parent) {
180
+ $postTree["{$post->menu_order}-{$post->ID}"] = &$postData;
181
+ } else {
182
+ $postMap[$post->post_parent]['children'][$post->ID] = &$postData;
183
+ }
184
+ unset($postData);
185
+ }
186
+
187
+ // Adding children posts with lost parent to tree
188
+ foreach ($postMap as &$postData) {
189
+ if (!isset($postData['post']) && is_array($postData['children'])) {
190
+ foreach ($postData['children'] as &$childPostData) {
191
+ $childPost = $childPostData['post'];
192
+ $postTree["{$childPost->menu_order}-{$childPost->ID}"] = &$childPostData;
193
+ }
194
+ }
195
+ }
196
+ asort($postTree);
197
+
198
+ return $postTree;
199
+ }
200
+
201
+
202
+ protected function theNestableList(array $tree){
203
+ ?>
204
+ <ol class="dd-list">
205
+ <?php foreach ($tree as $item) : ?>
206
+ <li class="dd-item" data-id="<?php echo $item['post']->ID; ?>">
207
+ <div class="dd-handle">
208
+ <?php
209
+ $title = esc_attr($item['post']->post_title);
210
+ echo "{$title} [{$item['post']->ID}: {$item['post']->post_name}]" ; ?>
211
+ </div>
212
+ <?php if (!empty($item['children'])) : ?>
213
+ <?php $this->theNestableList($item['children']); ?>
214
+ <?php endif; ?>
215
+ </li>
216
+ <?php endforeach; ?>
217
+ </ol>
218
+ <?php
219
+ }
220
+
221
+
222
+ protected function checkPermission(){
223
+ $postTypeObject = get_post_type_object($this->postType);
224
+ if (!current_user_can($postTypeObject->cap->edit_posts)) {
225
+ header('HTTP/1.0 403 Forbidden');
226
+ echo sprintf("You don't have permission for editing this %s", $postTypeObject->labels->name);
227
+ die();
228
+ }
229
+ }
230
+
231
+
232
+ protected function updatePostHierarchy($postData, $parentId = 0){
233
+ $this->currentPostOrder++;
234
+ wp_update_post(array(
235
+ 'ID' => absint($postData['id']),
236
+ 'post_parent' => absint($parentId),
237
+ 'menu_order' => $this->currentPostOrder
238
+ ));
239
+
240
+ if (!empty($postData['children'])) {
241
+ foreach ($postData['children'] as $childPostData) {
242
+ $this->updatePostHierarchy($childPostData, $postData['id']);
243
+ }
244
+ }
245
+ }
246
+ }
includes/extensions/categoryPage/category.init.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * Robo Gallery
4
+ * Version: 1.0
5
+ * By Robosoft
6
+ *
7
+ * Contact: https://robosoft.co/robogallery/
8
+ * Created: 2015
9
+ * Licensed under the GPLv2 license - http://opensource.org/licenses/gpl-2.0.php
10
+ *
11
+ * Copyright (c) 2014-2016, Robosoft. All rights reserved.
12
+ * Available only in https://robosoft.co/robogallery/
13
+ */
14
+
15
+ if ( ! defined( 'ABSPATH' ) ) exit;
16
+
17
+ /*if(!function_exists('rbs_gallery_category_init')){
18
+ function rbs_gallery_category_init(){*/
19
+ rbs_gallery_include('category.class.php', plugin_dir_path( __FILE__ ) );
20
+ new ROBO_GALLERY_CATEGORY_PAGE( ROBO_GALLERY_TYPE_POST );
21
+ /* }
22
+ add_action( 'init', 'rbs_gallery_category_init' );
23
+ }*/
includes/extensions/categoryPage/css/index.html ADDED
File without changes
includes/extensions/categoryPage/css/style.css ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .nestable-list.dd,
2
+ .nestable-list .dd {
3
+ position: relative;
4
+ display: block;
5
+ margin: 0;
6
+ padding: 0;
7
+ list-style: none;
8
+ font-size: 13px;
9
+ line-height: 20px;
10
+ }
11
+
12
+ .nestable-list .dd-list {
13
+ display: block;
14
+ position: relative;
15
+ margin: 0;
16
+ padding: 0;
17
+ list-style: none;
18
+ }
19
+
20
+ .nestable-list .dd-list .dd-list {
21
+ padding-left: 30px;
22
+ }
23
+
24
+ .nestable-list .dd-collapsed .dd-list {
25
+ display: none;
26
+ }
27
+
28
+ .nestable-list .dd-item,
29
+ .nestable-list .dd-empty,
30
+ .nestable-list .dd-placeholder {
31
+ display: block;
32
+ position: relative;
33
+ margin: 0;
34
+ padding: 0;
35
+ min-height: 20px;
36
+ font-size: 13px;
37
+ line-height: 20px;
38
+ }
39
+
40
+ .nestable-list .dd-handle {
41
+ display: block;
42
+ height: 30px;
43
+ margin: 5px 0;
44
+ padding: 5px 10px;
45
+ color: #333;
46
+ text-decoration: none;
47
+ font-weight: bold;
48
+ border: 1px solid #ccc;
49
+ background: #fafafa;
50
+ background: -webkit-linear-gradient(top, #fafafa 0%, #eee 100%);
51
+ background: -moz-linear-gradient(top, #fafafa 0%, #eee 100%);
52
+ background: linear-gradient(top, #fafafa 0%, #eee 100%);
53
+ -webkit-border-radius: 3px;
54
+ border-radius: 3px;
55
+ box-sizing: border-box;
56
+ -moz-box-sizing: border-box;
57
+ }
58
+
59
+ .nestable-list .dd-handle:hover {
60
+ color: #2ea8e5;
61
+ background: #fff;
62
+ }
63
+
64
+ .nestable-list .dd-item > button {
65
+ display: block;
66
+ position: relative;
67
+ cursor: pointer;
68
+ float: left;
69
+ width: 25px;
70
+ height: 20px;
71
+ margin: 5px 0;
72
+ padding: 0;
73
+ text-indent: 100%;
74
+ white-space: nowrap;
75
+ overflow: hidden;
76
+ border: 0;
77
+ background: transparent;
78
+ font-size: 12px;
79
+ line-height: 1;
80
+ text-align: center;
81
+ font-weight: bold;
82
+ }
83
+
84
+ .nestable-list .dd-item > button:before {
85
+ content: '+';
86
+ display: block;
87
+ position: absolute;
88
+ width: 100%;
89
+ text-align: center;
90
+ text-indent: 0;
91
+ }
92
+
93
+ .nestable-list .dd-item > button[data-action="collapse"]:before {
94
+ content: '-';
95
+ }
96
+
97
+ .nestable-list .dd-placeholder,
98
+ .nestable-list .dd-empty {
99
+ margin: 5px 0;
100
+ padding: 0;
101
+ min-height: 30px;
102
+ background: #f2fbff;
103
+ border: 1px dashed #b6bcbf;
104
+ box-sizing: border-box;
105
+ -moz-box-sizing: border-box;
106
+ }
107
+
108
+ .nestable-list .dd-empty {
109
+ border: 1px dashed #bbb;
110
+ min-height: 100px;
111
+ background-color: #e5e5e5;
112
+ background-image: -webkit-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff),
113
+ -webkit-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
114
+ background-image: -moz-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff),
115
+ -moz-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
116
+ background-image: linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff),
117
+ linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
118
+ background-size: 60px 60px;
119
+ background-position: 0 0, 30px 30px;
120
+ }
121
+
122
+ .nestable-list .dd-dragel {
123
+ position: absolute;
124
+ pointer-events: none;
125
+ z-index: 9999;
126
+ }
127
+
128
+ .nestable-list .dd-dragel > .dd-item .dd-handle {
129
+ margin-top: 0;
130
+ }
131
+
132
+ .nestable-list .dd-dragel .dd-handle {
133
+ -webkit-box-shadow: 2px 4px 6px 0 rgba(0, 0, 0, .1);
134
+ box-shadow: 2px 4px 6px 0 rgba(0, 0, 0, .1);
135
+ }
136
+
137
+ /* EXTRA STYLE */
138
+ #hierarchy-post-attributes-metabox .actions {
139
+ text-align: right;
140
+ }
141
+
142
+ .wrapper-nestable-list {
143
+ position: relative;
144
+ width: 100%;
145
+ height: 100%;
146
+ }
147
+ .nestable-list-spinner {
148
+ display: none;
149
+ position: absolute;
150
+ top: 0;
151
+ left: 0;
152
+ width: 100%;
153
+ height: 100%;
154
+ background: rgba(255, 255, 255, 0.5);
155
+ }
156
+ .nestable-list-spinner img {
157
+ position: absolute;
158
+ top: 50%;
159
+ left: 50%;
160
+ margin: -20px 0 0 -20px;
161
+ }
includes/extensions/categoryPage/index.html ADDED
File without changes
includes/extensions/categoryPage/js/index.html ADDED
File without changes
includes/extensions/categoryPage/js/jquery.nestable.js ADDED
@@ -0,0 +1,484 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * Nestable jQuery Plugin - Copyright (c) 2012 David Bushell - http://dbushell.com/
3
+ * Dual-licensed under the BSD or MIT licenses
4
+ */
5
+ ;(function($, window, document, undefined)
6
+ {
7
+ var hasTouch = 'ontouchstart' in document;
8
+
9
+ /**
10
+ * Detect CSS pointer-events property
11
+ * events are normally disabled on the dragging element to avoid conflicts
12
+ * https://github.com/ausi/Feature-detection-technique-for-pointer-events/blob/master/modernizr-pointerevents.js
13
+ */
14
+ var hasPointerEvents = (function()
15
+ {
16
+ var el = document.createElement('div'),
17
+ docEl = document.documentElement;
18
+ if (!('pointerEvents' in el.style)) {
19
+ return false;
20
+ }
21
+ el.style.pointerEvents = 'auto';
22
+ el.style.pointerEvents = 'x';
23
+ docEl.appendChild(el);
24
+ var supports = window.getComputedStyle && window.getComputedStyle(el, '').pointerEvents === 'auto';
25
+ docEl.removeChild(el);
26
+ return !!supports;
27
+ })();
28
+
29
+ var defaults = {
30
+ listNodeName : 'ol',
31
+ itemNodeName : 'li',
32
+ rootClass : 'dd',
33
+ listClass : 'dd-list',
34
+ itemClass : 'dd-item',
35
+ dragClass : 'dd-dragel',
36
+ handleClass : 'dd-handle',
37
+ collapsedClass : 'dd-collapsed',
38
+ placeClass : 'dd-placeholder',
39
+ noDragClass : 'dd-nodrag',
40
+ emptyClass : 'dd-empty',
41
+ expandBtnHTML : '<button data-action="expand" type="button">Expand</button>',
42
+ collapseBtnHTML : '<button data-action="collapse" type="button">Collapse</button>',
43
+ group : 0,
44
+ maxDepth : 5,
45
+ threshold : 20
46
+ };
47
+
48
+ function Plugin(element, options)
49
+ {
50
+ this.w = $(document);
51
+ this.el = $(element);
52
+ this.options = $.extend({}, defaults, options);
53
+ this.init();
54
+ }
55
+
56
+ Plugin.prototype = {
57
+
58
+ init: function()
59
+ {
60
+ var list = this;
61
+
62
+ list.reset();
63
+
64
+ list.el.data('nestable-group', this.options.group);
65
+
66
+ list.placeEl = $('<div class="' + list.options.placeClass + '"/>');
67
+
68
+ $.each(this.el.find(list.options.itemNodeName), function(k, el) {
69
+ list.setParent($(el));
70
+ });
71
+
72
+ list.el.on('click', 'button', function(e) {
73
+ if (list.dragEl) {
74
+ return;
75
+ }
76
+ var target = $(e.currentTarget),
77
+ action = target.data('action'),
78
+ item = target.parent(list.options.itemNodeName);
79
+ if (action === 'collapse') {
80
+ list.collapseItem(item);
81
+ }
82
+ if (action === 'expand') {
83
+ list.expandItem(item);
84
+ }
85
+ });
86
+
87
+ var onStartEvent = function(e)
88
+ {
89
+ var handle = $(e.target);
90
+ if (!handle.hasClass(list.options.handleClass)) {
91
+ if (handle.closest('.' + list.options.noDragClass).length) {
92
+ return;
93
+ }
94
+ handle = handle.closest('.' + list.options.handleClass);
95
+ }
96
+
97
+ if (!handle.length || list.dragEl) {
98
+ return;
99
+ }
100
+
101
+ list.isTouch = /^touch/.test(e.type);
102
+ if (list.isTouch && e.touches.length !== 1) {
103
+ return;
104
+ }
105
+
106
+ e.preventDefault();
107
+ list.dragStart(e.touches ? e.touches[0] : e);
108
+ };
109
+
110
+ var onMoveEvent = function(e)
111
+ {
112
+ if (list.dragEl) {
113
+ e.preventDefault();
114
+ list.dragMove(e.touches ? e.touches[0] : e);
115
+ }
116
+ };
117
+
118
+ var onEndEvent = function(e)
119
+ {
120
+ if (list.dragEl) {
121
+ e.preventDefault();
122
+ list.dragStop(e.touches ? e.touches[0] : e);
123
+ }
124
+ };
125
+
126
+ if (hasTouch) {
127
+ list.el[0].addEventListener('touchstart', onStartEvent, false);
128
+ window.addEventListener('touchmove', onMoveEvent, false);
129
+ window.addEventListener('touchend', onEndEvent, false);
130
+ window.addEventListener('touchcancel', onEndEvent, false);
131
+ }
132
+
133
+ list.el.on('mousedown', onStartEvent);
134
+ list.w.on('mousemove', onMoveEvent);
135
+ list.w.on('mouseup', onEndEvent);
136
+
137
+ },
138
+
139
+ serialize: function()
140
+ {
141
+ var data,
142
+ depth = 0,
143
+ list = this;
144
+ step = function(level, depth)
145
+ {
146
+ var array = [ ],
147
+ items = level.children(list.options.itemNodeName);
148
+ items.each(function()
149
+ {
150
+ var li = $(this),
151
+ item = $.extend({}, li.data()),
152
+ sub = li.children(list.options.listNodeName);
153
+ if (sub.length) {
154
+ item.children = step(sub, depth + 1);
155
+ }
156
+ array.push(item);
157
+ });
158
+ return array;
159
+ };
160
+ data = step(list.el.find(list.options.listNodeName).first(), depth);
161
+ return data;
162
+ },
163
+
164
+ serialise: function()
165
+ {
166
+ return this.serialize();
167
+ },
168
+
169
+ reset: function()
170
+ {
171
+ this.mouse = {
172
+ offsetX : 0,
173
+ offsetY : 0,
174
+ startX : 0,
175
+ startY : 0,
176
+ lastX : 0,
177
+ lastY : 0,
178
+ nowX : 0,
179
+ nowY : 0,
180
+ distX : 0,
181
+ distY : 0,
182
+ dirAx : 0,
183
+ dirX : 0,
184
+ dirY : 0,
185
+ lastDirX : 0,
186
+ lastDirY : 0,
187
+ distAxX : 0,
188
+ distAxY : 0
189
+ };
190
+ this.isTouch = false;
191
+ this.moving = false;
192
+ this.dragEl = null;
193
+ this.dragRootEl = null;
194
+ this.dragDepth = 0;
195
+ this.hasNewRoot = false;
196
+ this.pointEl = null;
197
+ },
198
+
199
+ expandItem: function(li)
200
+ {
201
+ li.removeClass(this.options.collapsedClass);
202
+ li.children('[data-action="expand"]').hide();
203
+ li.children('[data-action="collapse"]').show();
204
+ li.children(this.options.listNodeName).show();
205
+ },
206
+
207
+ collapseItem: function(li)
208
+ {
209
+ var lists = li.children(this.options.listNodeName);
210
+ if (lists.length) {
211
+ li.addClass(this.options.collapsedClass);
212
+ li.children('[data-action="collapse"]').hide();
213
+ li.children('[data-action="expand"]').show();
214
+ li.children(this.options.listNodeName).hide();
215
+ }
216
+ },
217
+
218
+ expandAll: function()
219
+ {
220
+ var list = this;
221
+ list.el.find(list.options.itemNodeName).each(function() {
222
+ list.expandItem($(this));
223
+ });
224
+ },
225
+
226
+ collapseAll: function()
227
+ {
228
+ var list = this;
229
+ list.el.find(list.options.itemNodeName).each(function() {
230
+ list.collapseItem($(this));
231
+ });
232
+ },
233
+
234
+ setParent: function(li)
235
+ {
236
+ if (li.children(this.options.listNodeName).length) {
237
+ li.prepend($(this.options.expandBtnHTML));
238
+ li.prepend($(this.options.collapseBtnHTML));
239
+ }
240
+ li.children('[data-action="expand"]').hide();
241
+ },
242
+
243
+ unsetParent: function(li)
244
+ {
245
+ li.removeClass(this.options.collapsedClass);
246
+ li.children('[data-action]').remove();
247
+ li.children(this.options.listNodeName).remove();
248
+ },
249
+
250
+ dragStart: function(e)
251
+ {
252
+ var mouse = this.mouse,
253
+ target = $(e.target),
254
+ dragItem = target.closest(this.options.itemNodeName);
255
+
256
+ this.placeEl.css('height', dragItem.height());
257
+
258
+ mouse.offsetX = e.offsetX !== undefined ? e.offsetX : e.pageX - target.offset().left;
259
+ mouse.offsetY = e.offsetY !== undefined ? e.offsetY : e.pageY - target.offset().top;
260
+ mouse.startX = mouse.lastX = e.pageX;
261
+ mouse.startY = mouse.lastY = e.pageY;
262
+
263
+ this.dragRootEl = this.el;
264
+
265
+ this.dragEl = $(document.createElement(this.options.listNodeName)).addClass(this.options.listClass + ' ' + this.options.dragClass);
266
+ this.dragEl.css('width', dragItem.width());
267
+
268
+ dragItem.after(this.placeEl);
269
+ dragItem[0].parentNode.removeChild(dragItem[0]);
270
+ dragItem.appendTo(this.dragEl);
271
+
272
+ $(document.body).append(this.dragEl);
273
+ this.dragEl.css({
274
+ 'left' : e.pageX - mouse.offsetX,
275
+ 'top' : e.pageY - mouse.offsetY
276
+ });
277
+ // total depth of dragging item
278
+ var i, depth,
279
+ items = this.dragEl.find(this.options.itemNodeName);
280
+ for (i = 0; i < items.length; i++) {
281
+ depth = $(items[i]).parents(this.options.listNodeName).length;
282
+ if (depth > this.dragDepth) {
283
+ this.dragDepth = depth;
284
+ }
285
+ }
286
+ },
287
+
288
+ dragStop: function(e)
289
+ {
290
+ var el = this.dragEl.children(this.options.itemNodeName).first();
291
+ el[0].parentNode.removeChild(el[0]);
292
+ this.placeEl.replaceWith(el);
293
+
294
+ this.dragEl.remove();
295
+ this.el.trigger('change');
296
+ if (this.hasNewRoot) {
297
+ this.dragRootEl.trigger('change');
298
+ }
299
+ this.reset();
300
+ },
301
+
302
+ dragMove: function(e)
303
+ {
304
+ var list, parent, prev, next, depth,
305
+ opt = this.options,
306
+ mouse = this.mouse;
307
+
308
+ this.dragEl.css({
309
+ 'left' : e.pageX - mouse.offsetX,
310
+ 'top' : e.pageY - mouse.offsetY
311
+ });
312
+
313
+ // mouse position last events
314
+ mouse.lastX = mouse.nowX;
315
+ mouse.lastY = mouse.nowY;
316
+ // mouse position this events
317
+ mouse.nowX = e.pageX;
318
+ mouse.nowY = e.pageY;
319
+ // distance mouse moved between events
320
+ mouse.distX = mouse.nowX - mouse.lastX;
321
+ mouse.distY = mouse.nowY - mouse.lastY;
322
+ // direction mouse was moving
323
+ mouse.lastDirX = mouse.dirX;
324
+ mouse.lastDirY = mouse.dirY;
325
+ // direction mouse is now moving (on both axis)
326
+ mouse.dirX = mouse.distX === 0 ? 0 : mouse.distX > 0 ? 1 : -1;
327
+ mouse.dirY = mouse.distY === 0 ? 0 : mouse.distY > 0 ? 1 : -1;
328
+ // axis mouse is now moving on
329
+ var newAx = Math.abs(mouse.distX) > Math.abs(mouse.distY) ? 1 : 0;
330
+
331
+ // do nothing on first move
332
+ if (!mouse.moving) {
333
+ mouse.dirAx = newAx;
334
+ mouse.moving = true;
335
+ return;
336
+ }
337
+
338
+ // calc distance moved on this axis (and direction)
339
+ if (mouse.dirAx !== newAx) {
340
+ mouse.distAxX = 0;
341
+ mouse.distAxY = 0;
342
+ } else {
343
+ mouse.distAxX += Math.abs(mouse.distX);
344
+ if (mouse.dirX !== 0 && mouse.dirX !== mouse.lastDirX) {
345
+ mouse.distAxX = 0;
346
+ }
347
+ mouse.distAxY += Math.abs(mouse.distY);
348
+ if (mouse.dirY !== 0 && mouse.dirY !== mouse.lastDirY) {
349
+ mouse.distAxY = 0;
350
+ }
351
+ }
352
+ mouse.dirAx = newAx;
353
+
354
+ /**
355
+ * move horizontal
356
+ */
357
+ if (mouse.dirAx && mouse.distAxX >= opt.threshold) {
358
+ // reset move distance on x-axis for new phase
359
+ mouse.distAxX = 0;
360
+ prev = this.placeEl.prev(opt.itemNodeName);
361
+ // increase horizontal level if previous sibling exists and is not collapsed
362
+ if (mouse.distX > 0 && prev.length && !prev.hasClass(opt.collapsedClass)) {
363
+ // cannot increase level when item above is collapsed
364
+ list = prev.find(opt.listNodeName).last();
365
+ // check if depth limit has reached
366
+ depth = this.placeEl.parents(opt.listNodeName).length;
367
+ if (depth + this.dragDepth <= opt.maxDepth) {
368
+ // create new sub-level if one doesn't exist
369
+ if (!list.length) {
370
+ list = $('<' + opt.listNodeName + '/>').addClass(opt.listClass);
371
+ list.append(this.placeEl);
372
+ prev.append(list);
373
+ this.setParent(prev);
374
+ } else {
375
+ // else append to next level up
376
+ list = prev.children(opt.listNodeName).last();
377
+ list.append(this.placeEl);
378
+ }
379
+ }
380
+ }
381
+ // decrease horizontal level
382
+ if (mouse.distX < 0) {
383
+ // we can't decrease a level if an item preceeds the current one
384
+ next = this.placeEl.next(opt.itemNodeName);
385
+ if (!next.length) {
386
+ parent = this.placeEl.parent();
387
+ this.placeEl.closest(opt.itemNodeName).after(this.placeEl);
388
+ if (!parent.children().length) {
389
+ this.unsetParent(parent.parent());
390
+ }
391
+ }
392
+ }
393
+ }
394
+
395
+ var isEmpty = false;
396
+
397
+ // find list item under cursor
398
+ if (!hasPointerEvents) {
399
+ this.dragEl[0].style.visibility = 'hidden';
400
+ }
401
+ this.pointEl = $(document.elementFromPoint(e.pageX - document.body.scrollLeft, e.pageY - (window.pageYOffset || document.documentElement.scrollTop)));
402
+ if (!hasPointerEvents) {
403
+ this.dragEl[0].style.visibility = 'visible';
404
+ }
405
+ if (this.pointEl.hasClass(opt.handleClass)) {
406
+ this.pointEl = this.pointEl.parent(opt.itemNodeName);
407
+ }
408
+ if (this.pointEl.hasClass(opt.emptyClass)) {
409
+ isEmpty = true;
410
+ }
411
+ else if (!this.pointEl.length || !this.pointEl.hasClass(opt.itemClass)) {
412
+ return;
413
+ }
414
+
415
+ // find parent list of item under cursor
416
+ var pointElRoot = this.pointEl.closest('.' + opt.rootClass),
417
+ isNewRoot = this.dragRootEl.data('nestable-id') !== pointElRoot.data('nestable-id');
418
+
419
+ /**
420
+ * move vertical
421
+ */
422
+ if (!mouse.dirAx || isNewRoot || isEmpty) {
423
+ // check if groups match if dragging over new root
424
+ if (isNewRoot && opt.group !== pointElRoot.data('nestable-group')) {
425
+ return;
426
+ }
427
+ // check depth limit
428
+ depth = this.dragDepth - 1 + this.pointEl.parents(opt.listNodeName).length;
429
+ if (depth > opt.maxDepth) {
430
+ return;
431
+ }
432
+ var before = e.pageY < (this.pointEl.offset().top + this.pointEl.height() / 2);
433
+ parent = this.placeEl.parent();
434
+ // if empty create new list to replace empty placeholder
435
+ if (isEmpty) {
436
+ list = $(document.createElement(opt.listNodeName)).addClass(opt.listClass);
437
+ list.append(this.placeEl);
438
+ this.pointEl.replaceWith(list);
439
+ }
440
+ else if (before) {
441
+ this.pointEl.before(this.placeEl);
442
+ }
443
+ else {
444
+ this.pointEl.after(this.placeEl);
445
+ }
446
+ if (!parent.children().length) {
447
+ this.unsetParent(parent.parent());
448
+ }
449
+ if (!this.dragRootEl.find(opt.itemNodeName).length) {
450
+ this.dragRootEl.append('<div class="' + opt.emptyClass + '"/>');
451
+ }
452
+ // parent root list has changed
453
+ if (isNewRoot) {
454
+ this.dragRootEl = pointElRoot;
455
+ this.hasNewRoot = this.el[0] !== this.dragRootEl[0];
456
+ }
457
+ }
458
+ }
459
+
460
+ };
461
+
462
+ $.fn.nestable = function(params)
463
+ {
464
+ var lists = this,
465
+ retval = this;
466
+
467
+ lists.each(function()
468
+ {
469
+ var plugin = $(this).data("nestable");
470
+
471
+ if (!plugin) {
472
+ $(this).data("nestable", new Plugin(this, params));
473
+ $(this).data("nestable-id", new Date().getTime());
474
+ } else {
475
+ if (typeof params === 'string' && typeof plugin[params] === 'function') {
476
+ retval = plugin[params]();
477
+ }
478
+ }
479
+ });
480
+
481
+ return retval || lists;
482
+ };
483
+
484
+ })(window.jQuery || window.Zepto, window, document);
includes/extensions/categoryPage/js/script.js ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ;(function ($, undefined){
2
+
3
+
4
+ function DialogEdit() {
5
+ this.$element = $('.wrapper-nestable-list');
6
+ this.$nestableList = this.$element.find('.nestable-list');
7
+ this.$nestableList.nestable({group: 1, maxDepth: 100});
8
+
9
+ this.init();
10
+ }
11
+ DialogEdit.prototype = {
12
+ init: function() {
13
+ var self = this;
14
+ $('.save_category').click(function(event) {
15
+ event.preventDefault();
16
+ self.save() ;
17
+ });
18
+ },
19
+
20
+ save : function () {
21
+ var self = this,
22
+ hierarchyPosts = this.$nestableList.nestable('serialise');
23
+
24
+ self.spinner(true);
25
+ $.ajax({
26
+ url: hierarchyPostAttributes.ajaxUrl,
27
+ method: 'post',
28
+ data: {
29
+ action: hierarchyPostAttributes.dialog.action.save,
30
+ hierarchy_posts: hierarchyPosts
31
+ },
32
+ success: function (response) {
33
+ self.spinner(false);
34
+ self.destroy();
35
+ },
36
+ error: function (jqXHR) {
37
+ self.destroy();
38
+ new DialogError(jqXHR.responseText);
39
+ }
40
+ });
41
+ },
42
+
43
+ spinner: function(isShow) {
44
+ if (isShow) {
45
+ var $spinner = this.$element.find('.nestable-list-spinner').clone();
46
+ $spinner.appendTo(this.$element.closest('.ui-dialog.ui-widget')).show();
47
+ } else {
48
+ this.$element.find('.nestable-list-spinner').remove();
49
+ }
50
+ },
51
+
52
+ destroy: function () {
53
+ this.$element.dialog('close');
54
+ this.$element.remove();
55
+ }
56
+ };
57
+
58
+ function DialogError(message) {
59
+ this.$element = $('<div id="hierarchy-post-error">' + message + '</div>');
60
+ this.show()
61
+ }
62
+ DialogError.prototype = {
63
+ show: function () {
64
+ var self = this;
65
+
66
+ self.$element.appendTo('body');
67
+ self.$element.dialog({
68
+ 'dialogClass' : 'wp-dialog',
69
+ 'title': hierarchyPostAttributes.error.title,
70
+ 'modal' : true,
71
+ 'autoOpen' : true,
72
+ 'closeOnEscape' : false,
73
+ 'buttons' : [
74
+ {
75
+ 'text' : hierarchyPostAttributes.error.button.ok.label,
76
+ 'class' : 'button',
77
+ 'click' : function() { return self.destroy(); }
78
+ }
79
+ ],
80
+ 'close': function() { return self.destroy(); }
81
+ });
82
+ },
83
+ destroy: function () {
84
+ this.$element.dialog('close');
85
+ this.$element.remove();
86
+ }
87
+ };
88
+
89
+ $(document).ready(function() {
90
+ new DialogEdit();
91
+ });
92
+ }(jQuery));
includes/extensions/zip/Core/AbstractException.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ * @author Greg Kappatos
5
+ *
6
+ * This class serves as a proxy for all \PHPZip\Zip\Exception classes.
7
+ * It is empty for now, but properties can be added in the future without
8
+ * breaking any code.
9
+ *
10
+ */
11
+
12
+ namespace PHPZip\Zip\Core;
13
+
14
+ abstract class AbstractException extends \Exception {}
includes/extensions/zip/Core/AbstractZipArchive.php ADDED
@@ -0,0 +1,1046 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ * @author A. Grandt <php@grandt.com>
5
+ * @author Greg Kappatos
6
+ *
7
+ * This class serves as an abstract superclass for zip archives.
8
+ *
9
+ */
10
+
11
+ namespace PHPZip\Zip\Core;
12
+
13
+ use com\grandt\BinStringStatic;
14
+ use PHPZip\Zip\Listener\ZipArchiveListener as ZipArchiveListener;
15
+ use PHPZip\Zip\Exception\IncompatiblePhpVersion as IncompatiblePhpVersionException;
16
+ use PHPZip\Zip\Exception\InvalidPhpConfiguration as InvalidPhpConfigurationException;
17
+ use PHPZip\Zip\Exception\HeadersSent as HeadersSentException;
18
+ use PHPZip\Zip\Exception\BufferNotEmpty as BufferNotEmptyException;
19
+ use PHPZip\Zip\Exception\LengthMismatch as LengthMismatchException;
20
+ use ZipMerge\Zip\Core\AbstractZipWriter;
21
+ use ZipMerge\Zip\Core\Header\ZipFileEntry;
22
+ use ZipMerge\Zip\Stream\ZipMerge;
23
+
24
+
25
+ abstract class AbstractZipArchive extends AbstractZipWriter {
26
+ const APP_NAME = 'PHPZip';
27
+ const VERSION = "2.0.8";
28
+ const MIN_PHP_VERSION = 5.3; // for namespaces
29
+
30
+ const CONTENT_TYPE = 'application/zip';
31
+
32
+ const NULL_BYTE = "\x00";
33
+ const NULL_WORD = "\x00\x00"; // Two nul bytes, used often enough.
34
+ const NULL_DWORD = "\x00\x00\x00\x00";
35
+
36
+ const ZIP_CENTRAL_FILE_HEADER = "PK\x01\x02"; // Central file header signature
37
+ const ZIP_LOCAL_FILE_HEADER = "PK\x03\x04"; // Local file header signature
38
+ const ZIP_LOCAL_DATA_DESCRIPTOR = "PK\x07\x08"; // Local Header, data descriptor
39
+ const ZIP_END_OF_CENTRAL_DIRECTORY = "PK\x05\x06"; // End of Central directory record
40
+
41
+ const HEADER_UNIX_TYPE_1 = 'UX'; // \x55\x58 or 0x5855 It has been replaced by the extended-timestamp extra block 'UT' (0x5455) and the Unix type 2 extra block 'Ux' (0x7855).
42
+ const HEADER_UNIX_TYPE_2 = 'Ux'; // \x55\x78 or 0x7855
43
+ const HEADER_UNIX_TYPE_3 = 'ux'; // \x75\x78 or 0x7875
44
+ const HEADER_EXTENDED_TIMESTAMP = 'UT'; // \x55\x54 or 0x5455
45
+ const HEADER_UNICODE_PATH = 'up'; // \x75\x70 or 0x7075
46
+ const HEADER_UNICODE_COMMENT = 'uc'; // \x75\x63 or 0x6375
47
+
48
+ const EXT_FILE_ATTR_DIR = 010173200020; // Permission 755 drwxr-xr-x = (((S_IFDIR | 0755) << 16) | S_DOS_D);
49
+ const EXT_FILE_ATTR_FILE = 020151000040; // Permission 644 -rw-r--r-- = (((S_IFREG | 0644) << 16) | S_DOS_A);
50
+
51
+ const ATTR_VERSION_TO_EXTRACT = "\x14\x00"; // Version needed to extract = 20 (File is compressed using Deflate compression)
52
+ const ATTR_MADE_BY_VERSION = "\x1E\x03"; // Made By Version
53
+
54
+ const DEFAULT_GZ_TYPE = "\x08\x00"; // Compression type 8 = deflate
55
+ const DEFAULT_GP_FLAGS = self::NULL_WORD; // General Purpose bit flags for compression type 8 it is: 0=Normal, 1=Maximum, 2=Fast, 3=super fast compression.
56
+
57
+ const DEFAULT_GZ_TYPE_STORED = self::NULL_WORD; // Compression type 0 = stored
58
+ const DEFAULT_GP_FLAGS_STORED = self::NULL_WORD; // Compression type 0 = stored
59
+
60
+ // UID 1000, GID 0
61
+ const EXTRA_FIELD_NEW_UNIX_GUID = "ux\x0B\x00\x01\x04\xE8\x03\x00\x00\x04\x00\x00\x00\x00"; // \x75\x78 3rd gen Unis GUID
62
+ const EXTRA_FIELD_NEW_UNIX_GUID_CD = "ux\x00\x00"; // \x75\x78 3rd gen Unis GUID CD record version must have length 0.
63
+
64
+ protected $zipComment = null;
65
+ protected $cdRec = array(); // central directory
66
+ protected $offset = 0;
67
+ protected $isFinalized = false;
68
+ protected $addExtraField = true;
69
+
70
+ protected $streamChunkSize = 0;
71
+ protected $streamFilePath = null;
72
+ protected $streamTimestamp = null;
73
+ protected $streamFileComment = null;
74
+ protected $streamFile = null;
75
+ protected $streamData = null;
76
+ protected $streamFileLength = 0;
77
+ protected $streamExtFileAttr = null;
78
+
79
+ /**
80
+ * A custom temporary folder, or a callable that returns a custom temporary file.
81
+ * @var string|callable
82
+ */
83
+ public static $temp = null;
84
+
85
+ private $_listeners = array();
86
+ private $_phpConfigurationWatch = array(
87
+ // 'mbstring.func_overload' => '0' // throw an exception if setting in php.ini is not '0'
88
+ );
89
+
90
+ /**
91
+ * Constructor.
92
+ *
93
+ * @author A. Grandt <php@grandt.com>
94
+ * @author Greg Kappatos
95
+ *
96
+ * @param boolean $streamChunkSize Size of each chunk
97
+ *
98
+ * @throws \PHPZip\Zip\Exception\InvalidPhpConfiguration In case of errors
99
+ */
100
+ protected function __construct($streamChunkSize) {
101
+ $this->streamChunkSize = $streamChunkSize;
102
+
103
+ if (count($this->_phpConfigurationWatch) > 0) {
104
+ foreach ($this->_phpConfigurationWatch as $k => $v) {
105
+ $s = (string)$v;
106
+ if (@ini_get($k) !== $s) {
107
+ $this->_throwException(new InvalidPhpConfigurationException(array(
108
+ 'setting' => $k,
109
+ 'expected' => $s,
110
+ )));
111
+ break; // technically not needed.
112
+ }
113
+ }
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Extra fields on the Zip directory records are Unix time codes needed for compatibility on the default Mac zip archive tool.
119
+ * These are enabled as default, as they do no harm elsewhere and only add 26 bytes per file added.
120
+ *
121
+ * @author A. Grandt <php@grandt.com>
122
+ *
123
+ * @param bool $setExtraField true (default) will enable adding of extra fields, anything else will disable it.
124
+ */
125
+ public function setExtraField($setExtraField = true) {
126
+ $this->addExtraField = ($setExtraField === true);
127
+ }
128
+
129
+ /**
130
+ * Set Zip archive comment.
131
+ *
132
+ * @author A. Grandt <php@grandt.com>
133
+ *
134
+ * @param string $newComment New comment. null to clear.
135
+ *
136
+ * @return bool $success
137
+ */
138
+ public function setComment($newComment = null) {
139
+ if ($this->isFinalized) {
140
+ return false;
141
+ }
142
+
143
+ $this->zipComment = $newComment;
144
+
145
+ return true;
146
+ }
147
+
148
+ /**
149
+ * Add an empty directory entry to the zip archive.
150
+ * Basically this is only used if an empty directory is added.
151
+ *
152
+ * @author A. Grandt <php@grandt.com>
153
+ * @author Greg Kappatos
154
+ *
155
+ * @param string $directoryPath Directory Path and name to be added to the archive.
156
+ * @param int $timestamp (Optional) Timestamp for the added directory, if omitted or set to 0, the current time will be used.
157
+ * @param string $fileComment (Optional) Comment to be added to the archive for this directory. To use $fileComment, $timestamp must be given.
158
+ * @param int $extFileAttr (Optional) The external file reference, use generateExtAttr to generate this.
159
+ *
160
+ * @return bool $success
161
+ */
162
+ public function addDirectory($directoryPath, $timestamp = 0, $fileComment = null, $extFileAttr = self::EXT_FILE_ATTR_DIR) {
163
+ // TODO: get rid of magic numbers.
164
+ $result = false;
165
+
166
+ if (!$this->isFinalized) {
167
+ $directoryPath = str_replace("\\", '/', $directoryPath);
168
+ $directoryPath = rtrim($directoryPath, '/');
169
+
170
+ if (BinStringStatic::_strlen($directoryPath) > 0) {
171
+ $this->buildZipEntry($directoryPath.'/',
172
+ $fileComment,
173
+ self::DEFAULT_GZ_TYPE_STORED,
174
+ self::DEFAULT_GP_FLAGS_STORED,
175
+ $timestamp,
176
+ "\x00\x00\x00\x00",
177
+ 0, 0, $extFileAttr);
178
+ $result = true;
179
+ }
180
+ }
181
+ return $result;
182
+ }
183
+
184
+ /**
185
+ * Add a file to the archive at the specified location and file name.
186
+ *
187
+ * @author A. Grandt <php@grandt.com>
188
+ * @author Greg Kappatos
189
+ *
190
+ * @param string $data File data.
191
+ * @param string $filePath File path and name to be used in the archive.
192
+ * @param int $timestamp (Optional) Timestamp for the added file, if omitted or set to 0, the current time will be used.
193
+ * @param string $fileComment (Optional) Comment to be added to the archive for this file. To use $fileComment, $timestamp must be given.
194
+ * @param bool $compress (Optional) Compress file, if set to false the file will only be stored. Default true.
195
+ * @param int $extFileAttr (Optional) The external file reference, use generateExtAttr to generate this.
196
+ *
197
+ * @return bool $success
198
+ */
199
+ public function addFile($data, $filePath, $timestamp = 0, $fileComment = null, $compress = null, $extFileAttr = self::EXT_FILE_ATTR_FILE) {
200
+ if ($this->isFinalized) {
201
+ return false;
202
+ }
203
+
204
+ if (is_resource($data) && get_resource_type($data) === 'stream') {
205
+ $this->addLargeFile($data, $filePath, $timestamp, $fileComment, $extFileAttr);
206
+ return false;
207
+ }
208
+
209
+ $gzData = '';
210
+ $gzType = self::DEFAULT_GZ_TYPE;
211
+ $gpFlags = self::DEFAULT_GP_FLAGS;
212
+ $dataLength = BinStringStatic::_strlen($data);
213
+ $fileCRC32 = pack("V", crc32($data));
214
+ $gzLength = $dataLength;
215
+
216
+ if ($compress) {
217
+ $gzTmp = gzcompress($data);
218
+ // gzcompress adds a 2 byte header and 4 byte Adler-32 CRC at the end, which we can't use.
219
+ $gzData = substr($gzTmp, 2, -4);
220
+ // The 2 byte header does contain useful data,
221
+ // though in this case the 2 parameters we'd be interested in will
222
+ // always be 8 for compression type, and 2 for General purpose flag.
223
+ $gzLength = BinStringStatic::_strlen($gzData);
224
+ }
225
+
226
+ if ($gzLength >= $dataLength) {
227
+ $gzLength = $dataLength;
228
+ $gzData = $data;
229
+
230
+ $gzType = self::DEFAULT_GZ_TYPE_STORED;
231
+ $gpFlags = self::DEFAULT_GP_FLAGS_STORED;
232
+ }
233
+
234
+ $this->onBeginAddFile(array(
235
+ 'gzLength' => $gzLength,
236
+ ));
237
+
238
+ $this->buildZipEntry($filePath, $fileComment, $gpFlags, $gzType, $timestamp, $fileCRC32, $gzLength, $dataLength, $extFileAttr);
239
+
240
+ $this->onEndAddFile(array(
241
+ 'gzData' => $gzData,
242
+ ));
243
+
244
+ $this->_notifyListeners(null, array(
245
+ 'data' => $data,
246
+ ));
247
+
248
+ return true;
249
+ }
250
+
251
+ /**
252
+ * Add the content to a directory.
253
+ *
254
+ * @author Adam Schmalhofer <Adam.Schmalhofer@gmx.de>
255
+ * @author A. Grandt <php@grandt.com>
256
+ *
257
+ * @param string $realPath Path on the file system.
258
+ * @param string $zipPath File path and name to be used in the archive.
259
+ * @param bool $recursive Add content recursively, default is true.
260
+ * @param bool $followSymlinks Follow and add symbolic links, if they are accessible, default is true.
261
+ * @param array &$addedFiles Reference to the added files, this is used to prevent duplicates, default is an empty array.
262
+ * If you start the function by parsing an array, the array will be populated with the $realPath
263
+ * and $zipPath kay/value pairs added to the archive by the function.
264
+ * @param bool $overrideFilePermissions Force the use of the file/dir permissions set in the $extDirAttr
265
+ * and $extFileAttr parameters.
266
+ * @param int $extDirAttr Permissions for directories.
267
+ * @param int $extFileAttr Permissions for files.
268
+ */
269
+ public function addDirectoryContent($realPath, $zipPath, $recursive = true, $followSymlinks = true, &$addedFiles = array(),
270
+ $overrideFilePermissions = false, $extDirAttr = self::EXT_FILE_ATTR_DIR, $extFileAttr = self::EXT_FILE_ATTR_FILE) {
271
+ if (file_exists($realPath) && !isset($addedFiles[realpath($realPath)])) {
272
+ if (is_dir($realPath)) {
273
+ $this->addDirectory(
274
+ $zipPath,
275
+ 0,
276
+ null,
277
+ $overrideFilePermissions ? $extDirAttr : ZipUtils::getFileExtAttr($realPath)
278
+ );
279
+ }
280
+
281
+ $addedFiles[realpath($realPath)] = $zipPath;
282
+
283
+ $iter = new \DirectoryIterator($realPath);
284
+
285
+ foreach ($iter as $file) {
286
+ /* @var $file \DirectoryIterator */
287
+ if ($file->isDot()) {
288
+ continue;
289
+ }
290
+
291
+ $newRealPath = $file->getPathname();
292
+ $newZipPath = \RelativePath::pathJoin($zipPath, $file->getFilename());
293
+
294
+ if (file_exists($newRealPath) && ($followSymlinks || !is_link($newRealPath))) {
295
+ if ($file->isFile()) {
296
+ $addedFiles[realpath($newRealPath)] = $newZipPath;
297
+ $this->addLargeFile(
298
+ $newRealPath,
299
+ $newZipPath,
300
+ 0,
301
+ null,
302
+ $overrideFilePermissions ? $extFileAttr : ZipUtils::getFileExtAttr($newRealPath)
303
+ );
304
+ } else if ($recursive) {
305
+ $this->addDirectoryContent(
306
+ $newRealPath,
307
+ $newZipPath,
308
+ $recursive,
309
+ $followSymlinks,
310
+ $addedFiles,
311
+ $overrideFilePermissions,
312
+ $extDirAttr,
313
+ $extFileAttr
314
+ );
315
+ } else {
316
+ $this->addDirectory(
317
+ $zipPath,
318
+ 0,
319
+ null,
320
+ $overrideFilePermissions ? $extDirAttr : ZipUtils::getFileExtAttr($newRealPath)
321
+ );
322
+ }
323
+ }
324
+ }
325
+ }
326
+ }
327
+
328
+ /**
329
+ * Append the contents of an existing zip file to the current, WITHOUT re-compressing the data within it.
330
+ *
331
+ * @param string $file the path to the zip file to be added.
332
+ * @param string $subPath place the contents in the $subPath sub-folder, default is '', and places the
333
+ * content in the root of the new zip file.
334
+ */
335
+ public function appendZip($file, $subPath = '') {
336
+ $zipMerge = new ZipMerge(null);
337
+ $zipMerge->appendZip($file, $subPath, $this);
338
+ $files = $zipMerge->finalize();
339
+
340
+ /* @var $files array */
341
+ foreach ($files as $fileEntry) {
342
+ /* @var $fileEntry ZipFileEntry */
343
+ $fileEntry->offset = $this->offset;
344
+ $this->cdRec[] = $fileEntry->getCentralDirectoryHeader();
345
+ $this->offset += BinStringStatic::_strlen( $fileEntry->getLocalHeader()) + $fileEntry->gzLength;
346
+ }
347
+ }
348
+
349
+ /**
350
+ * Add a file to the archive at the specified location and file name.
351
+ *
352
+ * @author A. Grandt <php@grandt.com>
353
+ * @author Greg Kappatos
354
+ *
355
+ * @param string $dataFile File name/path.
356
+ * @param string $filePath File path and name to be used in the archive.
357
+ * @param int $timestamp (Optional) Timestamp for the added file, if omitted or set to 0, the current time will be used.
358
+ * @param string $fileComment (Optional) Comment to be added to the archive for this file. To use $fileComment, $timestamp must be given.
359
+ * @param int $extFileAttr (Optional) The external file reference, use generateExtAttr to generate this.
360
+ *
361
+ * @return bool $success
362
+ */
363
+ public function addLargeFile($dataFile, $filePath, $timestamp = 0, $fileComment = null, $extFileAttr = self::EXT_FILE_ATTR_FILE) {
364
+ $result = false;
365
+
366
+ if (!$this->isFinalized) {
367
+
368
+ if (is_string($dataFile) && is_file($dataFile)) {
369
+ $this->processFile($dataFile, $filePath, $timestamp, $fileComment, $extFileAttr);
370
+ } else if (is_resource($dataFile) && get_resource_type($dataFile) == "stream") {
371
+ $fh = $dataFile;
372
+ $this->openStream($filePath, $timestamp, $fileComment, $extFileAttr);
373
+
374
+ while (!feof($fh)) {
375
+ $this->addStreamData(fread($fh, $this->streamChunkSize));
376
+ }
377
+ $this->closeStream();
378
+ }
379
+ $result = true;
380
+ }
381
+
382
+ $this->_notifyListeners(null, array(
383
+ 'file' => $dataFile,
384
+ 'result' => $result,
385
+ ));
386
+
387
+ return $result;
388
+ }
389
+
390
+ /**
391
+ * Create a stream to be used for large entries.
392
+ *
393
+ * @author A. Grandt <php@grandt.com>
394
+ * @author Greg Kappatos
395
+ *
396
+ * @param string $filePath File path and name to be used in the archive.
397
+ * @param int $timestamp (Optional) Timestamp for the added file, if omitted or set to 0, the current time will be used.
398
+ * @param string $fileComment (Optional) Comment to be added to the archive for this file. To use $fileComment, $timestamp must be given.
399
+ * @param int $extFileAttr (Optional) The external file reference, use generateExtAttr to generate this.
400
+ *
401
+ * @throws \PHPZip\Zip\Exception\IncompatiblePhpVersion Throws an exception in case of errors
402
+ *
403
+ * @return bool $success
404
+ */
405
+ public function openStream($filePath, $timestamp = 0, $fileComment = null, $extFileAttr = self::EXT_FILE_ATTR_FILE) {
406
+
407
+ $result = false;
408
+
409
+ if (!function_exists('sys_get_temp_dir')) {
410
+ $this->_throwException(new IncompatiblePhpVersionException(array(
411
+ 'appName' => self::APP_NAME,
412
+ 'appVersion' => self::VERSION,
413
+ 'minVersion' => self::MIN_PHP_VERSION,
414
+ )));
415
+ }
416
+
417
+ if (!$this->isFinalized) {
418
+ $this->onOpenStream();
419
+
420
+ if (BinStringStatic::_strlen($this->streamFilePath) > 0) {
421
+ $this->closeStream();
422
+ }
423
+
424
+ $this->streamFile = self::getTemporaryFile();
425
+ $this->streamData = fopen($this->streamFile, "wb");
426
+ $this->streamFilePath = $filePath;
427
+ $this->streamTimestamp = $timestamp;
428
+ $this->streamFileComment = $fileComment;
429
+ $this->streamFileLength = 0;
430
+ $this->streamExtFileAttr = $extFileAttr;
431
+
432
+ $result = true;
433
+ }
434
+
435
+ $this->_notifyListeners(null, array(
436
+ 'file' => $this->streamFile,
437
+ 'result' => $result,
438
+ ));
439
+
440
+ return $result;
441
+ }
442
+
443
+ /**
444
+ * Add data to the open stream.
445
+ *
446
+ * @author A. Grandt <php@grandt.com>
447
+ * @author Greg Kappatos
448
+ *
449
+ * @param string $data
450
+ *
451
+ * @throws LengthMismatchException Throws an exception in case of errors
452
+ *
453
+ * @return mixed length in bytes added or false if the archive is finalized or there are no open stream.
454
+ */
455
+ public function addStreamData($data) {
456
+ if ($this->isFinalized || BinStringStatic::_strlen($this->streamFilePath) == 0) {
457
+ return false;
458
+ }
459
+
460
+ $dataLength = BinStringStatic::_strlen($data);
461
+ $length = fwrite($this->streamData, $data, $dataLength);
462
+
463
+ if ($length != $dataLength) {
464
+ $this->_throwException(new LengthMismatchException(array(
465
+ 'expected' => BinStringStatic::_strlen($data),
466
+ 'written' => (!$length ? 'NONE!' : $length),
467
+ )));
468
+ }
469
+
470
+ $this->streamFileLength += $length;
471
+
472
+ return $length;
473
+ }
474
+
475
+ /**
476
+ * Close the current stream.
477
+ *
478
+ * @author A. Grandt <php@grandt.com>
479
+ *
480
+ * @return bool $success
481
+ */
482
+ public function closeStream() {
483
+ if ($this->isFinalized || BinStringStatic::_strlen($this->streamFilePath) == 0) {
484
+ return false;
485
+ }
486
+
487
+ fflush($this->streamData);
488
+ fclose($this->streamData);
489
+
490
+ $this->processFile(
491
+ $this->streamFile,
492
+ $this->streamFilePath,
493
+ $this->streamTimestamp,
494
+ $this->streamFileComment,
495
+ $this->streamExtFileAttr
496
+ );
497
+
498
+ $this->streamData = null;
499
+ $this->streamFilePath = null;
500
+ $this->streamTimestamp = null;
501
+ $this->streamFileComment = null;
502
+ $this->streamFileLength = 0;
503
+ $this->streamExtFileAttr = null;
504
+
505
+ // Windows is a little slow at times, so a millisecond later, we can unlink this.
506
+ unlink($this->streamFile);
507
+ $this->streamFile = null;
508
+
509
+ return true;
510
+ }
511
+
512
+ /**
513
+ * Process the current file.
514
+ *
515
+ * @author A. Grandt <php@grandt.com>
516
+ * @author Greg Kappatos
517
+ *
518
+ * @param string $dataFile
519
+ * @param string $filePath
520
+ * @param int $timestamp
521
+ * @param string $fileComment
522
+ * @param int $extFileAttr
523
+ *
524
+ * @return bool $success
525
+ */
526
+ protected function processFile($dataFile, $filePath, $timestamp = 0, $fileComment = null, $extFileAttr = self::EXT_FILE_ATTR_FILE) {
527
+
528
+ // TODO: change the magic numbers below to constants.
529
+
530
+ if ($this->isFinalized) {
531
+ return false;
532
+ }
533
+
534
+ $tempZip = self::getTemporaryFile();
535
+
536
+ $zip = new \ZipArchive;
537
+ $rv = $zip->open($tempZip, \ZipArchive::CREATE | \ZipArchive::OVERWRITE);
538
+
539
+ if ($rv === true) { // open returns true if successful, however one of the error values is 1, which will also read as true.
540
+ $zip->addFile($dataFile, 'file');
541
+ $zip->close();
542
+ } else {
543
+ // TODO: An error occurred reading the ZipArchive temp file (Seen on Windows installations)
544
+ }
545
+
546
+ $handle = fopen($tempZip, "rb");
547
+ $stats = fstat($handle);
548
+ $eof = $stats['size']-72; // set EOF to the position of the end of the zip data, before the CD record.
549
+ // Should probably use 34+gzLength instead.
550
+
551
+ fseek($handle, 6); // Skip Zip local file header and version
552
+
553
+ $gpFlags = fread($handle, 2);
554
+ $gzType = fread($handle, 2);
555
+ fread($handle, 4); // Skip DOS Time and Date
556
+ $fileCRC32 = fread($handle, 4);
557
+
558
+ $v = unpack("Vval", fread($handle, 4));
559
+ $gzLength = $v['val'];
560
+
561
+ $v = unpack("Vval", fread($handle, 4));
562
+ $dataLength = $v['val'];
563
+
564
+ $this->buildZipEntry($filePath, $fileComment, $gpFlags, $gzType, $timestamp, $fileCRC32, $gzLength, $dataLength, $extFileAttr);
565
+
566
+ $pos = 34;
567
+ fseek($handle, $pos); // Position pointer at the start of the actual zip data.
568
+
569
+ while (!feof($handle) && $pos < $eof) {
570
+ $len = $this->streamChunkSize;
571
+
572
+ if ($pos + $this->streamChunkSize > $eof) {
573
+ $len = $eof - $pos;
574
+ }
575
+ $data = fread($handle, $len);
576
+ $pos += $len;
577
+
578
+ $this->onProcessFile(array(
579
+ 'data' => $data,
580
+ ));
581
+ }
582
+
583
+ fclose($handle);
584
+ unlink($tempZip);
585
+
586
+ $this->_notifyListeners(null, array(
587
+ 'file' => $dataFile,
588
+ ));
589
+
590
+ return true;
591
+ }
592
+
593
+ /**
594
+ * Build the Zip file structures
595
+ *
596
+ * @author A. Grandt <php@grandt.com>
597
+ * @author Greg Kappatos
598
+ *
599
+ * @param string $filePath
600
+ * @param string $fileComment
601
+ * @param string $gpFlags
602
+ * @param string $gzType
603
+ * @param int $timestamp
604
+ * @param string $fileCRC32
605
+ * @param int $gzLength
606
+ * @param int $dataLength
607
+ * @param int $extFileAttr Use self::EXT_FILE_ATTR_FILE for files, self::EXT_FILE_ATTR_DIR for Directories.
608
+ */
609
+ protected function buildZipEntry($filePath, $fileComment, $gpFlags, $gzType, $timestamp, $fileCRC32, $gzLength, $dataLength, $extFileAttr) {
610
+ $filePath = str_replace("\\", "/", $filePath);
611
+ $fileCommentLength = (empty($fileComment) ? 0 : BinStringStatic::_strlen($fileComment));
612
+ $timestamp = (int)$timestamp;
613
+ $timestamp = ($timestamp == 0 ? time() : $timestamp);
614
+
615
+ $dosTime = ZipUtils::getDosTime($timestamp);
616
+ $tsPack = pack("V", $timestamp);
617
+
618
+ if (!isset($gpFlags) || BinStringStatic::_strlen($gpFlags) != 2) {
619
+ $gpFlags = self::DEFAULT_GP_FLAGS;
620
+ }
621
+
622
+ $isFileUTF8 = mb_check_encoding($filePath, "UTF-8") && !mb_check_encoding($filePath, "ASCII");
623
+ $isCommentUTF8 = !empty($fileComment) && mb_check_encoding($fileComment, "UTF-8") && !mb_check_encoding($fileComment, "ASCII");
624
+
625
+ $locExField = "";
626
+ $cenExField = "";
627
+
628
+ if ($this->addExtraField) {
629
+ $locExField .= self::HEADER_EXTENDED_TIMESTAMP . "\x09\x00\x03"
630
+ . $tsPack . $tsPack
631
+ . self::EXTRA_FIELD_NEW_UNIX_GUID;
632
+ $cenExField .= self::HEADER_EXTENDED_TIMESTAMP . "\x05\x00\x03"
633
+ . $tsPack
634
+ . self::EXTRA_FIELD_NEW_UNIX_GUID_CD;
635
+ }
636
+
637
+ if ($isFileUTF8 || $isCommentUTF8) {
638
+ $flag = 0;
639
+ $gpFlagsV = unpack("vflags", $gpFlags);
640
+ if (isset($gpFlagsV['flags'])) {
641
+ $flag = $gpFlagsV['flags'];
642
+ }
643
+ $gpFlags = pack("v", $flag | (1 << 11));
644
+
645
+ if ($isFileUTF8) {
646
+ $utfExField = self::HEADER_UNICODE_PATH // utf8 encoded File path extra field
647
+ . pack ("v", (5 + BinStringStatic::_strlen($filePath)))
648
+ . "\x01"
649
+ . pack("V", crc32($filePath))
650
+ . $filePath;
651
+
652
+ $locExField .= $utfExField;
653
+ $cenExField .= $utfExField;
654
+ }
655
+ if ($isCommentUTF8) {
656
+ $cenExField .= self::HEADER_UNICODE_COMMENT // utf8 encoded file comment extra field
657
+ . pack ("v", (5 + BinStringStatic::_strlen($fileComment)))
658
+ . "\x01"
659
+ . pack("V", crc32($fileComment))
660
+ . $fileComment;
661
+ }
662
+ }
663
+
664
+ $header = $gpFlags . $gzType . $dosTime. $fileCRC32
665
+ . pack("VVv", $gzLength, $dataLength, BinStringStatic::_strlen($filePath)); // File name length
666
+
667
+ $zipEntry = self::ZIP_LOCAL_FILE_HEADER
668
+ . self::ATTR_VERSION_TO_EXTRACT
669
+ . $header
670
+ . pack("v", BinStringStatic::_strlen($locExField)) // Extra field length
671
+ . $filePath // FileName
672
+ . $locExField; // Extra fields
673
+
674
+ $this->onBuildZipEntry(array(
675
+ 'zipEntry' => $zipEntry,
676
+ ));
677
+
678
+ $cdEntry = self::ZIP_CENTRAL_FILE_HEADER
679
+ . self::ATTR_MADE_BY_VERSION
680
+ . ($dataLength === 0 ? "\x0A\x00" : self::ATTR_VERSION_TO_EXTRACT)
681
+ . $header
682
+ . pack("v", BinStringStatic::_strlen($cenExField)) // Extra field length
683
+ . pack("v", $fileCommentLength) // File comment length
684
+ . self::NULL_WORD // Disk number start
685
+ . self::NULL_WORD // internal file attributes
686
+ . pack("V", $extFileAttr) // External file attributes
687
+ . pack("V", $this->offset) // Relative offset of local header
688
+ . $filePath // FileName
689
+ . $cenExField; // Extra fields
690
+
691
+ if (!empty($fileComment)) {
692
+ $cdEntry .= $fileComment; // Comment
693
+ }
694
+
695
+ $this->cdRec[] = $cdEntry;
696
+ $this->offset += BinStringStatic::_strlen($zipEntry) + $gzLength;
697
+
698
+ $this->_notifyListeners(null, array(
699
+ 'file' => $zipEntry,
700
+ ));
701
+ }
702
+
703
+ /**
704
+ * Build the base standard response headers, and ensure the content can be streamed.
705
+ *
706
+ * @author A. Grandt <php@grandt.com>
707
+ * @author Greg Kappatos
708
+ *
709
+ * @param String $fileName The name of the Zip archive, in ISO-8859-1 (or ASCII) encoding, ie. "archive.zip". Optional, defaults to null, which means that no ISO-8859-1 encoded file name will be specified.
710
+ * @param String $contentType Content mime type. Optional, defaults to "application/zip".
711
+ * @param String $utf8FileName The name of the Zip archive, in UTF-8 encoding. Optional, defaults to null, which means that no UTF-8 encoded file name will be specified.
712
+ * @param bool $inline Use Content-Disposition with "inline" instead of "attached". Optional, defaults to false.
713
+ *
714
+ * @throws \PHPZip\Zip\Exception\IncompatiblePhpVersion, BufferNotEmpty, HeadersSent In case of errors
715
+ *
716
+ * @return bool Always returns true (for backward compatibility).
717
+ */
718
+ public function buildResponseHeader($fileName = null, $contentType = self::CONTENT_TYPE, $utf8FileName = null, $inline = false) {
719
+ $ob = null;
720
+ $headerFile = null;
721
+ $headerLine = null;
722
+ $zlibConfig = 'zlib.output_compression';
723
+
724
+ $this->onBeginBuildResponseHeader();
725
+
726
+ if (!function_exists('sys_get_temp_dir')) {
727
+ $this->_throwException(new IncompatiblePhpVersionException(array(
728
+ 'appName' => self::APP_NAME,
729
+ 'appVersion' => self::VERSION,
730
+ 'minVersion' => self::MIN_PHP_VERSION,
731
+ )));
732
+ }
733
+
734
+ $ob = ob_get_contents();
735
+ if ($ob !== false && BinStringStatic::_strlen($ob)) {
736
+ $this->_throwException(new BufferNotEmptyException(array(
737
+ 'outputBuffer' => $ob,
738
+ 'fileName' => $fileName,
739
+ )));
740
+ }
741
+
742
+ if (headers_sent($headerFile, $headerLine)) {
743
+ $this->_throwException(new HeadersSentException(array(
744
+ 'headerFile' => $headerFile,
745
+ 'headerLine' => $headerLine,
746
+ 'fileName' => $fileName,
747
+ )));
748
+ }
749
+
750
+ if (@ini_get($zlibConfig)) {
751
+ @ini_set($zlibConfig, 'Off');
752
+ }
753
+
754
+ $cd = 'Content-Disposition: ' . ($inline ? 'inline' : 'attachment');
755
+
756
+ if ($fileName) {
757
+ $cd .= '; filename="' . $fileName . '"';
758
+ }
759
+
760
+ if ($utf8FileName) {
761
+ $cd .= "; filename*=UTF-8''" . rawurlencode($utf8FileName);
762
+ }
763
+
764
+ header('Pragma: public');
765
+ header('Last-Modified: ' . gmdate('D, d M Y H:i:s T'));
766
+ header('Expires: 0');
767
+ header('Accept-Ranges: bytes');
768
+ header('Content-Type: ' . $contentType);
769
+ header($cd);
770
+
771
+ $this->onEndBuildResponseHeader();
772
+
773
+ $this->_notifyListeners(null, array(
774
+ 'file' => $fileName,
775
+ 'utf8FileName' => $utf8FileName,
776
+ 'contentType' => $contentType,
777
+ ));
778
+
779
+ return true;
780
+ }
781
+
782
+ /**
783
+ * Close the archive.
784
+ * A closed archive can no longer have new files added to it.
785
+ *
786
+ * @author A. Grandt <php@grandt.com>
787
+ *
788
+ * @return bool Success
789
+ */
790
+ public function finalize() {
791
+ if (!$this->isFinalized) {
792
+ if (BinStringStatic::_strlen($this->streamFilePath) > 0) {
793
+ $this->closeStream();
794
+ }
795
+
796
+ $cd = implode("", $this->cdRec);
797
+
798
+ $cdRecSize = pack("v", sizeof($this->cdRec));
799
+ $cdRec = $cd . self::ZIP_END_OF_CENTRAL_DIRECTORY
800
+ . self::NULL_DWORD // really two words, used for split archives: #ofThisDisk . #ofDiskWithCD. Both 0.
801
+ . $cdRecSize . $cdRecSize
802
+ . pack("VV", BinStringStatic::_strlen($cd), $this->offset);
803
+
804
+ if (!empty($this->zipComment)) {
805
+ $cdRec .= pack("v", BinStringStatic::_strlen($this->zipComment))
806
+ . $this->zipComment;
807
+ } else {
808
+ $cdRec .= self::NULL_WORD;
809
+ }
810
+
811
+ $this->zipWrite($cdRec);
812
+ $this->zipFlushBuffer();
813
+
814
+ $this->isFinalized = true;
815
+ $this->cdRec = null;
816
+
817
+ return true;
818
+ }
819
+
820
+ return false;
821
+ }
822
+
823
+ /**
824
+ * Check PHP version.
825
+ *
826
+ * @author A. Grandt <php@grandt.com>
827
+ */
828
+ public function checkVersion() {
829
+ if (version_compare(PHP_VERSION, self::MIN_PHP_VERSION, '<') || !function_exists('sys_get_temp_dir') ) {
830
+ die ("ERROR: " . self::APP_NAME . " " . self::VERSION . " requires PHP version " . self::MIN_PHP_VERSION . " or above.");
831
+ }
832
+ }
833
+
834
+ /*
835
+ * ************************************************************************
836
+ * Abstract methods.
837
+ * ************************************************************************
838
+ */
839
+
840
+ /**
841
+ * Called when specialised action is needed
842
+ * while building a zip entry.
843
+ *
844
+ * @author A. Grandt <php@grandt.com>
845
+ * @author Greg Kappatos
846
+ *
847
+ * @param array $params Array that contains zipEntry.
848
+ */
849
+ abstract protected function onBuildZipEntry(array $params);
850
+
851
+ /**
852
+ * Called when specialised action is needed
853
+ * at the start of adding a file to the archive.
854
+ *
855
+ * @author A. Grandt <php@grandt.com>
856
+ * @author Greg Kappatos
857
+ *
858
+ * @param array $params Array that contains gzLength.
859
+ */
860
+ abstract protected function onBeginAddFile(array $params);
861
+
862
+ /**
863
+ * Called when specialised action is needed
864
+ * at the end of adding a file to the archive.
865
+ *
866
+ * @author A. Grandt <php@grandt.com>
867
+ * @author Greg Kappatos
868
+ *
869
+ * @param array $params Array that contains gzData.
870
+ */
871
+ abstract protected function onEndAddFile(array $params);
872
+
873
+ /**
874
+ * Called when specialised action is needed
875
+ * at the start of sending the zip file|stream
876
+ * response headers.
877
+ *
878
+ * @author A. Grandt <php@grandt.com>
879
+ * @author Greg Kappatos
880
+ */
881
+ abstract protected function onBeginBuildResponseHeader();
882
+
883
+ /**
884
+ * Called when specialised action is needed
885
+ * at the end of sending the zip file|stream
886
+ * response headers.
887
+ *
888
+ * @author A. Grandt <php@grandt.com>
889
+ * @author Greg Kappatos
890
+ */
891
+ abstract protected function onEndBuildResponseHeader();
892
+
893
+ /**
894
+ * Called when specialised action is needed
895
+ * while opening a file|stream.
896
+ *
897
+ * @author A. Grandt <php@grandt.com>
898
+ * @author Greg Kappatos
899
+ */
900
+ abstract protected function onOpenStream();
901
+
902
+ /**
903
+ * Called when specialised action is needed
904
+ * while processing a file.
905
+ *
906
+ * @author A. Grandt <php@grandt.com>
907
+ * @author Greg Kappatos
908
+ *
909
+ * @param array $params Array that contains data.
910
+ */
911
+ abstract protected function onProcessFile(array $params);
912
+
913
+ /**
914
+ * Verify if the memory buffer is about to be exceeded.
915
+ *
916
+ * @author A. Grandt <php@grandt.com>
917
+ *
918
+ * @param int $gzLength length of the pending data.
919
+ */
920
+ abstract public function zipVerifyMemBuffer($gzLength);
921
+
922
+ /**
923
+ *
924
+ * @author A. Grandt <php@grandt.com>
925
+ *
926
+ * @param string $data
927
+ */
928
+ //abstract public function zipWrite($data);
929
+
930
+ /**
931
+ * Flush Zip Data stored in memory, to a temp file.
932
+ *
933
+ * @author A. Grandt <php@grandt.com>
934
+ *
935
+ */
936
+ abstract public function zipFlush();
937
+
938
+ /**
939
+ *
940
+ * @author A. Grandt <php@grandt.com>
941
+ *
942
+ */
943
+ abstract public function zipFlushBuffer();
944
+
945
+ /*
946
+ * ************************************************************************
947
+ * Listener methods.
948
+ * ************************************************************************
949
+ */
950
+
951
+ /**
952
+ * Listen to events fired by this class.
953
+ *
954
+ * @author Greg Kappatos
955
+ *
956
+ * @param ZipArchiveListener $listener Class that implements the ZipArchiveListener interface.
957
+ */
958
+ public function addListener(ZipArchiveListener $listener) {
959
+ $this->_listeners[] = $listener;
960
+ }
961
+
962
+ /**
963
+ * Stop listening to events fired by this class.
964
+ *
965
+ * @author Greg Kappatos
966
+ *
967
+ * @param ZipArchiveListener $listener Class that implements the ZipArchiveListener interface.
968
+ */
969
+ public function removeListener(ZipArchiveListener $listener) {
970
+ $key = array_search($listener, $this->_listeners);
971
+
972
+ if ($key !== false) {
973
+ unset($this->_listeners[$key]);
974
+ }
975
+ }
976
+
977
+ /**
978
+ * Helper method to fire appropriate event.
979
+ *
980
+ * @author Greg Kappatos
981
+ *
982
+ * @param string|null $method (Optional) The name of the event to fire. If this is null, then the calling method is used.
983
+ * @param array $data Method parameters passed as an array.
984
+ */
985
+ private function _notifyListeners($method = null, array $data = array()) {
986
+ if (is_null($method)) {
987
+ $backtrace = debug_backtrace();
988
+ if (sizeof($backtrace) > 0) {
989
+ $trace = $backtrace[1];
990
+ $method = 'on' . ucwords($trace['function']);
991
+ }
992
+ }
993
+
994
+ foreach ($this->_listeners as $listener) {
995
+ if (count($data) > 0) {
996
+ $listener->$method($data);
997
+ } else {
998
+ $listener->$method();
999
+ }
1000
+ }
1001
+ }
1002
+
1003
+ /**
1004
+ * Helper method to fire OnException event for listeners and then throw the appropriate exception.
1005
+ *
1006
+ * @author Greg Kappatos
1007
+ *
1008
+ * @param AbstractException $exception Whatever exception needs to be thrown.
1009
+ *
1010
+ * @throws AbstractException $exception
1011
+ */
1012
+ private function _throwException(AbstractException $exception) {
1013
+ $this->_notifyListeners('onException', array(
1014
+ 'exception' => $exception,
1015
+ ));
1016
+
1017
+ throw $exception;
1018
+ }
1019
+
1020
+ /*
1021
+ * ************************************************************************
1022
+ * Static methods/
1023
+ * ************************************************************************
1024
+ */
1025
+
1026
+ /**
1027
+ *
1028
+ * @author A. Grandt <php@grandt.com>
1029
+ * @author Greg Kappatos
1030
+ *
1031
+ * @return string The full path to a temporary file.
1032
+ */
1033
+ public static function getTemporaryFile() {
1034
+ if (is_callable(self::$temp)) {
1035
+ $file = @call_user_func(self::$temp);
1036
+
1037
+ if (is_string($file) && BinStringStatic::_strlen($file) && is_writable($file)) {
1038
+ return $file;
1039
+ }
1040
+ }
1041
+
1042
+ $dir = (is_string(self::$temp) && BinStringStatic::_strlen(self::$temp)) ? self::$temp : sys_get_temp_dir();
1043
+
1044
+ return tempnam($dir, __NAMESPACE__);
1045
+ }
1046
+ }
includes/extensions/zip/Core/ZipUtils.php ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace PHPZip\Zip\Core;
3
+
4
+ use com\grandt\BinStringStatic;
5
+
6
+ class ZipUtils {
7
+ // Unix file types
8
+ const S_IFIFO = 0010000; // named pipe (fifo)
9
+ const S_IFCHR = 0020000; // character special
10
+ const S_IFDIR = 0040000; // directory
11
+ const S_IFBLK = 0060000; // block special
12
+ const S_IFREG = 0100000; // regular
13
+ const S_IFLNK = 0120000; // symbolic link
14
+ const S_IFSOCK = 0140000; // socket
15
+
16
+ // setuid/setgid/sticky bits, the same as for chmod:
17
+ const S_ISUID = 0004000; // set user id on execution
18
+ const S_ISGID = 0002000; // set group id on execution
19
+ const S_ISTXT = 0001000; // sticky bit
20
+
21
+ // And of course, the other 12 bits are for the permissions, the same as for chmod:
22
+ // When adding these up, you can also just write the permissions as a single octal number
23
+ // ie. 0755. The leading 0 specifies octal notation.
24
+ const S_IRWXU = 0000700; // RWX mask for owner
25
+ const S_IRUSR = 0000400; // R for owner
26
+ const S_IWUSR = 0000200; // W for owner
27
+ const S_IXUSR = 0000100; // X for owner
28
+ const S_IRWXG = 0000070; // RWX mask for group
29
+ const S_IRGRP = 0000040; // R for group
30
+ const S_IWGRP = 0000020; // W for group
31
+ const S_IXGRP = 0000010; // X for group
32
+ const S_IRWXO = 0000007; // RWX mask for other
33
+ const S_IROTH = 0000004; // R for other
34
+ const S_IWOTH = 0000002; // W for other
35
+ const S_IXOTH = 0000001; // X for other
36
+ const S_ISVTX = 0001000; // save swapped text even after use
37
+
38
+ // File type, sticky and permissions are added up, and shifted 16 bits left BEFORE adding the DOS flags.
39
+ // DOS file type flags, we really only use the S_DOS_D flag.
40
+ const S_DOS_A = 0000040; // DOS flag for Archive
41
+ const S_DOS_D = 0000020; // DOS flag for Directory
42
+ const S_DOS_V = 0000010; // DOS flag for Volume
43
+ const S_DOS_S = 0000004; // DOS flag for System
44
+ const S_DOS_H = 0000002; // DOS flag for Hidden
45
+ const S_DOS_R = 0000001; // DOS flag for Read Only
46
+
47
+ /**
48
+ * Calculate the 2 byte dos time used in the zip entries.
49
+ *
50
+ * @author A. Grandt <php@grandt.com>
51
+ *
52
+ * @param int $timestamp
53
+ *
54
+ * @return string 2-byte encoded DOS Date
55
+ */
56
+ public static function getDosTime($timestamp = 0) {
57
+ $timestamp = (int)$timestamp;
58
+ $oldTZ = @date_default_timezone_get();
59
+ date_default_timezone_set('UTC');
60
+
61
+ $date = ($timestamp == 0 ? getdate() : getdate($timestamp));
62
+ date_default_timezone_set($oldTZ);
63
+
64
+ if ($date["year"] >= 1980) { // Dos dates start on 1 Jan 1980
65
+ return pack("V", (($date["mday"] + ($date["mon"] << 5) + (($date["year"] - 1980) << 9)) << 16) |
66
+ (($date["seconds"] >> 1) + ($date["minutes"] << 5) + ($date["hours"] << 11)));
67
+ }
68
+ return "\x00\x00\x00\x00";
69
+ }
70
+
71
+ /**
72
+ * Create the file permissions for a file or directory, for use in the extFileAttr parameters.
73
+ *
74
+ * @author A. Grandt <php@grandt.com>
75
+ *
76
+ * @param int $owner Unix permissions for owner (octal from 00 to 07)
77
+ * @param int $group Unix permissions for group (octal from 00 to 07)
78
+ * @param int $other Unix permissions for others (octal from 00 to 07)
79
+ * @param bool $isFile
80
+ *
81
+ * @return string EXTERNAL_REF field.
82
+ */
83
+ public static function generateExtAttr($owner = 07, $group = 05, $other = 05, $isFile = true) {
84
+ $fp = $isFile ? self::S_IFREG : self::S_IFDIR;
85
+ $fp |= (($owner & 07) << 6) | (($group & 07) << 3) | ($other & 07);
86
+
87
+ return ($fp << 16) | ($isFile ? self::S_DOS_A : self::S_DOS_D);
88
+ }
89
+
90
+ /**
91
+ * Get the file permissions for a file or directory, for use in the extFileAttr parameters.
92
+ *
93
+ * @author A. Grandt <php@grandt.com>
94
+ *
95
+ * @param string $filename
96
+ *
97
+ * @return string|bool external ref field, or false if the file is not found.
98
+ */
99
+ public static function getFileExtAttr($filename) {
100
+ if (file_exists($filename)) {
101
+ $fp = fileperms($filename) << 16;
102
+ return $fp | (is_dir($filename) ? self::S_DOS_D : self::S_DOS_A);
103
+ }
104
+
105
+ return false;
106
+ }
107
+
108
+ public static function testBit($data, $bit) {
109
+ $bv = 1 << $bit;
110
+ return ($data & $bv) == $bv;
111
+ }
112
+
113
+ public static function setBit(&$data, $bit, $value = true) {
114
+ if ($value) {
115
+ $data |= (1 << $bit);
116
+ } else {
117
+ self::clrBit($data, $bit);
118
+ }
119
+
120
+ }
121
+
122
+ public static function clrBit(&$data, $bit) {
123
+ $data &= ~(1 << $bit);
124
+ }
125
+ }
includes/extensions/zip/Core/index.html ADDED
File without changes
includes/extensions/zip/Exception/BufferNotEmpty.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ * @author Greg Kappatos
5
+ *
6
+ * This class serves as a concrete exception.
7
+ * It will be thrown if the output buffer contains data while
8
+ * trying to perform any operations with this library.
9
+ *
10
+ */
11
+
12
+ namespace PHPZip\Zip\Exception;
13
+
14
+ use PHPZip\Zip\Core\AbstractException;
15
+
16
+ class BufferNotEmpty extends AbstractException {
17
+
18
+ private $_outputBuffer = null;
19
+ private $_fileName = null;
20
+
21
+ /**
22
+ * Constructor
23
+ *
24
+ * @author A. Grandt <php@grandt.com>
25
+ * @author Greg Kappatos
26
+ *
27
+ * @param array $config Configuration array containing outputBuffer and fileName
28
+ */
29
+ public function __construct(array $config){
30
+ $this->_outputBuffer = $config['outputBuffer'];
31
+ $this->_fileName = isset($config['fileName']) ? $config['fileName'] : null;
32
+
33
+ $message = is_null($this->_fileName) ? '' : "Unable to send '{$this->_fileName}'. ";
34
+ $message .= "Output buffer contains the following text (typically warning or errors):\n{$this->_outputBuffer}";
35
+
36
+ parent::__construct($message);
37
+ }
38
+
39
+ public function getOutputBuffer(){
40
+ return $this->_outputBuffer;
41
+ }
42
+
43
+ public function getFileName(){
44
+ return $this->_fileName;
45
+ }
46
+ }
includes/extensions/zip/Exception/HeaderPositionError.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ * @author Greg Kappatos
5
+ *
6
+ * This class serves as a concrete exception.
7
+ * It will be thrown if the output length of fwrite() does not match
8
+ * the input length. So far, this only occurs in Core\AbstractZipArchive::addStreamData()
9
+ *
10
+ */
11
+
12
+ namespace PHPZip\Zip\Exception;
13
+
14
+ use PHPZip\Zip\Core\AbstractException;
15
+
16
+ class HeaderPositionError extends AbstractException {
17
+
18
+ private $_expected = null;
19
+ private $_actual = null;
20
+
21
+ /**
22
+ * Constructor
23
+ *
24
+ * @author A. Grandt <php@grandt.com>
25
+ * @author Greg Kappatos
26
+ *
27
+ * @param array $config Configuration array containing expected and written
28
+ */
29
+ public function __construct(array $config){
30
+ $this->_expected = (string)$config['expected'];
31
+ $this->_actual = (string)$config['actual'];
32
+
33
+ $message = sprintf(
34
+ '%s %s %s %s %s',
35
+ (string)($this->_actual - $this->_expected),
36
+ ' extra bytes before header. Expected pos ',
37
+ $this->_expected,
38
+ ' but found the header at ',
39
+ $this->_actual
40
+ );
41
+
42
+ parent::__construct($message);
43
+ }
44
+
45
+ public function getExpected(){
46
+ return $this->_expected;
47
+ }
48
+
49
+ public function getActual(){
50
+ return $this->_actual;
51
+ }
52
+ }
includes/extensions/zip/Exception/HeadersSent.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ * @author Greg Kappatos
5
+ *
6
+ * This class serves as a concrete exception.
7
+ * It will be thrown if any headers have been sent, or if any
8
+ * output has been printed or echoed.
9
+ *
10
+ */
11
+
12
+ namespace PHPZip\Zip\Exception;
13
+
14
+ use PHPZip\Zip\Core\AbstractException;
15
+
16
+ class HeadersSent extends AbstractException {
17
+
18
+ private $_headerFile = null;
19
+ private $_headerLine = null;
20
+ private $_fileName = null;
21
+
22
+ /**
23
+ * Constructor
24
+ *
25
+ * @author A. Grandt <php@grandt.com>
26
+ * @author Greg Kappatos
27
+ *
28
+ * @param array $config Configuration array containing headerFile, headerLine and fileName
29
+ */
30
+ public function __construct(array $config){
31
+ $this->_headerFile = $config['headerFile'];
32
+ $this->_headerLine = $config['headerLine'];
33
+ $this->_fileName = isset($config['fileName']) ? $config['fileName'] : null;
34
+
35
+ $message = is_null($this->_fileName) ? '' : "Unable to send '{$this->_fileName}'. ";
36
+ $message .= "Headers have already been sent from '{$this->_headerFile}' in line {$this->_headerLine}";
37
+
38
+ parent::__construct($message);
39
+ }
40
+
41
+ public function getHeaderFile(){
42
+ return $this->_headerFile;
43
+ }
44
+
45
+ public function getHeaderLine(){
46
+ return $this->_headerLine;
47
+ }
48
+
49
+ public function getFileName(){
50
+ return $this->_fileName;
51
+ }
52
+ }
includes/extensions/zip/Exception/IncompatiblePhpVersion.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ * @author Greg Kappatos
5
+ *
6
+ * This class serves as a concrete exception.
7
+ * It will be thrown if the current PHP version is below the minimum
8
+ * required version.
9
+ *
10
+ */
11
+
12
+ namespace PHPZip\Zip\Exception;
13
+
14
+ use PHPZip\Zip\Core\AbstractException;
15
+
16
+ class IncompatiblePhpVersion extends AbstractException {
17
+
18
+ private $_minVersion = null;
19
+ private $_currentVersion = null;
20
+
21
+ /**
22
+ * Constructor
23
+ *
24
+ * @author A. Grandt <php@grandt.com>
25
+ * @author Greg Kappatos
26
+ *
27
+ * @param array $config Configuration array containing appName, appVersion and minVersion (PHP)
28
+ */
29
+ public function __construct(array $config){
30
+ $this->_minVersion = (string)$config['minVersion'];
31
+ $this->_currentVersion = (string)phpversion();
32
+
33
+ $message = sprintf(
34
+ '%s %s %s %s %s (%s %s).',
35
+ $config['appName'],
36
+ (string)$config['appVersion'],
37
+ 'requires PHP version',
38
+ $this->_minVersion,
39
+ 'or above',
40
+ $this->_currentVersion,
41
+ 'detected'
42
+ );
43
+
44
+ parent::__construct($message);
45
+ }
46
+
47
+ public function getMinVersion(){
48
+ return $this->_minVersion;
49
+ }
50
+
51
+ public function getCurrentVersion(){
52
+ return $this->_currentVersion;
53
+ }
54
+ }
includes/extensions/zip/Exception/InvalidPhpConfiguration.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ * @author Greg Kappatos
5
+ *
6
+ * This class serves as a concrete exception.
7
+ * It will be thrown if an invalid setting is detected in php.ini
8
+ * that will prevent this library from operating properly.
9
+ *
10
+ */
11
+
12
+ namespace PHPZip\Zip\Exception;
13
+
14
+ use PHPZip\Zip\Core\AbstractException;
15
+
16
+ class InvalidPhpConfiguration extends AbstractException {
17
+
18
+ private $_setting = null;
19
+ private $_expected = null;
20
+ private $_actual = null;
21
+
22
+ /**
23
+ * Constructor
24
+ *
25
+ * @author Greg Kappatos
26
+ *
27
+ * @param array $config Configuration array containing php.ini settings: setting and expected (value)
28
+ */
29
+ public function __construct(array $config){
30
+ $this->_setting = $config['setting'];
31
+ $this->_expected = $config['expected'];
32
+ $this->_actual = (string)@ini_get($this->_setting);
33
+
34
+ $message = sprintf(
35
+ '%s %s "%s" %s %s %s',
36
+ 'Invalid PHP Configuration: ',
37
+ $this->_setting,
38
+ $this->_actual,
39
+ 'Please change this setting to',
40
+ $this->_expected,
41
+ 'to continue.'
42
+ );
43
+
44
+ parent::__construct($message);
45
+ }
46
+
47
+ public function getSetting(){
48
+ return $this->_setting;
49
+ }
50
+
51
+ public function getExpected(){
52
+ return $this->_expected;
53
+ }
54
+
55
+ public function getActual(){
56
+ return $this->_actual;
57
+ }
58
+ }
includes/extensions/zip/Exception/LengthMismatch.php ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ * @author Greg Kappatos
5
+ *
6
+ * This class serves as a concrete exception.
7
+ * It will be thrown if the output length of fwrite() does not match
8
+ * the input length. So far, this only occurs in Core\AbstractZipArchive::addStreamData()
9
+ *
10
+ */
11
+
12
+ namespace PHPZip\Zip\Exception;
13
+
14
+ use PHPZip\Zip\Core\AbstractException;
15
+
16
+ class LengthMismatch extends AbstractException {
17
+
18
+ private $_expected = null;
19
+ private $_written = null;
20
+
21
+ /**
22
+ * Constructor
23
+ *
24
+ * @author A. Grandt <php@grandt.com>
25
+ * @author Greg Kappatos
26
+ *
27
+ * @param array $config Configuration array containing expected and written
28
+ */
29
+ public function __construct(array $config){
30
+ $this->_expected = (string)$config['expected'];
31
+ $this->_written = (string)$config['written'];
32
+
33
+ $message = sprintf(
34
+ '%s %s %s %s',
35
+ 'Length Mismatch Error: Expected',
36
+ $this->_expected,
37
+ 'bytes, wrote',
38
+ $this->_written
39
+ );
40
+
41
+ parent::__construct($message);
42
+ }
43
+
44
+ public function getExpected(){
45
+ return $this->_expected;
46
+ }
47
+
48
+ public function getWritten(){
49
+ return $this->_written;
50
+ }
51
+ }
includes/extensions/zip/Exception/index.html ADDED
File without changes
includes/extensions/zip/File/Zip.php ADDED
@@ -0,0 +1,187 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ * @author A. Grandt <php@grandt.com>
5
+ * @author Greg Kappatos
6
+ *
7
+ * This class serves as a concrete zip file archive.
8
+ *
9
+ */
10
+
11
+ namespace PHPZip\Zip\File;
12
+
13
+ use com\grandt\BinStringStatic;
14
+ use PHPZip\Zip\Core\AbstractZipArchive;
15
+
16
+ class Zip extends AbstractZipArchive {
17
+
18
+ const MEMORY_THRESHOLD = 1048576; // 1 MB - Auto create temp file if the zip data exceeds this
19
+ const STREAM_CHUNK_SIZE = 65536; // 64 KB
20
+
21
+ private $_zipData = null;
22
+ private $_zipFile = null;
23
+
24
+ public function __construct($useZipFile = false) {
25
+ parent::__construct(self::STREAM_CHUNK_SIZE);
26
+
27
+ if ($useZipFile) {
28
+ $this->_zipFile = tmpfile();
29
+ } else {
30
+ $this->_zipData = '';
31
+ }
32
+ }
33
+
34
+ public function __destruct() {
35
+ if (is_resource($this->_zipFile)) {
36
+ fclose($this->_zipFile);
37
+ }
38
+
39
+ $this->_zipData = null;
40
+ }
41
+
42
+ public function setZipFile($fileName) {
43
+ if (is_file($fileName)) {
44
+ unlink($fileName);
45
+ }
46
+
47
+ $fd = fopen($fileName, "x+b");
48
+
49
+ if (is_resource($this->_zipFile)) {
50
+ rewind($this->_zipFile);
51
+
52
+ while (!feof($this->_zipFile)) {
53
+ fwrite($fd, fread($this->_zipFile, $this->streamChunkSize));
54
+ }
55
+
56
+ fclose($this->_zipFile);
57
+ } else {
58
+ fwrite($fd, $this->_zipData);
59
+ $this->_zipData = null;
60
+ }
61
+
62
+ $this->_zipFile = $fd;
63
+ return true;
64
+ }
65
+
66
+ public function saveZipFile($fileName) {
67
+ return $this->setZipFile($fileName);
68
+ }
69
+
70
+ public function getZipFile() {
71
+ if (!$this->isFinalized) {
72
+ $this->finalize();
73
+ }
74
+
75
+ $this->zipFlush();
76
+ rewind($this->_zipFile);
77
+ return $this->_zipFile;
78
+ }
79
+
80
+ public function sendZip($fileName = null, $contentType = self::CONTENT_TYPE, $utf8FileName = null, $inline = false) {
81
+ if (!$this->isFinalized) {
82
+ $this->finalize();
83
+ }
84
+
85
+ if ($this->buildResponseHeader($fileName, $contentType, $utf8FileName, $inline)) {
86
+ return true;
87
+ }
88
+ return false;
89
+ }
90
+
91
+ public function getZipData() {
92
+ $result = null;
93
+
94
+ if (!$this->isFinalized) {
95
+ $this->finalize();
96
+ }
97
+
98
+ if (!is_resource($this->_zipFile)) {
99
+ $result = $this->_zipData;
100
+ } else {
101
+ rewind($this->_zipFile);
102
+ $stat = fstat($this->_zipFile);
103
+ $result = fread($this->_zipFile, $stat['size']);
104
+ }
105
+
106
+ return $result;
107
+ }
108
+
109
+ public function getArchiveSize() {
110
+ if (!is_resource($this->_zipFile)) {
111
+ return BinStringStatic::_strlen($this->_zipData);
112
+ }
113
+
114
+ $stat = fstat($this->_zipFile);
115
+ return $stat['size'];
116
+ }
117
+
118
+ public function onBuildZipEntry(array $params) {
119
+ $this->zipWrite($params['zipEntry']);
120
+ }
121
+
122
+ public function onBeginAddFile(array $params) {
123
+ if (!is_resource($this->_zipFile) && ($this->offset + $params['gzLength']) > self::MEMORY_THRESHOLD) {
124
+ $this->zipFlush();
125
+ }
126
+ }
127
+
128
+ public function onEndAddFile(array $params) {
129
+ $this->zipWrite($params['gzData']);
130
+ }
131
+
132
+ public function onBeginBuildResponseHeader() {
133
+ if (!$this->isFinalized) {
134
+ $this->finalize();
135
+ }
136
+ }
137
+
138
+ public function onEndBuildResponseHeader() {
139
+ header('Connection: close');
140
+ header('Content-Length: ' . $this->getArchiveSize());
141
+
142
+ if (!is_resource($this->_zipFile)) {
143
+ echo $this->_zipData;
144
+ } else {
145
+ rewind($this->_zipFile);
146
+
147
+ while (!feof($this->_zipFile)) {
148
+ echo fread($this->_zipFile, $this->streamChunkSize);
149
+ }
150
+ }
151
+ }
152
+
153
+ public function onOpenStream() {
154
+ $this->zipFlush();
155
+ }
156
+
157
+ public function onProcessFile(array $params) {
158
+ $this->zipWrite($params['data']);
159
+ }
160
+
161
+ public function zipVerifyMemBuffer($gzLength) {
162
+ if (!is_resource($this->_zipFile) && ($this->offset + $gzLength) > self::MEMORY_THRESHOLD) {
163
+ $this->zipFlush();
164
+ }
165
+ }
166
+
167
+ public function zipWrite($data) {
168
+ if (!is_resource($this->_zipFile)) {
169
+ $this->_zipData .= $data;
170
+ } else {
171
+ fwrite($this->_zipFile, $data);
172
+ fflush($this->_zipFile);
173
+ }
174
+ }
175
+
176
+ public function zipFlush() {
177
+ if (!is_resource($this->_zipFile)) {
178
+ $this->_zipFile = tmpfile();
179
+ fwrite($this->_zipFile, $this->_zipData);
180
+ $this->_zipData = null;
181
+ }
182
+ }
183
+
184
+ public function zipFlushBuffer() {
185
+ // Does nothing.
186
+ }
187
+ }
includes/extensions/zip/File/index.html ADDED
File without changes
includes/extensions/zip/Listener/ZipArchiveListener.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ * @author Greg Kappatos
5
+ *
6
+ * This class serves as an observer/listener which can be implemented
7
+ * by any other class who is interested in the PHPZip events.
8
+ * Simply implement the methods and call Stream\ZipStream or
9
+ * File\Zip::addListener($this) from inside your class.
10
+ *
11
+ */
12
+
13
+ namespace PHPZip\Zip\Listener;
14
+
15
+ interface ZipArchiveListener {
16
+
17
+ public function onBuildZipEntry(array $params);
18
+
19
+ public function onOpenStream(array $params);
20
+
21
+ public function onAddFile(array $params);
22
+
23
+ public function onAddLargeFile(array $params);
24
+
25
+ public function onSendZip(array $params);
26
+
27
+ public function onException(array $params);
28
+
29
+ }
includes/extensions/zip/Listener/index.html ADDED
File without changes
includes/extensions/zip/Stream/ZipStream.php ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ * @author A. Grandt <php@grandt.com>
5
+ * @author Greg Kappatos
6
+ *
7
+ * This class serves as a concrete zip stream archive.
8
+ *
9
+ */
10
+
11
+ namespace PHPZip\Zip\Stream;
12
+
13
+ use PHPZip\Zip\Core\AbstractZipArchive;
14
+
15
+ class ZipStream extends AbstractZipArchive {
16
+
17
+ const STREAM_CHUNK_SIZE = 16384; // 16 KB
18
+ private $maxStreamBufferLength = 1048576;
19
+
20
+ /**
21
+ * Constructor.
22
+ *
23
+ * @author A. Grandt <php@grandt.com>
24
+ * @author Greg Kappatos
25
+ *
26
+ * @param String $fileName The name of the Zip archive, in ISO-8859-1 (or ASCII) encoding, ie. "archive.zip". Optional, defaults to NULL, which means that no ISO-8859-1 encoded file name will be specified.
27
+ * @param String $contentType Content mime type. Optional, defaults to "application/zip".
28
+ * @param String $utf8FileName The name of the Zip archive, in UTF-8 encoding. Optional, defaults to NULL, which means that no UTF-8 encoded file name will be specified.
29
+ * @param bool $inline Use Content-Disposition with "inline" instead of "attached". Optional, defaults to FALSE.
30
+ *
31
+ * @throws \PHPZip\Zip\Exception\BufferNotEmpty, HeadersSent, IncompatiblePhpVersion, InvalidPhpConfiguration In case of errors
32
+ */
33
+ public function __construct($fileName = '', $contentType = self::CONTENT_TYPE, $utf8FileName = null, $inline = false) {
34
+ parent::__construct(self::STREAM_CHUNK_SIZE);
35
+ $this->buildResponseHeader($fileName, $contentType, $utf8FileName, $inline);
36
+ }
37
+
38
+ /**
39
+ * Destructor.
40
+ * Perform clean up actions.
41
+ * Please note that frameworks are absolutely prohibited from sending ANYTHING to the output after the Zip is sent.
42
+ *
43
+ * @author A. Grandt <php@grandt.com>
44
+ */
45
+ public function __destruct(){
46
+ $this->isFinalized = true;
47
+ $this->cdRec = null;
48
+ }
49
+
50
+ /*
51
+ * ************************************************************************
52
+ * Superclass callbacks.
53
+ * ************************************************************************
54
+ */
55
+
56
+ /**
57
+ * Called by superclass when specialised action is needed
58
+ * while building a zip entry.
59
+ *
60
+ * @author A. Grandt <php@grandt.com>
61
+ * @author Greg Kappatos
62
+ *
63
+ * @param array $params Array that contains zipEntry.
64
+ */
65
+ public function onBuildZipEntry(array $params){
66
+ print($params['zipEntry']);
67
+ }
68
+
69
+ /**
70
+ * Called by superclass when specialised action is needed
71
+ * at the start of adding a file to the archive.
72
+ *
73
+ * @author A. Grandt <php@grandt.com>
74
+ * @author Greg Kappatos
75
+ *
76
+ * @param array $params Array that contains gzLength.
77
+ */
78
+ public function onBeginAddFile(array $params){
79
+ // Do nothing.
80
+ }
81
+
82
+ /**
83
+ * Called by superclass when specialised action is needed
84
+ * at the end of adding a file to the archive.
85
+ *
86
+ * @author A. Grandt <php@grandt.com>
87
+ * @author Greg Kappatos
88
+ *
89
+ * @param array $params Array that contains gzData.
90
+ */
91
+ public function onEndAddFile(array $params){
92
+ print($params['gzData']);
93
+ }
94
+
95
+ /**
96
+ * Called by superclass when specialised action is needed
97
+ * at the start of sending the zip stream response header.
98
+ *
99
+ * @author A. Grandt <php@grandt.com>
100
+ * @author Greg Kappatos
101
+ */
102
+ public function onBeginBuildResponseHeader(){
103
+ // Do nothing.
104
+ }
105
+
106
+ /**
107
+ * Called by superclass when specialised action is needed
108
+ * at the end of sending the zip stream response header.
109
+ *
110
+ * @author A. Grandt <php@grandt.com>
111
+ * @author Greg Kappatos
112
+ */
113
+ public function onEndBuildResponseHeader(){
114
+ //header("Connection: Keep-Alive");
115
+ $this->zipFlushBuffer();
116
+ }
117
+
118
+ /**
119
+ * Called by superclass when specialised action is needed
120
+ * while opening a stream.
121
+ *
122
+ * @author A. Grandt <php@grandt.com>
123
+ * @author Greg Kappatos
124
+ */
125
+ public function onOpenStream(){
126
+ // Do nothing.
127
+ }
128
+
129
+ /**
130
+ * Called by superclass when specialised action is needed
131
+ * while processing a file.
132
+ *
133
+ * @author A. Grandt <php@grandt.com>
134
+ * @author Greg Kappatos
135
+ *
136
+ * @param array $params Array that contains data.
137
+ */
138
+ public function onProcessFile(array $params){
139
+ print($params['data']);
140
+ $this->zipFlushBuffer();
141
+ }
142
+
143
+ /**
144
+ * Verify if the memory buffer is about to be exceeded.
145
+ *
146
+ * @author A. Grandt <php@grandt.com>
147
+ *
148
+ * @param int $gzLength length of the pending data.
149
+ */
150
+ public function zipVerifyMemBuffer($gzLength) {
151
+ if (ob_get_length() !== FALSE && ob_get_length() > $this->maxStreamBufferLength) {
152
+
153
+ ob_flush();
154
+
155
+ while (ob_get_length() > $this->maxStreamBufferLength) {
156
+ usleep(500000);
157
+ }
158
+ }
159
+ }
160
+
161
+ /**
162
+ *
163
+ * @author A. Grandt <php@grandt.com>
164
+ *
165
+ * @param string $data
166
+ */
167
+ public function zipWrite($data) {
168
+ print($data);
169
+ }
170
+
171
+ /**
172
+ * Flush Zip Data stored in memory, to a temp file.
173
+ *
174
+ * @author A. Grandt <php@grandt.com>
175
+ *
176
+ */
177
+ public function zipFlush() {
178
+ // Does nothing.
179
+ }
180
+
181
+ /**
182
+ *
183
+ * @author A. Grandt <php@grandt.com>
184
+ *
185
+ */
186
+ public function zipFlushBuffer() {
187
+ flush();
188
+ $this->zipVerifyMemBuffer(0);
189
+ }
190
+
191
+ /**
192
+ * @return int
193
+ */
194
+ public function getMaxStreamBufferLength() {
195
+ return $this->maxStreamBufferLength;
196
+ }
197
+
198
+ /**
199
+ * @param int $maxStreamBufferLength
200
+ */
201
+ public function setMaxStreamBufferLength($maxStreamBufferLength) {
202
+ $this->maxStreamBufferLength = $maxStreamBufferLength;
203
+ }
204
+ }
includes/extensions/zip/Stream/index.html ADDED
File without changes
includes/extensions/zip/index.html ADDED
File without changes
includes/frontend/rbs_gallery_class.php CHANGED
@@ -86,7 +86,10 @@ class roboGallery extends roboGalleryUtils{
86
  public $debug = 0;
87
 
88
  public $seoContent = '';
89
-
 
 
 
90
  function updateCountView(){
91
  if(!$this->id) return ;
92
  $count_key = 'gallery_views_count';
@@ -100,6 +103,9 @@ class roboGallery extends roboGalleryUtils{
100
  }
101
 
102
  function __construct($attr){
 
 
 
103
  $this->helper = new roboGalleryHelper();
104
  $this->galleryId = 'rbs_gallery_'.uniqid();
105
 
@@ -107,8 +113,6 @@ class roboGallery extends roboGalleryUtils{
107
 
108
  $this->id = $attr['id'];
109
 
110
-
111
-
112
  $options_id = (int) get_post_meta( $this->id, ROBO_GALLERY_PREFIX.'options', true );
113
  if($options_id){
114
  $this->real_id = $this->id;
@@ -187,7 +191,40 @@ class roboGallery extends roboGalleryUtils{
187
  public function getGallery( ){
188
  if( !$this->id ) return '';
189
 
190
- $this->updateCountView();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
 
192
  //$galleryImages = get_post_meta( $this->options_id && $this->real_id ? $this->real_id : $this->id, ROBO_GALLERY_PREFIX.'galleryImages', true );;
193
  //if( !$galleryImages || !is_array( $galleryImages ) || !count($galleryImages) || !(int)$galleryImages[0] ) return '';
@@ -439,13 +476,7 @@ class roboGallery extends roboGalleryUtils{
439
 
440
  if(count($this->selectImages->imgArray)){
441
 
442
- if( get_option( ROBO_GALLERY_PREFIX.'jqueryVersion', 'build' )=='forced' ){
443
- $this->robo_gallery_styles();
444
- $this->robo_gallery_scripts();
445
- } else {
446
- add_action( 'get_footer', array($this, 'robo_gallery_styles') );
447
- add_action( 'get_footer', array($this, 'robo_gallery_scripts') );
448
- }
449
 
450
  for ($i=0; $i<count($this->selectImages->imgArray); $i++) {
451
 
@@ -572,7 +603,23 @@ class roboGallery extends roboGalleryUtils{
572
  }
573
  }
574
  }
575
- return $this->returnHtml;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
576
  }
577
 
578
 
86
  public $debug = 0;
87
 
88
  public $seoContent = '';
89
+
90
+ public $startTime = 0 ;
91
+ public $endTime = 0 ;
92
+
93
  function updateCountView(){
94
  if(!$this->id) return ;
95
  $count_key = 'gallery_views_count';
103
  }
104
 
105
  function __construct($attr){
106
+
107
+ $this->startTime = microtime(true);
108
+
109
  $this->helper = new roboGalleryHelper();
110
  $this->galleryId = 'rbs_gallery_'.uniqid();
111
 
113
 
114
  $this->id = $attr['id'];
115
 
 
 
116
  $options_id = (int) get_post_meta( $this->id, ROBO_GALLERY_PREFIX.'options', true );
117
  if($options_id){
118
  $this->real_id = $this->id;
191
  public function getGallery( ){
192
  if( !$this->id ) return '';
193
 
194
+ $cache = get_post_meta( $this->id, ROBO_GALLERY_PREFIX.'cache', true );
195
+
196
+ if($cache){
197
+ $cacheId = $this->real_id ? $this->real_id : $this->id ;
198
+ $cached_result = get_transient( 'robo_gallery_cached_id'. $cacheId );
199
+ }
200
+
201
+ //$cached_result = '';
202
+
203
+ if( get_option( ROBO_GALLERY_PREFIX.'jqueryVersion', 'build' )=='forced' ){
204
+ $this->robo_gallery_styles();
205
+ $this->robo_gallery_scripts();
206
+ } else {
207
+ add_action( 'get_footer', array($this, 'robo_gallery_styles') );
208
+ add_action( 'get_footer', array($this, 'robo_gallery_scripts') );
209
+ }
210
+
211
+ $this->updateCountView();
212
+
213
+
214
+ if( $cache && $cached_result ){
215
+
216
+ $debugText = '';
217
+
218
+ if($this->debug){
219
+ $this->endTime = microtime(true);
220
+ $execution_time = ($this->endTime - $this->startTime);
221
+ $debugText = '<b>Total Execution Time (cache) </b> '.$execution_time;
222
+ }
223
+
224
+ return $debugText.$cached_result;
225
+ }
226
+
227
+
228
 
229
  //$galleryImages = get_post_meta( $this->options_id && $this->real_id ? $this->real_id : $this->id, ROBO_GALLERY_PREFIX.'galleryImages', true );;
230
  //if( !$galleryImages || !is_array( $galleryImages ) || !count($galleryImages) || !(int)$galleryImages[0] ) return '';
476
 
477
  if(count($this->selectImages->imgArray)){
478
 
479
+
 
 
 
 
 
 
480
 
481
  for ($i=0; $i<count($this->selectImages->imgArray); $i++) {
482
 
603
  }
604
  }
605
  }
606
+
607
+ $debugText = '';
608
+
609
+ if( $cache ){
610
+ set_transient( 'robo_gallery_cached_id'.$cacheId , $this->returnHtml, 12 * HOUR_IN_SECONDS );
611
+
612
+ if($this->debug){
613
+ $this->endTime = microtime(true);
614
+ $execution_time = ($this->endTime - $this->startTime);
615
+ $debugText = '<b>Total Execution Time:</b> '.$execution_time;
616
+ }
617
+ }
618
+
619
+
620
+
621
+
622
+ return $debugText.$this->returnHtml;
623
  }
624
 
625
 
includes/options/cache.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * Robo Gallery By Robosoft
4
+ * Version: 2.6.18
5
+ * Contact: https://robosoft.co/robogallery/
6
+ * Available only in https://robosoft.co/robogallery/
7
+ */
8
+ if ( ! defined( 'ABSPATH' ) ) exit;
9
+
10
+ $cache_box = new_cmb2_box( array(
11
+ 'id' => ROBO_GALLERY_PREFIX . 'cache_metabox',
12
+ 'title' => '<span class="dashicons dashicons-dashboard"></span> '.__( 'Cache', 'robo-gallery' ),
13
+ 'object_types' => array( ROBO_GALLERY_TYPE_POST ),
14
+ 'show_names' => false,
15
+ 'context' => 'normal',
16
+ 'priority' => 'high',
17
+ ));
18
+
19
+ $cache_box->add_field( array(
20
+ 'name' => __('Cache','robo-gallery'),
21
+ 'default' => '',
22
+ 'options' => array(
23
+ '' => 'Disable',
24
+ '1' => 'Enable',
25
+ ),
26
+ 'id' => ROBO_GALLERY_PREFIX .'cache',
27
+ 'type' => 'rbsradiobutton',
28
+ 'before_row' => '
29
+ <div class="rbs_block">
30
+
31
+ <div class="row">
32
+ <div class="col-sm-12">
33
+ '.__('Make your gallery unbelievable faster. With enabled cache option you gallery load faster in ten times.', 'robo-gallery').'
34
+ </div>
35
+ </div>
36
+
37
+ <br />
38
+ ',
39
+ 'after_row' => '
40
+
41
+ <div class="row">
42
+ <div class="col-sm-12">
43
+ '.__('If you modify settings gallery generate new cache after save.', 'robo-gallery').'
44
+ </div>
45
+ </div>
46
+
47
+ </div> ',
48
+ ));
includes/options/rbs_gallery_options_images.php CHANGED
@@ -23,6 +23,13 @@ $images_group = new_cmb2_box( array(
23
  'show_names' => false,
24
  ));
25
 
 
 
 
 
 
 
 
26
  $images_group->add_field(array(
27
  'name' => __( 'Manage Images', 'rbs_gallery' ),
28
  'desc' => __( 'Click on Manage Images button to open Images Manager where you can upload, edit or delete images from gallery. Also here you can edit settings of every particular image, define alt, links, description text', 'rbs_gallery' ),
23
  'show_names' => false,
24
  ));
25
 
26
+ /*$images_group->add_field(array(
27
+ 'name' => __( 'cache_id', 'rbs_gallery' ),
28
+ 'id' => ROBO_GALLERY_PREFIX . 'cache_id',
29
+ 'type' => 'hidden',
30
+ 'default' => uniqid(),
31
+ ));
32
+ */
33
  $images_group->add_field(array(
34
  'name' => __( 'Manage Images', 'rbs_gallery' ),
35
  'desc' => __( 'Click on Manage Images button to open Images Manager where you can upload, edit or delete images from gallery. Also here you can edit settings of every particular image, define alt, links, description text', 'rbs_gallery' ),
includes/options/rbs_gallery_options_tools.php CHANGED
@@ -28,6 +28,8 @@ if(isset($_GET['post'])){
28
  'type' => 'title',
29
  'before_row' => '<div class="rbs_block">'
30
  .'<div class="rbs-center-block rbs-margin-block rbs-post-tools">'
 
 
31
  .'<button id="rbs_create_article" data-galleryid="'.(int)$_GET['post'].'" class="btn btn-info btn-lg ">'
32
  .'<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> '
33
  .__('Create post','rbs_gallery')
@@ -37,7 +39,7 @@ if(isset($_GET['post'])){
37
  .'<span class="glyphicon glyphicon-list-alt" aria-hidden="true"></span> '
38
  .__('Posts List','rbs_gallery')
39
  .'</button>'
40
- .'<p class="rbs_desc">'.__('Here you can create and customize new post with gallery inside it','rbs_gallery').'</p> '
41
  .'<p>'
42
  .'<span class="glyphicon glyphicon-eye-open"></span> '
43
  .__('Gallery Views','rbs_gallery').': '
28
  'type' => 'title',
29
  'before_row' => '<div class="rbs_block">'
30
  .'<div class="rbs-center-block rbs-margin-block rbs-post-tools">'
31
+ .'<p class="rbs_desc">'.__('Here you can create and customize new post with gallery inside it','rbs_gallery').'</p> '
32
+
33
  .'<button id="rbs_create_article" data-galleryid="'.(int)$_GET['post'].'" class="btn btn-info btn-lg ">'
34
  .'<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> '
35
  .__('Create post','rbs_gallery')
39
  .'<span class="glyphicon glyphicon-list-alt" aria-hidden="true"></span> '
40
  .__('Posts List','rbs_gallery')
41
  .'</button>'
42
+ .'<p></p>'
43
  .'<p>'
44
  .'<span class="glyphicon glyphicon-eye-open"></span> '
45
  .__('Gallery Views','rbs_gallery').': '
includes/rbs_gallery_edit.php CHANGED
@@ -24,7 +24,9 @@ function rbs_gallery_group_metabox() {
24
  }
25
 
26
  rbs_gallery_include( array(
 
27
  'voting.php',
 
28
  'rbs_gallery_options_guides.php',
29
  'rbs_gallery_options_images.php',
30
  ), ROBO_GALLERY_OPTIONS_PATH);
24
  }
25
 
26
  rbs_gallery_include( array(
27
+ 'cache.php',
28
  'voting.php',
29
+
30
  'rbs_gallery_options_guides.php',
31
  'rbs_gallery_options_images.php',
32
  ), ROBO_GALLERY_OPTIONS_PATH);
includes/rbs_gallery_init.php CHANGED
@@ -113,6 +113,8 @@ function create_post_type_robo_gallery() {
113
  }
114
  add_action( 'init', 'create_post_type_robo_gallery' );
115
 
 
 
116
  if(!function_exists('rbs_gallery_main_init')){
117
  function rbs_gallery_main_init() {
118
 
@@ -168,7 +170,9 @@ if(!function_exists('rbs_gallery_main_init')){
168
  }
169
 
170
  /* only backend */
171
- if( is_admin() ) rbs_gallery_include(array('rbs_gallery_media.php', 'rbs_gallery_menu.php', 'rbs_gallery_settings.php' ), ROBO_GALLERY_INCLUDES_PATH);
 
 
172
 
173
  /* Frontend*/
174
  rbs_gallery_include(array('rbs_gallery_source.php', 'rbs_gallery_helper.php', 'rbs_gallery_class_utils.php', 'rbs_gallery_class.php', 'rbs_gallery_frontend.php' ), ROBO_GALLERY_FRONTEND_PATH);
113
  }
114
  add_action( 'init', 'create_post_type_robo_gallery' );
115
 
116
+ rbs_gallery_include('cache.php', ROBO_GALLERY_INCLUDES_PATH);
117
+
118
  if(!function_exists('rbs_gallery_main_init')){
119
  function rbs_gallery_main_init() {
120
 
170
  }
171
 
172
  /* only backend */
173
+ if( is_admin() ){
174
+ rbs_gallery_include(array('rbs_gallery_media.php', 'rbs_gallery_menu.php', 'rbs_gallery_settings.php' ), ROBO_GALLERY_INCLUDES_PATH);
175
+ }
176
 
177
  /* Frontend*/
178
  rbs_gallery_include(array('rbs_gallery_source.php', 'rbs_gallery_helper.php', 'rbs_gallery_class_utils.php', 'rbs_gallery_class.php', 'rbs_gallery_frontend.php' ), ROBO_GALLERY_FRONTEND_PATH);
includes/rbs_gallery_settings.php CHANGED
@@ -83,14 +83,12 @@ class Robo_Gallery_Settings {
83
  echo '
84
  <div class="wrap">
85
  <h1>'.__('Robo Gallery', 'robo-gallery').'</h1>';
 
 
86
 
87
  $this->tabs();
88
 
89
  echo '<form method="post" action="options.php?tab='.$this->active_tab.'">';
90
-
91
-
92
-
93
- settings_errors();
94
 
95
  echo '<table class="form-table">';
96
 
83
  echo '
84
  <div class="wrap">
85
  <h1>'.__('Robo Gallery', 'robo-gallery').'</h1>';
86
+
87
+ settings_errors();
88
 
89
  $this->tabs();
90
 
91
  echo '<form method="post" action="options.php?tab='.$this->active_tab.'">';
 
 
 
 
92
 
93
  echo '<table class="form-table">';
94
 
readme.txt CHANGED
@@ -1,10 +1,10 @@
1
  === Gallery - Photo Gallery and Images Gallery ===
2
  Contributors: gallerysupport, robosoft
3
  Donate link: https://robosoft.co/robogallery
4
- Tags: gallery, photo gallery, images gallery, gallery images, responsive gallery, categories gallery, Polaroid gallery, gallery lightbox, portfolio gallery, video gallery, Gallery Plugin, Robo Gallery
5
  Requires at least: 3.3
6
  Tested up to: 4.8
7
- Stable tag: 2.6.22
8
  License: GPLv2 or later
9
  License URI: https://www.gnu.org/licenses/gpl-3.0.html
10
 
@@ -94,6 +94,8 @@ This interface gallery button have wide range of the front end interface customi
94
  * **Advanced Load more function** - in gallery implemented very attractive navigation mode. Auto pre loading images like endless list of the gallery images. This gallery load more function have alot of customization options to make it work the way you need.
95
  * **SEO code optimization** - in gallery implemented few front end code output modes. One simplified mode with all core front end gallery code elements another mode with additional not visible elements. This option have additional modes. This SEO output modes give you default output mode, thumbnail, thumnails+links mode.
96
  * **Gallery Template** - in our gallery we have advanced templating engine for gallery images description. Every hover text of gallery image could be edit and customized with built-in templating options.
 
 
97
 
98
  = Gallery Pro Key Features =
99
 
@@ -257,6 +259,9 @@ If any problem occurs, please contact us.
257
 
258
  == Changelog ==
259
 
 
 
 
260
  = 2.6.22 =
261
  * Update Robo Gallery ordering page
262
 
@@ -417,6 +422,9 @@ If any problem occurs, please contact us.
417
 
418
  == Upgrade Notice ==
419
 
 
 
 
420
  = 2.6.22 =
421
  Update Robo Gallery ordering page
422
 
1
  === Gallery - Photo Gallery and Images Gallery ===
2
  Contributors: gallerysupport, robosoft
3
  Donate link: https://robosoft.co/robogallery
4
+ Tags: gallery, photo gallery, images gallery, gallery images, wordpress gallery plugin, responsive gallery, categories gallery, Polaroid gallery, gallery lightbox, portfolio gallery, video gallery, Gallery Plugin, Robo Gallery
5
  Requires at least: 3.3
6
  Tested up to: 4.8
7
+ Stable tag: 2.7.0
8
  License: GPLv2 or later
9
  License URI: https://www.gnu.org/licenses/gpl-3.0.html
10
 
94
  * **Advanced Load more function** - in gallery implemented very attractive navigation mode. Auto pre loading images like endless list of the gallery images. This gallery load more function have alot of customization options to make it work the way you need.
95
  * **SEO code optimization** - in gallery implemented few front end code output modes. One simplified mode with all core front end gallery code elements another mode with additional not visible elements. This option have additional modes. This SEO output modes give you default output mode, thumbnail, thumnails+links mode.
96
  * **Gallery Template** - in our gallery we have advanced templating engine for gallery images description. Every hover text of gallery image could be edit and customized with built-in templating options.
97
+ * **Gallery Cache** - incredible new super cache option make your gallery load ten time faster. This function use absolutely new model of the images load. When you enable cache for big size gallery it's gonna be much faster and effective to use our plugin. Your visitors will be really surprised by the speed of the page load.
98
+
99
 
100
  = Gallery Pro Key Features =
101
 
259
 
260
  == Changelog ==
261
 
262
+ = 2.7.0 =
263
+ * New super gallery cache function
264
+
265
  = 2.6.22 =
266
  * Update Robo Gallery ordering page
267
 
422
 
423
  == Upgrade Notice ==
424
 
425
+ = 2.7.0 =
426
+ New super gallery cache function
427
+
428
  = 2.6.22 =
429
  Update Robo Gallery ordering page
430
 
robogallery.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Robo Gallery
4
  Plugin URI: https://robosoft.co/wordpress-gallery-plugin
5
  Description: Gallery modes photo gallery, images gallery, video gallery, Polaroid gallery, gallery lighbox, portfolio gallery, responsive gallery
6
- Version: 2.6.22
7
  Author: RoboSoft
8
  Author URI: https://robosoft.co/wordpress-gallery-plugin
9
  License: GPLv3 or later
@@ -15,13 +15,13 @@ if(!defined('WPINC'))die;
15
  if(!defined("ABSPATH"))exit;
16
 
17
  define("ROBO_GALLERY", 1);
18
- define("ROBO_GALLERY_VERSION", '2.6.22');
19
 
20
  if( !defined("ROBO_GALLERY_PATH") ) define("ROBO_GALLERY_PATH", plugin_dir_path( __FILE__ ));
21
 
22
  define("ROBO_GALLERY_SPECIAL", 1);
23
- define("ROBO_GALLERY_EVENT_DATE", '2017-09-03');
24
- define("ROBO_GALLERY_EVENT_HOUR", 24);
25
 
26
  add_action( 'plugins_loaded', 'rbs_gallery_load_textdomain' );
27
  function rbs_gallery_load_textdomain() {
3
  Plugin Name: Robo Gallery
4
  Plugin URI: https://robosoft.co/wordpress-gallery-plugin
5
  Description: Gallery modes photo gallery, images gallery, video gallery, Polaroid gallery, gallery lighbox, portfolio gallery, responsive gallery
6
+ Version: 2.7.0
7
  Author: RoboSoft
8
  Author URI: https://robosoft.co/wordpress-gallery-plugin
9
  License: GPLv3 or later
15
  if(!defined("ABSPATH"))exit;
16
 
17
  define("ROBO_GALLERY", 1);
18
+ define("ROBO_GALLERY_VERSION", '2.7.0');
19
 
20
  if( !defined("ROBO_GALLERY_PATH") ) define("ROBO_GALLERY_PATH", plugin_dir_path( __FILE__ ));
21
 
22
  define("ROBO_GALLERY_SPECIAL", 1);
23
+ define("ROBO_GALLERY_EVENT_DATE", '2017-10-14');
24
+ define("ROBO_GALLERY_EVENT_HOUR", 48);
25
 
26
  add_action( 'plugins_loaded', 'rbs_gallery_load_textdomain' );
27
  function rbs_gallery_load_textdomain() {