PluginProbe ʕ •ᴥ•ʔ
UpdraftPlus: WP Backup & Migration Plugin / 1.12.40
UpdraftPlus: WP Backup & Migration Plugin v1.12.40
1.26.4 1.26.3 1.9.19 1.9.25 1.9.26 1.9.30 1.9.31 1.9.32 1.9.4 1.9.40 1.9.41 1.9.42 1.9.43 1.9.44 1.9.45 1.9.46 1.9.5 1.9.50 1.9.51 1.9.60 1.9.62 1.9.63 1.9.64 1.11.12 1.4.8 1.11.15 1.4.9 1.11.17 1.5.16 1.11.18 1.5.20 1.11.2 1.5.21 1.11.20 1.5.22 1.11.23 1.5.5 1.11.24 1.5.6 1.11.25 1.5.7 1.11.26 1.5.8 1.11.27 1.5.9 1.11.28 1.6.1 1.11.3 1.6.17 1.11.4 1.6.2 1.11.5 1.6.46 1.11.8 1.7.0 1.11.9 1.7.1 1.12.0 1.7.18 1.12.1 1.7.20 1.12.12 1.7.3 1.12.13 1.7.34 1.12.15 1.7.35 1.12.17 1.7.39 1.12.2 1.7.40 1.12.20 1.7.41 1.12.23 1.8.1 1.12.24 1.8.11 1.12.25 1.8.12 1.12.28 1.8.13 1.12.29 1.8.2 1.12.30 1.8.5 1.12.32 1.8.8 1.12.34 1.9.0 1.12.35 1.9.13 1.12.37 1.9.15 1.12.39 1.9.17 1.12.4 1.12.40 1.12.6 1.13.1 1.13.11 1.13.12 1.13.15 1.13.16 1.13.2 1.13.3 1.13.4 1.13.5 1.13.6 1.13.7 1.13.8 1.13.9 1.14.10 1.14.11 1.14.12 1.14.13 1.14.2 1.14.3 1.14.4 1.14.5 1.14.7 1.14.9 1.15.0 1.15.2 1.15.3 1.15.5 1.15.6 1.15.7 1.16.0 1.16.10 1.16.11 1.16.12 1.16.13 1.16.14 1.16.15 1.16.16 1.16.17 1.16.20 1.16.21 1.16.22 1.16.23 1.16.24 1.16.25 1.16.26 1.16.28 1.16.29 1.16.32 1.16.34 1.16.35 1.16.36 1.16.37 1.16.4 1.16.40 1.16.41 1.16.42 1.16.43 1.16.44 1.16.45 1.16.46 1.16.47 1.16.48 1.16.49 1.16.5 1.16.50 1.16.51 1.16.53 1.16.55 1.16.56 1.16.59 1.16.6 1.16.60 1.16.61 1.16.62 1.16.63 1.16.64 1.16.65 1.16.66 1.16.67 1.16.68 1.16.69 1.16.7 1.16.8 1.16.9 1.2.0 1.2.1 1.2.10 1.2.11 1.2.12 1.2.14 1.2.15 1.2.16 1.2.17 1.2.19 1.2.2 1.2.20 1.2.24 1.2.25 1.2.26 1.2.27 1.2.28 1.2.29 1.2.3 1.2.30 1.2.31 1.2.33 1.2.35 1.2.36 1.2.38 1.2.39 1.2.4 1.2.40 1.2.41 1.2.42 1.2.43 1.2.44 1.2.45 1.2.46 1.2.5 1.2.7 1.2.8 1.2.9 1.22.1 1.22.10 1.22.11 1.22.12 1.22.14 1.22.15 1.22.16 1.22.17 1.22.18 1.22.19 1.22.20 1.22.21 1.22.22 1.22.23 1.22.24 1.22.3 1.22.4 1.22.5 1.22.6 1.22.7 1.22.8 1.22.9 1.23.1 1.23.10 1.23.11 1.23.12 1.23.13 1.23.15 1.23.16 1.23.2 1.23.3 1.23.4 1.23.5 1.23.6 1.23.7 1.23.8 1.23.9 1.24.1 1.24.10 1.24.11 1.24.12 1.24.2 trunk 1.24.3 0.7.4 1.24.4 0.7.7 1.24.5 0.8.28 1.24.6 0.8.29 1.24.7 0.8.30 1.24.8 0.8.31 1.24.9 0.8.32 1.25.1 0.8.33 1.25.2 0.8.36 1.25.3 0.8.37 1.25.5 0.8.50 1.25.6 0.8.51 1.25.7 0.9.1 1.25.8 0.9.10 1.25.9 0.9.11 1.26.1 0.9.12 1.26.2 0.9.2 1.3.10 0.9.20 1.3.12 0.9.21 1.3.14 0.9.22 1.3.15 1.0.10 1.3.17 1.0.11 1.3.18 1.0.12 1.3.19 1.0.15 1.3.2 1.0.16 1.3.20 1.0.18 1.3.22 1.0.20 1.3.23 1.0.3 1.3.24 1.0.4 1.3.25 1.0.5 1.3.3 1.0.6 1.3.4 1.0.7 1.3.6 1.0.8 1.3.7 1.0.9 1.3.8 1.1.0 1.3.9 1.1.10 1.4.0 1.1.11 1.4.10 1.1.12 1.4.11 1.1.13 1.4.12 1.1.14 1.4.13 1.1.15 1.4.14 1.1.16 1.4.15 1.1.17 1.4.2 1.1.2 1.4.27 1.1.3 1.4.28 1.1.5 1.4.29 1.1.6 1.4.30 1.1.8 1.4.4 1.1.9 1.4.48 1.10.1 1.4.5 1.10.3 1.4.6 1.11.1 1.4.7
updraftplus / class-zip.php
updraftplus Last commit date
addons 13 years ago central 9 years ago css 9 years ago images 9 years ago includes 9 years ago languages 9 years ago methods 9 years ago templates 9 years ago vendor 9 years ago admin.php 9 years ago backup.php 9 years ago changelog.txt 9 years ago class-updraftplus.php 9 years ago class-zip.php 9 years ago clean-composer.sh 9 years ago composer.json 9 years ago composer.lock 9 years ago example-decrypt.php 9 years ago index.html 9 years ago options.php 9 years ago readme.txt 9 years ago restorer.php 9 years ago updraftplus.php 9 years ago
class-zip.php
343 lines
1 <?php
2
3 if (!defined ('ABSPATH')) die('No direct access allowed');
4
5 if (class_exists('ZipArchive')):
6 # We just add a last_error variable for comaptibility with our UpdraftPlus_PclZip object
7 class UpdraftPlus_ZipArchive extends ZipArchive {
8 public $last_error = 'Unknown: ZipArchive does not return error messages';
9 }
10 endif;
11
12 # A ZipArchive compatibility layer, with behaviour sufficient for our usage of ZipArchive
13 class UpdraftPlus_PclZip {
14
15 protected $pclzip;
16 protected $path;
17 protected $addfiles;
18 protected $adddirs;
19 private $statindex;
20 private $include_mtime = false;
21 public $last_error;
22
23 public function __construct() {
24 $this->addfiles = array();
25 $this->adddirs = array();
26 // Put this in a non-backed-up, writeable location, to make sure that huge temporary files aren't created and then added to the backup - and that we have somewhere writable
27 global $updraftplus;
28 if (!defined('PCLZIP_TEMPORARY_DIR')) define('PCLZIP_TEMPORARY_DIR', trailingslashit($updraftplus->backups_dir_location()));
29 }
30
31 # Used to include mtime in statindex (by default, not done - to save memory; probably a bit paranoid)
32 public function ud_include_mtime() {
33 $this->include_mtime = true;
34 }
35
36 public function __get($name) {
37 if ($name == 'numFiles' || $name == 'numAll') {
38
39 if (empty($this->pclzip)) return false;
40
41 $statindex = $this->pclzip->listContent();
42
43 if (empty($statindex)) {
44 $this->statindex = array();
45 // We return a value that is == 0, but allowing a PclZip error to be detected (PclZip returns 0 in the case of an error).
46 if (0 === $statindex) $this->last_error = $this->pclzip->errorInfo(true);
47 return (0 === $statindex) ? false : 0;
48 }
49
50 if ($name == 'numFiles') {
51
52 $result = array();
53 foreach ($statindex as $i => $file) {
54 if (!isset($statindex[$i]['folder']) || 0 == $statindex[$i]['folder']) {
55 $result[] = $file;
56 }
57 unset($statindex[$i]);
58 }
59
60 $this->statindex=$result;
61
62 } else {
63 $this->statindex=$statindex;
64 }
65
66 return count($this->statindex);
67 }
68
69 return null;
70
71 }
72
73 public function statIndex($i) {
74 if (empty($this->statindex[$i])) return array('name' => null, 'size' => 0);
75 $v = array('name' => $this->statindex[$i]['filename'], 'size' => $this->statindex[$i]['size']);
76 if ($this->include_mtime) $v['mtime'] = $this->statindex[$i]['mtime'];
77 return $v;
78 }
79
80 public function open($path, $flags = 0) {
81
82 if(!class_exists('PclZip')) include_once(ABSPATH.'/wp-admin/includes/class-pclzip.php');
83 if(!class_exists('PclZip')) {
84 $this->last_error = "No PclZip class was found";
85 return false;
86 }
87
88 # Route around PHP bug (exact version with the problem not known)
89 $ziparchive_create_match = (version_compare(PHP_VERSION, '5.2.12', '>') && defined('ZIPARCHIVE::CREATE')) ? ZIPARCHIVE::CREATE : 1;
90
91 if ($flags == $ziparchive_create_match && file_exists($path)) @unlink($path);
92
93 $this->pclzip = new PclZip($path);
94
95 if (empty($this->pclzip)) {
96 $this->last_error = 'Could not get a PclZip object';
97 return false;
98 }
99
100 # Make the empty directory we need to implement addEmptyDir()
101 global $updraftplus;
102 $updraft_dir = $updraftplus->backups_dir_location();
103 if (!is_dir($updraft_dir.'/emptydir') && !mkdir($updraft_dir.'/emptydir')) {
104 $this->last_error = "Could not create empty directory ($updraft_dir/emptydir)";
105 return false;
106 }
107
108 $this->path = $path;
109
110 return true;
111
112 }
113
114 # Do the actual write-out - it is assumed that close() is where this is done. Needs to return true/false
115 public function close() {
116 if (empty($this->pclzip)) {
117 $this->last_error = 'Zip file was not opened';
118 return false;
119 }
120
121 global $updraftplus;
122 $updraft_dir = $updraftplus->backups_dir_location();
123
124 $activity = false;
125
126 # Add the empty directories
127 foreach ($this->adddirs as $dir) {
128 if (false == $this->pclzip->add($updraft_dir.'/emptydir', PCLZIP_OPT_REMOVE_PATH, $updraft_dir.'/emptydir', PCLZIP_OPT_ADD_PATH, $dir)) {
129 $this->last_error = $this->pclzip->errorInfo(true);
130 return false;
131 }
132 $activity = true;
133 }
134
135 foreach ($this->addfiles as $rdirname => $adirnames) {
136 foreach ($adirnames as $adirname => $files) {
137 if (false == $this->pclzip->add($files, PCLZIP_OPT_REMOVE_PATH, $rdirname, PCLZIP_OPT_ADD_PATH, $adirname)) {
138 $this->last_error = $this->pclzip->errorInfo(true);
139 return false;
140 }
141 $activity = true;
142 }
143 unset($this->addfiles[$rdirname]);
144 }
145
146 $this->pclzip = false;
147 $this->addfiles = array();
148 $this->adddirs = array();
149
150 clearstatcache();
151 if ($activity && filesize($this->path) < 50) {
152 $this->last_error = "Write failed - unknown cause (check your file permissions)";
153 return false;
154 }
155
156 return true;
157 }
158
159 # Note: basename($add_as) is irrelevant; that is, it is actually basename($file) that will be used. But these are always identical in our usage.
160 public function addFile($file, $add_as) {
161 # Add the files. PclZip appears to do the whole (copy zip to temporary file, add file, move file) cycle for each file - so batch them as much as possible. We have to batch by dirname(). On a test with 1000 files of 25KB each in the same directory, this reduced the time needed on that directory from 120s to 15s (or 5s with primed caches).
162 $rdirname = dirname($file);
163 $adirname = dirname($add_as);
164 $this->addfiles[$rdirname][$adirname][] = $file;
165 }
166
167 # PclZip doesn't have a direct way to do this
168 public function addEmptyDir($dir) {
169 $this->adddirs[] = $dir;
170 }
171
172 public function extract($path_to_extract, $path) {
173 return $this->pclzip->extract(PCLZIP_OPT_PATH, $path_to_extract, PCLZIP_OPT_BY_NAME, $path);
174 }
175
176 }
177
178 class UpdraftPlus_BinZip extends UpdraftPlus_PclZip {
179
180 private $binzip;
181
182 public function __construct() {
183 global $updraftplus_backup;
184 $this->binzip = $updraftplus_backup->binzip;
185 if (!is_string($this->binzip)) {
186 $this->last_error = "No binary zip was found";
187 return false;
188 }
189 return parent::__construct();
190 }
191
192 public function addFile($file, $add_as) {
193
194 global $updraftplus;
195 # Get the directory that $add_as is relative to
196 $base = $updraftplus->str_lreplace($add_as, '', $file);
197
198 if ($file == $base) {
199 // Shouldn't happen; but see: https://bugs.php.net/bug.php?id=62119
200 $updraftplus->log("File skipped due to unexpected name mismatch (locale: ".setlocale(LC_CTYPE, "0")."): file=$file add_as=$add_as", 'notice', false, true);
201 } else {
202 $rdirname = untrailingslashit($base);
203 # Note: $file equals $rdirname/$add_as
204 $this->addfiles[$rdirname][] = $add_as;
205 }
206
207 }
208
209 # The standard zip binary cannot list; so we use PclZip for that
210 # Do the actual write-out - it is assumed that close() is where this is done. Needs to return true/false
211 public function close() {
212
213 if (empty($this->pclzip)) {
214 $this->last_error = 'Zip file was not opened';
215 return false;
216 }
217
218 global $updraftplus, $updraftplus_backup;
219 $updraft_dir = $updraftplus->backups_dir_location();
220
221 $activity = false;
222
223 # BinZip does not like zero-sized zip files
224 if (file_exists($this->path) && 0 == filesize($this->path)) @unlink($this->path);
225
226 $descriptorspec = array(
227 0 => array('pipe', 'r'),
228 1 => array('pipe', 'w'),
229 2 => array('pipe', 'w')
230 );
231 $exec = $this->binzip;
232 if (defined('UPDRAFTPLUS_BINZIP_OPTS') && UPDRAFTPLUS_BINZIP_OPTS) $exec .= ' '.UPDRAFTPLUS_BINZIP_OPTS;
233 $exec .= " -v -@ ".escapeshellarg($this->path);
234
235 $last_recorded_alive = time();
236 $something_useful_happened = $updraftplus->something_useful_happened;
237 $orig_size = file_exists($this->path) ? filesize($this->path) : 0;
238 $last_size = $orig_size;
239 clearstatcache();
240
241 $added_dirs_yet = false;
242
243 # If there are no files to add, but there are empty directories, then we need to make sure the directories actually get added
244 if (0 == count($this->addfiles) && 0 < count($this->adddirs)) {
245 $dir = realpath($updraftplus_backup->make_zipfile_source);
246 $this->addfiles[$dir] = '././.';
247 }
248 // Loop over each destination directory name
249 foreach ($this->addfiles as $rdirname => $files) {
250
251 $process = proc_open($exec, $descriptorspec, $pipes, $rdirname);
252
253 if (!is_resource($process)) {
254 $updraftplus->log('BinZip error: proc_open failed');
255 $this->last_error = 'BinZip error: proc_open failed';
256 return false;
257 }
258
259 if (!$added_dirs_yet) {
260 # Add the directories - (in fact, with binzip, non-empty directories automatically have their entries added; but it doesn't hurt to add them explicitly)
261 foreach ($this->adddirs as $dir) {
262 fwrite($pipes[0], $dir."/\n");
263 }
264 $added_dirs_yet=true;
265 }
266
267 $read = array($pipes[1], $pipes[2]);
268 $except = null;
269
270 if (!is_array($files) || 0 == count($files)) {
271 fclose($pipes[0]);
272 $write = array();
273 } else {
274 $write = array($pipes[0]);
275 }
276
277 while ((!feof($pipes[1]) || !feof($pipes[2]) || (is_array($files) && count($files)>0)) && false !== ($changes = @stream_select($read, $write, $except, 0, 200000))) {
278
279 if (is_array($write) && in_array($pipes[0], $write) && is_array($files) && count($files)>0) {
280 $file = array_pop($files);
281 // Send the list of files on stdin
282 fwrite($pipes[0], $file."\n");
283 if (0 == count($files)) fclose($pipes[0]);
284 }
285
286 if (is_array($read) && in_array($pipes[1], $read)) {
287 $w = fgets($pipes[1]);
288 // Logging all this really slows things down; use debug to mitigate
289 if ($w && $updraftplus_backup->debug) $updraftplus->log("Output from zip: ".trim($w), 'debug');
290 if (time() > $last_recorded_alive + 5) {
291 $updraftplus->record_still_alive();
292 $last_recorded_alive = time();
293 }
294 if (file_exists($this->path)) {
295 $new_size = @filesize($this->path);
296 if (!$something_useful_happened && $new_size > $orig_size + 20) {
297 $updraftplus->something_useful_happened();
298 $something_useful_happened = true;
299 }
300 clearstatcache();
301 # Log when 20% bigger or at least every 50MB
302 if ($new_size > $last_size*1.2 || $new_size > $last_size + 52428800) {
303 $updraftplus->log(basename($this->path).sprintf(": size is now: %.2f MB", round($new_size/1048576,1)));
304 $last_size = $new_size;
305 }
306 }
307 }
308
309 if (is_array($read) && in_array($pipes[2], $read)) {
310 $last_error = fgets($pipes[2]);
311 if (!empty($last_error)) $this->last_error = rtrim($last_error);
312 }
313
314 // Re-set
315 $read = array($pipes[1], $pipes[2]);
316 $write = (is_array($files) && count($files) >0) ? array($pipes[0]) : array();
317 $except = null;
318
319 }
320
321 fclose($pipes[1]);
322 fclose($pipes[2]);
323
324 $ret = proc_close($process);
325
326 if ($ret != 0 && $ret != 12) {
327 if ($ret < 128) {
328 $updraftplus->log("Binary zip: error (code: $ret - look it up in the Diagnostics section of the zip manual at http://www.info-zip.org/mans/zip.html for interpretation... and also check that your hosting account quota is not full)");
329 } else {
330 $updraftplus->log("Binary zip: error (code: $ret - a code above 127 normally means that the zip process was deliberately killed ... and also check that your hosting account quota is not full)");
331 }
332 if (!empty($w) && !$updraftplus_backup->debug) $updraftplus->log("Last output from zip: ".trim($w), 'debug');
333 return false;
334 }
335
336 unset($this->addfiles[$rdirname]);
337 }
338
339 return true;
340 }
341
342 }
343