Passed
Push — master ( 742be8...9fb175 )
by Robin
04:11
created

Connection::read()   B

Complexity

Conditions 7
Paths 17

Size

Total Lines 29
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 7.049

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 21
nc 17
nop 1
dl 0
loc 29
ccs 18
cts 20
cp 0.9
crap 7.049
rs 8.6506
c 1
b 0
f 0
1
<?php
2
/**
3
 * Copyright (c) 2014 Robin Appelman <[email protected]>
4
 * This file is licensed under the Licensed under the MIT license:
5
 * http://opensource.org/licenses/MIT
6
 */
7
8
namespace Icewind\SMB\Wrapped;
9
10
use Icewind\SMB\Exception\AuthenticationException;
11
use Icewind\SMB\Exception\ConnectException;
12
use Icewind\SMB\Exception\ConnectionException;
13
use Icewind\SMB\Exception\InvalidHostException;
14
use Icewind\SMB\Exception\NoLoginServerException;
15
16
class Connection extends RawConnection {
17
	const DELIMITER = 'smb:';
18
	const DELIMITER_LENGTH = 4;
19
20
	/** @var Parser */
21
	private $parser;
22
23 508
	public function __construct($command, Parser $parser, $env = []) {
24 508
		parent::__construct($command, $env);
25 508
		$this->parser = $parser;
26 508
	}
27
28
	/**
29
	 * send input to smbclient
30
	 *
31
	 * @param string $input
32
	 */
33 508
	public function write($input) {
34 508
		parent::write($input . PHP_EOL);
35 508
	}
36
37
	/**
38
	 * @throws ConnectException
39
	 */
40 508
	public function clearTillPrompt() {
41 508
		$this->write('');
42
		do {
43 508
			$promptLine = $this->readLine();
44 508
			$this->parser->checkConnectionError($promptLine);
45 508
		} while (!$this->isPrompt($promptLine));
46 508
		$this->write('');
47 508
		$this->readLine();
48 508
	}
49
50
	/**
51
	 * get all unprocessed output from smbclient until the next prompt
52
	 *
53
	 * @param callable $callback (optional) callback to call for every line read
54
	 * @return string[]
55
	 * @throws AuthenticationException
56
	 * @throws ConnectException
57
	 * @throws ConnectionException
58
	 * @throws InvalidHostException
59
	 * @throws NoLoginServerException
60
	 */
61 506
	public function read(callable $callback = null) {
62 506
		if (!$this->isValid()) {
63
			throw new ConnectionException('Connection not valid');
64
		}
65 506
		$promptLine = $this->readLine(); //first line is prompt
66 506
		$this->parser->checkConnectionError($promptLine);
67
68 506
		$output = [];
69 506
		if (!$this->isPrompt($promptLine)) {
70 2
			$line = $promptLine;
71
		} else {
72 506
			$line = $this->readLine();
73
		}
74 506
		if ($line === false) {
75
			$this->unknownError($promptLine);
76
		}
77 506
		while (!$this->isPrompt($line)) { //next prompt functions as delimiter
78 502
			if (is_callable($callback)) {
79 4
				$result = $callback($line);
80 4
				if ($result === false) { // allow the callback to close the connection for infinite running commands
81 4
					$this->close(true);
82 4
					break;
83
				}
84
			} else {
85 498
				$output[] .= $line;
86
			}
87 498
			$line = $this->readLine();
88
		}
89 506
		return $output;
90
	}
91
92
	/**
93
	 * Check
94
	 *
95
	 * @param $line
96
	 * @return bool
97
	 */
98 508
	private function isPrompt($line) {
99 508
		return mb_substr($line, 0, self::DELIMITER_LENGTH) === self::DELIMITER || $line === false;
100
	}
101
102
	/**
103
	 * @param string $promptLine (optional) prompt line that might contain some info about the error
104
	 * @throws ConnectException
105
	 */
106
	private function unknownError($promptLine = '') {
107
		if ($promptLine) { //maybe we have some error we missed on the previous line
108
			throw new ConnectException('Unknown error (' . $promptLine . ')');
109
		} else {
110
			$error = $this->readError(); // maybe something on stderr
111
			if ($error) {
112
				throw new ConnectException('Unknown error (' . $error . ')');
113
			} else {
114
				throw new ConnectException('Unknown error');
115
			}
116
		}
117
	}
118
119 508
	public function close($terminate = true) {
120 508
		if (is_resource($this->getInputStream())) {
121 508
			$this->write('close' . PHP_EOL);
122
		}
123 508
		parent::close($terminate);
124 508
	}
125
}
126