SecLibSshProcess::connect()   B
last analyzed

Complexity

Conditions 9
Paths 8

Size

Total Lines 34
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 9
eloc 17
c 1
b 0
f 0
nc 8
nop 7
dl 0
loc 34
rs 8.0555
1
<?php
2
3
/*
4
 * This file is part of the GitCommandBundle package.
5
 *
6
 * (c) Paul Schweppe <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace VersionControl\GitCommandBundle\Service;
13
14
use InvalidArgumentException;
15
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
16
use VersionControl\GitCommandBundle\GitCommands\Exception\RunGitCommandException;
17
use phpseclib\Net\SSH2;
18
use phpseclib\Crypt\RSA;
19
20
/**
21
 * Use PhpSecLib to make SSH2 requests.
22
 *
23
 * @link https://github.com/phpseclib/phpseclib
24
 *
25
 * @author Paul Schweppe <[email protected]>
26
 */
27
class SecLibSshProcess implements SshProcessInterface
28
{
29
    /**
30
     * @var EventDispatcherInterface
31
     */
32
    protected $dispatcher;
33
34
    /**
35
     * @var array
36
     */
37
    protected $config;
38
39
    /**
40
     * @var SSH2|null
41
     */
42
    protected $shell;
43
44
    /**
45
     * @var array
46
     */
47
    protected $stdout;
48
49
    /**
50
     * @var array
51
     */
52
    protected $stderr;
53
54
    /**
55
     * //EventDispatcherInterface $eventDispatcher,.
56
     *
57
     */
58
    public function __construct()
59
    {
60
        $this->shell = null;
61
        $this->stdout = array();
62
        $this->stdin = array();
0 ignored issues
show
Bug Best Practice introduced by
The property stdin does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
63
        $this->stderr = array();
64
    }
65
66
    /**
67
     * @param string $glue
68
     *
69
     * @return array|string
70
     */
71
    public function getStdout($glue = "\n")
72
    {
73
        if (!$glue) {
74
            $output = $this->stdout;
75
        } else {
76
            $output = implode($glue, $this->stdout);
77
        }
78
79
        return $output;
80
    }
81
82
    /**
83
     * @param string $glue
84
     *
85
     * @return array|string
86
     */
87
    public function getStderr($glue = "\n")
88
    {
89
        if (!$glue) {
90
            return $this->stderr;
91
        }
92
93
        return implode($glue, $this->stderr);
94
    }
95
96
    /**
97
     * @param array $commands
98
     * @param string $host
99
     * @param string $username
100
     * @param int $port
101
     * @param string $password
102
     * @param string|null $publicKeyFile
103
     * @param string|null $privateKeyFile
104
     * @param string $passphrase
105
     *
106
     * @return array
107
     * @throws RunGitCommandException
108
     */
109
    public function run(
110
        array $commands,
111
        string $host,
112
        string $username,
113
        int $port = 22,
114
        ?string $password = null,
115
        ?string $publicKeyFile = null,
116
        ?string $privateKeyFile = null,
117
        ?string $passphrase = null
118
    ): array {
119
        $this->reset();
120
121
        if ($this->shell === null) {
122
            $this->connect($host, $username, $port, $password, $pubkeyFile, $privkeyFile, $passphrase);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $pubkeyFile seems to be never defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable $privkeyFile seems to be never defined.
Loading history...
Bug introduced by
It seems like $password can also be of type string; however, parameter $password of VersionControl\GitComman...ibSshProcess::connect() does only seem to accept null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

122
            $this->connect($host, $username, $port, /** @scrutinizer ignore-type */ $password, $pubkeyFile, $privkeyFile, $passphrase);
Loading history...
Bug introduced by
It seems like $passphrase can also be of type string; however, parameter $privateKeyPassword of VersionControl\GitComman...ibSshProcess::connect() does only seem to accept null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

122
            $this->connect($host, $username, $port, $password, $pubkeyFile, $privkeyFile, /** @scrutinizer ignore-type */ $passphrase);
Loading history...
123
        }
124
125
        foreach ($commands as $command) {
126
            $this->execute($command);
127
        }
128
129
        //$this->disconnect();
130
131
        return $this->stdout;
132
    }
133
134
    /**
135
     * Resets out puts for next command.
136
     */
137
    protected function reset()
138
    {
139
        $this->stdout = array();
140
        $this->stdin = array();
0 ignored issues
show
Bug Best Practice introduced by
The property stdin does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
141
        $this->stderr = array();
142
    }
143
144
    /**
145
     * @param $host
146
     * @param $username
147
     * @param int $port
148
     * @param null $password
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $password is correct as it would always require null to be passed?
Loading history...
149
     * @param null $pubkeyFile
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $pubkeyFile is correct as it would always require null to be passed?
Loading history...
150
     * @param null $privateKey
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $privateKey is correct as it would always require null to be passed?
Loading history...
151
     * @param null $privateKeyPassword
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $privateKeyPassword is correct as it would always require null to be passed?
Loading history...
152
     *
153
     * @throws InvalidArgumentException
154
     */
155
    protected function connect(
156
        $host,
157
        $username,
158
        $port = 22,
159
        $password = null,
160
        $pubkeyFile = null,
161
        $privateKey = null,
162
        $privateKeyPassword = null
163
    ) {
164
        $this->shell = new SSH2($host, $port);
165
166
        if (!$this->shell) {
167
            throw new InvalidArgumentException(sprintf('SSH connection failed on "%s:%s"', $host, $port));
168
        }
169
170
        if (isset($username) && trim($privateKey)) {
171
            $key = new RSA();
172
            if ($privateKeyPassword) {
0 ignored issues
show
introduced by
$privateKeyPassword is of type null, thus it always evaluated to false.
Loading history...
173
                $key->setPassword($privateKeyPassword);
174
            }
175
            $key->loadKey($privateKey);
176
            if (!$this->shell->login($username, $key)) {
177
                throw new InvalidArgumentException(sprintf('SSH authentication failed for user "%s" using private key',
178
                    $username, $pubkeyFile));
179
            }
180
        } elseif ($username && $password) {
0 ignored issues
show
introduced by
$password is of type null, thus it always evaluated to false.
Loading history...
181
            if (!$this->shell->login($username, $password)) {
182
                throw new InvalidArgumentException(sprintf('SSH authentication failed for user "%s"', $username));
183
            }
184
        }
185
        $this->shell->getServerPublicHostKey();
186
187
        $this->stdout = array();
188
        $this->stdin = array();
0 ignored issues
show
Bug Best Practice introduced by
The property stdin does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
189
    }
190
191
    public function disconnect()
192
    {
193
        if ($this->shell) {
194
            //$this->shell->disconnect();
195
        }
196
    }
197
198
    /**
199
     * @param array $command
200
     *
201
     * @throws RunGitCommandException
202
     */
203
    protected function execute($command)
204
    {
205
        $this->shell->enableQuietMode();
0 ignored issues
show
Bug introduced by
The method enableQuietMode() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

205
        $this->shell->/** @scrutinizer ignore-call */ 
206
                      enableQuietMode();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
206
207
        $stdOutput = $this->shell->exec($command);
0 ignored issues
show
Bug introduced by
$command of type array is incompatible with the type string expected by parameter $command of phpseclib\Net\SSH2::exec(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

207
        $stdOutput = $this->shell->exec(/** @scrutinizer ignore-type */ $command);
Loading history...
208
        $stdError = $this->shell->getStdError();
209
        $exitStatus = $this->shell->getExitStatus();
210
211
        $stdout = explode("\n", $stdOutput);
212
        $stderr = array_filter(explode("\n", $stdError));
213
214
        if ($exitStatus != 0) {
215
            //print_r($stderr);
216
            throw new RunGitCommandException(
217
                sprintf(
218
                    "Error in command shell:%s \n Error Response:%s%s",
219
                    $command,
0 ignored issues
show
Bug introduced by
$command of type array is incompatible with the type string expected by parameter $args of sprintf(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

219
                    /** @scrutinizer ignore-type */ $command,
Loading history...
220
                    implode("\n", $stderr),
221
                    $stdOutput
222
                )
223
            );
224
        }
225
226
        $this->stdout = array_merge($this->stdout, $stdout);
227
228
        if (is_array($stderr)) {
0 ignored issues
show
introduced by
The condition is_array($stderr) is always true.
Loading history...
229
            $this->stderr = array_merge($this->stderr, $stderr);
230
231
            if ($exitStatus === 0) {
232
                $this->stdout = array_merge($this->stdout, $stderr);
233
            }
234
        }
235
    }
236
237
    /**
238
     * Get exit status
239
     * @return false|int
240
     */
241
    public function getExitStatus()
242
    {
243
        return $this->shell->getExitStatus();
244
    }
245
246
    public function __destruct()
247
    {
248
        $this->disconnect();
249
    }
250
}
251