/** * Restore the database from a local file. * * @SideEffects: * Restores dump file to local database * * @return bool true on success, false on fail * @throws PermissionFailureException * @throws Exception */ public function execute() { $this->checkPerm(); $fullPath = FileSystemTools::build_path($this->Path, $this->FileName); if (!file_exists($fullPath)) { $this->failed("No such file '{$fullPath}'"); throw new Exception("No such file {$fullPath}"); } // detect if we should use GZIP from the file name terminal extension being '.gz' if (substr($this->FileName, -3) == '.gz') { $this->UseGZIP = true; $command = sprintf("gunzip < %s | %s --host=%s --user=%s --password=%s %s ", $fullPath, Replicant::config()->get('path_to_mysql'), DatabaseTools::getDBCredential('Server'), DatabaseTools::getDBCredential('UserName'), DatabaseTools::getDBCredential('Password'), $this->Database); } else { $command = sprintf("%s --host=%s --user=%s --password=%s %s < %s", Replicant::config()->get('path_to_mysql'), DatabaseTools::getDBCredential('Server'), DatabaseTools::getDBCredential('UserName'), DatabaseTools::getDBCredential('Password'), $this->Database, $fullPath); } $this->step("Restoring database '{$this->UserName}@{$this->RemoteHost}:{$this->Database}' from '{$fullPath}'"); if ($this->system($command, $retval)) { // we need a new one here as existing one will be gone when database // ReplicantActionRestore::create(static::ActionRestore, "", static::ResultMessageSuccess, "Restoring database '$this->UserName@$this->RemoteHost:$this->Database' from '$fullPath'"); $this->success("Restored database '{$this->Database}' from '{$fullPath}'"); return true; } else { $this->failed("Failed, command returned #{$retval}"); return false; } }
/** * Dump database to the local filesystem via mysqldump command and optionally gzipping output. * * @SideEffects: * Dumps database to local filesystem. * * @return bool true on success, false on fail * @throws PermissionFailureException */ public function execute() { $fullPath = FileSystemTools::build_path($this->Path, $this->FileName) . ($this->UseGZIP ? ".gz" : ''); $this->step("Dumping database '{$this->Database}' to '{$fullPath}'"); // local server dump requested, create paths and dump the file. if (!is_dir($this->Path)) { // path doesn't exist, create it recursively $this->step("Creating folder '{$this->Path}'"); if (!FileSystemTools::make_path($this->Path)) { $this->failed("Failed to create path '{$this->Path}'"); return false; } } $excludeTables = ''; if (count(Replicant::config()->get('exclude_tables'))) { $excludeTables = " --ignore-table={$this->Database}." . implode(" --ignore-table={$this->Database}.", Replicant::config()->get('exclude_tables')) . " "; } $command = sprintf("%s --host=%s --user=%s --password=%s %s %s %s %s", Replicant::config()->get('path_to_mysqldump'), DatabaseTools::getDBCredential('Server'), DatabaseTools::getDBCredential('UserName'), DatabaseTools::getDBCredential('Password'), $excludeTables, $this->Database, $this->UseGZIP ? " | gzip > " : " > ", $fullPath); $ok = $this->system($command, $retval); if ($ok) { $this->success("Dumped Database to {$fullPath}"); } else { $this->failed("Execute returned #{$retval}"); } return $ok; }
/** * Fetch a file or if no FileName set all files found at remote location. * * @SideEffects: * Writes files to local filesystem * * If all files then don't overwrite existing files, otherwise if a single file then overwrite it every time. * * @return int number of files fetched */ public function execute() { $this->checkPerm(); $transport = Replicant::transportFactory($this->Protocol, $this->RemoteHost, $this->Proxy, $this->UserName, $this->Password); // if we have a FileName then only enqueue that file, otherwise get a list of files from remote host and enqueue all for fetching (existing files won't be refetched in this case). if (!$this->FileName) { $this->step("Fetching file list from '{$this->Protocol}://{$this->UserName}@{$this->RemoteHost}/{$this->Path}'"); try { $files = $transport->fetchFileList($this->Path); } catch (Exception $e) { $this->failed("Failed to get file list: " . $e->getMessage()); return 0; } } else { $fullPath = FileSystemTools::build_path($this->Path, $this->FileName); $this->step("Enqueuing file '{$fullPath}'"); // create the files array as a single entry with path and name $files = array(array('Path' => $this->Path, 'FileName' => $this->FileName)); } $numFiles = count($files); $numFetched = 0; $this->step("Fetching #{$numFiles} files"); foreach ($files as $fileInfo) { // strip off extension here or alpha will reject request $fileName = $fileInfo['FileName']; $remotePathName = FileSystemTools::build_path(Replicant::config()->get('remote_path'), basename($fileName)); $localPathName = FileSystemTools::build_path(Replicant::asset_path(), $fileName); $overwrite = $this->FileName != ''; $this->step("Fetching file '{$remotePathName}' with overwrite (" . ($overwrite ? "set" : "not set") . ")"); try { if (false !== $transport->fetchFile($remotePathName, $localPathName, $overwrite)) { $numFetched++; } } catch (Exception $e) { $this->failed("Failed to fetch file '{$remotePathName}': " . $e->getMessage()); // EARLY EXIT! return false; } } $this->success("Fetched #{$numFetched} files of #{$numFiles}"); return $numFetched; }
/** * Save record as normal, then if the record was new invoke the record class (which should be derived from ReplicantAction) to perform the action. * * If the remote address is provided * * @param $data * @param $form * @return HTMLText|SS_HTTPResponse|ViewableData_Customised|void */ public function doSave($data, $form) { $list = $this->gridField->getList(); $controller = Controller::curr(); $new_record = !$this->record->isInDB(); $ok = false; try { $this->record->update($data); // $form->saveInto($this->record); $this->record->write(); // now actually run the action. If it is a dump action and the remote host is not localhost then we call dump on the remote host instead. if ($this->record->ClassName != 'ReplicantActionDump' || $this->record->RemoteHost == 'localhost') { $ok = $this->record->execute(); } else { $transport = Replicant::transportFactory($this->record->Protocol, $this->record->RemoteHost, $this->record->Proxy, $this->record->UserName, $this->record->Password); $path = "replicant/dump" . ($this->record->UseGZIP ? "&UseGZIP=1" : ""); $url = $transport->buildURL($path); $this->record->step("Dumping on remote system {$url}"); try { $result = $transport->fetchPage($path); } catch (Exception $e) { $result = $e->getMessage(); } // TODO SW better result checking here $ok = false !== strpos($result, 'Success'); if ($ok) { $this->record->success("Dumped Database on {$url}: {$result}"); } else { $this->record->failed("Failed calling {$url}: {$result}"); } } if ($ok) { $link = '"' . $this->record->Title . '"'; $message = _t('GridFieldDetailForm.Saved', 'Saved {name} {link}', array('name' => $this->record->i18n_singular_name(), 'link' => $link)); $form->sessionMessage($message, 'good'); } else { $message = _t('Error', 'Failed to {message}: {error}', array('message' => $this->record->i18n_singular_name(), 'error' => $this->record->ResultInfo)); $form->sessionMessage($message, 'bad'); } $list->add($this->record, null); } catch (ValidationException $e) { $this->record->failed($e->getResult()->message()); $form->sessionMessage($e->getResult()->message(), 'bad'); $responseNegotiator = new PjaxResponseNegotiator(array('CurrentForm' => function () use(&$form) { return $form->forTemplate(); }, 'default' => function () use(&$controller) { return $controller->redirectBack(); })); if ($controller->getRequest()->isAjax()) { $controller->getRequest()->addHeader('X-Pjax', 'CurrentForm'); } return $responseNegotiator->respond($controller->getRequest()); } catch (Exception $e) { $this->record->failed($e->getMessage()); $form->sessionMessage($e->getMessage(), 'bad'); $responseNegotiator = new PjaxResponseNegotiator(array('CurrentForm' => function () use(&$form) { return $form->forTemplate(); }, 'default' => function () use(&$controller) { return $controller->redirectBack(); })); if ($controller->getRequest()->isAjax()) { $controller->getRequest()->addHeader('X-Pjax', 'CurrentForm'); } return $responseNegotiator->respond($controller->getRequest()); } $noActionURL = $controller->removeAction($data['url']); $controller->getRequest()->addHeader('X-Pjax', 'Content'); return $controller->redirect($noActionURL, 302); }
/** * Return absolute path to the folder where Replicant will be storing files. * * @return string */ public static function asset_path() { return Director::getAbsFile(Replicant::config()->get('files_path')); }
/** * Update with some sensible defaults. * @param array $data * @return DataObject */ public function update($data) { return parent::update(CollectionTools::options_from_array($data, array('RemoteHost' => $_SERVER['SERVER_NAME'], 'Protocol' => $_SERVER['SERVER_PROTOCOL'], 'Proxy' => '', 'Path' => Replicant::asset_path(), 'UserName' => Member::currentUser()->Email))); }
/** * Fetch one or all remote dump files and writes to local filesystem. * * If filename is supplied as getVar then only that file will be retrieved, otherwise all files which don't exist locally will be retrieved up to number getVar. * * If filename is supplied as getVar then file will overwrite existing file. * * SideEffects: * Reads files from remote system. * Writes files to local filesystem. * Outputs results * * @param SS_HTTPRequest $request * @return int number of files fetched * @throws PermissionFailureException */ public function fetch(SS_HTTPRequest $request) { $options = CollectionTools::options_from_array($request->getVars(), array('RemoteHost' => $request->getIP(), 'Path' => Replicant::asset_path(), 'FileName' => '', 'UserName' => null, 'Password' => null)); $action = ReplicantActionFetch::create(); $action->checkPerm()->update($options)->execute(); return $action->format(); }
/** * Return an array of known proxies from Replicant::config::$proxies. Key and value is proxy name except for optional '' => 'none'. * * @param bool $includeEmptyOption prepend list with '' => 'none' * @return array */ public function getProxyList($includeEmptyOption = true) { $proxies = array_combine(Replicant::config()->get('proxies'), Replicant::config()->get('proxies')); if ($includeEmptyOption) { $proxies = array('' => 'none') + $proxies; } return $proxies; }