log("Cloud Files authentication URL: ".$new_authurl); if (empty($user) || empty($apikey)) throw new Exception(__('Authorisation failed (check your credentials)', 'updraftplus')); $client = new Rackspace($new_authurl, array( 'username' => $user, 'apiKey' => $apikey )); $this->client = $client; if ($disablesslverify) { $client->setSslVerification(false); } else { if ($useservercerts) { $client->setConfig(array($client::SSL_CERT_AUTHORITY, 'system')); } else { $client->setSslVerification(UPDRAFTPLUS_DIR.'/includes/cacert.pem', true, 2); } } return $client->objectStoreService('cloudFiles', $region); } public function backup($backup_array) { global $updraftplus, $updraftplus_backup; $opts = $this->get_opts(); $this->container = $opts['path']; try { $service = $this->get_service($opts['user'], $opts['apikey'], $opts['authurl'], UpdraftPlus_Options::get_updraft_option('updraft_ssl_useservercerts'), UpdraftPlus_Options::get_updraft_option('updraft_ssl_disableverify'), $opts['region']); } catch(AuthenticationError $e) { $updraftplus->log('Cloud Files authentication failed ('.$e->getMessage().')'); $updraftplus->log(__('Cloud Files authentication failed', 'updraftplus').' ('.$e->getMessage().')', 'error'); return false; } catch (Exception $e) { $updraftplus->log('Cloud Files error - failed to access the container ('.$e->getMessage().') (line: '.$e->getLine().', file: '.$e->getFile().')'); $updraftplus->log(__('Cloud Files error - failed to access the container', 'updraftplus').' ('.$e->getMessage().')', 'error'); return false; } # Get the container try { $this->container_object = $service->getContainer($this->container); } catch (Exception $e) { $updraftplus->log('Could not access Cloud Files container ('.get_class($e).', '.$e->getMessage().') (line: '.$e->getLine().', file: '.$e->getFile().')'); $updraftplus->log(__('Could not access Cloud Files container', 'updraftplus').' ('.get_class($e).', '.$e->getMessage().')', 'error'); return false; } foreach ($backup_array as $key => $file) { # First, see the object's existing size (if any) $uploaded_size = $this->get_remote_size($file); try { if (1 === $updraftplus->chunked_upload($this, $file, "cloudfiles://".$this->container."/$file", 'Cloud Files', UpdraftPlus_BackupModule_cloudfiles_opencloudsdk::CHUNK_SIZE, $uploaded_size)) { try { if (false !== ($data = fopen($updraftplus->backups_dir_location().'/'.$file, 'r+'))) { $this->container_object->uploadObject($file, $data); $updraftplus->log("Cloud Files regular upload: success"); $updraftplus->uploaded_file($file); } else { throw new Exception('uploadObject failed: fopen failed'); } } catch (Exception $e) { $this->log("$logname regular upload: failed ($file) (".$e->getMessage().")"); $this->log("$file: ".sprintf(__('%s Error: Failed to upload','updraftplus'),$logname), 'error'); } } } catch (Exception $e) { $updraftplus->log(__('Cloud Files error - failed to upload file', 'updraftplus').' ('.$e->getMessage().') (line: '.$e->getLine().', file: '.$e->getFile().')'); $updraftplus->log(sprintf(__('%s error - failed to upload file', 'updraftplus'),'Cloud Files').' ('.$e->getMessage().')', 'error'); return false; } } return array('cloudfiles_object' => $this->container_object, 'cloudfiles_orig_path' => $opts['path'], 'cloudfiles_container' => $this->container); } function get_remote_size($file) { try { $response = $this->container_object->getClient()->head($this->container_object->getUrl($file))->send(); $response_object = $this->container_object->dataObject()->populateFromResponse($response)->setName($file); return $response_object->getContentLength(); } catch (Exception $e) { # Allow caller to distinguish between zero-sized and not-found return false; } } function chunked_upload_finish($file) { $chunk_path = 'chunk-do-not-delete-'.$file; try { $headers = array( 'Content-Length' => 0, 'X-Object-Manifest' => sprintf('%s/%s', $this->container, $chunk_path.'_' ) ); $url = $this->container_object->getUrl($file); $this->container_object->getClient()->put($url, $headers)->send(); return true; } catch (Exception $e) { return false; } } function chunked_upload($file, $fp, $i, $upload_size, $upload_start, $upload_end) { global $updraftplus; $upload_remotepath = 'chunk-do-not-delete-'.$file.'_'.$i; $remote_size = $this->get_remote_size($upload_remotepath); // 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 // Didn't make the difference - instead we just check below for actual success even when Curl reports an error // $chunk_object->headers = array('Expect' => ''); if ($remote_size >= $upload_size) { $updraftplus->log("Cloud Files: Chunk $i ($upload_start - $upload_end): already uploaded"); } else { $updraftplus->log("Cloud Files: Chunk $i ($upload_start - $upload_end): begin upload"); // Upload the chunk try { $data = fread($fp, $upload_size); $this->container_object->uploadObject($upload_remotepath, $data); } catch (Exception $e) { $updraftplus->log("Cloud Files chunk upload: error: ($file / $i) (".$e->getMessage().") (line: ".$e->getLine().', file: '.$e->getFile().')'); // 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. $remote_size = $this->get_remote_size($upload_remotepath); if ($remote_size >= $upload_size) { $updraftplus->log("$file: Chunk now exists; ignoring error (presuming it was an apparently known curl bug)"); } else { $updraftplus->log("$file: ".sprintf(__('%s Error: Failed to upload','updraftplus'),'Cloud Files'), 'error'); return false; } } } return true; } public function delete($files, $data = false) { global $updraftplus; if (is_string($files)) $files = array($files); if (is_array($data)) { $container_object = $data['cloudfiles_object']; $container = $data['cloudfiles_container']; $path = $data['cloudfiles_orig_path']; } else { $opts = $this->get_opts(); $container = $opts['path']; $path = $container; try { $service = $this->get_service($opts['user'], $opts['apikey'], $opts['authurl'], UpdraftPlus_Options::get_updraft_option('updraft_ssl_useservercerts'), UpdraftPlus_Options::get_updraft_option('updraft_ssl_disableverify'), $opts['region']); } catch(AuthenticationError $e) { $updraftplus->log('Cloud Files authentication failed ('.$e->getMessage().')'); $updraftplus->log(__('Cloud Files authentication failed', 'updraftplus').' ('.$e->getMessage().')', 'error'); return false; } catch (Exception $e) { $updraftplus->log('Cloud Files error - failed to access the container ('.$e->getMessage().')'); $updraftplus->log(__('Cloud Files error - failed to access the container', 'updraftplus').' ('.$e->getMessage().')', 'error'); return false; } # Get the container try { $container_object = $service->getContainer($container); } catch (Exception $e) { $updraftplus->log('Could not access Cloud Files container ('.get_class($e).', '.$e->getMessage().')'); $updraftplus->log(__('Could not access Cloud Files container', 'updraftplus').' ('.get_class($e).', '.$e->getMessage().')', 'error'); return false; } } $ret = true; foreach ($files as $file) { $updraftplus->log("Cloud Files: Delete remote: container=$container, path=$file"); // We need to search for chunks $chunk_path = "chunk-do-not-delete-".$file; try { $objects = $container_object->objectList(array('prefix' => $chunk_path)); $index = 0; while (false !== ($chunk = $objects->offsetGet($index)) && !empty($chunk)) { try { $name = $chunk->name; $container_object->dataObject()->setName($name)->delete(); $updraftplus->log('Cloud Files: Chunk deleted: '.$name); } catch (Exception $e) { $updraftplus->log("Cloud Files chunk delete failed: $name: ".$e->getMessage()); } $index++; } } catch (Exception $e) { $updraftplus->log('Cloud Files chunk delete failed: '.$e->getMessage()); } # Finally, delete the object itself try { $container_object->dataObject()->setName($file)->delete(); $updraftplus->log('Cloud Files: Deleted: '.$file); } catch (Exception $e) { $updraftplus->log('Cloud Files delete failed: '.$e->getMessage()); $ret = false; } } return $ret; } function download($file) { global $updraftplus; $opts = $this->get_opts(); try { $service = $this->get_service($opts['user'], $opts['apikey'], $opts['authurl'], UpdraftPlus_Options::get_updraft_option('updraft_ssl_useservercerts'), UpdraftPlus_Options::get_updraft_option('updraft_ssl_disableverify'), $opts['region']); } catch(AuthenticationError $e) { $updraftplus->log('Cloud Files authentication failed ('.$e->getMessage().')'); $updraftplus->log(__('Cloud Files authentication failed', 'updraftplus').' ('.$e->getMessage().')', 'error'); return false; } catch (Exception $e) { $updraftplus->log('Cloud Files error - failed to access the container ('.$e->getMessage().')'); $updraftplus->log(__('Cloud Files error - failed to access the container', 'updraftplus').' ('.$e->getMessage().')', 'error'); return false; } $container = untrailingslashit($opts['path']); $updraftplus->log("Cloud Files download: cloudfiles://$container/$file"); # Get the container try { $this->container_object = $service->getContainer($container); } catch (Exception $e) { $updraftplus->log('Could not access Cloud Files container ('.get_class($e).', '.$e->getMessage().')'); $updraftplus->log(__('Could not access Cloud Files container', 'updraftplus').' ('.get_class($e).', '.$e->getMessage().')', 'error'); return false; } # Get information about the object within the container $remote_size = $this->get_remote_size($file); if (false === $remote_size) { $updraftplus->log('Could not access Cloud Files object'); $updraftplus->log(__('The Cloud Files object was not found', 'error')); return false; } return (!is_bool($remote_size)) ? $updraftplus->chunked_download($file, $this, $remote_size, true, $this->container_object) : false; } public function chunked_download($file, $headers, $container_object) { try { $dl = $container_object->getObject($file, $headers); } catch (Exception $e) { global $updraftplus; $updraftplus->log("$file: Failed to download (".$e->getMessage().")"); $updraftplus->log("$file: ".sprintf(__("%s Error",'updraftplus'), 'Cloud Files').": ".__('Error downloading remote file: Failed to download'.' ('.$e->getMessage().")",'updraftplus'), 'error'); return false; } return $dl->getContent(); } public function credentials_test() { if (empty($_POST['apikey'])) { printf(__("Failure: No %s was given.",'updraftplus'),__('API key','updraftplus')); die; } if (empty($_POST['user'])) { printf(__("Failure: No %s was given.",'updraftplus'),__('Username','updraftplus')); die; } $key = stripslashes($_POST['apikey']); $user = $_POST['user']; $path = $_POST['path']; $authurl = $_POST['authurl']; $useservercerts = $_POST['useservercerts']; $disableverify = $_POST['disableverify']; $region = (empty($_POST['region'])) ? null : $_POST['region']; if (preg_match("#^([^/]+)/(.*)$#", $path, $bmatches)) { $container = $bmatches[1]; $path = $bmatches[2]; } else { $container = $path; $path = ''; } if (empty($container)) { _e('Failure: No container details were given.' ,'updraftplus'); return; } try { $method = new UpdraftPlus_BackupModule_cloudfiles_opencloudsdk; $service = $method->get_service($user, $key, $authurl, $useservercerts, $disableverify, $region); } catch(Guzzle\Http\Exception\ClientErrorResponseException $e) { $response = $e->getResponse(); $code = $response->getStatusCode(); $reason = $response->getReasonPhrase(); if (401 == $code && 'Unauthorized' == $reason) { echo __('Authorisation failed (check your credentials)', 'updraftplus'); } else { echo __('Authorisation failed (check your credentials)', 'updraftplus')." ($code:$reason)"; } die; } catch(AuthenticationError $e) { echo __('Cloud Files authentication failed', 'updraftplus').' ('.$e->getMessage().')'; die; } catch (Exception $e) { echo __('Cloud Files authentication failed', 'updraftplus').' ('.get_class($e).', '.$e->getMessage().')'; die; } try { $container_object = $service->getContainer($container); } catch(Guzzle\Http\Exception\ClientErrorResponseException $e) { $response = $e->getResponse(); $code = $response->getStatusCode(); $reason = $response->getReasonPhrase(); if (404 == $code) { $container_object = $service->createContainer($container); } else { echo __('Authorisation failed (check your credentials)', 'updraftplus')." ($code:$reason)"; die; } } catch (Exception $e) { echo __('Cloud Files authentication failed', 'updraftplus').' ('.get_class($e).', '.$e->getMessage().')'; die; } if (!is_a($container_object, 'OpenCloud\ObjectStore\Resource\Container') && !is_a($container_object, 'Container')) { echo __('Cloud Files authentication failed', 'updraftplus').' ('.get_class($container_object).')'; die; } $try_file = md5(rand()).'.txt'; try { $object = $container_object->uploadObject($try_file, 'UpdraftPlus test file', array('content-type' => 'text/plain')); } catch (Exception $e) { echo __('Cloud Files error - we accessed the container, but failed to create a file within it', 'updraftplus').' ('.get_class($e).', '.$e->getMessage().')'; return; } echo __('Success', 'updraftplus').": ".__('We accessed the container, and were able to create files within it.', 'updraftplus'); try { if (!empty($object)) @$object->delete(); } catch (Exception $e) { } } public function config_print() { $opts = $this->get_opts(); ?> Rackspace Cloud Files

show_double_warning(''.__('Warning','updraftplus').': '.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 requires %s. Please do not file any support requests; there is no alternative.",'updraftplus'),'Cloud Files', 'mbstring'), 'cloudfiles'); } $updraftplus_admin->curl_check('Rackspace Cloud Files', false, 'cloudfiles'); ?>

from your Rackspace Cloud console (read instructions here), then pick a container name to use for storage. This container will be created for you if it does not already exist.','updraftplus');?>

: : :
'.__('To create a new Rackspace API sub-user and API key that has access only to this Rackspace container, use this add-on.', 'updraftplus')).''; ?>
: :