Completed
Push — stable2 ( 10fadc...4d0e89 )
by Robin
07:41
created

NativeShare   A

Complexity

Total Complexity 34

Size/Duplication

Total Lines 293
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 34
lcom 1
cbo 9
dl 0
loc 293
ccs 0
cts 96
cp 0
rs 9.68
c 0
b 0
f 0

20 Methods

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