Completed
Push — master ( 4d8337...e43287 )
by Thomas
01:38
created

FileOperationTrait::isExecutable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 3
c 0
b 0
f 0
ccs 0
cts 2
cp 0
rs 10
cc 1
nc 1
nop 0
crap 2
1
<?php
2
namespace phootwork\file;
3
4
use \DateTime;
5
use phootwork\file\exception\FileException;
6
use phootwork\lang\Text;
7
8
trait FileOperationTrait {
9
10
	/** @var string */
11
	protected $pathname;
12
	
13
	/**
14
	 * Static instantiator
15
	 * 
16
	 * @param string $pathname
17
	 * @return static
18
	 */
19 1
	public static function create($pathname) {
20 1
		return new static($pathname);
21
	}
22
23 19
	protected function init($pathname) {
24 19
		$this->pathname = ''.$pathname; // "cast" to string
25 19
	}
26
27
	/**
28
	 * Returns the file extensions
29
	 * 
30
	 * @return string the file extension
31
	 */
32 1
	public function getExtension() {
33 1
		return pathinfo($this->pathname, PATHINFO_EXTENSION);
34
	}
35
36
	/**
37
	 * Returns the filename
38
	 * 
39
	 * @return string the filename
40
	 */
41 6
	public function getFilename() {
42 6
		return basename($this->pathname);
43
	}
44
	
45
	/**
46
	 * Gets the path without filename
47
	 * 
48
	 * @return string
49
	 */
50 8
	public function getDirname() {
51 8
		return dirname($this->pathname);
52
	}
53
	
54
	/**
55
	 * Gets the path to the file
56
	 * 
57
	 * @return string
58
	 */
59 7
	public function getPathname() {
60 7
		return $this->pathname;
61
	}
62
	
63
	/**
64
	 * Converts the path into a path object
65
	 *
66
	 * @return Path
67
	 */
68 1
	public function toPath() {
69 1
		return new Path($this->pathname);
70
	}
71
	
72
	/**
73
	 * Gets last access time.
74
	 * 
75
	 * @return DateTime
76
	 */
77 1
	public function getLastAccessedAt() {
78 1
		$timestamp = fileatime($this->pathname);
79 1
		$time = new DateTime();
80 1
		$time->setTimestamp($timestamp);
81 1
		return $time;
82
	}
83
	
84
	/**
85
	 * Gets the created time.
86
	 *
87
	 * @return DateTime
88
	 */
89 1
	public function getCreatedAt() {
90 1
		$timestamp = filemtime($this->pathname);
91 1
		$time = new DateTime();
92 1
		$time->setTimestamp($timestamp);
93 1
		return $time;
94
	}
95
	
96
	/**
97
	 * Gets last modified time.
98
	 *
99
	 * @return DateTime
100
	 */
101
	public function getModifiedAt() {
102
		$timestamp = filemtime($this->pathname);
103
		$time = new DateTime();
104
		$time->setTimestamp($timestamp);
105
		return $time;
106
	}
107
	
108
	/**
109
	 * Gets file inode
110
	 * 
111
	 * @return int Returns the inode number of the file, or FALSE on failure. 
112
	 */
113
	public function getInode() {
114
		return fileinode($this->pathname);
115
	}
116
	
117
	/**
118
	 * Gets file group
119
	 * 
120
	 * @return int Returns the group ID, or FALSE if an error occurs.
121
	 */
122
	public function getGroup() {
123
		return filegroup($this->pathname);
124
	}
125
	
126
	/**
127
	 * Gets file owner
128
	 *
129
	 * @return int Returns the user ID of the owner, or FALSE on failure.
130
	 */
131
	public function getOwner() {
132
		return fileowner($this->pathname);
133
	}
134
	
135
	/**
136
	 * Gets file permissions
137
	 * 
138
	 * @return int Returns the file's permissions as a numeric mode. Lower bits of this 
139
	 * 		mode are the same as the permissions expected by chmod(), however on most platforms 
140
	 * 		the return value will also include information on the type of file given as filename. 
141
	 * 		The examples below demonstrate how to test the return value for specific permissions 
142
	 * 		and file types on POSIX systems, including Linux and Mac OS X. 
143
	 */
144
	public function getPermissions() {
145
		return fileperms($this->pathname);
146
	}
147
	
148
	/**
149
	 * Checks its existance
150
	 *
151
	 * @return boolean Returns TRUE if exists; FALSE otherwise. Will return FALSE for symlinks
152
	 * 		pointing to non-existing files.
153
	 */
154 16
	public function exists() {
155 16
		return file_exists($this->pathname);
156
	}
157
	
158
	/**
159
	 * Tells whether is executable
160
	 *
161
	 * @return boolean Returns TRUE if exists and is executable.
162
	 */
163
	public function isExecutable() {
164
		return is_executable($this->pathname);
165
	}
166
	
167
	/**
168
	 * Tells whether is readable
169
	 *
170
	 * @return boolean Returns TRUE if exists and is readable.
171
	 */
172 3
	public function isReadable() {
173 3
		return is_readable($this->pathname);
174
	}
175
	
176
	/**
177
	 * Tells whether is writable
178
	 * 
179
	 * @return boolean Returns TRUE if exists and is writable. 
180
	 */
181
	public function isWritable() {
182
		return is_writable($this->pathname);
183
	}
184
185
	/**
186
	 * Tells whether the filename is a symbolic link
187
	 *
188
	 * @return boolean Returns TRUE if the filename exists and is a symbolic link, FALSE otherwise.
189
	 */
190 4
	public function isLink() {
191 4
		return is_link($this->pathname);
192
	}
193
	
194
	/**
195
	 * Returns the target if this is a symbolic link
196
	 * 
197
	 * @see #isLink
198
	 * @return Path|null The target path or null if this isn't a link
199
	 */
200 1
	public function getLinkTarget() {
201 1
		if ($this->isLink()) {
202 1
			return new Path(readlink($this->pathname));
203
		}
204 1
		return null;
205
	}
206
	
207
	/**
208
	 * Attempts to change the group.
209
	 *
210
	 * Only the superuser may change the group arbitrarily; other users may
211
	 * change the group of a file to any group of which that user is a member.
212
	 *
213
	 * @param mixed $group A group name or number.
214
	 * @return boolean Returns TRUE on success or FALSE on failure.
215
	 */
216
	public function setGroup($group) {
217
		if ($this->isLink()) {
218
			return lchgrp($this->pathname, $group);
219
		} else {
220
			return chgrp($this->pathname, $group);
221
		}
222
	}
223
	
224
	/**
225
	 * Attempts to change the mode.
226
	 *
227
	 * @see #setGroup
228
	 * @see #setOwner
229
	 *
230
	 * @param int $mode
231
	 * 		Note that mode is not automatically assumed to be an octal value, so strings
232
	 * 		(such as "g+w") will not work properly. To ensure the expected operation, you
233
	 * 		need to prefix mode with a zero (0).
234
	 *
235
	 * @return boolean Returns TRUE on success or FALSE on failure.
236
	 */
237 3
	public function setMode($mode) {
238 3
		if ($this->isLink()) {
239
			return lchmod($this->pathname, $mode);
240
		} else {
241 3
			return chmod($this->pathname, $mode);
242
		}
243
	}
244
	
245
	/**
246
	 * Changes file owner
247
	 *
248
	 * Attempts to change the owner. Only the superuser may change the owner of a file.
249
	 *
250
	 * @param mixed $user A user name or number.
251
	 * @return boolean Returns TRUE on success or FALSE on failure.
252
	 */
253
	public function setOwner($user) {
254
		if ($this->isLink()) {
255
			return lchown($this->pathname, $user);
256
		} else {
257
			return chown($this->pathname, $user);
258
		}
259
	}
260
	
261
	/**
262
	 * Copies the file
263
	 *
264
	 * If the destination file already exists, it will be overwritten.
265
	 *
266
	 * @throws FileException When an error appeared.
267
	 * @param string|Path $destination The destination path.
268
	 */
269 2
	public function copy($destination) {
270 2
		$destination = $this->getDestination($destination);
0 ignored issues
show
Bug introduced by
It seems like $destination defined by $this->getDestination($destination) on line 270 can also be of type object<phootwork\file\Path>; however, phootwork\file\FileOpera...Trait::getDestination() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
271
	
272 2
		if (!@copy($this->getPathname(), $destination)) {
273 1
			throw new FileException(sprintf('Failed to copy %s to %s', $this->pathname, $destination));
274
		}
275 1
	}
276
	
277
	/**
278
	 * Moves the file
279
	 *
280
	 * @throws FileException When an error appeared.
281
	 * @param string|Path $destination
282
	 */
283 2
	public function move($destination) {
284 2
		$destination = $this->getDestination($destination);
0 ignored issues
show
Bug introduced by
It seems like $destination defined by $this->getDestination($destination) on line 284 can also be of type object<phootwork\file\Path>; however, phootwork\file\FileOpera...Trait::getDestination() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
285
286 2
		if (@rename($this->getPathname(), $destination)) {
287 1
			$this->pathname = $destination;
0 ignored issues
show
Documentation Bug introduced by
It seems like $destination of type object<phootwork\file\Path> is incompatible with the declared type string of property $pathname.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
288 1
		} else {
289 1
			throw new FileException(sprintf('Failed to move %s to %s', $this->pathname, $destination));
290
		}
291 1
	}
292
	
293
	/**
294
	 * Transforms destination into path and ensures, parent directory exists
295
	 * 
296
	 * @param string $destination
297
	 * @return Path
298
	 */
299 4
	private function getDestination($destination) {
300 4
		$destination = $destination instanceof Path ? $destination : new Path($destination);
301 4
		$targetDir = new Directory($destination->getDirname());
302 4
		$targetDir->make();
303 4
		return $destination;
304
	}
305
	
306
	/**
307
	 * Creates a symlink to the given destination
308
	 * 
309
	 * @param string|Path $destination
310
	 */
311 1
	public function linkTo($destination) {
312 1
		$target = new FileDescriptor($destination); 
313 1
		$targetDir = new Directory($target->getDirname());
314 1
		$targetDir->make();
315
		
316 1
		$ok = false;
317 1
		if ($target->isLink()) {
318
			if (!$target->getLinkTarget()->equals($this->pathname)) {
319
				$target->delete();
320
			} else {
321
				$ok = true;
322
			}
323
		}
324
325 1
		if (!$ok && @symlink($this->pathname, $target->getPathname()) !== true) {
326
			$report = error_get_last();
327
			if (is_array($report) && DIRECTORY_SEPARATOR === '\\' && strpos($report['message'], 'error code(1314)') !== false) {
328
				throw new FileException('Unable to create symlink due to error code 1314: \'A required privilege is not held by the client\'. Do you have the required Administrator-rights?');
329
			}
330
			throw new FileException(sprintf('Failed to create symbolic link from %s to %s', $this->pathname, $targetDir));
331
		}
332 1
	}
333
334
	public abstract function delete();
335
336
}