Completed
Push — notify ( 11023c...2522f2 )
by Robin
02:18
created

Connection::isPrompt()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 2
eloc 2
nc 2
nop 1
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;
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
	/**
21
	 * send input to smbclient
22
	 *
23
	 * @param string $input
24
	 */
25
	public function write($input) {
26
		parent::write($input . PHP_EOL);
27
	}
28
29
	/**
30
	 * get all unprocessed output from smbclient until the next prompt
31
	 *
32
	 * @param callable $callback (optional) callback to call for every line read
33
	 * @return string
34
	 * @throws AuthenticationException
35
	 * @throws ConnectException
36
	 * @throws ConnectionException
37
	 * @throws InvalidHostException
38
	 * @throws NoLoginServerException
39
	 */
40
	public function read(callable $callback = null) {
41
		if (!$this->isValid()) {
42
			throw new ConnectionException('Connection not valid');
43
		}
44
		$promptLine = $this->readLine(); //first line is prompt
45
		$this->checkConnectionError($promptLine);
46
47
		$output = array();
48
		$line = $this->readLine();
49
		if ($line === false) {
50
			$this->unknownError($promptLine);
51
		}
52
		while (!$this->isPrompt($line)) { //next prompt functions as delimiter
53
			if (is_callable($callback)) {
54
				$result = $callback($line);
55
				if ($result === false) { // allow the callback to close the connection for infinite running commands
56
					$this->close(true);
57
				}
58
			} else {
59
				$output[] .= $line;
60
			}
61
			$line = $this->readLine();
62
		}
63
		return $output;
64
	}
65
66
	/**
67
	 * Check
68
	 *
69
	 * @param $line
70
	 * @return bool
71
	 */
72
	private function isPrompt($line) {
73
		return mb_substr($line, 0, self::DELIMITER_LENGTH) === self::DELIMITER || $line === false;
74
	}
75
76
	/**
77
	 * @param string $promptLine (optional) prompt line that might contain some info about the error
78
	 * @throws ConnectException
79
	 */
80
	private function unknownError($promptLine = '') {
81
		if ($promptLine) { //maybe we have some error we missed on the previous line
82
			throw new ConnectException('Unknown error (' . $promptLine . ')');
83
		} else {
84
			$error = $this->readError(); // maybe something on stderr
85
			if ($error) {
86
				throw new ConnectException('Unknown error (' . $error . ')');
87
			} else {
88
				throw new ConnectException('Unknown error');
89
			}
90
		}
91
	}
92
93
	/**
94
	 * check if the first line holds a connection failure
95
	 *
96
	 * @param $line
97
	 * @throws AuthenticationException
98
	 * @throws InvalidHostException
99
	 * @throws NoLoginServerException
100
	 */
101
	private function checkConnectionError($line) {
102
		$line = rtrim($line, ')');
103
		if (substr($line, -23) === ErrorCodes::LogonFailure) {
104
			throw new AuthenticationException('Invalid login');
105
		}
106
		if (substr($line, -26) === ErrorCodes::BadHostName) {
107
			throw new InvalidHostException('Invalid hostname');
108
		}
109
		if (substr($line, -22) === ErrorCodes::Unsuccessful) {
110
			throw new InvalidHostException('Connection unsuccessful');
111
		}
112
		if (substr($line, -28) === ErrorCodes::ConnectionRefused) {
113
			throw new InvalidHostException('Connection refused');
114
		}
115
		if (substr($line, -26) === ErrorCodes::NoLogonServers) {
116
			throw new NoLoginServerException('No login server');
117
		}
118
	}
119
120
	public function close($terminate = true) {
121
		if (is_resource($this->getInputStream())) {
122
			$this->write('close' . PHP_EOL);
123
		}
124
		parent::close($terminate);
125
	}
126
}
127