Completed
Push — master ( cfa673...036dbf )
by Robin
07:03
created

RawConnection::readAll()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 7
ccs 6
cts 6
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 0
crap 2
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\ConnectionException;
11
12
class RawConnection {
13
	/**
14
	 * @var string
15
	 */
16
	private $command;
17
18
	/**
19
	 * @var string[]
20
	 */
21
	private $env;
22
23
	/**
24
	 * @var resource[] $pipes
25
	 *
26
	 * $pipes[0] holds STDIN for smbclient
27
	 * $pipes[1] holds STDOUT for smbclient
28
	 */
29
	private $pipes;
30
31
	/**
32
	 * @var resource $process
33
	 */
34
	private $process;
35
36 777
	public function __construct($command, $env = array()) {
37 777
		$this->command = $command;
38 777
		$this->env = $env;
39 777
		$this->connect();
40 777
	}
41
42 777
	private function connect() {
43
		$descriptorSpec = array(
44 777
			0 => array('pipe', 'r'), // child reads from stdin
45 777
			1 => array('pipe', 'w'), // child writes to stdout
46 777
			2 => array('pipe', 'w'), // child writes to stderr
47 777
			3 => array('pipe', 'r'), // child reads from fd#3
48 777
			4 => array('pipe', 'r'), // child reads from fd#4
49 777
			5 => array('pipe', 'w')  // child writes to fd#5
50 777
		);
51 777
		setlocale(LC_ALL, Server::LOCALE);
52 777
		$env = array_merge($this->env, array(
53 777
			'CLI_FORCE_INTERACTIVE' => 'y', // Needed or the prompt isn't displayed!!
54 777
			'LC_ALL' => Server::LOCALE,
55 777
			'LANG' => Server::LOCALE,
56
			'COLUMNS' => 8192 // prevent smbclient from line-wrapping it's output
57 777
		));
58 777
		$this->process = proc_open($this->command, $descriptorSpec, $this->pipes, '/', $env);
59 777
		if (!$this->isValid()) {
60
			throw new ConnectionException();
61
		}
62 777
	}
63
64
	/**
65
	 * check if the connection is still active
66
	 *
67
	 * @return bool
68
	 */
69 777
	public function isValid() {
70 777
		if (is_resource($this->process)) {
71 777
			$status = proc_get_status($this->process);
72 777
			return $status['running'];
73
		} else {
74
			return false;
75
		}
76
	}
77
78
	/**
79
	 * send input to the process
80
	 *
81
	 * @param string $input
82
	 */
83 765
	public function write($input) {
84 765
		fwrite($this->getInputStream(), $input);
85 765
		fflush($this->getInputStream());
86 765
	}
87
88
	/**
89
	 * read a line of output
90
	 *
91
	 * @return string|false
92
	 */
93 774
	public function readLine() {
94 774
		return stream_get_line($this->getOutputStream(), 4086, "\n");
95
	}
96
97
	/**
98
	 * read a line of output
99
	 *
100
	 * @return string
101
	 */
102
	public function readError() {
103
		return trim(stream_get_line($this->getErrorStream(), 4086));
104
	}
105
106
	/**
107
	 * get all output until the process closes
108
	 *
109
	 * @return array
110
	 */
111 15
	public function readAll() {
112 15
		$output = array();
113 15
		while ($line = $this->readLine()) {
114 15
			$output[] = $line;
115 15
		}
116 15
		return $output;
117
	}
118
119 765
	public function getInputStream() {
120 765
		return $this->pipes[0];
121
	}
122
123 774
	public function getOutputStream() {
124 774
		return $this->pipes[1];
125
	}
126
127
	public function getErrorStream() {
128
		return $this->pipes[2];
129
	}
130
131 777
	public function getAuthStream() {
132 777
		return $this->pipes[3];
133
	}
134
135 48
	public function getFileInputStream() {
136 48
		return $this->pipes[4];
137
	}
138
139 48
	public function getFileOutputStream() {
140 48
		return $this->pipes[5];
141
	}
142
143 777
	public function writeAuthentication($user, $password) {
144 777
		$auth = ($password === false)
145 777
			? "username=$user"
146 777
			: "username=$user\npassword=$password";
147
148 777
		if (fwrite($this->getAuthStream(), $auth) === false) {
149
			fclose($this->getAuthStream());
150
			return false;
151
		}
152 777
		fclose($this->getAuthStream());
153 777
		return true;
154
	}
155
156 777
	public function close($terminate = true) {
157 777
		if (!is_resource($this->process)) {
158 63
			return;
159
		}
160 777
		if ($terminate) {
161
			// if for case that posix_ functions are not available
162 777
			if (function_exists('posix_kill')) {
163 777
				$status = proc_get_status($this->process);
164 777
				$ppid = $status['pid'];
165 777
				$pids = preg_split('/\s+/', `ps -o pid --no-heading --ppid $ppid`);
166 777
				foreach($pids as $pid) {
167 777
					if(is_numeric($pid)) {
168
						//9 is the SIGKILL signal
169 764
						posix_kill($pid, 9);
170 764
					}
171 777
				}
172 777
			}
173 777
			proc_terminate($this->process);
174 777
		}
175 777
		proc_close($this->process);
176 777
	}
177
178 3
	public function reconnect() {
179 3
		$this->close();
180 3
		$this->connect();
181 3
	}
182
183 777
	public function __destruct() {
184 777
		$this->close();
185 777
	}
186
}
187