TikiWiki/tiki-manager

View on GitHub
src/Libs/Host/SSHWrapperAdapter.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php
// Copyright (c) 2016, Avan.Tech, et. al.
// Copyright (c) 2008, Luis Argerich, Garland Foster, Eduardo Polidor, et. al.
// All Rights Reserved. See copyright.txt for details and a complete list of authors.
// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.

namespace TikiManager\Libs\Host;

use Symfony\Component\Process\Process;

class SSHWrapperAdapter
{
    private $host;
    private $user;
    private $port;
    private $env;
    private $location;

    public function __construct($host, $user, $port)
    {
        $this->host = $host;
        $this->user = $user;
        $this->port = $port ?: 22;
        $_ENV['HTTP_ACCEPT_ENCODING'] = '';
        $this->env  = $_ENV ?: [];
        $this->location = '';
    }

    private function getCommandPrefix($options = [])
    {
        $options['-i'] = !empty($options['pubkey']) ? $options['pubkey'] : $_ENV['SSH_KEY'];
        $options['-F'] = !empty($options['config']) ? $options['config'] : $_ENV['SSH_CONFIG'];
        $options['-p'] = !empty($options['port']) ? $options['port'] : $this->port;

        $options = array_filter($options, 'strlen');
        $options = array_map('escapeshellarg', $options);
        $target = $this->user . '@' . $this->host;

        $prefix = 'ssh';
        foreach ($options as $key => $value) {
            $prefix .= ' ' . $key . ' ' . $value;
        }
        $prefix .= ' ' . escapeshellarg($target);

        return $prefix;
    }

    private function getHost()
    {
        return $this->host;
    }

    private function getUser()
    {
        return $this->user;
    }

    private function getPort()
    {
        return $this->port;
    }

    private function getEnv()
    {
        return $this->env;
    }

    private function getLocation()
    {
        return $this->location;
    }

    private function prepareEnv($env = null)
    {
        $line = '';
        $env = $env ?: $this->env;
        if (!is_array($env) || empty($env)) {
            return $line;
        }
        foreach ($env as $key => $value) {
            $value = preg_replace('/(\s)/', '\\\$1', $value);
            $value = sprintf('export %s=%s;', $key, escapeshellarg($value));
            $line .= $value;
        }
        return $line;
    }

    public function runCommand($command, $options = [])
    {
        $cwd = !empty($options['cwd']) ? $options['cwd'] : $this->location;
        $env = !empty($options['env']) ? $options['env'] : $this->env;

        $cwd = !empty($cwd) ? sprintf('cd %s;', $cwd) : '';
        $env = $this->prepareEnv($env);

        $commandLine = $this->getCommandPrefix();
        $commandLine .= ' ';
        $commandLine .= escapeshellarg('set -e; ' .$env . $cwd . $command->getFullCommand());

        $process = Process::fromShellCommandline($commandLine)
            ->setTimeout($_ENV['COMMAND_EXECUTION_TIMEOUT']);

        $stdin = $command->getStdin();
        if ($stdin) {
            $process->setInput($stdin);
        }
        $process->run();

        $command->setStdout($process->getOutput());
        $command->setStderr($process->getErrorOutput());
        $command->setProcess($process);
        $command->setReturn($process->getExitCode());

        return $command;
    }

    public function runCommands($commands, $output = false)
    {
        $key = $_ENV['SSH_KEY'];
        $config = $_ENV['SSH_CONFIG'];

        if ($this->location) {
            array_unshift($commands, 'cd ' . escapeshellarg($this->location));
        }

        foreach ($this->env as $name => $value) {
            array_unshift($commands, "export $name=$value");
        }

        $string = implode(' && ', $commands);
        $fullCommand = escapeshellarg($string);

        $port = $this->port != 22 ? " -p {$this->port} " : null;

        $command = "ssh -i $key $port -F $config {$this->user}@{$this->host} $fullCommand";
        $command .= ($output ? '' : ' 2>> '.$_ENV['TRIM_OUTPUT']);

        $process = Process::fromShellCommandline($command)
            ->setTimeout(3600);
        $process->run();

        return $process->getOutput();
    }

    public function setHost($host)
    {
        $this->host = $host;
    }

    public function setUser($user)
    {
        $this->user = $user;
    }

    public function setPort($port)
    {
        $this->port = $port ?: 22;
    }

    public function setEnv($env)
    {
        $this->env = $env ?: [];
    }

    public function setLocation($location)
    {
        $this->location = $location;
    }

    public function unsetHandle()
    {
        return true;
    }
}