Completed
Push — master ( 9aa90f...051175 )
by Paul
06:58
created

SshProcess::run()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 21
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 6
c 1
b 0
f 0
nc 4
nop 8
dl 0
loc 21
rs 10

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/*
3
 * This file is part of the GitCommandBundle package.
4
 *
5
 * (c) Paul Schweppe <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace VersionControl\GitCommandBundle\Service;
12
13
use InvalidArgumentException;
14
use RuntimeException;
15
16
/**
17
 * Uses php SSH2 library to run SSH Process.
18
 *
19
 * @author Paul Schweppe <[email protected]>
20
 */
21
class SshProcess implements SshProcessInterface
22
{
23
    /**
24
     * @var array
25
     */
26
    protected $config;
27
28
    /**
29
     * @var resource
30
     */
31
    protected $session;
32
33
    /**
34
     * @var resource
35
     */
36
    protected $shell;
37
38
    /**
39
     * @var array
40
     */
41
    protected $stdout = [];
42
43
    /**
44
     * @var array
45
     */
46
    protected $stderr = [];
47
48
    /**
49
     * @var array
50
     */
51
    private $stdin = [];
52
53
    /**
54
     * @param string $glue
55
     *
56
     * @return array|string
57
     */
58
    public function getStdout($glue = "\n")
59
    {
60
        if (!$glue) {
61
            $output = $this->stdout;
62
        } else {
63
            $output = implode($glue, $this->stdout);
64
        }
65
66
        return $output;
67
    }
68
69
    /**
70
     * @param string $glue
71
     *
72
     * @return array|string
73
     */
74
    public function getStderr($glue = "\n")
75
    {
76
        if (!$glue) {
77
            return $this->stderr;
78
        }
79
80
        return implode($glue, $this->stderr);
81
    }
82
83
    /**
84
     * @param array $commands
85
     * @param string $host
86
     * @param string $username
87
     * @param int $port
88
     * @param string $password
89
     * @param string|null $publicKeyFile
90
     * @param string|null $privateKeyFile
91
     * @param string $passphrase
92
     *
93
     * @return void
94
     */
95
    public function run(
96
        array $commands,
97
        string $host,
98
        string $username,
99
        int $port = 22,
100
        ?string $password = null,
101
        ?string $publicKeyFile = null,
102
        ?string $privateKeyFile = null,
103
        ?string $passphrase = null
104
    ): array {
105
        $this->reset();
106
107
        if ($this->shell === null) {
108
            $this->connect($host, $username, $port, $password, $publicKeyFile, $privateKeyFile, $passphrase);
109
        }
110
111
        foreach ($commands as $command) {
112
            $this->execute($command);
113
        }
114
115
        return $this->stdout;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->stdout returns the type array which is incompatible with the documented return type void.
Loading history...
116
    }
117
118
    /**
119
     * Resets out puts for next command.
120
     */
121
    protected function reset(): void
122
    {
123
        $this->stdout = [];
124
        $this->stdin = [];
125
        $this->stderr = [];
126
    }
127
128
    /**
129
     * @param string $host
130
     * @param string $username
131
     * @param int $port
132
     * @param null|string $password
133
     * @param null|string $publicKeyFile
134
     * @param null|string $privateKeyFile
135
     * @param null|string $passphrase
136
     *
137
     * @throws InvalidArgumentException
138
     * @throws RuntimeException
139
     */
140
    protected function connect(
141
        string $host,
142
        string $username,
143
        int $port = 22,
144
        ?string $password = null,
145
        ?string $publicKeyFile = null,
146
        ?string $privateKeyFile = null,
147
        ?string $passphrase = null
148
    ): void {
149
        $this->session = ssh2_connect($host, $port);
150
151
        if (!$this->session) {
152
            throw new InvalidArgumentException(sprintf('SSH connection failed on "%s:%s"', $host, $port));
153
        }
154
155
        if (isset($username) && $publicKeyFile !== null && $privateKeyFile !== null) {
156
            if (!ssh2_auth_pubkey_file($this->session, $username, $publicKeyFile, $privateKeyFile, $passphrase)) {
157
                throw new InvalidArgumentException(
158
                    sprintf('SSH authentication failed for user "%s" with public key "%s"', $username, $publicKeyFile)
159
                );
160
            }
161
        } elseif ($username && $password) {
162
            if (!ssh2_auth_password($this->session, $username, $password)) {
163
                throw new InvalidArgumentException(sprintf('SSH authentication failed for user "%s"', $username));
164
            }
165
        }
166
167
        $this->shell = ssh2_shell($this->session);
168
169
        if (!$this->shell) {
170
            throw new RuntimeException(sprintf('Failed opening shell'));
171
        }
172
173
        $this->stdout = [];
174
        $this->stdin = [];
175
    }
176
177
    public function disconnect(): void
178
    {
179
        if ($this->shell) {
180
            fclose($this->shell);
181
        }
182
    }
183
184
    /**
185
     * @param string $command
186
     *
187
     * @throws RuntimeException
188
     */
189
    protected function execute(string $command): void
190
    {
191
        $outStream = ssh2_exec($this->session, $command);
192
        $errStream = ssh2_fetch_stream($outStream, SSH2_STREAM_STDERR);
193
194
        stream_set_blocking($outStream, true);
195
        stream_set_blocking($errStream, true);
196
197
        $stdout = explode("\n", stream_get_contents($outStream));
198
        $stderr = explode("\n", stream_get_contents($errStream));
199
200
        if (count($stderr) > 1) {
201
            throw new RuntimeException(
202
                sprintf(
203
                    "Error in command shell:%s \n Error Response:%s",
204
                    $command,
205
                    implode("\n", $stderr)
206
                )
207
            );
208
        }
209
210
        $this->stdout = array_merge($this->stdout, $stdout);
211
212
        if (is_array($stderr)) {
0 ignored issues
show
introduced by
The condition is_array($stderr) is always true.
Loading history...
213
            $this->stderr = array_merge($this->stderr, $stderr);
214
        }
215
216
        fclose($outStream);
217
        fclose($errStream);
218
    }
219
220
    public function __destruct()
221
    {
222
        $this->disconnect();
223
    }
224
225
    public function getExitStatus()
226
    {
227
        if (count($this->stderr) > 0) {
228
            return 1;
229
        }
230
231
        return 0;
232
    }
233
}
234