PluginProbe ʕ •ᴥ•ʔ
UpdraftPlus: WP Backup & Migration Plugin / 1.9.50
UpdraftPlus: WP Backup & Migration Plugin v1.9.50
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 images 11 years ago includes 11 years ago languages 11 years ago methods 11 years ago oc 11 years ago admin.php 11 years ago backup.php 11 years ago class-updraftplus.php 11 years ago class-zip.php 11 years ago example-decrypt.php 11 years ago index.html 12 years ago options.php 11 years ago readme.txt 11 years ago restorer.php 11 years ago updraftplus.php 11 years ago
class-zip.php
323 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 class UpdraftPlus_BinZip extends UpdraftPlus_PclZip {
13
14 private $binzip;
15
16 public function __construct() {
17 global $updraftplus_backup;
18 $this->binzip = $updraftplus_backup->binzip;
19 if (!is_string($this->binzip)) {
20 $this->last_error = "No binary zip was found";
21 return false;
22 }
23 return parent::__construct();
24 }
25
26 public function addFile($file, $add_as) {
27
28 global $updraftplus;
29 # Get the directory that $add_as is relative to
30 $base = $updraftplus->str_lreplace($add_as, '', $file);
31
32 if ($file == $base) {
33 // Shouldn't happen; but see: https://bugs.php.net/bug.php?id=62119
34 $updraftplus->log("File skipped due to unexpected name mismatch (locale: ".setlocale(LC_CTYPE, "0")."): $file", 'notice', false, true);
35 } else {
36 $rdirname = untrailingslashit($base);
37 # Note: $file equals $rdirname/$add_as
38 $this->addfiles[$rdirname][] = $add_as;
39 }
40
41 }
42
43 # The standard zip binary cannot list; so we use PclZip for that
44 # Do the actual write-out - it is assumed that close() is where this is done. Needs to return true/false
45 public function close() {
46
47 if (empty($this->pclzip)) {
48 $this->last_error = 'Zip file was not opened';
49 return false;
50 }
51
52 global $updraftplus, $updraftplus_backup;
53 $updraft_dir = $updraftplus->backups_dir_location();
54
55 $activity = false;
56
57 # BinZip does not like zero-sized zip files
58 if (file_exists($this->path) && 0 == filesize($this->path)) @unlink($this->path);
59
60 $descriptorspec = array(
61 0 => array('pipe', 'r'),
62 1 => array('pipe', 'w'),
63 2 => array('pipe', 'w')
64 );
65 $exec = $this->binzip." -v -@ ".escapeshellarg($this->path);
66 $last_recorded_alive = time();
67 $something_useful_happened = $updraftplus->something_useful_happened;
68 $orig_size = file_exists($this->path) ? filesize($this->path) : 0;
69 $last_size = $orig_size;
70 clearstatcache();
71
72 $added_dirs_yet = false;
73
74 # If there are no files to add, but there are empty directories, then we need to make sure the directories actually get added
75 if (0 == count($this->addfiles) && 0 < count($this->adddirs)) {
76 $dir = realpath($updraftplus_backup->make_zipfile_source);
77 $this->addfiles[$dir] = '././.';
78 }
79 // Loop over each destination directory name
80 foreach ($this->addfiles as $rdirname => $files) {
81
82 $process = proc_open($exec, $descriptorspec, $pipes, $rdirname);
83
84 if (!is_resource($process)) {
85 $updraftplus->log('BinZip error: proc_open failed');
86 $this->last_error = 'BinZip error: proc_open failed';
87 return false;
88 }
89
90 if (!$added_dirs_yet) {
91 # Add the directories - (in fact, with binzip, non-empty directories automatically have their entries added; but it doesn't hurt to add them explicitly)
92 foreach ($this->adddirs as $dir) {
93 fwrite($pipes[0], $dir."/\n");
94 }
95 $added_dirs_yet=true;
96 }
97
98 $read = array($pipes[1], $pipes[2]);
99 $except = null;
100
101 if (!is_array($files) || 0 == count($files)) {
102 fclose($pipes[0]);
103 $write = array();
104 } else {
105 $write = array($pipes[0]);
106 }
107
108 while ((!feof($pipes[1]) || !feof($pipes[2]) || (is_array($files) && count($files)>0)) && false !== ($changes = @stream_select($read, $write, $except, 0, 200000))) {
109
110 if (is_array($write) && in_array($pipes[0], $write) && is_array($files) && count($files)>0) {
111 $file = array_pop($files);
112 // Send the list of files on stdin
113 fwrite($pipes[0], $file."\n");
114 if (0 == count($files)) fclose($pipes[0]);
115 }
116
117 if (is_array($read) && in_array($pipes[1], $read)) {
118 $w = fgets($pipes[1]);
119 // Logging all this really slows things down; use debug to mitigate
120 if ($w && $updraftplus_backup->debug) $updraftplus->log("Output from zip: ".trim($w), 'debug');
121 if (time() > $last_recorded_alive + 5) {
122 $updraftplus->record_still_alive();
123 $last_recorded_alive = time();
124 }
125 if (file_exists($this->path)) {
126 $new_size = @filesize($this->path);
127 if (!$something_useful_happened && $new_size > $orig_size + 20) {
128 $updraftplus->something_useful_happened();
129 $something_useful_happened = true;
130 }
131 clearstatcache();
132 # Log when 20% bigger or at least every 50Mb
133 if ($new_size > $last_size*1.2 || $new_size > $last_size + 52428800) {
134 $updraftplus->log(basename($this->path).sprintf(": size is now: %.2f Mb", round($new_size/1048576,1)));
135 $last_size = $new_size;
136 }
137 }
138 }
139
140 if (is_array($read) && in_array($pipes[2], $read)) {
141 $last_error = fgets($pipes[2]);
142 if (!empty($last_error)) $this->last_error = rtrim($last_error);
143 }
144
145 // Re-set
146 $read = array($pipes[1], $pipes[2]);
147 $write = (is_array($files) && count($files) >0) ? array($pipes[0]) : array();
148 $except = null;
149
150 }
151
152 fclose($pipes[1]);
153 fclose($pipes[2]);
154
155 $ret = proc_close($process);
156
157 if ($ret != 0 && $ret != 12) {
158 if ($ret < 128) {
159 $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)");
160 } else {
161 $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)");
162 }
163 if (!empty($w) && !$updraftplus_backup->debug) $updraftplus->log("Last output from zip: ".trim($w), 'debug');
164 return false;
165 }
166
167 unset($this->addfiles[$rdirname]);
168 }
169
170 return true;
171 }
172
173 }
174
175 # A ZipArchive compatibility layer, with behaviour sufficient for our usage of ZipArchive
176 class UpdraftPlus_PclZip {
177
178 protected $pclzip;
179 protected $path;
180 protected $addfiles;
181 protected $adddirs;
182 private $statindex;
183 private $include_mtime = false;
184 public $last_error;
185
186 public function __construct() {
187 $this->addfiles = array();
188 $this->adddirs = array();
189 // 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
190 global $updraftplus;
191 if (!defined('PCLZIP_TEMPORARY_DIR')) define('PCLZIP_TEMPORARY_DIR', trailingslashit($updraftplus->backups_dir_location()));
192 }
193
194 # Used to include mtime in statindex (by default, not done - to save memory; probably a bit paranoid)
195 public function ud_include_mtime() {
196 $this->include_mtime = true;
197 }
198
199 public function __get($name) {
200 if ($name != 'numFiles') return null;
201
202 if (empty($this->pclzip)) return false;
203
204 $statindex = $this->pclzip->listContent();
205
206 if (empty($statindex)) {
207 $this->statindex=array();
208 return 0;
209 }
210
211 $result = array();
212 foreach ($statindex as $i => $file) {
213 if (!isset($statindex[$i]['folder']) || 0 == $statindex[$i]['folder']) {
214 $result[] = $file;
215 }
216 unset($statindex[$i]);
217 }
218
219 $this->statindex=$result;
220
221 return count($this->statindex);
222
223 }
224
225 public function statIndex($i) {
226 if (empty($this->statindex[$i])) return array('name' => null, 'size' => 0);
227 $v = array('name' => $this->statindex[$i]['filename'], 'size' => $this->statindex[$i]['size']);
228 if ($this->include_mtime) $v['mtime'] = $this->statindex[$i]['mtime'];
229 return $v;
230 }
231
232 public function open($path, $flags = 0) {
233 if(!class_exists('PclZip')) include_once(ABSPATH.'/wp-admin/includes/class-pclzip.php');
234 if(!class_exists('PclZip')) {
235 $this->last_error = "No PclZip class was found";
236 return false;
237 }
238
239 # Route around PHP bug (exact version with the problem not known)
240 $ziparchive_create_match = (version_compare(PHP_VERSION, '5.2.12', '>') && defined('ZIPARCHIVE::CREATE')) ? ZIPARCHIVE::CREATE : 1;
241
242 if ($flags == $ziparchive_create_match && file_exists($path)) @unlink($path);
243
244 $this->pclzip = new PclZip($path);
245 if (empty($this->pclzip)) {
246 $this->last_error = 'Could not get a PclZip object';
247 return false;
248 }
249
250 # Make the empty directory we need to implement addEmptyDir()
251 global $updraftplus;
252 $updraft_dir = $updraftplus->backups_dir_location();
253 if (!is_dir($updraft_dir.'/emptydir') && !mkdir($updraft_dir.'/emptydir')) {
254 $this->last_error = "Could not create empty directory ($updraft_dir/emptydir)";
255 return false;
256 }
257
258 $this->path = $path;
259
260 return true;
261
262 }
263
264 # Do the actual write-out - it is assumed that close() is where this is done. Needs to return true/false
265 public function close() {
266 if (empty($this->pclzip)) {
267 $this->last_error = 'Zip file was not opened';
268 return false;
269 }
270
271 global $updraftplus;
272 $updraft_dir = $updraftplus->backups_dir_location();
273
274 $activity = false;
275
276 # Add the empty directories
277 foreach ($this->adddirs as $dir) {
278 if (false == $this->pclzip->add($updraft_dir.'/emptydir', PCLZIP_OPT_REMOVE_PATH, $updraft_dir.'/emptydir', PCLZIP_OPT_ADD_PATH, $dir)) {
279 $this->last_error = $this->pclzip->errorInfo(true);
280 return false;
281 }
282 $activity = true;
283 }
284
285 foreach ($this->addfiles as $rdirname => $adirnames) {
286 foreach ($adirnames as $adirname => $files) {
287 if (false == $this->pclzip->add($files, PCLZIP_OPT_REMOVE_PATH, $rdirname, PCLZIP_OPT_ADD_PATH, $adirname)) {
288 $this->last_error = $this->pclzip->errorInfo(true);
289 return false;
290 }
291 $activity = true;
292 }
293 unset($this->addfiles[$rdirname]);
294 }
295
296 $this->pclzip = false;
297 $this->addfiles = array();
298 $this->adddirs = array();
299
300 clearstatcache();
301 if ($activity && filesize($this->path) < 50) {
302 $this->last_error = "Write failed - unknown cause (check your file permissions)";
303 return false;
304 }
305
306 return true;
307 }
308
309 # 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.
310 public function addFile($file, $add_as) {
311 # 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).
312 $rdirname = dirname($file);
313 $adirname = dirname($add_as);
314 $this->addfiles[$rdirname][$adirname][] = $file;
315 }
316
317 # PclZip doesn't have a direct way to do this
318 public function addEmptyDir($dir) {
319 $this->adddirs[] = $dir;
320 }
321
322 }
323