__('Cancelled before could download from %1$s folder %2$s', "duplicator-pro"), $this->getStypeName(), $this->getStorageFolder() ); case 'success': return sprintf( __('Downloaded package from %1$s folder %2$s', "duplicator-pro"), $this->getStypeName(), $this->getStorageFolder() ); default: throw new Exception('Invalid key'); } } /** * Get action text * * @param bool $isDownload Changes the text if the transfer is from storage to local * * @return string */ public function getActionText($isDownload = false) { return $isDownload ? $this->getDownloadActionKeyText('action') : $this->getUploadActionKeyText('action'); } /** * Get pending action text * * @param bool $isDownload Changes the text if the transfer is from storage to local * * @return string */ public function getPendingText($isDownload = false) { return $isDownload ? $this->getDownloadActionKeyText('pending') : $this->getUploadActionKeyText('pending'); } /** * Returns the text to display when the package has failed to copy to the storage location * * @param bool $isDownload Changes the text if the transfer is from storage to local * * @return string */ public function getFailedText($isDownload = false) { return $isDownload ? $this->getDownloadActionKeyText('failed') : $this->getUploadActionKeyText('failed'); } /** * Returns the text to display when the package has been cancelled before it could be copied to the storage location * * @param bool $isDownload Changes the text if the transfer is from storage to local * * @return string */ public function getCancelledText($isDownload = false) { return $isDownload ? $this->getDownloadActionKeyText('cancelled') : $this->getUploadActionKeyText('cancelled'); } /** * Returns the text to display when the package has been successfully copied to the storage location * * @param bool $isDownload Changes the text if the transfer is from storage to local * * @return string */ public function getSuccessText($isDownload = false) { return $isDownload ? $this->getDownloadActionKeyText('success') : $this->getUploadActionKeyText('success'); } /** * * @return string */ protected static function getDefaultStorageFolder() { /** @var array */ $parsetUrl = SnapURL::parseUrl(get_home_url()); if (is_string($parsetUrl['host']) && strlen($parsetUrl['host']) > 0) { $parsetUrl['host'] = preg_replace("([^\w\d\-_~,;\[\]\(\)\/\.])", '', $parsetUrl['host']); } $parsetUrl['scheme'] = false; $parsetUrl['port'] = false; $parsetUrl['query'] = false; $parsetUrl['fragment'] = false; $parsetUrl['user'] = false; $parsetUrl['pass'] = false; if (is_string($parsetUrl['path']) && strlen($parsetUrl['path']) > 0) { $parsetUrl['path'] = preg_replace("([^\w\d\-_~,;\[\]\(\)\/\.])", '', $parsetUrl['path']); } return ltrim(SnapURL::buildUrl($parsetUrl), '/\\'); } /** * Render form config fields * * @param bool $echo Echo or return * * @return string */ abstract public function renderConfigFields($echo = true); /** * Render remote localtion info * * @param bool $failed Failed upload * @param bool $cancelled Cancelled upload * @param bool $packageExists Package exists * @param bool $echo Echo or return * * @return string */ public function renderRemoteLocationInfo($failed = false, $cancelled = false, $packageExists = true, $echo = true) { return TplMng::getInstance()->render( 'admin_pages/storages/parts/remote_localtion_info', [ 'failed' => $failed, 'cancelled' => $cancelled, 'packageExists' => $packageExists, 'storage' => $this, ], $echo ); } /** * Storages test * * @param string $message Test message * * @return bool return true if success, false otherwise */ public function test(&$message = '') { $this->testLog->reset(); $message = sprintf(__('Testing %s storage...', 'duplicator-pro'), $this->getStypeName()); $this->testLog->addMessage($message); if ($this->isSupported() == false) { $message = sprintf(__('Storage %s isn\'t supported on current server', 'duplicator-pro'), $this->getStypeName()); $this->testLog->addMessage($message); return false; } if ($this->isValid() == false) { $message = sprintf(__('Storage %s config data isn\'t valid', 'duplicator-pro'), $this->getStypeName()); $this->testLog->addMessage($message); return false; } try { $adapter = $this->getAdapter(); } catch (Exception $e) { // This exception is captured temporally until all storage has implemented its adapter. /** @todo remove this remove this when it is okay */ return true; } $testFileName = 'dup_test_' . md5(uniqid((string) rand(), true)) . '.txt'; $this->testLog->addMessage(sprintf(__('Checking if the temporary file exists "%1$s"...', 'duplicator-pro'), $testFileName)); if ($adapter->exists($testFileName)) { $this->testLog->addMessage(sprintf(__( 'File with the temporary file name already exists, please try again "%1$s"', 'duplicator-pro' ), $testFileName)); $message = __('File with the temporary file name already exists, please try again', 'duplicator-pro'); return false; } $this->testLog->addMessage(sprintf(__('Creating temporary file "%1$s"...', 'duplicator-pro'), $testFileName)); if (!$adapter->createFile($testFileName, 'test')) { $this->testLog->addMessage( __( 'There was a problem when storing the temporary file', 'duplicator-pro' ) ); $message = __('There was a problem storing the temporary file', 'duplicator-pro'); return false; } $this->testLog->addMessage(sprintf(__('Checking if the temporary file exists "%1$s"...', 'duplicator-pro'), $testFileName)); if (!$adapter->isFile($testFileName)) { $this->testLog->addMessage(sprintf(__( 'The temporary file was not found "%1$s"', 'duplicator-pro' ), $testFileName)); $message = __('The temporary file was not found', 'duplicator-pro'); return false; } $this->testLog->addMessage(sprintf(__('Deleting temporary file "%1$s"...', 'duplicator-pro'), $testFileName)); if (!$adapter->delete($testFileName)) { $this->testLog->addMessage(sprintf(__( 'There was a problem when deleting the temporary file "%1$s"', 'duplicator-pro' ), $testFileName)); $message = __('There was a problem deleting the temporary file', 'duplicator-pro'); return false; } $this->testLog->addMessage(__('Successfully stored and deleted file', 'duplicator-pro')); $message = __('Successfully stored and deleted file', 'duplicator-pro'); return true; } /** * Get last test messages * * @return string */ public function getTestLog() { return (string) $this->testLog; } /** * Get copied storage from source id. * If destId is existing storage is accepted source id with only the same type * * @param int $sourceId Source storage id * @param int $targetId Target storage id, if <= 0 create new storage * * @return false|static Return false on failure or storage object with updated value */ public static function getCopyStorage($sourceId, $targetId = -1) { if (($source = static::getById($sourceId)) === false) { return false; } if ($targetId <= 0) { $class = get_class($source); /** @var static */ $target = new $class(); } else { /** @var false|static */ $target = static::getById($targetId); if ($target == false) { return false; } if ($source->getSType() != $target->getSType()) { return false; } } $skipProps = [ 'id', 'testLog', ]; $reflect = new ReflectionClass($source); foreach ($reflect->getProperties() as $prop) { if (in_array($prop->getName(), $skipProps)) { continue; } if ($prop->isStatic()) { continue; } $prop->setAccessible(true); if ($prop->getName() == 'name') { $newName = sprintf(__('%1$s - Copy', "duplicator-pro"), $prop->getValue($source)); $prop->setValue($target, $newName); } else { $prop->setValue($target, $prop->getValue($source)); } } return $target; } /** * Get all storages by type * * @param int $sType Storage type * * @return self[]|false return entities list of false on failure */ public static function getAllBySType($sType) { return self::getAll(0, 0, null, function (self $storage) use ($sType) { return ($storage->getSType() == $sType); }); } /** * To export data * * @return array */ public function settingsExport() { $data = JsonSerialize::serializeToData($this, JsonSerialize::JSON_SKIP_MAGIC_METHODS | JsonSerialize::JSON_SKIP_CLASS_NAME); unset($data['testLog']); return $data; } /** * Update object properties from import data * * @param array $data data to import * @param string $dataVersion version of data * @param array $extraData extra data, useful form id mapping etc. * * @return bool True if success, otherwise false */ public function settingsImport($data, $dataVersion, array $extraData = []) { $skipProps = ['id']; $reflect = new ReflectionClass(self::class); $props = $reflect->getProperties(); foreach ($props as $prop) { if (in_array($prop->getName(), $skipProps)) { continue; } if (!isset($data[$prop->getName()])) { continue; } $prop->setAccessible(true); $prop->setValue($this, $data[$prop->getName()]); } return true; } /** * Save new storage to DB * * @return int|false The id or false on failure */ protected function insert() { if (($id = parent::insert()) === false) { return false; } do_action('duplicator_pro_after_storage_create', $id); return $id; } /** * Delete this storage * * @return bool True on success, or false on error. */ public function delete() { $id = $this->id; if (parent::delete() === false) { return false; } DUP_PRO_Package::by_status_callback(function (DUP_PRO_Package $package) use ($id) { foreach ($package->upload_infos as $key => $upload_info) { if ($upload_info->getStorageId() == $id) { DUP_PRO_Log::traceObject("deleting uploadinfo from package $package->ID", $upload_info); unset($package->upload_infos[$key]); $package->save(); break; } } }); DUP_PRO_Schedule_Entity::listCallback(function (DUP_PRO_Schedule_Entity $schedule) use ($id) { if (($key = array_search($id, $schedule->storage_ids)) !== false) { $key = (int) $key; //use array_splice() instead of unset() to reset keys array_splice($schedule->storage_ids, $key, 1); if (count($schedule->storage_ids) === 0) { $schedule->active = false; } $schedule->save(); } }); do_action('duplicator_pro_after_storage_delete', $id); return true; } }