PluginProbe
UpdraftPlus: WP Backup & Migration Plugin / 1.9.31
UpdraftPlus: WP Backup & Migration Plugin v1.9.31
1.26.7 1.26.6 1.26.5 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 All 371 releases
updraftplus / methods / openstack-base.php

openstack-base.php in UpdraftPlus: WP Backup & Migration Plugin 1.9.31, at methods/openstack-base.php

470 lines 17.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 class UpdraftPlus_BackupModule_openstack_base {
4
5 protected $chunk_size = 5242880;
6
7 protected $client;
8 protected $method;
9 protected $desc;
10 protected $long_desc;
11 protected $img_url;
12
13 public function __construct($method, $desc, $long_desc = null, $img_url = '') {
14 $this->method = $method;
15 $this->desc = $desc;
16 $this->long_desc = (is_string($long_desc)) ? $long_desc : $desc;
17 $this->img_url = $img_url;
18 }
19
20 public function backup($backup_array) {
21
22 global $updraftplus, $updraftplus_backup;
23
24 $opts = $this->get_opts();
25
26 $this->container = $opts['path'];
27
28 try {
29 $service = $this->get_service($opts, UpdraftPlus_Options::get_updraft_option('updraft_ssl_useservercerts'), UpdraftPlus_Options::get_updraft_option('updraft_ssl_disableverify'));
30 } catch(AuthenticationError $e) {
31 $updraftplus->log($this->desc.' authentication failed ('.$e->getMessage().')');
32 $updraftplus->log(sprintf(__('%s authentication failed', 'updraftplus'), $this->desc).' ('.$e->getMessage().')', 'error');
33 return false;
34 } catch (Exception $e) {
35 $updraftplus->log($this->desc.' error - failed to access the container ('.$e->getMessage().') (line: '.$e->getLine().', file: '.$e->getFile().')');
36 $updraftplus->log(sprintf(__('%s error - failed to access the container', 'updraftplus'), $this->desc).' ('.$e->getMessage().')', 'error');
37 return false;
38 }
39 # Get the container
40 try {
41 $this->container_object = $service->getContainer($this->container);
42 } catch (Exception $e) {
43 $updraftplus->log('Could not access '.$this->desc.' container ('.get_class($e).', '.$e->getMessage().') (line: '.$e->getLine().', file: '.$e->getFile().')');
44 $updraftplus->log(sprintf(__('Could not access %s container', 'updraftplus'), $this->desc).' ('.get_class($e).', '.$e->getMessage().')', 'error');
45 return false;
46 }
47
48 foreach ($backup_array as $key => $file) {
49
50 # First, see the object's existing size (if any)
51 $uploaded_size = $this->get_remote_size($file);
52
53 try {
54 if (1 === $updraftplus->chunked_upload($this, $file, $this->method."://".$this->container."/$file", $this->desc, $this->chunk_size, $uploaded_size)) {
55 try {
56 if (false !== ($data = fopen($updraftplus->backups_dir_location().'/'.$file, 'r+'))) {
57 $this->container_object->uploadObject($file, $data);
58 $updraftplus->log($this->desc." regular upload: success");
59 $updraftplus->uploaded_file($file);
60 } else {
61 throw new Exception('uploadObject failed: fopen failed');
62 }
63 } catch (Exception $e) {
64 $this->log("$logname regular upload: failed ($file) (".$e->getMessage().")");
65 $this->log("$file: ".sprintf(__('%s Error: Failed to upload','updraftplus'),$logname), 'error');
66 }
67 }
68 } catch (Exception $e) {
69 $updraftplus->log($this->desc.' error - failed to upload file'.' ('.$e->getMessage().') (line: '.$e->getLine().', file: '.$e->getFile().')');
70 $updraftplus->log(sprintf(__('%s error - failed to upload file', 'updraftplus'), $this->desc).' ('.$e->getMessage().')', 'error');
71 return false;
72 }
73 }
74
75 return array('object' => $this->container_object, 'orig_path' => $opts['path'], 'container' => $this->container);
76
77 }
78
79 private function get_remote_size($file) {
80 try {
81 $response = $this->container_object->getClient()->head($this->container_object->getUrl($file))->send();
82 $response_object = $this->container_object->dataObject()->populateFromResponse($response)->setName($file);
83 return $response_object->getContentLength();
84 } catch (Exception $e) {
85 # Allow caller to distinguish between zero-sized and not-found
86 return false;
87 }
88 }
89
90 public function listfiles($match = 'backup_') {
91 $opts = $this->get_opts();
92 $container = $opts['path'];
93 $path = $container;
94
95 if (empty($opts['user']) || (empty($opts['apikey']) && empty($opts['password']))) return new WP_Error('no_settings', __('No settings were found','updraftplus'));
96
97 try {
98 $service = $this->get_service($opts, UpdraftPlus_Options::get_updraft_option('updraft_ssl_useservercerts'), UpdraftPlus_Options::get_updraft_option('updraft_ssl_disableverify'));
99 } catch (Exception $e) {
100 return new WP_Error('no_access', sprintf(__('%s error - failed to access the container', 'updraftplus'), $this->desc).' ('.$e->getMessage().')');
101 }
102
103 # Get the container
104 try {
105 $this->container_object = $service->getContainer($container);
106 } catch (Exception $e) {
107 return new WP_Error('no_access', sprintf(__('%s error - failed to access the container', 'updraftplus'), $this->desc).' ('.$e->getMessage().')');
108 }
109
110 $results = array();
111 try {
112 $objects = $this->container_object->objectList(array('prefix' => $match));
113 $index = 0;
114 while (false !== ($file = $objects->offsetGet($index)) && !empty($file)) {
115 try {
116 if ((is_object($file) && !empty($file->name))) {
117 $result = array('name' => $file->name);
118 # Rackspace returns the size of a manifested file properly; other OpenStack implementations may not
119 if (!empty($file->bytes)) {
120 $result['size'] = $file->bytes;
121 } else {
122 $size = $this->get_remote_size($file->name);
123 if (false !== $size && $size > 0) $result['size'] = $size;
124 }
125 $results[] = $result;
126 }
127 } catch (Exception $e) {
128 }
129 $index++;
130 }
131 } catch (Exception $e) {
132 }
133
134 return $results;
135 }
136
137 public function chunked_upload_finish($file) {
138
139 $chunk_path = 'chunk-do-not-delete-'.$file;
140 try {
141
142 $headers = array(
143 'Content-Length' => 0,
144 'X-Object-Manifest' => sprintf('%s/%s',
145 $this->container,
146 $chunk_path.'_'
147 )
148 );
149
150 $url = $this->container_object->getUrl($file);
151 $this->container_object->getClient()->put($url, $headers)->send();
152 return true;
153
154 } catch (Exception $e) {
155 return false;
156 }
157 }
158
159 public function chunked_upload($file, $fp, $i, $upload_size, $upload_start, $upload_end) {
160
161 global $updraftplus;
162
163 $upload_remotepath = 'chunk-do-not-delete-'.$file.'_'.$i;
164
165 $remote_size = $this->get_remote_size($upload_remotepath);
166
167 // Without this, some versions of Curl add Expect: 100-continue, which results in Curl then giving this back: curl error: 55) select/poll returned error
168 // Didn't make the difference - instead we just check below for actual success even when Curl reports an error
169 // $chunk_object->headers = array('Expect' => '');
170
171 if ($remote_size >= $upload_size) {
172 $updraftplus->log($this->desc.": Chunk $i ($upload_start - $upload_end): already uploaded");
173 } else {
174 $updraftplus->log($this->desc.": Chunk $i ($upload_start - $upload_end): begin upload");
175 // Upload the chunk
176 try {
177 $data = fread($fp, $upload_size);
178 $this->container_object->uploadObject($upload_remotepath, $data);
179 } catch (Exception $e) {
180 $updraftplus->log($this->desc." chunk upload: error: ($file / $i) (".$e->getMessage().") (line: ".$e->getLine().', file: '.$e->getFile().')');
181 // Experience shows that Curl sometimes returns a select/poll error (curl error 55) even when everything succeeded. Google seems to indicate that this is a known bug.
182
183 $remote_size = $this->get_remote_size($upload_remotepath);
184
185 if ($remote_size >= $upload_size) {
186 $updraftplus->log("$file: Chunk now exists; ignoring error (presuming it was an apparently known curl bug)");
187 } else {
188 $updraftplus->log("$file: ".sprintf(__('%s Error: Failed to upload','updraftplus'), $this->desc), 'error');
189 return false;
190 }
191 }
192 }
193 return true;
194 }
195
196
197 public function delete($files, $data = false) {
198
199 global $updraftplus;
200 if (is_string($files)) $files = array($files);
201
202 if (is_array($data)) {
203 $container_object = $data['object'];
204 $container = $data['container'];
205 $path = $data['orig_path'];
206 } else {
207 $opts = $this->get_opts();
208 $container = $opts['path'];
209 $path = $container;
210 try {
211 $service = $this->get_service($opts, UpdraftPlus_Options::get_updraft_option('updraft_ssl_useservercerts'), UpdraftPlus_Options::get_updraft_option('updraft_ssl_disableverify'));
212 } catch(AuthenticationError $e) {
213 $updraftplus->log($this->desc.' authentication failed ('.$e->getMessage().')');
214 $updraftplus->log(sprintf(__('%s authentication failed', 'updraftplus'), $this->desc).' ('.$e->getMessage().')', 'error');
215 return false;
216 } catch (Exception $e) {
217 $updraftplus->log($this->desc.' error - failed to access the container ('.$e->getMessage().')');
218 $updraftplus->log(sprintf(__('%s error - failed to access the container', 'updraftplus'), $this->desc).' ('.$e->getMessage().')', 'error');
219 return false;
220 }
221 # Get the container
222 try {
223 $container_object = $service->getContainer($container);
224 } catch (Exception $e) {
225 $updraftplus->log('Could not access '.$this->desc.' container ('.get_class($e).', '.$e->getMessage().')');
226 $updraftplus->log(sprintf(__('Could not access %s container', 'updraftplus'), $this->desc).' ('.get_class($e).', '.$e->getMessage().')', 'error');
227 return false;
228 }
229
230 }
231
232 $ret = true;
233 foreach ($files as $file) {
234
235 $updraftplus->log($this->desc.": Delete remote: container=$container, path=$file");
236
237 // We need to search for chunks
238 $chunk_path = "chunk-do-not-delete-".$file;
239
240 try {
241 $objects = $container_object->objectList(array('prefix' => $chunk_path));
242 $index = 0;
243 while (false !== ($chunk = $objects->offsetGet($index)) && !empty($chunk)) {
244 try {
245 $name = $chunk->name;
246 $container_object->dataObject()->setName($name)->delete();
247 $updraftplus->log($this->desc.': Chunk deleted: '.$name);
248 } catch (Exception $e) {
249 $updraftplus->log($this->desc." chunk delete failed: $name: ".$e->getMessage());
250 }
251 $index++;
252 }
253 } catch (Exception $e) {
254 $updraftplus->log($this->desc.' chunk delete failed: '.$e->getMessage());
255 }
256
257 # Finally, delete the object itself
258 try {
259 $container_object->dataObject()->setName($file)->delete();
260 $updraftplus->log($this->desc.': Deleted: '.$file);
261 } catch (Exception $e) {
262 $updraftplus->log($this->desc.' delete failed: '.$e->getMessage());
263 $ret = false;
264 }
265 }
266 return $ret;
267 }
268
269 public function config_print_javascript_onready($keys = array()) {
270 ?>
271 jQuery('#updraft-<?php echo $this->method;?>-test').click(function(){
272 jQuery(this).html('<?php echo esc_js(__('Testing - Please Wait...','updraftplus'));?>');
273 var data = {
274 action: 'updraft_ajax',
275 subaction: 'credentials_test',
276 method: '<?php echo $this->method;?>',
277 nonce: '<?php echo wp_create_nonce('updraftplus-credentialtest-nonce'); ?>',
278 path: jQuery('#updraft_<?php echo $this->method;?>_path').val(),
279 <?php
280 foreach ($keys as $key) {
281 echo "\t\t\t\t$key: jQuery('#updraft_".$this->method."_$key').val(),\n";
282 }
283 ?>
284 useservercerts: jQuery('#updraft_ssl_useservercerts').val(),
285 disableverify: jQuery('#updraft_ssl_disableverify').val()
286 };
287 jQuery.post(ajaxurl, data, function(response) {
288 jQuery('#updraft-<?php echo $this->method;?>-test').html('<?php echo esc_js(sprintf(__('Test %s Settings','updraftplus'), $this->desc));?>');
289 alert('<?php echo esc_js(sprintf(__('%s settings test result:', 'updraftplus'), $this->desc));?> ' + response);
290 });
291 });
292 <?php
293 }
294
295 public function download($file) {
296
297 global $updraftplus;
298
299 $opts = $this->get_opts();
300
301 try {
302 $service = $this->get_service($opts, UpdraftPlus_Options::get_updraft_option('updraft_ssl_useservercerts'), UpdraftPlus_Options::get_updraft_option('updraft_ssl_disableverify'));
303 } catch(AuthenticationError $e) {
304 $updraftplus->log($this->desc.' authentication failed ('.$e->getMessage().')');
305 $updraftplus->log(sprintf(__('%s authentication failed', 'updraftplus'), $this->desc).' ('.$e->getMessage().')', 'error');
306 return false;
307 } catch (Exception $e) {
308 $updraftplus->log($this->desc.' error - failed to access the container ('.$e->getMessage().')');
309 $updraftplus->log(sprintf(__('%s error - failed to access the container', 'updraftplus'), $this->desc).' ('.$e->getMessage().')', 'error');
310 return false;
311 }
312
313 $container = untrailingslashit($opts['path']);
314 $updraftplus->log($this->desc." download: ".$this->method."://$container/$file");
315
316 # Get the container
317 try {
318 $this->container_object = $service->getContainer($container);
319 } catch (Exception $e) {
320 $updraftplus->log('Could not access '.$this->desc.' container ('.get_class($e).', '.$e->getMessage().')');
321 $updraftplus->log(sprintf(__('Could not access %s container', 'updraftplus'), $this->desc).' ('.get_class($e).', '.$e->getMessage().')', 'error');
322 return false;
323 }
324
325 # Get information about the object within the container
326 $remote_size = $this->get_remote_size($file);
327 if (false === $remote_size) {
328 $updraftplus->log('Could not access '.$this->desc.' object');
329 $updraftplus->log(sprintf(__('The %s object was not found', 'updraftplus'), $this->desc), 'error');
330 return false;
331 }
332
333 return (!is_bool($remote_size)) ? $updraftplus->chunked_download($file, $this, $remote_size, true, $this->container_object) : false;
334
335 }
336
337 public function chunked_download($file, $headers, $container_object) {
338 try {
339 $dl = $container_object->getObject($file, $headers);
340 } catch (Exception $e) {
341 global $updraftplus;
342 $updraftplus->log("$file: Failed to download (".$e->getMessage().")");
343 $updraftplus->log("$file: ".sprintf(__("%s Error",'updraftplus'), $this->desc).": ".__('Error downloading remote file: Failed to download'.' ('.$e->getMessage().")",'updraftplus'), 'error');
344 return false;
345 }
346 return $dl->getContent();
347 }
348
349 public function credentials_test_go($opts, $path, $useservercerts, $disableverify) {
350
351 if (preg_match("#^([^/]+)/(.*)$#", $path, $bmatches)) {
352 $container = $bmatches[1];
353 $path = $bmatches[2];
354 } else {
355 $container = $path;
356 $path = '';
357 }
358
359 if (empty($container)) {
360 _e('Failure: No container details were given.' ,'updraftplus');
361 return;
362 }
363
364 try {
365 $service = $this->get_service($opts, $useservercerts, $disableverify);
366 } catch(Guzzle\Http\Exception\ClientErrorResponseException $e) {
367 $response = $e->getResponse();
368 $code = $response->getStatusCode();
369 $reason = $response->getReasonPhrase();
370 if (401 == $code && 'Unauthorized' == $reason) {
371 echo __('Authorisation failed (check your credentials)', 'updraftplus');
372 } else {
373 echo __('Authorisation failed (check your credentials)', 'updraftplus')." ($code:$reason)";
374 }
375 die;
376 } catch(AuthenticationError $e) {
377 echo sprintf(__('%s authentication failed', 'updraftplus'), $this->desc).' ('.$e->getMessage().')';
378 die;
379 } catch (Exception $e) {
380 echo sprintf(__('%s authentication failed', 'updraftplus'), $this->desc).' ('.get_class($e).', '.$e->getMessage().')';
381 die;
382 }
383
384 try {
385 $container_object = $service->getContainer($container);
386 } catch(Guzzle\Http\Exception\ClientErrorResponseException $e) {
387 $response = $e->getResponse();
388 $code = $response->getStatusCode();
389 $reason = $response->getReasonPhrase();
390 if (404 == $code) {
391 $container_object = $service->createContainer($container);
392 } else {
393 echo __('Authorisation failed (check your credentials)', 'updraftplus')." ($code:$reason)";
394 die;
395 }
396 } catch (Exception $e) {
397 echo sprintf(__('%s authentication failed', 'updraftplus'), $this->desc).' ('.get_class($e).', '.$e->getMessage().')';
398 die;
399 }
400
401 if (!is_a($container_object, 'OpenCloud\ObjectStore\Resource\Container') && !is_a($container_object, 'Container')) {
402 echo sprintf(__('%s authentication failed', 'updraftplus'), $this->desc).' ('.get_class($container_object).')';
403 die;
404 }
405
406 $try_file = md5(rand()).'.txt';
407
408 try {
409 $object = $container_object->uploadObject($try_file, 'UpdraftPlus test file', array('content-type' => 'text/plain'));
410 } catch (Exception $e) {
411 echo sprintf(__('%s error - we accessed the container, but failed to create a file within it', 'updraftplus'), $this->desc).' ('.get_class($e).', '.$e->getMessage().')';
412 if (!empty($this->region)) echo ' '.sprintf(__('Region: %s', 'updraftplus'), $this->region);
413 return;
414 }
415
416 echo __('Success', 'updraftplus').": ".__('We accessed the container, and were able to create files within it.', 'updraftplus');
417 if (!empty($this->region)) echo ' '.sprintf(__('Region: %s', 'updraftplus'), $this->region);
418
419 try {
420 if (!empty($object)) {
421 # One OpenStack server we tested on did not delete unless we slept... some kind of race condition at their end
422 sleep(1);
423 $object->delete();
424 }
425 } catch (Exception $e) {
426 }
427
428 }
429
430 public function config_print_middlesection() {
431 }
432
433 public function config_print() {
434
435 ?>
436 <tr class="updraftplusmethod <?php echo $this->method;?>">
437 <td></td>
438 <td>
439 <?php
440 if (!empty($this->img_url)) { ?>
441 <img alt="<?php echo $this->long_desc;?>" src="<?php echo UPDRAFTPLUS_URL.$this->img_url ?>">
442 <?php } ?>
443 <p><em><?php printf(__('%s is a great choice, because UpdraftPlus supports chunked uploads - no matter how big your site is, UpdraftPlus can upload it a little at a time, and not get thwarted by timeouts.','updraftplus'),$this->long_desc);?></em></p></td>
444 </tr>
445
446 <tr class="updraftplusmethod <?php echo $this->method;?>">
447 <th></th>
448 <td>
449 <?php
450 // Check requirements.
451 global $updraftplus_admin;
452 if (!function_exists('mb_substr')) {
453 $updraftplus_admin->show_double_warning('<strong>'.__('Warning','updraftplus').':</strong> '.sprintf(__('Your web server\'s PHP installation does not included a required module (%s). Please contact your web hosting provider\'s support.', 'updraftplus'), 'mbstring').' '.sprintf(__("UpdraftPlus's %s module <strong>requires</strong> %s. Please do not file any support requests; there is no alternative.",'updraftplus'), $this->desc, 'mbstring'), $this->method);
454 }
455 $updraftplus_admin->curl_check($this->long_desc, false, $this->method);
456 ?>
457 </td>
458 </tr>
459
460 <?php $this->config_print_middlesection(); ?>
461
462 <tr class="updraftplusmethod <?php echo $this->method;?>">
463 <th></th>
464 <td><p><button id="updraft-<?php echo $this->method;?>-test" type="button" class="button-primary" style="font-size:18px !important"><?php echo sprintf(__('Test %s Settings','updraftplus'), $this->desc);?></button></p></td>
465 </tr>
466 <?php
467 }
468
469 }
470