File Manager

Current Directory: /home/astoriaah/www/administrator/components/com_akeeba/BackupEngine/Postproc
Viewing File: /home/astoriaah/www/administrator/components/com_akeeba/BackupEngine/Postproc/Box.php
<?php /** * Akeeba Engine * * @package akeebaengine * @copyright Copyright (c)2006-2022 Nicholas K. Dionysopoulos / Akeeba Ltd * @license GNU General Public License version 3, or later */ namespace Akeeba\Engine\Postproc; defined('AKEEBAENGINE') || die(); use Akeeba\Engine\Factory; use Akeeba\Engine\Platform; use Akeeba\Engine\Postproc\Connector\Box as ConnectorBox; use Akeeba\Engine\Postproc\Exception\BadConfiguration; use Akeeba\Engine\Postproc\Exception\RangeDownloadNotSupported; use Exception; use RuntimeException; class Box extends Base { /** * The retry count of this file (allow up to 2 retries after the first upload failure) * * @var int */ protected $tryCount = 0; /** * The currently configured directory * * @var string */ protected $directory; /** * The name of the OAuth2 callback method in the parent window (the configuration page) * * @var string */ protected $callbackMethod = 'akconfig_box_oauth_callback'; /** * The key in Akeeba Engine's settings registry for this post-processing method * * @var string */ protected $settingsKey = 'box'; public function __construct() { $this->supportsDownloadToBrowser = false; $this->supportsDelete = true; $this->supportsDownloadToFile = true; } public function oauthCallback(array $params) { $input = $params['input']; $data = [ 'access_token' => $input['access_token'], 'refresh_token' => $input['refresh_token'], ]; $serialisedData = json_encode($data); return <<< HTML <script type="application/javascript"> window.opener.{$this->callbackMethod}($serialisedData); </script> HTML; } public function processPart($localFilepath, $remoteBaseName = null) { /** @var ConnectorBox $connector */ $connector = $this->getConnector(); $connector->ping(); // Store the absolute remote path in the property $directory = $this->directory; $basename = empty($remoteBaseName) ? basename($localFilepath) : $remoteBaseName; $this->remotePath = $directory . '/' . $basename; // Get the remote file's pathname $remotePath = trim($directory, '/') . '/' . basename($localFilepath); // Single part upload $exception = null; // Try deleting the file first because Box doesn't allow replacing files Factory::getLog()->debug(sprintf("%s - Simple upload. Proactively deleting files with remote path $remotePath", __METHOD__)); $connector->deleteFileByName($remotePath); try { // Try to upload the file (single part upload) Factory::getLog()->debug(sprintf("%s - Performing simple upload", __METHOD__)); $connector->uploadSingleFile($remotePath, $localFilepath); } catch (Exception $e) { // Upload failed. Let's log the failure first. Factory::getLog()->debug(sprintf("%s - Simple upload failed, %s: %s", __METHOD__, 500, $e->getMessage())); // Increase the try counter $this->tryCount++; // If I exceeded my retry count I will throw am exception (hard failure) if ($this->tryCount > 2) { Factory::getLog()->debug(sprintf("%s - Maximum number of retries exceeded. The upload has failed.", __METHOD__)); throw new RuntimeException('Uploading to Box failed.', 500, $e); } // I need to retry. Factory::getLog()->debug(__METHOD__ . " - Error detected, trying to force-refresh the tokens"); $this->forceRefreshTokens(); Factory::getLog()->debug(__METHOD__ . " - The upload will be retried"); return false; } $this->tryCount = 0; return true; } public function downloadToFile($remotePath, $localFile, $fromOffset = null, $length = null) { if (!is_null($fromOffset)) { // Ranges are not supported throw new RangeDownloadNotSupported(); } /** @var ConnectorBox $connector */ $connector = $this->getConnector(); $connector->ping(); $connector->download($remotePath, $localFile); } public function delete($path) { /** @var ConnectorBox $connector */ $connector = $this->getConnector(); $connector->ping(); $connector->deleteFileByName($path); } protected function getOAuth2HelperUrl() { return ConnectorBox::helperUrl; } protected function makeConnector() { // Retrieve engine configuration data $config = Factory::getConfiguration(); $access_token = trim($config->get('engine.postproc.' . $this->settingsKey . '.access_token', '')); $refresh_token = trim($config->get('engine.postproc.' . $this->settingsKey . '.refresh_token', '')); $this->directory = $config->get('volatile.postproc.directory', null); if (empty($this->directory)) { $this->directory = $config->get('engine.postproc.' . $this->settingsKey . '.directory', ''); } // Sanity checks if (empty($refresh_token)) { throw new BadConfiguration('You have not linked Akeeba Backup with your Box account'); } if (!function_exists('curl_init')) { throw new BadConfiguration('cURL is not enabled, please enable it in order to post-process your archives'); } // Fix the directory name, if required $this->directory = empty($this->directory) ? '' : $this->directory; $this->directory = trim($this->directory); $this->directory = ltrim(Factory::getFilesystemTools()->TranslateWinPath($this->directory), '/'); $this->directory = Factory::getFilesystemTools()->replace_archive_name_variables($this->directory); $config->set('volatile.postproc.directory', $this->directory); // Get Download ID $dlid = Platform::getInstance()->get_platform_configuration_option('update_dlid', ''); if (empty($dlid)) { throw new BadConfiguration('You must enter your Download ID in the application configuration before using the “Upload to Box.com” feature.'); } $connector = new ConnectorBox($access_token, $refresh_token, $dlid); // Validate the tokens Factory::getLog()->debug(sprintf("%s - Validating the Box tokens", __METHOD__)); $pingResult = $connector->ping(); // Save new configuration if there was a refresh if ($pingResult['needs_refresh']) { Factory::getLog()->debug(sprintf("%s - Box tokens were refreshed", __METHOD__)); $config->set('engine.postproc.' . $this->settingsKey . '.access_token', $pingResult['access_token'], false); $config->set('engine.postproc.' . $this->settingsKey . '.refresh_token', $pingResult['refresh_token'], false); $profile_id = Platform::getInstance()->get_active_profile(); Platform::getInstance()->save_configuration($profile_id); } return $connector; } /** * Forcibly refresh the Box tokens * * @return void * * @throws Exception */ protected function forceRefreshTokens() { /** @var ConnectorBox $connector */ $connector = $this->getConnector(); $config = Factory::getConfiguration(); $pingResult = $connector->ping(true); Factory::getLog()->debug(sprintf("%s - Box tokens were forcibly refreshed", __METHOD__)); $config->set('engine.postproc.' . $this->settingsKey . '.access_token', $pingResult['access_token'], false); $config->set('engine.postproc.' . $this->settingsKey . '.refresh_token', $pingResult['refresh_token'], false); $profile_id = Platform::getInstance()->get_active_profile(); Platform::getInstance()->save_configuration($profile_id); } }