Completed
Push — notify ( cf23de )
by Robin
02:11
created

NativeShare::notify()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 3
rs 10
cc 1
eloc 2
nc 1
nop 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\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 View Code Duplication
	public function read($source) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
241
		$this->connect();
242
		$url = $this->buildUrl($source);
243
		$handle = $this->state->open($url, 'r');
244
		return NativeStream::wrap($this->state, $handle, 'r', $url);
245
	}
246
247
	/**
248
	 * Open a readable stream top a remote file
249
	 *
250
	 * @param string $source
251
	 * @return resource a read only stream with the contents of the remote file
252
	 *
253
	 * @throws \Icewind\SMB\Exception\NotFoundException
254
	 * @throws \Icewind\SMB\Exception\InvalidTypeException
255
	 */
256 View Code Duplication
	public function write($source) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
257
		$this->connect();
258
		$url = $this->buildUrl($source);
259
		$handle = $this->state->create($url);
260
		return NativeStream::wrap($this->state, $handle, 'w', $url);
261
	}
262
263
	/**
264
	 * Get extended attributes for the path
265
	 *
266
	 * @param string $path
267
	 * @param string $attribute attribute to get the info
268
	 * @return string the attribute value
269
	 */
270
	public function getAttribute($path, $attribute) {
271
		$this->connect();
272
273
		$result = $this->state->getxattr($this->buildUrl($path), $attribute);
274
		return $result;
275
	}
276
277
	/**
278
	 * Get extended attributes for the path
279
	 *
280
	 * @param string $path
281
	 * @param string $attribute attribute to get the info
282
	 * @param mixed $value
283
	 * @return string the attribute value
284
	 */
285
	public function setAttribute($path, $attribute, $value) {
286
		$this->connect();
287
288
		if ($attribute === 'system.dos_attr.mode' and is_int($value)) {
289
			$value = '0x' . dechex($value);
290
		}
291
292
		return $this->state->setxattr($this->buildUrl($path), $attribute, $value);
293
	}
294
295
	/**
296
	 * @param string $path
297
	 * @param int $mode a combination of FileInfo::MODE_READONLY, FileInfo::MODE_ARCHIVE, FileInfo::MODE_SYSTEM and FileInfo::MODE_HIDDEN, FileInfo::NORMAL
298
	 * @return mixed
299
	 */
300
	public function setMode($path, $mode) {
301
		return $this->setAttribute($path, 'system.dos_attr.mode', $mode);
302
	}
303
304
	/**
305
	 * @param string $path
306
	 * @param callable $callback callable which will be called for each received change
307
	 * @return mixed
308
	 */
309
	public function notify($path, callable $callback) {
310
		throw new \Exception('not implemented');
311
	}
312
313
	public function __destruct() {
314
		unset($this->state);
315
	}
316
}
317