Completed
Push — master ( c92ae0...dc7863 )
by Robin
03:57
created

RawConnection::readError()   A

Complexity

Conditions 1
Paths 1

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 1
eloc 2
nc 1
nop 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;
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
	public function __construct($command, $env = array()) {
37
		$this->command = $command;
38
		$this->env = $env;
39
		$this->connect();
40
	}
41
42
	private function connect() {
43
		$descriptorSpec = array(
44
			0 => array('pipe', 'r'), // child reads from stdin
45
			1 => array('pipe', 'w'), // child writes to stdout
46
			2 => array('pipe', 'w'), // child writes to stderr
47
			3 => array('pipe', 'r'), // child reads from fd#3
48
			4 => array('pipe', 'r'), // child reads from fd#4
49
			5 => array('pipe', 'w')  // child writes to fd#5
50
		);
51
		setlocale(LC_ALL, Server::LOCALE);
52
		$env = array_merge($this->env, array(
53
			'CLI_FORCE_INTERACTIVE' => 'y', // Needed or the prompt isn't displayed!!
54
			'LC_ALL' => Server::LOCALE,
55
			'LANG' => Server::LOCALE,
56
			'COLUMNS' => 8192 // prevent smbclient from line-wrapping it's output
57
		));
58
		$this->process = proc_open($this->command, $descriptorSpec, $this->pipes, '/', $env);
59
		if (!$this->isValid()) {
60
			throw new ConnectionException();
61
		}
62
	}
63
64
	/**
65
	 * check if the connection is still active
66
	 *
67
	 * @return bool
68
	 */
69
	public function isValid() {
70
		if (is_resource($this->process)) {
71
			$status = proc_get_status($this->process);
72
			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
	public function write($input) {
84
		fwrite($this->getInputStream(), $input);
85
		fflush($this->getInputStream());
86
	}
87
88
	/**
89
	 * read a line of output
90
	 *
91
	 * @return string
92
	 */
93
	public function readLine() {
94
		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
	public function readAll() {
112
		$output = array();
113
		while ($line = $this->readLine()) {
114
			$output[] = $line;
115
		}
116
		return $output;
117
	}
118
119
	public function getInputStream() {
120
		return $this->pipes[0];
121
	}
122
123
	public function getOutputStream() {
124
		return $this->pipes[1];
125
	}
126
127
	public function getErrorStream() {
128
		return $this->pipes[2];
129
	}
130
131
	public function getAuthStream() {
132
		return $this->pipes[3];
133
	}
134
135
	public function getFileInputStream() {
136
		return $this->pipes[4];
137
	}
138
139
	public function getFileOutputStream() {
140
		return $this->pipes[5];
141
	}
142
143
	public function writeAuthentication($user, $password) {
144
		$auth = ($password === false)
145
			? "username=$user"
146
			: "username=$user\npassword=$password";
147
148
		if (fwrite($this->getAuthStream(), $auth) === false) {
149
			fclose($this->getAuthStream());
150
			return false;
151
		}
152
		fclose($this->getAuthStream());
153
		return true;
154
	}
155
156
	public function close($terminate = true) {
157
		if (!is_resource($this->process)) {
158
			return;
159
		}
160
		if ($terminate) {
161
			// if for case that posix_ functions are not available
162
			if (function_exists('posix_kill')) {
163
				$status = proc_get_status($this->process);
164
				$ppid = $status['pid'];
165
				$pids = preg_split('/\s+/', `ps -o pid --no-heading --ppid $ppid`);
166
				foreach($pids as $pid) {
167
					if(is_numeric($pid)) {
168
						//9 is the SIGKILL signal
169
						posix_kill($pid, 9);
170
					}
171
				}
172
			}
173
			proc_terminate($this->process);
174
		}
175
		proc_close($this->process);
176
	}
177
178
	public function reconnect() {
179
		$this->close();
180
		$this->connect();
181
	}
182
183
	public function __destruct() {
184
		$this->close();
185
	}
186
}
187