Completed
Pull Request — master (#41)
by Robin
02:57
created

NativeShare   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 293
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 25
Bugs 2 Features 5
Metric Value
wmc 33
c 25
b 2
f 5
lcom 1
cbo 7
dl 0
loc 293
rs 9.3999

19 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A connect() 0 7 3
A getName() 0 3 1
A buildUrl() 0 10 2
A dir() 0 15 4
A stat() 0 3 1
A getStat() 0 4 1
A mkdir() 0 4 1
A rmdir() 0 4 1
A del() 0 4 1
A rename() 0 4 1
A put() 0 11 2
B get() 0 28 6
A read() 0 5 1
A write() 0 5 1
A getAttribute() 0 6 1
A setAttribute() 0 9 3
A setMode() 0 3 1
A __destruct() 0 3 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\InvalidPathException;
11
use Icewind\SMB\Exception\InvalidResourceException;
12
13
class NativeShare extends AbstractShare {
14
	/**
15
	 * @var Server $server
16
	 */
17
	private $server;
18
19
	/**
20
	 * @var string $name
21
	 */
22
	private $name;
23
24
	/**
25
	 * @var \Icewind\SMB\NativeState $state
26
	 */
27
	private $state;
28
29
	/**
30
	 * @param Server $server
31
	 * @param string $name
32
	 */
33
	public function __construct($server, $name) {
34
		parent::__construct();
35
		$this->server = $server;
36
		$this->name = $name;
37
		$this->state = new NativeState();
38
	}
39
40
	/**
41
	 * @throws \Icewind\SMB\Exception\ConnectionException
42
	 * @throws \Icewind\SMB\Exception\AuthenticationException
43
	 * @throws \Icewind\SMB\Exception\InvalidHostException
44
	 */
45
	protected function connect() {
46
		if ($this->state and $this->state instanceof NativeShare) {
47
			return;
48
		}
49
50
		$this->state->init($this->server->getWorkgroup(), $this->server->getUser(), $this->server->getPassword());
51
	}
52
53
	/**
54
	 * Get the name of the share
55
	 *
56
	 * @return string
57
	 */
58
	public function getName() {
59
		return $this->name;
60
	}
61
62
	private function buildUrl($path) {
63
		$this->verifyPath($path);
64
		$url = sprintf('smb://%s/%s', $this->server->getHost(), $this->name);
65
		if ($path) {
66
			$path = trim($path, '/');
67
			$url .= '/';
68
			$url .= implode('/', array_map('rawurlencode', explode('/', $path)));
69
		}
70
		return $url;
71
	}
72
73
	/**
74
	 * List the content of a remote folder
75
	 *
76
	 * @param string $path
77
	 * @return \Icewind\SMB\IFileInfo[]
78
	 *
79
	 * @throws \Icewind\SMB\Exception\NotFoundException
80
	 * @throws \Icewind\SMB\Exception\InvalidTypeException
81
	 */
82
	public function dir($path) {
83
		$this->connect();
84
		$files = array();
85
86
		$dh = $this->state->opendir($this->buildUrl($path));
87
		while ($file = $this->state->readdir($dh)) {
88
			$name = $file['name'];
89
			if ($name !== '.' and $name !== '..') {
90
				$files [] = new NativeFileInfo($this, $path . '/' . $name, $name);
91
			}
92
		}
93
94
		$this->state->closedir($dh);
95
		return $files;
96
	}
97
98
	/**
99
	 * @param string $path
100
	 * @return \Icewind\SMB\IFileInfo[]
101
	 */
102
	public function stat($path) {
103
		return new NativeFileInfo($this, $path, basename($path), $this->getStat($path));
104
	}
105
106
	public function getStat($path) {
107
		$this->connect();
108
		return $this->state->stat($this->buildUrl($path));
109
	}
110
111
	/**
112
	 * Create a folder on the share
113
	 *
114
	 * @param string $path
115
	 * @return bool
116
	 *
117
	 * @throws \Icewind\SMB\Exception\NotFoundException
118
	 * @throws \Icewind\SMB\Exception\AlreadyExistsException
119
	 */
120
	public function mkdir($path) {
121
		$this->connect();
122
		return $this->state->mkdir($this->buildUrl($path));
123
	}
124
125
	/**
126
	 * Remove a folder on the share
127
	 *
128
	 * @param string $path
129
	 * @return bool
130
	 *
131
	 * @throws \Icewind\SMB\Exception\NotFoundException
132
	 * @throws \Icewind\SMB\Exception\InvalidTypeException
133
	 */
134
	public function rmdir($path) {
135
		$this->connect();
136
		return $this->state->rmdir($this->buildUrl($path));
137
	}
138
139
	/**
140
	 * Delete a file on the share
141
	 *
142
	 * @param string $path
143
	 * @return bool
144
	 *
145
	 * @throws \Icewind\SMB\Exception\NotFoundException
146
	 * @throws \Icewind\SMB\Exception\InvalidTypeException
147
	 */
148
	public function del($path) {
149
		$this->connect();
150
		return $this->state->unlink($this->buildUrl($path));
151
	}
152
153
	/**
154
	 * Rename a remote file
155
	 *
156
	 * @param string $from
157
	 * @param string $to
158
	 * @return bool
159
	 *
160
	 * @throws \Icewind\SMB\Exception\NotFoundException
161
	 * @throws \Icewind\SMB\Exception\AlreadyExistsException
162
	 */
163
	public function rename($from, $to) {
164
		$this->connect();
165
		return $this->state->rename($this->buildUrl($from), $this->buildUrl($to));
166
	}
167
168
	/**
169
	 * Upload a local file
170
	 *
171
	 * @param string $source local file
172
	 * @param string $target remove file
173
	 * @return bool
174
	 *
175
	 * @throws \Icewind\SMB\Exception\NotFoundException
176
	 * @throws \Icewind\SMB\Exception\InvalidTypeException
177
	 */
178
	public function put($source, $target) {
179
		$this->connect();
180
		$sourceHandle = fopen($source, 'rb');
181
		$targetHandle = $this->state->create($this->buildUrl($target));
182
183
		while ($data = fread($sourceHandle, 4096)) {
184
			$this->state->write($targetHandle, $data);
185
		}
186
		$this->state->close($targetHandle);
187
		return true;
188
	}
189
190
	/**
191
	 * Download a remote file
192
	 *
193
	 * @param string $source remove file
194
	 * @param string $target local file
195
	 * @return bool
196
	 *
197
	 * @throws \Icewind\SMB\Exception\NotFoundException
198
	 * @throws \Icewind\SMB\Exception\InvalidTypeException
199
	 * @throws \Icewind\SMB\Exception\InvalidPathException
200
	 * @throws \Icewind\SMB\Exception\InvalidResourceException
201
	 */
202
	public function get($source, $target) {
203
		if (!$target) {
204
			throw new InvalidPathException('Invalid target path: Filename cannot be empty');
205
		}
206
		$targetHandle = @fopen($target, 'wb');
207
		if (!$targetHandle) {
208
			$error = error_get_last();
209
			if (is_array($error)) {
210
				$reason = $error['message'];
211
			} else {
212
				$reason = 'Unknown error';
213
			}
214
			throw new InvalidResourceException('Failed opening local file "' . $target . '" for writing: ' . $reason);
215
		}
216
217
		$this->connect();
218
		$sourceHandle = $this->state->open($this->buildUrl($source), 'r');
219
		if (!$sourceHandle) {
220
			fclose($targetHandle);
221
			throw new InvalidResourceException('Failed opening remote file "' . $source . '" for reading');
222
		}
223
224
		while ($data = $this->state->read($sourceHandle, 4096)) {
225
			fwrite($targetHandle, $data);
226
		}
227
		$this->state->close($sourceHandle);
228
		return true;
229
	}
230
231
	/**
232
	 * Open a readable stream top a remote file
233
	 *
234
	 * @param string $source
235
	 * @return resource a read only stream with the contents of the remote file
236
	 *
237
	 * @throws \Icewind\SMB\Exception\NotFoundException
238
	 * @throws \Icewind\SMB\Exception\InvalidTypeException
239
	 */
240
	public function read($source) {
241
		$this->connect();
242
		$handle = $this->state->open($this->buildUrl($source), 'r');
243
		return NativeStream::wrap($this->state, $handle, 'r');
244
	}
245
246
	/**
247
	 * Open a readable stream top a remote file
248
	 *
249
	 * @param string $source
250
	 * @return resource a read only stream with the contents of the remote file
251
	 *
252
	 * @throws \Icewind\SMB\Exception\NotFoundException
253
	 * @throws \Icewind\SMB\Exception\InvalidTypeException
254
	 */
255
	public function write($source) {
256
		$this->connect();
257
		$handle = $this->state->create($this->buildUrl($source));
258
		return NativeStream::wrap($this->state, $handle, 'w');
259
	}
260
261
	/**
262
	 * Get extended attributes for the path
263
	 *
264
	 * @param string $path
265
	 * @param string $attribute attribute to get the info
266
	 * @return string the attribute value
267
	 */
268
	public function getAttribute($path, $attribute) {
269
		$this->connect();
270
271
		$result = $this->state->getxattr($this->buildUrl($path), $attribute);
272
		return $result;
273
	}
274
275
	/**
276
	 * Get extended attributes for the path
277
	 *
278
	 * @param string $path
279
	 * @param string $attribute attribute to get the info
280
	 * @param mixed $value
281
	 * @return string the attribute value
282
	 */
283
	public function setAttribute($path, $attribute, $value) {
284
		$this->connect();
285
286
		if ($attribute === 'system.dos_attr.mode' and is_int($value)) {
287
			$value = '0x' . dechex($value);
288
		}
289
290
		return $this->state->setxattr($this->buildUrl($path), $attribute, $value);
291
	}
292
293
	/**
294
	 * @param string $path
295
	 * @param int $mode a combination of FileInfo::MODE_READONLY, FileInfo::MODE_ARCHIVE, FileInfo::MODE_SYSTEM and FileInfo::MODE_HIDDEN, FileInfo::NORMAL
296
	 * @return mixed
297
	 */
298
	public function setMode($path, $mode) {
299
		return $this->setAttribute($path, 'system.dos_attr.mode', $mode);
300
	}
301
302
	public function __destruct() {
303
		unset($this->state);
304
	}
305
}
306