ElggDiskFilestore::open()   B
last analyzed

Complexity

Conditions 10
Paths 20

Size

Total Lines 43

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 110

Importance

Changes 0
Metric Value
cc 10
nc 20
nop 2
dl 0
loc 43
ccs 0
cts 34
cp 0
crap 110
rs 7.6666
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * A filestore that uses disk as storage.
4
 *
5
 * @warning This should be used by a wrapper class
6
 * like {@link \ElggFile}.
7
 *
8
 * @package    Elgg.Core
9
 * @subpackage FileStore.Disk
10
 */
11
class ElggDiskFilestore extends \ElggFilestore {
12
	/**
13
	 * Directory root.
14
	 */
15
	private $dir_root;
16
17
	/**
18
	 * Number of entries per matrix dir.
19
	 * You almost certainly don't want to change this.
20
	 */
21
	const BUCKET_SIZE = 5000;
22
23
	/**
24
	 * Global Elgg configuration
25
	 * 
26
	 * @var \stdClass
27
	 */
28
	private $CONFIG;
29
30
	/**
31
	 * Construct a disk filestore using the given directory root.
32
	 *
33
	 * @param string $directory_root Root directory, must end in "/"
34
	 */
35
	public function __construct($directory_root = "") {
36
		global $CONFIG;
37
		$this->CONFIG = $CONFIG;
38
39
		if ($directory_root) {
40
			$this->dir_root = $directory_root;
41
		} else {
42
			$this->dir_root = $this->CONFIG->dataroot;
43
		}
44
	}
45
46
	/**
47
	 * Open a file for reading, writing, or both.
48
	 *
49
	 * @note All files are opened binary safe.
50
	 * @note This will try to create the a directory if it doesn't exist and is opened
51
	 * in write or append mode.
52
	 *
53
	 * @param \ElggFile $file The file to open
54
	 * @param string    $mode read, write, or append.
55
	 *
56
	 * @throws InvalidParameterException
57
	 * @return resource File pointer resource
58
	 * @todo This really shouldn't try to create directories if not writing.
59
	 */
60
	public function open(\ElggFile $file, $mode) {
61
		$fullname = $this->getFilenameOnFilestore($file);
62
63
		// Split into path and name
64
		$ls = strrpos($fullname, "/");
65
		if ($ls === false) {
66
			$ls = 0;
67
		}
68
69
		$path = substr($fullname, 0, $ls);
70
71
		if (($mode != 'write') && (!file_exists($fullname))) {
72
			return false;
73
		}
74
75
		// Try to create the dir for valid write modes
76
		if ($mode == 'write' || $mode == 'append') {
77
			try {
78
				$this->makeDirectoryRoot($path);
79
			} catch (Exception $e) {
80
				_elgg_services()->logger->warn("Couldn't create directory: $path");
81
				return false;
82
			}
83
		}
84
85
		switch ($mode) {
86
			case "read" :
87
				$mode = "rb";
88
				break;
89
			case "write" :
90
				$mode = "w+b";
91
				break;
92
			case "append" :
93
				$mode = "a+b";
94
				break;
95
			default:
96
				$msg = "Unrecognized file mode '" . $mode . "'";
97
				throw new \InvalidParameterException($msg);
98
		}
99
100
		return fopen($fullname, $mode);
101
102
	}
103
104
	/**
105
	 * Write data to a file.
106
	 *
107
	 * @param resource $f    File pointer resource
108
	 * @param mixed    $data The data to write.
109
	 *
110
	 * @return bool
111
	 */
112
	public function write($f, $data) {
113
		return fwrite($f, $data);
114
	}
115
116
	/**
117
	 * Read data from a file.
118
	 *
119
	 * @param resource $f      File pointer resource
120
	 * @param int      $length The number of bytes to read
121
	 * @param int      $offset The number of bytes to start after
122
	 *
123
	 * @return mixed Contents of file or false on fail.
124
	 */
125
	public function read($f, $length, $offset = 0) {
126
		if ($offset) {
127
			$this->seek($f, $offset);
128
		}
129
130
		return fread($f, $length);
131
	}
132
133
	/**
134
	 * Close a file pointer
135
	 *
136
	 * @param resource $f A file pointer resource
137
	 *
138
	 * @return bool
139
	 */
140
	public function close($f) {
141
		return fclose($f);
142
	}
143
144
	/**
145
	 * Delete an \ElggFile file.
146
	 *
147
	 * @param \ElggFile $file File to delete
148
	 *
149
	 * @return bool
150
	 */
151
	public function delete(\ElggFile $file) {
152
		$filename = $this->getFilenameOnFilestore($file);
153
		if (file_exists($filename)) {
154
			return unlink($filename);
155
		} else {
156
			return true;
157
		}
158
	}
159
160
	/**
161
	 * Seek to the specified position.
162
	 *
163
	 * @param resource $f        File resource
164
	 * @param int      $position Position in bytes
165
	 *
166
	 * @return bool
167
	 */
168
	public function seek($f, $position) {
169
		return fseek($f, $position);
170
	}
171
172
	/**
173
	 * Return the current location of the internal pointer
174
	 *
175
	 * @param resource $f File pointer resource
176
	 *
177
	 * @return int|false
178
	 */
179
	public function tell($f) {
180
		return ftell($f);
181
	}
182
183
	/**
184
	 * Tests for end of file on a file pointer
185
	 *
186
	 * @param resource $f File pointer resource
187
	 *
188
	 * @return bool
189
	 */
190
	public function eof($f) {
191
		return feof($f);
192
	}
193
194
	/**
195
	 * Returns the file size of an \ElggFile file.
196
	 *
197
	 * @param \ElggFile $file File object
198
	 *
199
	 * @return int The file size
200
	 */
201
	public function getFileSize(\ElggFile $file) {
202
		return filesize($this->getFilenameOnFilestore($file));
203
	}
204
205
	/**
206
	 * Get the filename as saved on disk for an \ElggFile object
207
	 *
208
	 * Returns an empty string if no filename set
209
	 *
210
	 * @param \ElggFile $file File object
211
	 *
212
	 * @return string The full path of where the file is stored
213
	 * @throws InvalidParameterException
214
	 */
215
	public function getFilenameOnFilestore(\ElggFile $file) {
216
		$owner_guid = $file->getOwnerGuid();
217
		if (!$owner_guid) {
218
			$owner_guid = _elgg_services()->session->getLoggedInUserGuid();
219
		}
220
221
		if (!$owner_guid) {
222
			$msg = "File " . $file->getFilename() . " (file guid:" . $file->guid . ") is missing an owner!";
223
			throw new \InvalidParameterException($msg);
224
		}
225
226
		$filename = $file->getFilename();
227
		if (!$filename) {
228
			return '';
229
		}
230
231
		$dir = new \Elgg\EntityDirLocator($owner_guid);
232
233
		return $this->dir_root . $dir . $file->getFilename();
234
	}
235
236
	/**
237
	 * Returns the contents of the \ElggFile file.
238
	 *
239
	 * @param \ElggFile $file File object
240
	 *
241
	 * @return string
242
	 */
243
	public function grabFile(\ElggFile $file) {
244
		return file_get_contents($file->getFilenameOnFilestore());
245
	}
246
247
	/**
248
	 * Tests if an \ElggFile file exists.
249
	 *
250
	 * @param \ElggFile $file File object
251
	 *
252
	 * @return bool
253
	 */
254
	public function exists(\ElggFile $file) {
255
		if (!$file->getFilename()) {
256
			return false;
257
		}
258
		return file_exists($this->getFilenameOnFilestore($file));
259
	}
260
261
	/**
262
	 * Returns the size of all data stored under a directory in the disk store.
263
	 *
264
	 * @param string $prefix         The prefix to check under.
265
	 * @param string $container_guid The guid of the entity whose data you want to check.
266
	 *
267
	 * @return int|false
268
	 */
269
	public function getSize($prefix, $container_guid) {
270
		if ($container_guid) {
271
			$dir = new \Elgg\EntityDirLocator($container_guid);
272
			return get_dir_size($this->dir_root . $dir . $prefix);
273
		} else {
274
			return false;
275
		}
276
	}
277
278
	// @codingStandardsIgnoreStart
279
	/**
280
	 * Create a directory $dirroot
281
	 *
282
	 * @param string $dirroot The full path of the directory to create
283
	 *
284
	 * @throws IOException
285
	 * @return true
286
	 * @deprecated 1.8 Use \ElggDiskFilestore::makeDirectoryRoot()
287
	 */
288
	protected function make_directory_root($dirroot) {
289
		elgg_deprecated_notice('\ElggDiskFilestore::make_directory_root() is deprecated by ::makeDirectoryRoot()', 1.8);
290
291
		return $this->makeDirectoryRoot($dirroot);
292
	}
293
	// @codingStandardsIgnoreEnd
294
295
	/**
296
	 * Create a directory $dirroot
297
	 *
298
	 * @param string $dirroot The full path of the directory to create
299
	 *
300
	 * @throws IOException
301
	 * @return true
302
	 */
303
	protected function makeDirectoryRoot($dirroot) {
304
		if (!file_exists($dirroot)) {
305
			if (!@mkdir($dirroot, 0700, true)) {
306
				throw new \IOException("Could not make " . $dirroot);
307
			}
308
		}
309
310
		return true;
311
	}
312
313
	/**
314
	 * Returns a list of attributes to save to the database when saving
315
	 * the \ElggFile object using this file store.
316
	 *
317
	 * @return array
318
	 */
319
	public function getParameters() {
320
		return array("dir_root" => $this->dir_root);
321
	}
322
323
	/**
324
	 * Sets parameters that should be saved to database.
325
	 *
326
	 * @param array $parameters Set parameters to save to DB for this filestore.
327
	 *
328
	 * @return bool
329
	 */
330
	public function setParameters(array $parameters) {
331
		if (isset($parameters['dir_root'])) {
332
			$this->dir_root = $parameters['dir_root'];
333
			return true;
334
		}
335
336
		return false;
337
	}
338
339
340
	
341
	/**
342
	 * Deprecated methods
343
	 */
344
345
	// @codingStandardsIgnoreStart
346
	/**
347
	 * Construct a file path matrix for an entity.
348
	 *
349
	 * @param int $identifier The guid of the entity to store the data under.
350
	 *
351
	 * @return string The path where the entity's data will be stored.
352
	 * @deprecated 1.8 Use \Elgg\EntityDirLocator
353
	 */
354
	protected function make_file_matrix($identifier) {
355
		elgg_deprecated_notice('\ElggDiskFilestore::make_file_matrix() is deprecated by \Elgg\EntityDirLocator', 1.8);
356
357
		return $this->makeFileMatrix($identifier);
0 ignored issues
show
Deprecated Code introduced by
The method ElggDiskFilestore::makeFileMatrix() has been deprecated with message: 1.9 Use \Elgg\EntityDirLocator()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
358
	}
359
	// @codingStandardsIgnoreEnd
360
361
	// @codingStandardsIgnoreStart
362
	/**
363
	 * Construct a filename matrix.
364
	 *
365
	 * Generates a matrix using the entity's creation time and
366
	 * unique guid.
367
	 *
368
	 * @param int $guid The entity to contrust a matrix for
369
	 *
370
	 * @deprecated 1.8 Use \ElggDiskFileStore::makeFileMatrix()
371
	 * @return string The
372
	 */
373
	protected function user_file_matrix($guid) {
374
		elgg_deprecated_notice('\ElggDiskFilestore::user_file_matrix() is deprecated by \Elgg\EntityDirLocator', 1.8);
375
376
		return $this->makeFileMatrix($guid);
0 ignored issues
show
Deprecated Code introduced by
The method ElggDiskFilestore::makeFileMatrix() has been deprecated with message: 1.9 Use \Elgg\EntityDirLocator()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
377
	}
378
	// @codingStandardsIgnoreEnd
379
380
	// @codingStandardsIgnoreStart
381
	/**
382
	 * Multibyte string tokeniser.
383
	 *
384
	 * Splits a string into an array. Will fail safely if mbstring is
385
	 * not installed.
386
	 *
387
	 * @param string $string  String
388
	 * @param string $charset The charset, defaults to UTF8
389
	 *
390
	 * @return array
391
	 * @deprecated 1.8 Files are stored by date and guid; no need for this.
392
	 */
393 View Code Duplication
	private function mb_str_split($string, $charset = 'UTF8') {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
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...
394
		elgg_deprecated_notice('\ElggDiskFilestore::mb_str_split() is deprecated.', 1.8);
395
396
		if (is_callable('mb_substr')) {
397
			$length = mb_strlen($string);
398
			$array = array();
399
400
			while ($length) {
401
				$array[] = mb_substr($string, 0, 1, $charset);
402
				$string = mb_substr($string, 1, $length, $charset);
403
404
				$length = mb_strlen($string);
405
			}
406
407
			return $array;
408
		} else {
409
			return str_split($string);
410
		}
411
	}
412
	// @codingStandardsIgnoreEnd
413
414
	/**
415
	 * Construct a file path matrix for an entity.
416
	 *
417
	 * @param int $guid The guid of the entity to store the data under.
418
	 *
419
	 * @return string The path where the entity's data will be stored relative to the data dir.
420
	 * @deprecated 1.9 Use \Elgg\EntityDirLocator()
421
	 */
422
	protected function makeFileMatrix($guid) {
423
		elgg_deprecated_notice('\ElggDiskFilestore::makeFileMatrix() is deprecated by \Elgg\EntityDirLocator', 1.9);
424
		$entity = get_entity($guid);
425
426
		if (!$entity instanceof \ElggEntity) {
427
			return false;
428
		}
429
430
		$dir = new \Elgg\EntityDirLocator($guid);
431
		return $dir->getPath();
432
	}
433
}
434