PluginProbe
UpdraftPlus: WP Backup & Migration Plugin / 1.22.14
UpdraftPlus: WP Backup & Migration Plugin v1.22.14
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 / cloudfiles.php

cloudfiles.php in UpdraftPlus: WP Backup & Migration Plugin 1.22.14, at methods/cloudfiles.php

605 lines 22.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined('UPDRAFTPLUS_DIR')) die('No direct access.');
4
5 /**
6 * Converted to job_options: yes
7 * Converted to array options: yes
8 * Migration code for "new"-style options removed: Feb 2017 (created: Dec 2013)
9 */
10
11 if (!class_exists('UpdraftPlus_BackupModule')) require_once(UPDRAFTPLUS_DIR.'/methods/backup-module.php');
12
13 /**
14 * Old SDK
15 */
16 class UpdraftPlus_BackupModule_cloudfiles_oldsdk extends UpdraftPlus_BackupModule {
17
18 /**
19 * This function does not catch any exceptions - that should be done by the caller
20 *
21 * @param String $user
22 * @param String $apikey
23 * @param String $authurl
24 * @param Boolean $useservercerts
25 * @return Array
26 */
27 private function getCF($user, $apikey, $authurl, $useservercerts = false) {
28
29 $storage = $this->get_storage();
30 if (!empty($storage)) return $storage;
31
32 if (!class_exists('UpdraftPlus_CF_Authentication')) include_once(UPDRAFTPLUS_DIR.'/includes/cloudfiles/cloudfiles.php');
33
34 if (!defined('UPDRAFTPLUS_SSL_DISABLEVERIFY')) define('UPDRAFTPLUS_SSL_DISABLEVERIFY', UpdraftPlus_Options::get_updraft_option('updraft_ssl_disableverify'));
35
36 $auth = new UpdraftPlus_CF_Authentication($user, trim($apikey), null, $authurl);
37
38 $this->log("authentication URL: $authurl");
39
40 $auth->authenticate();
41
42 $storage = new UpdraftPlus_CF_Connection($auth);
43
44 if (!$useservercerts) $storage->ssl_use_cabundle(UPDRAFTPLUS_DIR.'/includes/cacert.pem');
45
46 $this->set_storage($storage);
47
48 return $storage;
49
50 }
51
52 /**
53 * This method overrides the parent method and lists the supported features of this remote storage option.
54 *
55 * @return Array - an array of supported features (any features not
56 * mentioned are assumed to not be supported)
57 */
58 public function get_supported_features() {
59 // This options format is handled via only accessing options via $this->get_options()
60 return array('multi_options', 'config_templates', 'multi_storage', 'conditional_logic');
61 }
62
63 /**
64 * Retrieve default options for this remote storage module.
65 *
66 * @return Array - an array of options
67 */
68 public function get_default_options() {
69 return array(
70 'user' => '',
71 'authurl' => 'https://auth.api.rackspacecloud.com',
72 'apikey' => '',
73 'path' => '',
74 'region' => null
75 );
76 }
77
78 /**
79 * Check whether options have been set up by the user, or not
80 *
81 * @param Array $opts - the potential options
82 *
83 * @return Boolean
84 */
85 public function options_exist($opts) {
86 if (is_array($opts) && isset($opts['user']) && '' != $opts['user'] && !empty($opts['apikey'])) return true;
87 return false;
88 }
89
90 public function backup($backup_array) {
91
92 global $updraftplus;
93
94 $opts = $this->get_options();
95
96 $updraft_dir = $updraftplus->backups_dir_location().'/';
97
98 $container = $opts['path'];
99
100 try {
101 $storage = $this->getCF($opts['user'], $opts['apikey'], $opts['authurl'], UpdraftPlus_Options::get_updraft_option('updraft_ssl_useservercerts'));
102 $container_object = $storage->create_container($container);
103 } catch (AuthenticationException $e) {
104 $this->log('authentication failed ('.$e->getMessage().')');
105 $this->log(__('authentication failed', 'updraftplus').' ('.$e->getMessage().')', 'error');
106 return false;
107 } catch (NoSuchAccountException $s) {
108 $this->log('authentication failed ('.$e->getMessage().')');
109 $this->log(__('authentication failed', 'updraftplus').' ('.$e->getMessage().')', 'error');
110 return false;
111 } catch (Exception $e) {
112 $this->log('error - failed to create and access the container ('.$e->getMessage().')');
113 $this->log(__('error - failed to create and access the container', 'updraftplus').' ('.$e->getMessage().')', 'error');
114 return false;
115 }
116
117 $chunk_size = 5*1024*1024;
118
119 foreach ($backup_array as $file) {
120
121 $fullpath = $updraft_dir.$file;
122 $orig_file_size = filesize($fullpath);
123
124 // $cfpath = ($path == '') ? $file : "$path/$file";
125 // $chunk_path = ($path == '') ? "chunk-do-not-delete-$file" : "$path/chunk-do-not-delete-$file";
126 $cfpath = $file;
127 $chunk_path = "chunk-do-not-delete-$file";
128
129 try {
130 $object = new UpdraftPlus_CF_Object($container_object, $cfpath);
131 $object->content_type = "application/zip";
132
133 $uploaded_size = (isset($object->content_length)) ? $object->content_length : 0;
134
135 if ($uploaded_size <= $orig_file_size) {
136
137 $fp = @fopen($fullpath, "rb");// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
138 if (!$fp) {
139 $this->log("failed to open file: $fullpath");
140 $this->log("$file: ".__('Error: Failed to open local file', 'updraftplus'), 'error');
141 return false;
142 }
143
144 $chunks = floor($orig_file_size / $chunk_size);
145 // There will be a remnant unless the file size was exactly on a 5MB boundary
146 if ($orig_file_size % $chunk_size > 0) $chunks++;
147
148 $this->log("upload: $file (chunks: $chunks) -> cloudfiles://$container/$cfpath ($uploaded_size)");
149
150 if ($chunks < 2) {
151 try {
152 $object->load_from_filename($fullpath);
153 $this->log("regular upload: success");
154 $updraftplus->uploaded_file($file);
155 } catch (Exception $e) {
156 $this->log("regular upload: failed ($file) (".$e->getMessage().")");
157 $this->log("$file: ".__('Error: Failed to upload', 'updraftplus'), 'error');
158 }
159 } else {
160 $errors_so_far = 0;
161 for ($i = 1; $i <= $chunks; $i++) {
162 $upload_start = ($i-1)*$chunk_size;
163 // The file size -1 equals the byte offset of the final byte
164 $upload_end = min($i*$chunk_size-1, $orig_file_size-1);
165 $upload_remotepath = $chunk_path."_$i";
166 // Don't forget the +1; otherwise the last byte is omitted
167 $upload_size = $upload_end - $upload_start + 1;
168 $chunk_object = new UpdraftPlus_CF_Object($container_object, $upload_remotepath);
169 $chunk_object->content_type = "application/zip";
170 // 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
171 // Didn't make the difference - instead we just check below for actual success even when Curl reports an error
172 // $chunk_object->headers = array('Expect' => '');
173
174 $remote_size = (isset($chunk_object->content_length)) ? $chunk_object->content_length : 0;
175
176 if ($remote_size >= $upload_size) {
177 $this->log("Chunk $i ($upload_start - $upload_end): already uploaded");
178 } else {
179 $this->log("Chunk $i ($upload_start - $upload_end): begin upload");
180 // Upload the chunk
181 fseek($fp, $upload_start);
182 try {
183 $chunk_object->write($fp, $upload_size, false);
184 $updraftplus->record_uploaded_chunk(round(100*$i/$chunks, 1), $i, $fullpath);
185 } catch (Exception $e) {
186 $this->log("chunk upload: error: ($file / $i) (".$e->getMessage().")");
187 // 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.
188
189 $chunk_object = new UpdraftPlus_CF_Object($container_object, $upload_remotepath);
190 $chunk_object->content_type = "application/zip";
191 $remote_size = (isset($chunk_object->content_length)) ? $chunk_object->content_length : 0;
192
193 if ($remote_size >= $upload_size) {
194
195 $this->log("$file: Chunk now exists; ignoring error (presuming it was an apparently known curl bug)");
196
197 } else {
198
199 $this->log("$file: ".__('Error: Failed to upload', 'updraftplus'), 'error');
200 $errors_so_far++;
201 if ($errors_so_far >=3) return false;
202
203 }
204
205 }
206 }
207 }
208 if ($errors_so_far) return false;
209 // All chunks are uploaded - now upload the manifest
210
211 try {
212 $object->manifest = $container."/".$chunk_path."_";
213 // Put a zero-length file
214 $object->write("", 0, false);
215 $object->sync_manifest();
216 $this->log("upload: success");
217 $updraftplus->uploaded_file($file);
218 // } catch (InvalidResponseException $e) {
219 } catch (Exception $e) {
220 $this->log('error - failed to re-assemble chunks ('.$e->getMessage().')');
221 $this->log(__('error - failed to re-assemble chunks', 'updraftplus').' ('.$e->getMessage().')', 'error');
222 return false;
223 }
224 }
225 }
226
227 } catch (Exception $e) {
228 $this->log(__('error - failed to upload file', 'updraftplus').' ('.$e->getMessage().')');
229 $this->log(__('error - failed to upload file', 'updraftplus').' ('.$e->getMessage().')', 'error');
230 return false;
231 }
232
233 }
234
235 return array('cloudfiles_object' => $container_object, 'cloudfiles_orig_path' => $opts['path'], 'cloudfiles_container' => $container);
236
237 }
238
239 public function listfiles($match = 'backup_') {
240
241 $opts = $this->get_options();
242 $container = $opts['path'];
243
244 if (empty($opts['user']) || empty($opts['apikey'])) new WP_Error('no_settings', __('No settings were found', 'updraftplus'));
245
246 try {
247 $storage = $this->getCF($opts['user'], $opts['apikey'], $opts['authurl'], UpdraftPlus_Options::get_updraft_option('updraft_ssl_useservercerts'));
248 $container_object = $storage->create_container($container);
249 } catch (Exception $e) {
250 return new WP_Error('no_access', sprintf(__('%s authentication failed', 'updraftplus'), 'Cloud Files').' ('.$e->getMessage().')');
251 }
252
253 $results = array();
254
255 try {
256 $objects = $container_object->list_objects(0, null, $match);
257 foreach ($objects as $name) {
258 $result = array('name' => $name);
259 try {
260 $object = new UpdraftPlus_CF_Object($container_object, $name, true);
261 if (0 == $object->content_length) {
262 $result = false;
263 } else {
264 $result['size'] = $object->content_length;
265 }
266 } catch (Exception $e) {
267 // Catch
268 }
269 if (is_array($result)) $results[] = $result;
270 }
271 } catch (Exception $e) {
272 return new WP_Error('cf_error', 'Cloud Files error ('.$e->getMessage().')');
273 }
274
275 return $results;
276
277 }
278
279 /**
280 * Delete a single file from the service using the CloudFiles API
281 *
282 * @param Array $files - array of file paths to delete
283 * @param Array $cloudfilesarr - CloudFiles container and object details
284 * @param Array $sizeinfo - unused here
285 * @return Boolean|String - either a boolean true or an error code string
286 */
287 public function delete($files, $cloudfilesarr = false, $sizeinfo = array()) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- $sizeinfo is unused
288
289 if (is_string($files)) $files =array($files);
290
291 if ($cloudfilesarr) {
292 $container_object = $cloudfilesarr['cloudfiles_object'];
293 $container = $cloudfilesarr['cloudfiles_container'];
294 } else {
295 try {
296 $opts = $this->get_options();
297 $container = $opts['path'];
298 $storage = $this->getCF($opts['user'], $opts['apikey'], $opts['authurl'], UpdraftPlus_Options::get_updraft_option('updraft_ssl_useservercerts'));
299 $container_object = $storage->create_container($container);
300 } catch (Exception $e) {
301 $this->log('authentication failed ('.$e->getMessage().')');
302 $this->log(__('authentication failed', 'updraftplus').' ('.$e->getMessage().')', 'error');
303 return 'authentication_fail';
304 }
305 }
306
307 $ret = true;
308 foreach ($files as $file) {
309
310 $fpath = $file;
311
312 $this->log("Delete remote: container=$container, path=$fpath");
313
314 // We need to search for chunks
315 $chunk_path = "chunk-do-not-delete-$file";
316
317 try {
318 $objects = $container_object->list_objects(0, null, $chunk_path.'_');
319 foreach ($objects as $chunk) {
320 $this->log('Chunk to delete: '.$chunk);
321 $container_object->delete_object($chunk);
322 $this->log('Chunk deleted: '.$chunk);
323 }
324 } catch (Exception $e) {
325 $this->log('chunk delete failed: '.$e->getMessage());
326 }
327
328 try {
329 $container_object->delete_object($fpath);
330 $this->log('Deleted: '.$fpath);
331 } catch (Exception $e) {
332 $this->log('delete failed: '.$e->getMessage());
333 $ret = 'file_delete_error';
334 }
335 }
336 return $ret;
337 }
338
339 public function download($file) {
340
341 global $updraftplus;
342 $updraft_dir = $updraftplus->backups_dir_location();
343
344 $opts = $this->get_options();
345
346 try {
347 $storage = $this->getCF($opts['user'], $opts['apikey'], $opts['authurl'], UpdraftPlus_Options::get_updraft_option('updraft_ssl_useservercerts'));
348 } catch (AuthenticationException $e) {
349 $this->log('authentication failed ('.$e->getMessage().')');
350 $this->log(__('authentication failed', 'updraftplus').' ('.$e->getMessage().')', 'error');
351 return false;
352 } catch (NoSuchAccountException $s) {
353 $this->log('authentication failed ('.$e->getMessage().')');
354 $this->log(__('authentication failed', 'updraftplus').' ('.$e->getMessage().')', 'error');
355 return false;
356 } catch (Exception $e) {
357 $this->log('error - failed to create and access the container ('.$e->getMessage().')');
358 $this->log(__('error - failed to create and access the container', 'updraftplus').' ('.$e->getMessage().')', 'error');
359 return false;
360 }
361
362 $path = untrailingslashit($opts['path']);
363
364 $container = $path;
365
366 try {
367 $container_object = $storage->create_container($container);
368 } catch (Exception $e) {
369 $this->log('error - failed to create and access the container ('.$e->getMessage().')');
370 $this->log(__('error - failed to create and access the container', 'updraftplus').' ('.$e->getMessage().')', 'error');
371 return false;
372 }
373
374 $path = $file;
375
376 $this->log("download: cloudfiles://$container/$path");
377
378 try {
379 // The third parameter causes an exception to be thrown if the object does not exist remotely
380 $object = new UpdraftPlus_CF_Object($container_object, $path, true);
381
382 $fullpath = $updraft_dir.'/'.$file;
383
384 $start_offset = (file_exists($fullpath)) ? filesize($fullpath) : 0;
385
386 // Get file size from remote - see if we've already finished
387
388 $remote_size = $object->content_length;
389
390 if ($start_offset >= $remote_size) {
391 $this->log("file is already completely downloaded ($start_offset/$remote_size)");
392 return true;
393 }
394
395 // Some more remains to download - so let's do it
396 if (!$fh = fopen($fullpath, 'a')) {
397 $this->log("Error opening local file: $fullpath");
398 $this->log("$file: ".__('Error opening local file: Failed to download', 'updraftplus'), 'error');
399 return false;
400 }
401
402 $headers = array();
403 // If resuming, then move to the end of the file
404 if ($start_offset) {
405 $this->log("local file is already partially downloaded ($start_offset/$remote_size)");
406 fseek($fh, $start_offset);
407 $headers['Range'] = "bytes=$start_offset-";
408 }
409
410 // Now send the request itself
411 try {
412 $object->stream($fh, $headers);
413 } catch (Exception $e) {
414 $this->log("Failed to download: $file (".$e->getMessage().")");
415 $this->log("$file: ".__('Error downloading remote file: Failed to download', 'updraftplus').' ('.$e->getMessage().")", 'error');
416 return false;
417 }
418
419 // All-in-one-go method:
420 // $object->save_to_filename($fullpath);
421
422 } catch (NoSuchObjectException $e) {
423 $this->log('error - no such file exists. ('.$e->getMessage().')');
424 $this->log(__('Error - no such file exists.', 'updraftplus').' ('.$e->getMessage().')', 'error');
425 return false;
426 } catch (Exception $e) {
427 $this->log('error - failed to download the file ('.$e->getMessage().')');
428 $this->log(__('Error - failed to download the file', 'updraftplus').' ('.$e->getMessage().')', 'error');
429 return false;
430 }
431
432 return true;
433
434 }
435
436 /**
437 * Get the pre configuration template
438 *
439 * @return String - the template
440 */
441 public function get_pre_configuration_template() {
442
443 global $updraftplus_admin;
444
445 $classes = $this->get_css_classes(false);
446
447 ?>
448 <tr class="<?php echo $classes . ' ' . 'cloudfiles_pre_config_container';?>">
449 <td colspan="2">
450 <img alt="Rackspace Cloud Files" src="<?php echo UPDRAFTPLUS_URL;?>/images/rackspacecloud-logo.png"><br>
451 <?php
452 // Check requirements.
453 global $updraftplus_admin;
454 if (!function_exists('mb_substr')) {
455 $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'), 'Cloud Files', 'mbstring'), 'cloudfiles', false);
456 }
457 $updraftplus_admin->curl_check('Rackspace Cloud Files', false, 'cloudfiles', false);
458 ?>
459
460 <?php
461 echo '<p>' . __('Get your API key <a href="https://mycloud.rackspace.com/" target="_blank">from your Rackspace Cloud console</a> (<a href="http://www.rackspace.com/knowledge_center/article/rackspace-cloud-essentials-1-generating-your-api-key" target="_blank">read instructions here</a>), then pick a container name to use for storage. This container will be created for you if it does not already exist.', 'updraftplus').' <a href="https://updraftplus.com/faqs/there-appear-to-be-lots-of-extra-files-in-my-rackspace-cloud-files-container/" target="_blank">'.__('Also, you should read this important FAQ.', 'updraftplus').'</a></p>';
462 ?>
463 </td>
464 </tr>
465
466 <?php
467 }
468
469 /**
470 * Get the configuration template
471 *
472 * @return String - the template, ready for substitutions to be carried out
473 */
474 public function get_configuration_template() {
475 $classes = $this->get_css_classes();
476 $template_str = '
477 <tr class="'.$classes.'">
478 <th>'.__('US or UK Cloud', 'updraftplus').':</th>
479 <td>
480 <select data-updraft_settings_test="authurl" '.$this->output_settings_field_name_and_id('authurl', true).'>
481 <option {{#ifeq "https://auth.api.rackspacecloud.com" authurl}}selected="selected"{{/ifeq}} value="https://auth.api.rackspacecloud.com">'.__('US (default)', 'updraftplus').'</option>
482 <option {{#ifeq "https://lon.auth.api.rackspacecloud.com" authurl}}selected="selected"{{/ifeq}} value="https://lon.auth.api.rackspacecloud.com">'.__('UK', 'updraftplus').'</option>
483 </select>
484 </td>
485 </tr>
486 <input type="hidden" data-updraft_settings_test="region" '.$this->output_settings_field_name_and_id('region', true).' value="">';
487
488 /*
489 // Can put a message here if someone asks why region storage is not available (only available on new SDK)
490 <tr class="updraftplusmethod cloudfiles">
491 <th><?php _e('Rackspace Storage Region','updraftplus');?>:</th>
492 <td>
493 </td>
494 </tr>
495 */
496 $template_str .= '
497 <tr class="'.$classes.'">
498 <th>'.__('Cloud Files username', 'updraftplus').':</th>
499 <td><input data-updraft_settings_test="user" type="text" autocomplete="off" class="updraft_input--wide" '.$this->output_settings_field_name_and_id('user', true).' value="{{user}}" /></td>
500 </tr>
501 <tr class="'.$classes.'">
502 <th>'.__('Cloud Files API Key', 'updraftplus').':</th>
503 <td><input data-updraft_settings_test="apikey" type="'.apply_filters('updraftplus_admin_secret_field_type', 'password').'" autocomplete="off" class="updraft_input--wide" '.$this->output_settings_field_name_and_id('apikey', true).' value="{{apikey}}" />
504 </td>
505 </tr>
506 <tr class="'.$classes.'">
507 <th>'.apply_filters('updraftplus_cloudfiles_location_description', __('Cloud Files Container', 'updraftplus')).':</th>
508 <td><input data-updraft_settings_test="path" type="text" class="updraft_input--wide" '.$this->output_settings_field_name_and_id('path', true).' value="{{path}}" /></td>
509 </tr>';
510 $template_str .= $this->get_test_button_html(__('Cloud Files', 'updraftplus'));
511 return $template_str;
512 }
513
514 /**
515 * Modifies handerbar template options
516 *
517 * @param array $opts handerbar template options
518 * @return Array - Modified handerbar template options
519 */
520 public function transform_options_for_template($opts) {
521 $opts['apikey'] = trim($opts['apikey']);
522 $opts['authurl'] = isset($opts['authurl']) ? $opts['authurl'] : '';
523 return $opts;
524 }
525
526 /**
527 * Perform a test of user-supplied credentials, and echo the result
528 *
529 * @param Array $posted_settings - settings to test
530 */
531 public function credentials_test($posted_settings) {
532
533 if (empty($posted_settings['apikey'])) {
534 printf(__("Failure: No %s was given.", 'updraftplus'), __('API key', 'updraftplus'));
535 return;
536 }
537
538 if (empty($posted_settings['user'])) {
539 printf(__("Failure: No %s was given.", 'updraftplus'), __('Username', 'updraftplus'));
540 return;
541 }
542
543 $key = $posted_settings['apikey'];
544 $user = $posted_settings['user'];
545 $path = $posted_settings['path'];
546 $authurl = $posted_settings['authurl'];
547 $useservercerts = $posted_settings['useservercerts'];
548 $disableverify = $posted_settings['disableverify'];
549
550 if (preg_match("#^([^/]+)/(.*)$#", $path, $bmatches)) {
551 $container = $bmatches[1];
552 $path = $bmatches[2];
553 } else {
554 $container = $path;
555 $path = "";
556 }
557
558 if (empty($container)) {
559 _e("Failure: No container details were given.", 'updraftplus');
560 return;
561 }
562
563 define('UPDRAFTPLUS_SSL_DISABLEVERIFY', $disableverify);
564
565 try {
566 $storage = $this->getCF($user, $key, $authurl, $useservercerts);
567 $container_object = $storage->create_container($container);
568 } catch (AuthenticationException $e) {
569 echo __('Cloud Files authentication failed', 'updraftplus').' ('.$e->getMessage().')';
570 return;
571 } catch (NoSuchAccountException $s) {
572 echo __('Cloud Files authentication failed', 'updraftplus').' ('.$e->getMessage().')';
573 return;
574 } catch (Exception $e) {
575 echo __('Cloud Files authentication failed', 'updraftplus').' ('.$e->getMessage().')';
576 return;
577 }
578
579 $try_file = md5(rand()).'.txt';
580
581 try {
582 $object = $container_object->create_object($try_file);
583 $object->content_type = "text/plain";
584 $object->write('UpdraftPlus test file');
585 } catch (Exception $e) {
586 echo __('Cloud Files error - we accessed the container, but failed to create a file within it', 'updraftplus').' ('.$e->getMessage().')';
587 return;
588 }
589
590 echo __('Success', 'updraftplus').": ".__('We accessed the container, and were able to create files within it.', 'updraftplus');
591
592 @$container_object->delete_object($try_file);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
593 }
594 }
595
596 // Moved to the bottom to fix a bug in some version or install of PHP which required UpdraftPlus_BackupModule_cloudfiles_oldsdk to be defined earlier in the file (despite the conditionality) - see HS#19911
597 if (version_compare(PHP_VERSION, '5.3.3', '>=') && (!defined('UPDRAFTPLUS_CLOUDFILES_USEOLDSDK') || UPDRAFTPLUS_CLOUDFILES_USEOLDSDK != true)) {
598 include_once(UPDRAFTPLUS_DIR.'/methods/cloudfiles-new.php');
599 class UpdraftPlus_BackupModule_cloudfiles extends UpdraftPlus_BackupModule_cloudfiles_opencloudsdk {
600 }
601 } else {
602 class UpdraftPlus_BackupModule_cloudfiles extends UpdraftPlus_BackupModule_cloudfiles_oldsdk {
603 }
604 }
605