Passed
Push — travis-bionic ( 744b84 )
by Robin
03:35
created

Connection   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 109
Duplicated Lines 0 %

Test Coverage

Coverage 72.92%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 47
dl 0
loc 109
ccs 35
cts 48
cp 0.7292
rs 10
c 2
b 0
f 0
wmc 18

7 Methods

Rating   Name   Duplication   Size   Complexity  
A unknownError() 0 9 3
A isPrompt() 0 2 2
A __construct() 0 3 1
A write() 0 2 1
A clearTillPrompt() 0 8 2
A close() 0 6 2
B read() 0 29 7
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 750
	public function __construct($command, Parser $parser, $env = []) {
24 750
		parent::__construct($command, $env);
25 750
		$this->parser = $parser;
26 750
	}
27
28
	/**
29
	 * send input to smbclient
30
	 *
31
	 * @param string $input
32
	 */
33 750
	public function write($input) {
34 750
		parent::write($input . PHP_EOL);
35 750
	}
36
37
	/**
38
	 * @throws ConnectException
39
	 */
40 750
	public function clearTillPrompt() {
41 750
		$this->write('');
42
		do {
43 750
			$promptLine = $this->readLine();
44 750
			$this->parser->checkConnectionError($promptLine);
45 750
		} while (!$this->isPrompt($promptLine));
46 750
		$this->write('');
47 750
		$this->readLine();
48 750
	}
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 747
	public function read(callable $callback = null) {
62 747
		if (!$this->isValid()) {
63
			throw new ConnectionException('Connection not valid');
64
		}
65 747
		$promptLine = $this->readLine(); //first line is prompt
66 747
		$this->parser->checkConnectionError($promptLine);
67
68 747
		$output = [];
69 747
		if (!$this->isPrompt($promptLine)) {
70 3
			$line = $promptLine;
71
		} else {
72 747
			$line = $this->readLine();
73
		}
74 747
		if ($line === false) {
75
			$this->unknownError($promptLine);
76
		}
77 747
		while (!$this->isPrompt($line)) { //next prompt functions as delimiter
78 747
			if (is_callable($callback)) {
79
				$result = $callback($line);
80
				if ($result === false) { // allow the callback to close the connection for infinite running commands
81
					$this->close(true);
82
					break;
83
				}
84
			} else {
85 747
				$output[] .= $line;
86
			}
87 747
			$line = $this->readLine();
88
		}
89 747
		return $output;
90
	}
91
92
	/**
93
	 * Check
94
	 *
95
	 * @param $line
96
	 * @return bool
97
	 */
98 750
	private function isPrompt($line) {
99 750
		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 750
	public function close($terminate = true) {
120 750
		if (get_resource_type($this->getInputStream()) === 'stream') {
121
			// ignore any errors while trying to send the close command, the process might already be dead
122 750
			@$this->write('close' . PHP_EOL);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->write('close' . I...nd\SMB\Wrapped\PHP_EOL) targeting Icewind\SMB\Wrapped\Connection::write() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Security Best Practice introduced by
It seems like you do not handle an error condition for write(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

122
			/** @scrutinizer ignore-unhandled */ @$this->write('close' . PHP_EOL);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
123
		}
124 750
		parent::close($terminate);
125 750
	}
126
}
127