Skip to content

Commit

Permalink
revert-strange-file-overwrite-from-command-to-service
Browse files Browse the repository at this point in the history
  • Loading branch information
rlf authored and rlf committed Aug 29, 2019
1 parent 1b0d64c commit ee51b79
Showing 1 changed file with 165 additions and 88 deletions.
253 changes: 165 additions & 88 deletions Service/FileTransferService.php
Original file line number Diff line number Diff line change
@@ -1,127 +1,204 @@
<?php

namespace FileTransferBundle\Command;
namespace FileTransferBundle\Service;

use FileTransferBundle\Service\FileTransferService;
use Pimcore\Console\AbstractCommand;
use Pimcore\Console\Dumper;
use http\Exception\RuntimeException;
use phpseclib\Net\SFTP;
use Pimcore\Log\ApplicationLogger;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Finder\Finder;

class TransferFileCommand extends AbstractCommand
class FileTransferService
{
protected function configure()
const MODE_PUT = 'put';
const MODE_GET = 'get';

private $logger;
private $config;
private $mode;

public function __construct(array $parameters, ApplicationLogger $logger)
{
$this
->setName('transfer:file')
->setDescription('Transfer a file')
->addArgument(
'targetserverid',
InputArgument::REQUIRED,
'target server identifier')
->addArgument(
'sourcefile',
InputArgument::REQUIRED,
'source file')
->addArgument(
'targetfile',
InputArgument::REQUIRED,
'target file')
->addOption('method',
'm',
InputOption::VALUE_OPTIONAL,
"Determen if the service retreive files or push it to the server. Options: put,get",
FileTransferService::MODE_PUT)
->addOption('ignore',
'i',
InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY,
'',
[])
;
$this->config = $parameters;
$this->logger = $logger;
$this->logger->setComponent('FileTransfer');

$this->mode = self::MODE_PUT;
}

protected function execute(InputInterface $input, OutputInterface $output)
/**
* Set the mode where the service should be operating
*
* @param string $mode
*/
public function setMode(string $mode = self::MODE_PUT):void
{
$this->mode = $mode;
}

$sourcefile = $input->getArgument('sourcefile');
$targetfile = $input->getArgument('targetfile');
$targetserverid = $input->getArgument('targetserverid');
/**
* Returns the mode
*
* @return string
*/
public function getMode()
{
return $this->mode;
}

/** @var FileTransferService $service */
$service = $this->getContainer()->get('FileTransferBundle\Service\FileTransferService');
$service->setMode($input->getOption('method'));
public function getRemoteFiles($serverId, $source, $ignore = []): ?array
{
if ($this->mode === self::MODE_PUT) {
return null;
}

if ($service->getMode() === FileTransferService::MODE_GET) {
$files = $service->getRemoteFiles($targetserverid, '/PROD', $this->input->getOption('ignore', []));
$selectedFiles = [];

if (is_array($files)) {
foreach ($files as $file) {
$service->transferFile(
$targetserverid,
$sourcefile . $file,
$targetfile . $file);
}
}
$sftp = $this->loginInSftp($serverId);
$files = $sftp->nlist($source);

if (!$files) {
$e = "Directory can not be pulled from :" . $source;
$this->logger->error($e);
} else {
if ($this->useDirectoryMode($sourcefile)) {
$this->transferDirectory($service, $targetserverid, $sourcefile, $targetfile);
} else {
$service->transferFile($targetserverid, $sourcefile, $targetfile);
foreach ($files as $file) {

if (in_array($file, $ignore)) {
continue;
}

$selectedFiles[] = DIRECTORY_SEPARATOR . $file;
}
}

return $selectedFiles;
}

public function transferFile($serverid, $sourcefile, $targetfile)
{
$sftp = $this->loginInSftp($serverid);

$sftpFolderName = dirname($targetfile);

$this->logger->debug("Sftp folder name is $sftpFolderName");

$this->checkIfDirectoryExists($sftp, $sftpFolderName);

$this->changeToDirectory($sftp, $sftpFolderName);

switch ($this->mode) {
case FileTransferService::MODE_PUT:
$this->putToServer($sftp, $targetfile, $sourcefile);
break;
case FileTransferService::MODE_GET:
$this->getFromServer($sftp, $targetfile, $sourcefile);
break;
default:
throw new \RuntimeException("There is no mode selected please use -m or --method");
break;
}
}

/**
* Checks if the transfer is in directory mode
* Login in SFTP and give back the connection
*
* @param string $source
* @param string $target
* @return bool
* @return SFTP
*/
private function useDirectoryMode(string $source): bool
private function loginInSftp(string $serverid)
{
if (is_dir($source)) {
return true;
list ($address, $username, $password) = $this->getCredentials($serverid);

$sftp = new SFTP($address);
if (!$sftp->login($username, $password)) {
$e = "Sftp login failed for user " . $username;
$this->logger->error($e);
throw new \RuntimeException($e);
}

return false;
return $sftp;
}

/**
* Transfers the a complete directory to a remote server
* @return array
*/
private function getCredentials(string $serverid)
{
if (isset($this->config['servers'][$serverid])) {
$configure = $this->config['servers'][$serverid];

return [
$configure['address'],
$configure['username'],
$configure['password']
];
} else {
$e = "Config not found for server id " . $serverid;
$this->logger->error($e);
throw new \RuntimeException($e);
}
}
/**
* Checks if a directory remotely exists
*
* @param FileTransferService $service
* @param string $serverId
* @param string $source
* @param string $target
* @param SFTP $sftp
* @param string $sftpFolderName
*/
private function transferDirectory(FileTransferService $service, string $serverId, string $source, string $target): void
private function checkIfDirectoryExists(SFTP $sftp, string $sftpFolderName): void
{
$finder = new Finder();
$finder->files()->in($source);

/** @var ApplicationLogger $logger */
$logger = $this->getContainer()->get('monolog.logger.admin');
if (!$finder->hasResults()) {
$logger->notice('no files found', [
'component' => 'FileTransfer'
]);
return;
if (!$sftp->file_exists($sftpFolderName)) {
if (!$sftp->mkdir($sftpFolderName, 0777)) {
$e = "Can't create $sftpFolderName directory. " . $sftp->getLastSFTPError();
$this->logger->error($e);
throw new \RuntimeException($e);
}
} else {
$this->logger->debug("Directory exists $sftpFolderName");
}
}

foreach ($finder as $file) {
$destination = $target . $file->getFilename();
/**
* Change to the correct directory on the server
*
* @param SFTP $sftp
* @param string $targetFile
* @param string $sourceFile
*/
private function changeToDirectory(SFTP $sftp, string $sftpFolderName): void
{
if (!$sftp->chdir($sftpFolderName)) {
$e = "Can't chdir to $sftpFolderName directory. " . $sftp->getLastSFTPError();
$this->logger->error($e);
throw new \RuntimeException($e);
}
}

$service->transferFile(
$serverId,
$file,
$destination);
/**
* Upload the file to the server
*
* @param SFTP $sftp
* @param string $targetFile
* @param string $sourceFile
*/
private function putToServer(SFTP $sftp, string $targetFile, string $sourceFile): void
{
if (!$sftp->put($targetFile, $sourceFile, SFTP::SOURCE_LOCAL_FILE)) {
$e = "Couldn't send file to sftp. " . $sftp->getLastSFTPError();
$this->logger->error($e);
throw new \RuntimeException($e);
}
}

/**
* Download the file from the remote server
*
* @param SFTP $sftp
* @param string $targetFile
* @param string $sourceFile
*/
private function getFromServer(SFTP $sftp, string $targetFile, string $sourceFile): void
{
if (!$sftp->get($sourceFile, $targetFile)) {
$e = "Couldn't get file from sftp. " . $sftp->getLastSFTPError();
$this->logger->error($e);
throw new \RuntimeException($e);
}
}
}

0 comments on commit ee51b79

Please sign in to comment.