Current Path : /var/www/html/wp-content/plugins/duplicator-pro/src/Utils/ |
Current File : /var/www/html/wp-content/plugins/duplicator-pro/src/Utils/SFTPAdapter.php |
<?php /** * @package Duplicator * @copyright (c) 2022, Snapcreek LLC */ namespace Duplicator\Utils; use DUP_PRO_Log; use Duplicator\Utils\Exceptions\ChunkingTimeoutException; use Exception; use VendorDuplicator\phpseclib\Crypt\RSA; use VendorDuplicator\phpseclib\Net\SFTP; /** * SFTP class adapter */ class SFTPAdapter { /** @var string */ protected $server = ''; /** @var int */ protected $port = 22; /** @var string */ protected $username = ''; /** @var string */ protected $password = ''; /** @var string */ protected $privateKey = ''; /** @var string */ protected $privateKeyPassword = ''; /** @var ?IncrementalStatusMessage */ protected $messages = null; /** @var float */ private $timeLimit = -1.0; /** @var float */ private $timeStart = -1.0; /** @var SFTP */ private $sftp = null; /** * Class contructor * * @param string $server hosting domain or ip address * @param int $port hosting port * @param string $username hosting username * @param string $password hosting password * @param string $privateKey hosting private key * @param string $privateKeyPassword hosting private key password */ public function __construct( $server, $port = 22, $username = '', $password = '', $privateKey = '', $privateKeyPassword = '' ) { if (strlen($server) == 0) { throw new Exception(__('Server name is required to make sftp connection', 'duplicator-pro')); } if ($port <= 0) { throw new Exception(__('Server port is required to make sftp connection', 'duplicator-pro')); } if (strlen($username) == 0) { throw new Exception(__('Username is required to make sftp connection', 'duplicator-pro')); } if (strlen($password) == 0 && strlen($privateKey) == 0) { throw new Exception(__( 'You should provide either sftp user pasword or the private key to make sftp connection', 'duplicator-pro' )); } if (strlen($privateKey) > 0 && strlen($privateKeyPassword) == 0) { throw new Exception(__( 'You should provide private key password', 'duplicator-pro' )); } $this->server = $server; $this->port = $port; $this->username = $username; $this->password = $password; $this->privateKey = $privateKey; $this->privateKeyPassword = $privateKeyPassword; $this->sftp = new SFTP($this->server, $this->port); } /** * Class destructor * * @return void */ public function __destruct() { $this->disconnect(); } /** * Connect to an SFTP Server * * @return bool true on success, false on failure */ public function connect() { if ($this->messages === null) { $this->messages = new IncrementalStatusMessage(); } $this->disconnect(); if (!empty($this->privateKey)) { $key = $this->getPrivateKey(); } else { $key = null; } $this->messages->addMessage(sprintf( __('Connecting to SFTP server %1$s:%2$d', 'duplicator-pro'), $this->server, $this->port )); DUP_PRO_Log::trace("Connect to SFTP server " . $this->server . ':' . $this->port); $this->messages->addMessage(sprintf(__('Attempting to login to SFTP server %1$s', 'duplicator-pro'), $this->server)); DUP_PRO_Log::trace("Attempting to login to SFTP server " . $this->server); if (!is_null($key)) { $this->messages->addMessage(__('Login to SFTP using private key', 'duplicator-pro')); DUP_PRO_Log::trace("Login to SFTP using private key"); if ($this->sftp->login($this->username, $key)) { $this->messages->addMessage(__('Successfully connected to server using private key', 'duplicator-pro')); DUP_PRO_Log::infoTrace('Successfully connected to server using private key'); } else { DUP_PRO_Log::trace("Error opening SFTP connection using private key"); $this->messages->addMessage(__('Error opening SFTP connection using private key', 'duplicator-pro')); return false; } } else { DUP_PRO_Log::trace("Login to SFTP"); if ($this->sftp->login($this->username, $this->password)) { $this->messages->addMessage(__('Successfully connected to server using password', 'duplicator-pro')); DUP_PRO_Log::infoTrace('Successfully connected to server using password'); } else { DUP_PRO_Log::trace("Error opening SFTP connection using password"); $this->messages->addMessage(__('Error opening SFTP connection using password', 'duplicator-pro')); return false; } } return true; } /** * Disconnect SFTP connection * * @return void */ protected function disconnect() { if (!$this->sftp->isConnected()) { return; } DUP_PRO_Log::infoTrace("Disconnect SFTP Connection"); $this->sftp->disconnect(); } /** * Set an SFTP Private Key * * @return RSA return key object or false */ protected function getPrivateKey() { if (strlen($this->privateKey) == 0) { DUP_PRO_Log::trace("Private key is null"); throw new Exception('Private key is null'); } $key = new RSA(); if (!empty($this->privateKeyPassword)) { DUP_PRO_Log::trace("Get Private Key Object with Password"); $key->setPassword($this->privateKeyPassword); } else { DUP_PRO_Log::trace("Get Private Key Object"); } $key->loadKey($this->privateKey); DUP_PRO_Log::trace("Private Key Loaded"); return $key; } /** * Checks whether a file or directory exists * * @param string $path file path * * @return bool */ public function fileExists($path) { return $this->sftp->file_exists($path); } /** * Gets file size * * @param string $path file path * * @return mixed */ public function filesize($path) { return $this->sftp->filesize($path); } /** * Deletes a file on the SFTP server. * * @param string $path file path * @param bool $recursive true delete recurively * * @return bool */ public function delete($path, $recursive = true) { return $this->sftp->delete($path, $recursive); } /** * Returns a list of files in the given directory * * @param string $dir dir to stan * @param bool $recursive if true scan recurively * * @return mixed */ public function filesList($dir = '.', $recursive = false) { return $this->sftp->nlist($dir, $recursive); } /** * Uploads a file to the SFTP server. * * @param string $remote_file remote file name * @param string|resource $data local file data * @param int $offset offset from which data transfer will continue (not used if -1) * * @return bool */ public function put($remote_file, $data, $offset = -1) { return $this->sftp->put( $remote_file, $data, SFTP::SOURCE_LOCAL_FILE | SFTP::RESUME, $offset, $offset, array( $this, 'uploadProgress', ) ); } /** * Create directory recursively * * @param string $storagePath storage directory path * * @return string return the directory path */ public function mkDirRecursive($storagePath = '') { if (strlen($storagePath) == 0) { throw new Exception('Storage Folder is null.'); } if (!$this->sftp->isConnected()) { throw new Exception('You must connect to SFTP before making a directory.'); } $storageFolders = explode("/", $storagePath); $path = ''; foreach ($storageFolders as $dir) { $path = $path . '/' . $dir; if (!$this->sftp->file_exists($path)) { if (!$this->sftp->mkdir($path)) { $errorMessage = 'Directory not created ' . $path . '. Make sure you have write permissions on your SFTP server.'; throw new Exception($errorMessage); } } } DUP_PRO_Log::trace("Directory $storagePath is created via SFTP"); return $storagePath; } /** * Method that should be used to start the chunking count before the files get sent * * @param float $timeLimit Time in seeconds to limit the chunked upload to * * @return void */ public function startChunkingTimer($timeLimit = -1) { $this->timeStart = microtime(true); $this->timeLimit = $timeLimit; } /** * Call back that can be used for phpseclib to exit the process during chunking * * @param float $sent size of the sent chunf of the file * * @return bool */ public function uploadProgress($sent) { if ($this->timeLimit > -1) { if (microtime(true) - $this->timeStart >= $this->timeLimit) { throw new ChunkingTimeoutException("Time Limit Was Reached"); } } return true; } /** * @return callable */ public function getCallProgressCallback() { return array( $this, 'uploadProgress', ); } /** * Set incremental messages manager * * @param IncrementalStatusMessage $messages messages * * @return void */ public function setMessages(IncrementalStatusMessage $messages) { $this->messages = $messages; } }