Test Failed
Pull Request — master (#12)
by
unknown
03:12
created

TelnetClient::connect()   B

Complexity

Conditions 5
Paths 16

Size

Total Lines 22
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
dl 0
loc 22
ccs 0
cts 12
cp 0
rs 8.6737
c 0
b 0
f 0
cc 5
eloc 12
nc 16
nop 4
crap 30
1
<?php
2
3
/**
4
 * This file is part of graze/telnet-client.
5
 *
6
 * Copyright (c) 2016 Nature Delivered Ltd. <https://www.graze.com>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 *
11
 * @license https://github.com/graze/telnet-client/blob/master/LICENSE
12
 * @link https://github.com/graze/telnet-client
13
 */
14
15
namespace Graze\TelnetClient;
16
17
use \Graze\TelnetClient\TelnetClientInterface;
18
use \Graze\TelnetClient\PromptMatcher;
19
use \Graze\TelnetClient\PromptMatcherInterface;
20
use \Graze\TelnetClient\InterpretAsCommand;
21
use \Socket\Raw\Socket;
22
use \Socket\Raw\Factory as SocketFactory;
23
use \Graze\TelnetClient\TelnetClientBuilder;
24
use \Exception;
25
use \Graze\TelnetClient\Exception\TelnetException;
26
27
class TelnetClient implements TelnetClientInterface
28
{
29
    /**
30
     * @var SocketFactory
31
     */
32
    protected $socketFactory;
33
34
    /**
35
     * @var PromptMatcherInterface
36
     */
37
    protected $promptMatcher;
38
39
    /**
40
     * @var InterpretAsCommand
41
     */
42
    protected $interpretAsCommand;
43
44
    /**
45
     * @var string
46
     */
47
    protected $prompt = '\$';
48
49
    /**
50
     * @var string
51
     */
52
    protected $promptError = 'ERROR';
53
54
    /**
55
     * @var string
56
     */
57
    protected $lineEnding = "\n";
58
59
    /**
60
     * @var Socket
61
     */
62
    protected $socket;
63
64
    /**
65
     * @var string
66
     */
67
    protected $buffer;
68
69
    /**
70
     * @var string
71
     */
72
    protected $NULL;
73
74
    /**
75
     * @var string
76
     */
77
    protected $DC1;
78
79
    /**
80
     * @var string
81
     */
82
    protected $IAC;
83
84
    /**
85
     * @param SocketFactory $socketFactory
86
     * @param PromptMatcherInterface $promptMatcher
87
     * @param InterpretAsCommand $interpretAsCommand
88
     */
89
    public function __construct(
90
        SocketFactory $socketFactory,
91
        PromptMatcherInterface $promptMatcher,
92
        InterpretAsCommand $interpretAsCommand
93
    ) {
94
        $this->socketFactory = $socketFactory;
95
        $this->promptMatcher = $promptMatcher;
96
        $this->interpretAsCommand = $interpretAsCommand;
97
98
        $this->NULL = chr(0);
99
        $this->DC1 = chr(17);
100
    }
101
102
    /**
103
     * @param string $dsn
104
     * @param string $prompt
105
     * @param string $promptError
106
     * @param string $lineEnding
107
     *
108
     * @throws TelnetExceptionInterface
109
     */
110
    public function connect($dsn, $prompt = null, $promptError = null, $lineEnding = null)
111
    {
112
        if ($prompt !== null) {
113
            $this->setPrompt($prompt);
114
        }
115
116
        if ($promptError !== null) {
117
            $this->setPromptError($promptError);
118
        }
119
120
        if ($lineEnding !== null) {
121
            $this->setLineEnding($lineEnding);
122
        }
123
124
        try {
125
            $socket = $this->socketFactory->createClient($dsn);
126
        } catch (Exception $e) {
127
            throw new TelnetException(sprintf('unable to create socket connection to [%s]', $dsn), 0, $e);
128
        }
129
130
        $this->setSocket($socket);
131
    }
132
133
    /**
134
     * @param string $prompt
135
     */
136
    public function setPrompt($prompt)
137
    {
138
        $this->prompt = $prompt;
139
    }
140
141
    /**
142
     * @param string $promptError
143
     */
144
    public function setPromptError($promptError)
145
    {
146
        $this->promptError = $promptError;
147
    }
148
149
    /**
150
     * @param string $lineEnding
151
     */
152
    public function setLineEnding($lineEnding)
153
    {
154
        $this->lineEnding = $lineEnding;
155
    }
156
157
    /**
158
     * @param Socket $socket
159
     */
160 2
    public function setSocket(Socket $socket)
161
    {
162 2
        $this->socket = $socket;
163 2
    }
164
165
    /**
166
     * @return \Socket\Raw\Socket
167
     */
168
    public function getSocket()
169
    {
170
        return $this->socket;
171
    }
172
173
    /**
174
     * @param string $command
175
     * @param string $prompt
176
     *
177
     * @return \Graze\TelnetClient\TelnetResponseInterface
178
     */
179 3
    public function execute($command, $prompt = null)
180
    {
181 3
        if (!$this->socket) {
182 1
            throw new TelnetException('attempt to execute without a connection - call connect first');
183
        }
184
185 2
        $this->write($command);
186 1
        return $this->getResponse($prompt);
187
    }
188
189
    /**
190
     * @param string $command
191
     *
192
     * @return void
193
     * @throws TelnetExceptionInterface
194
     */
195 2
    protected function write($command)
196
    {
197
        try {
198 2
            $this->socket->write($command . $this->lineEnding);
199 1
        } catch (Exception $e) {
200 1
            throw new TelnetException(sprintf('failed writing to socket [%s]', $command), 0, $e);
201
        }
202 1
    }
203
204
    /**
205
     * @param string $prompt
206
     *
207
     * @return \Graze\TelnetClient\TelnetResponseInterface
208
     * @throws TelnetExceptionInterface
209
     */
210 1
    protected function getResponse($prompt = null)
211
    {
212 1
        $isError = false;
213 1
        $buffer = '';
214
        do {
215
            // process one character at a time
216
            try {
217 1
                $character = $this->socket->read(1);
218 1
            } catch (Exception $e) {
219 1
                throw new TelnetException('failed reading from socket', 0, $e);
220
            }
221
222
            if (in_array($character, [$this->NULL, $this->DC1])) {
223
                break;
224
            }
225
226
            if ($this->interpretAsCommand->interpret($character, $this->socket)) {
227
                continue;
228
            }
229
230
            $buffer .= $character;
231
232
            // check for prompt
233
            if ($this->promptMatcher->isMatch($prompt ?: $this->prompt, $buffer, $this->lineEnding)) {
234
                break;
235
            }
236
237
            // check for error prompt
238
            if ($this->promptMatcher->isMatch($this->promptError, $buffer, $this->lineEnding)) {
239
                $isError = true;
240
                break;
241
            }
242
243
        } while (true);
244
245
        return new TelnetResponse(
246
            $isError,
247
            $this->promptMatcher->getResponseText(),
248
            $this->promptMatcher->getMatches()
249
        );
250
    }
251
252
    /**
253
     * @return TelnetClientInterface
254
     */
255 1
    public static function factory()
256
    {
257 1
        return new static(
258 1
            new SocketFactory(),
259 1
            new PromptMatcher(),
0 ignored issues
show
Documentation introduced by
new \Graze\TelnetClient\PromptMatcher() is of type object<Graze\TelnetClient\PromptMatcher>, but the function expects a object<Graze\TelnetClient\PromptMatcherInterface>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
260 1
            new InterpretAsCommand()
261
        );
262
    }
263
264 2
    public function __destruct()
265
    {
266 2
        if (!$this->socket) {
267 2
            return;
268
        }
269
270
        $this->socket->close();
271
    }
272
}
273