class BackupMigrateDropboxAPI in Backup and Migrate Dropbox 7.3
Same name and namespace in other branches
- 7 backup_migrate_dropbox.dropbox_api.inc \BackupMigrateDropboxAPI
- 7.2 backup_migrate_dropbox.dropbox_api.inc \BackupMigrateDropboxAPI
BackupMigrateDropboxAPI contains all the details about the Dropbox api, authorization calls, endpoints, uris, parameters, error handling, and split requests for large uploads/downloads
The public methods are the interface to the B&M destination.
Hierarchy
- class \BackupMigrateDropboxAPI
Expanded class hierarchy of BackupMigrateDropboxAPI
File
- ./
backup_migrate_dropbox.dropbox_api.inc, line 10
View source
class BackupMigrateDropboxAPI {
/**
* @var resource|false
* A Curl handle. To reuse the curl handle we keep it open across calls
* to the Dropbox API.
*/
private $ch;
/**
* @var backup_migrate_destination_dropbox
* Contains the B&M destination that uses this Dropbox Api object to
* communicate with Dropbox as this Api needs access to its name, machine
* name, and settings.
*/
private $destination;
/** @var array */
private $upload_session = [];
/**
* @var bool
* Indicates if we are resending a request that failed earlier because the
* bearer token had expired. This prevents resending over and over again in
* case something else is going wrong.
*/
private $is_resending_after_refresh = FALSE;
/**
* BackupMigrateDropboxAPI constructor.
*
* @param backup_migrate_destination_dropbox $destination
*/
public function __construct(backup_migrate_destination_dropbox $destination) {
$this->ch = FALSE;
$this->destination = $destination;
}
public function __destruct() {
if (!empty($this->ch)) {
curl_close($this->ch);
}
}
/**
* Returns the (parameterized) authorize URL.
*
* @link https://www.dropbox.com/developers/documentation/http/documentation#oauth2-authorize
* @link https://dropbox.tech/developers/pkce--what-and-why-
*
* @param string $code_verifier
* The code verifier to use to construct the authorize url.
*
* @return string
* The URL to direct the user to, to allow him to give this app permission
* to access (a app specific folder on) his Dropbox account.
*
*/
public function get_authorize_url($code_verifier) {
global $language;
return url('https://www.dropbox.com/oauth2/authorize', [
'external' => TRUE,
'query' => [
'client_id' => $this
->get_app_id(),
'response_type' => 'code',
'token_access_type' => 'offline',
'code_challenge_method' => 'S256',
'code_challenge' => $this
->get_code_challenge($code_verifier),
'locale' => $language->language,
],
]);
}
/**
* Returns the Dropbox app id of this app.
*
* @return string
*
* @throws RuntimeException
*/
private function get_app_id() {
$client_id = variable_get('backup_migrate_dropbox_app_key');
if ($client_id === NULL) {
throw new RuntimeException('Module "Backup and Migrate Dropbox" not installed or updated correctly. Please run update.php on your site.');
}
return $client_id;
}
/**
* Makes a Dropbox code verifier for this installation.
*
* @link https://dropbox.tech/developers/pkce--what-and-why-
*
* @return string
* A Dropbox code verifier.
*
* @throws Exception
*/
public function create_code_verifier() {
if (version_compare(phpversion(), '7.0', '>=')) {
/** @noinspection PhpElementIsNotAvailableInCurrentPhpVersionInspection */
$random = random_bytes(32);
}
else {
$random = '';
while (strlen($random) < 32) {
$random .= chr(mt_rand(0, 255));
}
}
return $this
->base64_url_encode($random);
}
/**
* Returns the code challenge for the given code verifier.
*
* @link https://dropbox.tech/developers/pkce--what-and-why-
*
* @param string $code_verifier
*
* @return string
* The code challenge: the sha256 hashed code verifier.
*/
private function get_code_challenge($code_verifier) {
if ($code_verifier === NULL) {
throw new RuntimeException("Cannot create a code challenge when no code verifier is available.");
}
return $this
->base64_url_encode(hash('sha256', $code_verifier, TRUE));
}
/**
* Obtains a first bearer and a refresh token.
*
* The first time we get a bearer token we do so with the just obtained, short
* lived, access code. This will return a short lived bearer token and a long
* lived refresh token which we have to store for future use. This because the
* subsequent bearer tokens must be obtained with the refresh token, not the
* access code (that will have expired by then).
*
* @param string $access_code
* The short lived access code that the user obtained from the Dropbox
* authorization page.
* @param string $code_verifier
* The code verifier whose code challenge was used to obtain the access
* code.
*
* @return string|null
* The refresh token, or null if it could not be obtained. As a side effect,
* the short lived bearer token that is also returned will be stored for use
* during the next few hours.
*/
public function obtain_refresh_token($access_code, $code_verifier) {
$parameters = [
'code' => $access_code,
'grant_type' => 'authorization_code',
'code_verifier' => $code_verifier,
'client_id' => $this
->get_app_id(),
];
try {
$response = $this
->send_message('api', 'oauth2/token', $parameters);
if (!isset($response->refresh_token)) {
throw new RuntimeException('Could not obtain a refresh token');
}
BearerTokenInfos::set($this->destination
->get_id(), $response);
return $response->refresh_token;
} catch (RuntimeException $e) {
watchdog('backup_migrate', 'Backup Migrate Dropbox Error: ' . $e
->getMessage(), [], WATCHDOG_ERROR);
drupal_set_message('Backup Migrate Dropbox Error: ' . $e
->getMessage(), 'error');
return NULL;
}
}
/**
* Returns the refresh token for this Dropbox destination.
*
* @return string
* The refresh token for this Dropbox destination.
*
* @throws RuntimeException
*/
private function get_refresh_token() {
$refresh_token = $this->destination
->settings('refresh_token');
if ($refresh_token === NULL) {
$name = $this->destination
->get_name();
$id = $this->destination
->get_id();
$edit_destination_page = l('Edit destination page for this destination', "admin/config/system/backup_migrate/settings/destination/edit/{$id}");
throw new RuntimeException("Dropbox Destination '{$name}' not authorized correctly: refresh token missing. Please visit the {$edit_destination_page} and configure it anew.");
}
return $refresh_token;
}
/**
* Returns a short lived but not yet expired bearer token.
*
* If a bearer token is stored and not yet expired that is returned, otherwise
* that bearer token is replaced (and returned) by a new one.
*
* @return string
* A short lived but not yet expired bearer token.
*
* @throws RuntimeException
*/
private function get_bearer_token() {
$bearer_token = BearerTokenInfos::get($this->destination
->get_id());
return $bearer_token !== NULL ? $bearer_token : $this
->refresh_bearer_token();
}
/**
* Refreshes and returns an expired bearer token.
*
* If a bearer token expires, it needs to be refreshed, i.e. replaced by a new
* short lived (typically 4 hours) bearer token. We store these in a variable
* but also return it as it is needed directly.
*
* @return string
* The refreshed bearer token for this Dropbox destination.
*
* @throws RuntimeException
*/
private function refresh_bearer_token() {
$parameters = [
'refresh_token' => $this
->get_refresh_token(),
'grant_type' => 'refresh_token',
'client_id' => $this
->get_app_id(),
];
$response = $this
->send_message('api', 'oauth2/token', $parameters);
return BearerTokenInfos::set($this->destination
->get_id(), $response);
}
/**
* Returns the contents of a Dropbox folder.
*
* @link https://www.dropbox.com/developers/documentation/http/documentation#files-list_folder Dropbox API /list_folder
*
* @param string $folder
*
* @return object[]
* A list of file metadata of the files in the folder.
*
* @throws RuntimeException
*/
public function list_folder($folder) {
// Note, I once got this message: Dropbox error: Error in call to API
// function "files/list_folder": request body: path: Specify the root folder
// as an empty string rather than as "/". So we handle that case here.
if ($folder === '/') {
$folder = '';
}
// Simple listing: using Dropbox defaults:
// - Not recursive.
// - No deleted files.
// - Include mounted files (the app folder is a mounted folder).
$parameters = [
'path' => $folder,
'include_non_downloadable_files' => TRUE,
];
$response = $this
->send_message('api', 'files/list_folder', $parameters);
$files = $response->entries;
while ($response->has_more) {
$parameters = [
'cursor' => $response->cursor,
];
$response = $this
->send_message('api', 'files/list_folder/continue', $parameters);
$files = array_merge($files, $response->entries);
}
return $files;
}
/**
* Creates a folder on Dropbox.
*
* @link https://www.dropbox.com/developers/documentation/http/documentation#files-create_folder
*
* @param string $folder
* The folder to create.
*
* @return object
* A list of folder metadata for the created folder.
*
* @throws RuntimeException
* The folder could not be created. If that is because it already exists,
* the exception message will contain something like
* '... path/conflict/folder/.. ...'.
*/
public function create_folder($folder) {
if ($folder[0] !== '/') {
$folder = '/' . $folder;
}
$parameters = [
'path' => $folder,
'autorename' => FALSE,
];
return $this
->send_message('api', 'files/create_folder', $parameters);
}
/**
* Downloads the file from the given Dropbox $path.
*
* @link https://www.dropbox.com/developers/documentation/http/documentation#files-download Dropbox API /download
*
* @param string $path
* Path of file to download.
* @return string
* The contents of the requested file.
*
* @throws RuntimeException
*/
public function file_download($path) {
$parameters = [
'path' => $path,
];
return $this
->send_message('content', 'files/download', $parameters);
}
/**
* Uploads a file to the given path.
*
* If the upload is larger then:
* - what Dropbox can handle per request.
* - or the internal memory available to PHP
* The upload is split into multiple smaller chunks, otherwise it is uploaded
* in 1 part.
*
* @param string $file
* Name of local file to upload its contents from.
* @param string $path
* Path on Dropbox (including the file name) to upload the file contents to.
*
* @return object
* The json decoded response.
*
* @throws RuntimeException
*/
public function file_upload($file, $path) {
// Cut PHP memory limit by 10% to allow for other in memory data.
$php_memory_limit = intval($this
->byte_size(ini_get('memory_limit')) * 0.9);
// Dropbox currently has a 150M upload limit per transaction.
$dropbox_upload_limit = $this
->byte_size('150M');
// For testing or in case the 10% leeway isn't enough allow a smaller upload
// limit as an advanced setting. This variable has no ui but can be set with
// drush or through the variable module.
$manual_upload_limit = $this
->byte_size(variable_get('backup_migrate_dropbox_upload_limit', '150M'));
// Use the smallest value for the max file size.
$max_file_size = min($php_memory_limit, $dropbox_upload_limit, $manual_upload_limit);
// File.
$file_size = filesize($file);
// If the file size is greater than
if ($file_size > $max_file_size) {
// Open file.
$file_handle = fopen($file, 'rb');
if (!$file_handle) {
throw new RuntimeException('Cannot open backup file (1).');
}
// Start.
$content = fread($file_handle, $max_file_size);
if (!$content) {
throw new RuntimeException('Cannot read backup file (2).');
}
$this
->_file_upload_session_start($content);
// Append.
while (!feof($file_handle)) {
// Get content.
$content = fread($file_handle, $max_file_size);
if (!$content) {
throw new RuntimeException('Cannot read backup file (3).');
}
$this
->_file_upload_session_append($content);
}
// Finish.
$result = $this
->_file_upload_session_finish($path);
}
else {
$content = file_get_contents($file);
if (!$content) {
throw new RuntimeException('Cannot open backup file (4).');
}
$result = $this
->_file_upload_upload($path, $content);
}
return $result;
}
/**
* Starts a multi-request upload.
*
* @link https://www.dropbox.com/developers/documentation/http/documentation#files-upload_session-start Dropbox API /upload_session/start
*
* @param string $content
*
* @return object
* The json decoded response.
*
* @throws RuntimeException
* @noinspection PhpReturnValueOfMethodIsNeverUsedInspection
*/
private function _file_upload_session_start($content) {
$result = $this
->send_message('content', 'files/upload_session/start', [], $content);
if (!isset($result->session_id)) {
throw new RuntimeException('No session id returned.');
}
$this->upload_session['session_id'] = $result->session_id;
$this->upload_session['offset'] = strlen($content);
return $result;
}
/**
* Uploads 1 part of a multi-request upload.
*
* @link https://www.dropbox.com/developers/documentation/http/documentation#files-upload_session-append Dropbox API /upload_session/append
*
* @param string $content
*
* @return object
* The json decoded response.
*
* @throws RuntimeException
* @noinspection PhpReturnValueOfMethodIsNeverUsedInspection
*/
private function _file_upload_session_append($content) {
$parameters = [
'cursor' => $this->upload_session,
];
$result = $this
->send_message('content', 'files/upload_session/append_v2', $parameters, $content);
$this->upload_session['offset'] += strlen($content);
return $result;
}
/**
* Ends a multi-request upload.
*
* @link https://www.dropbox.com/developers/documentation/http/documentation#files-upload_session-finish Dropbox API /upload_session/finish
*
* @param string $path
*
* @return object
* The json decoded response.
*
* @throws RuntimeException
*/
private function _file_upload_session_finish($path) {
$parameters = [
'cursor' => $this->upload_session,
'commit' => [
'path' => $path,
'mode' => 'add',
'autorename' => TRUE,
'mute' => TRUE,
],
];
return $this
->send_message('content', 'files/upload_session/finish', $parameters);
}
/**
* Uploads the $contents of a file (with 1 request) to the indicated $path.
*
* @link https://www.dropbox.com/developers/documentation/http/documentation#files-upload Dropbox API /upload
*
* @param string $path
* @param string $content
*
* @return object
* The json decoded response.
*
* @throws RuntimeException
*/
private function _file_upload_upload($path, $content) {
// Simple upload.
$parameters = [
'path' => $path,
'mode' => 'add',
'autorename' => TRUE,
'mute' => FALSE,
];
return $this
->send_message('content', 'files/upload', $parameters, $content);
}
/**
* Deletes the file at the given $path.
*
* @link https://www.dropbox.com/developers/documentation/http/documentation#files-delete Dropbox API /delete
*
* @param string $path
*
* @return object
* The json decoded response.
*
* @throws RuntimeException
*/
public function file_delete($path) {
$parameters = [
'path' => $path,
];
return $this
->send_message('api', 'files/delete_v2', $parameters);
}
/**
* Sends a request to Dropbox and returns the response.
*
* @param string $endpointType
* This type determines the url to use and how to process parameters. It can
* be one of:
* - 'api'
* - 'content'
* More info about end points can be found at:
* {@link https://www.dropbox.com/developers/documentation/http/documentation#formats}
* @param string $command
* The Dropbox API function to call. Will be used as the path part of the
* url.
* @param array|null $parameters
* The parameters for this command. Will be send in the body or as a header.
* @param string|null $content
* File contents for the request. Will be send in the body.
*
* @return object|string
* The response form the Dropbox Api. If the response was a json encoded
* object, that object will be returned, otherwise the unaltered response
* will be returned, e.g. the contents of a file.
*
* @throws RuntimeException
* Excerpt from the Dropbox documentation on error handling:
* - 400 Bad input parameter. The response body is a plaintext message with
* more information.
* - 401 Bad or expired token. This can happen if the access token is
* expired or if the access token has been revoked by Dropbox or the user.
* To fix this, you should re-authenticate the user. The Content-Type of
* the response is JSON of typeAuthError.
* - 403 The user or team account doesn't have access to the endpoint or
* feature. The Content-Type of the response is JSON of typeAccessError.
* - 409 Endpoint-specific error. Look to the JSON response body for the
* specifics of the error.
* - 429 Your app is making too many requests for the given user or team and
* is being rate limited. Your app should wait for the number of seconds
* specified in the "Retry-After" response header before trying again. The
* Content-Type of the response can be JSON or plaintext. If it is JSON,
* it will be typeRateLimitError. You can find more information in the
* data ingress guide.
* - 5xx An error occurred on the Dropbox servers. Check status.dropbox.com
* for announcements about Dropbox service issues.
* {@see https://www.dropbox.com/developers/documentation/http/documentation#error_handling}.
*/
private function send_message($endpointType, $command, $parameters = null, $content = null) {
// Prepare the request: url, headers and the body.
$headers = [];
$headers[] = 'Accept: application/json, application/octet-stream';
if ($command === 'oauth2/token') {
// The oauth2/token process actually belongs to a 3rd endpoint type,
// having a different URL and content-type (and therefore body encoding).
$headers[] = 'Content-type: application/x-www-form-urlencoded';
$url = "https://{$endpointType}.dropbox.com/{$command}";
$body = http_build_query($parameters);
}
else {
$url = "https://{$endpointType}.dropboxapi.com/2/{$command}";
$headers[] = 'Authorization: Bearer ' . $this
->get_bearer_token();
if ($endpointType === 'content') {
// Content end points (may) have real content in the body and therefore
// expect the parameters in the 'Dropbox-API-Arg' header.
$headers[] = 'Content-type: application/octet-stream';
if (!empty($parameters)) {
$headers[] = 'Dropbox-API-Arg: ' . json_encode($parameters);
}
$body = $content;
}
else {
$headers[] = 'Content-type: application/json; charset=utf-8';
$body = json_encode($parameters);
}
}
$http_result = $this
->send_http_request($url, $headers, $body);
//$this->log($http_result); // enable during development, or in case of problems.
if ($http_result->code === 200) {
if ($this
->is_json_response($endpointType, $command)) {
$result = json_decode($http_result->body);
// Not sure if errors can be returned with a 200 or if that is only done
// with a 4xx, to be sure I just check for the error_summary field.
if (isset($result->error_summary)) {
$message = $this
->get_dropbox_error_message($http_result->body);
throw new RuntimeException("Dropbox error: {$message}");
}
}
else {
// Plain result, e.g. file contents: no decoding needed.
$result = $http_result->body;
}
}
elseif ($http_result->code === 401) {
$error_message = json_decode($http_result->body)->error_summary;
if (strpos($error_message, 'expired_access_token') !== FALSE && !$this->is_resending_after_refresh) {
try {
$this->is_resending_after_refresh = TRUE;
$this
->refresh_bearer_token();
$result = $this
->send_message($endpointType, $command, $parameters, $content);
} finally {
$this->is_resending_after_refresh = FALSE;
}
}
else {
throw new RuntimeException("Dropbox authentication error: {$error_message}", $http_result->code);
}
}
elseif ($http_result->code < 500) {
$message = $this
->get_dropbox_error_message($http_result->body);
throw new RuntimeException("Dropbox error: {$message}", $http_result->code);
}
else {
$message = 'An error occurred on the Dropbox servers. Check https://status.dropbox.com/ for announcements about Dropbox service issues.';
$body_message = $this
->get_dropbox_error_message($http_result->body);
if (!empty($body_message)) {
$message .= " Details: {$body_message}";
}
throw new RuntimeException($message, $http_result->code);
}
return $result;
}
/**
* Executes a curl request.
*
* @param string $url
* @param array $headers
* @param string $body
*
* @return object
* An object with the following properties:
* - body: the returned response
* - http_code: the HTTP result code
* - meta: an associative array with meta info about the executed curl
* request: the result of {@see curl_getinfo()} called without an option
* passed in) plus an entry 'method_time', containing the time spent in
* the method (which during local development was at most 0.0002s higher
* then the key 'total_time' as returned by Curl). Can be used for logging
* or timing.
*
* @throws RuntimeException
* On any error at the curl level, which will be rare, an exception will be
* thrown. Thus http responses (and codes) that indicate an error are
* returned as an object.
*/
private function send_http_request($url, $headers, $body) {
$start = microtime(TRUE);
$request = $this
->get_curl_handle();
$options = [
CURLOPT_URL => $url,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_POST => TRUE,
CURLOPT_RETURNTRANSFER => TRUE,
];
if (!empty($body)) {
$options[CURLOPT_POSTFIELDS] = $body;
}
curl_setopt_array($request, $options);
$result = curl_exec($request);
if ($result === FALSE || !empty(curl_error($request))) {
watchdog('backup_migrate', "Backup Migrate Dropbox Error: send_http_request({$url}): Curl error: " . curl_error($request), [], WATCHDOG_ERROR);
throw new RuntimeException('Curl error: ' . curl_error($request));
}
return (object) [
'body' => $result,
'code' => (int) curl_getinfo($request, CURLINFO_RESPONSE_CODE),
'meta' => curl_getinfo($request) + [
'method_time' => microtime(TRUE) - $start,
],
];
}
/**
* Returns the Curl handle.
*
* If no Curl handle has been created yet, one will be created.
*
* Reuse of the curl handle has been seen to be given some performance
* improvement over creating new handles for each http request. Especially
* when getting the list of backups, a large number of requests may be sent to
* Dropbox. But still each request easily takes more than 0.5s, so on large
* sets of retained back-up files, building this list still takes a
* considerable amount of time.
*
* Note: it would be better to keep a handle per host as the gain is in
* setting up the connection (name lookup and connecting with ssl). (@todo?)
*
* A better performance improvement would be downloading multiple (info) files
* at once, but the Dropbox API does not offer that. The only feature that
* Dropbox offers is downloading a whole folder at once as a zip, but then the
* info files would have to be placed in their own folder, not alongside the
* back-up files themselves. (@todo?)
*
* @return resource
*
* @throws RuntimeException
*/
private function get_curl_handle() {
if (empty($this->ch)) {
$this->ch = curl_init();
if (empty($this->ch)) {
throw new RuntimeException('Could not open a Curl session');
}
}
else {
// Reuse the handle but reset the options.
curl_reset($this->ch);
}
return $this->ch;
}
/**
* Extracts a preferably human readable error message from a Dropbox response.
*
* See 'Endpoint-specific errors' at
* @link https://www.dropbox.com/developers/documentation/http/documentation#error_handling.
*
* @param string $response
*
* @return string
* The Dropbox error message.
*/
private function get_dropbox_error_message($response) {
$message_object = json_decode($response);
if ($message_object === NULL) {
// Plaintext message.
$message = $response;
}
elseif (isset($message_object->user_message)) {
$message = $message_object->user_message;
}
elseif (isset($message_object->error_summary)) {
$message = $message_object->error_summary;
}
else {
// Message with unknown/unexpected properties: return json string.
$message = $response;
}
return $message;
}
/**
* Returns whether the response should be a json string or file contents.
*
* - 'api' endpoints always return json.
* - 'content' endpoints may return:
* - File contents (files/download).
* - A json encoded object.
* - Nothing (files/upload_session/append_v2).
*
* @param string $endpointType
* @param string $command
*
* @return bool
* True if the response is expected to be a json string, false otherwise.
*/
private function is_json_response($endpointType, $command) {
return $endpointType === 'api' || !in_array($command, [
'files/download',
'files/upload_session/append_v2',
]);
}
/**
* Encodes a code verifier or code challenge in Base64URL.
*
* @link https://dropbox.tech/developers/pkce--what-and-why-
* @link https://tools.ietf.org/html/rfc4648#section-5
*
* @param string $code
* The code to encode in base64URL.
*
* @return string
* The code encoded in base64URL.
*/
private function base64_url_encode($code) {
return rtrim(strtr(base64_encode($code), '+/', '-_'), '=');
}
/**
* Logs some debug/tracing/timing information.
*
* Will not be used in official releases, should only be used during
* development or when problems are researched.
*
* @param object $http_result
* See the return value of {@see send_http_request}
*/
protected function log($http_result) {
$meta = $http_result->meta;
$url = $meta['url'];
$method_time = $meta['method_time'];
$total_time = $meta['total_time'];
$namelookup_time = $meta['namelookup_time'];
$connect_time = $meta['connect_time'];
$transfer_time = $total_time - $meta['starttransfer_time'];
file_put_contents(DRUPAL_ROOT . '/curl.log', sprintf("%s: %-50s: %.4f %.4f %.4f %.4f %.4f\n", date('c'), $url, $method_time, $total_time, $namelookup_time, $connect_time, $transfer_time), FILE_APPEND);
}
/**
* Converts a size pattern to a numeric size.
*
* Code pulled from Stack Overflow: http://stackoverflow.com/q/1336581/819883.
*
* @param string $byteString
*
* @return int
*
*/
private function byte_size($byteString) {
preg_match('/^\\s*([0-9.]+)\\s*([KMGT])B?\\s*$/i', $byteString, $matches);
if (!(count($matches) >= 3)) {
return 0;
}
$num = (double) $matches[1];
switch (strtoupper($matches[2])) {
/** @noinspection PhpMissingBreakStatementInspection */
case 'T':
$num *= DRUPAL_KILOBYTE;
/** @noinspection PhpMissingBreakStatementInspection */
case 'G':
$num *= DRUPAL_KILOBYTE;
/** @noinspection PhpMissingBreakStatementInspection */
case 'M':
$num *= DRUPAL_KILOBYTE;
case 'K':
$num *= DRUPAL_KILOBYTE;
}
return intval($num);
}
}
Members
Name![]() |
Modifiers | Type | Description | Overrides |
---|---|---|---|---|
BackupMigrateDropboxAPI:: |
private | property | A Curl handle. To reuse the curl handle we keep it open across calls to the Dropbox API. | |
BackupMigrateDropboxAPI:: |
private | property | Contains the B&M destination that uses this Dropbox Api object to communicate with Dropbox as this Api needs access to its name, machine name, and settings. | |
BackupMigrateDropboxAPI:: |
private | property | Indicates if we are resending a request that failed earlier because the bearer token had expired. This prevents resending over and over again in case something else is going wrong. | |
BackupMigrateDropboxAPI:: |
private | property | @var array | |
BackupMigrateDropboxAPI:: |
private | function | Encodes a code verifier or code challenge in Base64URL. | |
BackupMigrateDropboxAPI:: |
private | function | Converts a size pattern to a numeric size. | |
BackupMigrateDropboxAPI:: |
public | function | Makes a Dropbox code verifier for this installation. | |
BackupMigrateDropboxAPI:: |
public | function | Creates a folder on Dropbox. | |
BackupMigrateDropboxAPI:: |
public | function | Deletes the file at the given $path. | |
BackupMigrateDropboxAPI:: |
public | function | Downloads the file from the given Dropbox $path. | |
BackupMigrateDropboxAPI:: |
public | function | Uploads a file to the given path. | |
BackupMigrateDropboxAPI:: |
private | function | Returns the Dropbox app id of this app. | |
BackupMigrateDropboxAPI:: |
public | function | Returns the (parameterized) authorize URL. | |
BackupMigrateDropboxAPI:: |
private | function | Returns a short lived but not yet expired bearer token. | |
BackupMigrateDropboxAPI:: |
private | function | Returns the code challenge for the given code verifier. | |
BackupMigrateDropboxAPI:: |
private | function | Returns the Curl handle. | |
BackupMigrateDropboxAPI:: |
private | function | Extracts a preferably human readable error message from a Dropbox response. | |
BackupMigrateDropboxAPI:: |
private | function | Returns the refresh token for this Dropbox destination. | |
BackupMigrateDropboxAPI:: |
private | function | Returns whether the response should be a json string or file contents. | |
BackupMigrateDropboxAPI:: |
public | function | Returns the contents of a Dropbox folder. | |
BackupMigrateDropboxAPI:: |
protected | function | Logs some debug/tracing/timing information. | |
BackupMigrateDropboxAPI:: |
public | function | Obtains a first bearer and a refresh token. | |
BackupMigrateDropboxAPI:: |
private | function | Refreshes and returns an expired bearer token. | |
BackupMigrateDropboxAPI:: |
private | function | Executes a curl request. | |
BackupMigrateDropboxAPI:: |
private | function | Sends a request to Dropbox and returns the response. | |
BackupMigrateDropboxAPI:: |
private | function | Uploads 1 part of a multi-request upload. | |
BackupMigrateDropboxAPI:: |
private | function | Ends a multi-request upload. | |
BackupMigrateDropboxAPI:: |
private | function | Starts a multi-request upload. | |
BackupMigrateDropboxAPI:: |
private | function | Uploads the $contents of a file (with 1 request) to the indicated $path. | |
BackupMigrateDropboxAPI:: |
public | function | BackupMigrateDropboxAPI constructor. | |
BackupMigrateDropboxAPI:: |
public | function |