Elgg  Version master
DiskFilestore.php
Go to the documentation of this file.
1 <?php
2 
4 
10 
17 class DiskFilestore extends Filestore {
18 
22  protected $dir_root;
23 
28  const BUCKET_SIZE = 5000;
29 
35  public function __construct($directory_root = '') {
36  if (!$directory_root) {
37  $directory_root = _elgg_services()->config->dataroot;
38  }
39 
40  $this->dir_root = Paths::sanitize($directory_root);
41  }
42 
56  public function open(\ElggFile $file, string $mode) {
57  $fullname = $this->getFilenameOnFilestore($file);
58 
59  // Split into path and name
60  $ls = strrpos($fullname, '/');
61  if ($ls === false) {
62  $ls = 0;
63  }
64 
65  $path = substr($fullname, 0, $ls);
66 
67  if (($mode === 'read') && (!file_exists($fullname))) {
68  return false;
69  }
70 
71  // Try to create the dir for valid write modes
72  if ($mode == 'write' || $mode == 'append') {
73  try {
74  $this->makeDirectoryRoot($path);
75  } catch (\Exception $e) {
76  _elgg_services()->logger->warning($e);
77  return false;
78  }
79  }
80 
81  switch ($mode) {
82  case 'read':
83  $mode = 'rb';
84  break;
85  case 'write':
86  $mode = 'w+b';
87  break;
88  case 'append':
89  $mode = 'a+b';
90  break;
91  default:
92  throw new DomainException("Unrecognized file mode '{$mode}'");
93  }
94 
95  return fopen($fullname, $mode);
96  }
97 
106  public function write($f, $data): int {
107  return fwrite($f, $data);
108  }
109 
119  public function read($f, int $length, int $offset = 0): string|false {
120  if ($offset) {
121  $this->seek($f, $offset);
122  }
123 
124  return fread($f, $length);
125  }
126 
134  public function close($f): bool {
135  return fclose($f);
136  }
137 
146  public function delete(\ElggFile $file, bool $follow_symlinks = true): bool {
147  $filename = $this->getFilenameOnFilestore($file);
148  if (file_exists($filename) || is_link($filename)) {
149  if ($follow_symlinks && is_link($filename) && file_exists($filename)) {
150  $target = readlink($filename);
151  file_exists($target) && unlink($target);
152  }
153 
154  return unlink($filename);
155  }
156 
157  return true;
158  }
159 
168  public function seek($f, int $position): int {
169  return fseek($f, $position);
170  }
171 
179  public function tell($f): int|false {
180  return ftell($f);
181  }
182 
190  public function eof($f): bool {
191  return feof($f);
192  }
193 
201  public function getFileSize(\ElggFile $file): int {
202  return filesize($this->getFilenameOnFilestore($file));
203  }
204 
215  public function getFilenameOnFilestore(\ElggFile $file): string {
216 
217  $owner_guid = null;
218  if (!empty($file->guid) && $file->getSubtype() === 'file') {
219  $owner_guid = $file->guid;
220  }
221 
222  if (empty($owner_guid)) {
223  $owner_guid = $file->owner_guid ?: _elgg_services()->session_manager->getLoggedInUserGuid();
224  }
225 
226  if (empty($owner_guid)) {
227  throw new InvalidArgumentException("File {$file->getFilename()} (file guid: {$file->guid}) is missing an owner!");
228  }
229 
230  $filename = $file->getFilename();
231  if (!$filename) {
232  return '';
233  }
234 
235  $dir = new \Elgg\EntityDirLocator($owner_guid);
236 
237  return Paths::sanitize($this->dir_root . $dir . $file->getFilename(), false);
238  }
239 
247  public function grabFile(\ElggFile $file): string|false {
248  return file_get_contents($file->getFilenameOnFilestore());
249  }
250 
258  public function exists(\ElggFile $file): bool {
259  if (!$file->getFilename()) {
260  return false;
261  }
262 
263  try {
264  $real_filename = $this->getFilenameOnFilestore($file);
265  } catch (InvalidArgumentException $e) {
266  // something wrong with the filename
267  return false;
268  }
269 
270  return file_exists($real_filename);
271  }
272 
281  protected function makeDirectoryRoot($dirroot): void {
282  if (file_exists($dirroot)) {
283  return;
284  }
285 
286  error_clear_last();
287  if (!@mkdir($dirroot, 0755, true)) {
288  $last_error = error_get_last();
289 
290  $message = elgg_extract('message', $last_error);
291  if (!elgg_is_empty($message)) {
292  $message = ": {$message}";
293  }
294 
295  throw new IOException("Couldn't create directory: {$dirroot}{$message}");
296  }
297  }
298 
305  public function getParameters(): array {
306  return [
307  'dir_root' => $this->dir_root,
308  ];
309  }
310 
318  public function setParameters(array $parameters): bool {
319  if (isset($parameters['dir_root'])) {
320  $this->dir_root = Paths::sanitize($parameters['dir_root']);
321  return true;
322  }
323 
324  return false;
325  }
326 }
getSubtype()
Get the entity subtype.
Exception thrown if an argument is not of the expected type.
seek($f, int $position)
Seek to the specified position.
$mode
Configure site maintenance mode.
$position
Definition: add.php:11
An IO Exception, throw when an IO Exception occurs.
Definition: IOException.php:12
if(!$item instanceof\ElggEntity) $length
Definition: excerpt.php:16
read($f, int $length, int $offset=0)
Read data from a file.
c Accompany it with the information you received as to the offer to distribute corresponding source complete source code means all the source code for all modules it plus any associated interface definition plus the scripts used to control compilation and installation of the executable as a special the source code distributed need not include anything that is normally and so on of the operating system on which the executable unless that component itself accompanies the executable If distribution of executable or object code is made by offering access to copy from a designated then offering equivalent access to copy the source code from the same place counts as distribution of the source even though third parties are not compelled to copy the source along with the object code You may not or distribute the Program except as expressly provided under this License Any attempt otherwise to sublicense or distribute the Program is void
Definition: LICENSE.txt:215
if(empty($count)) $offset
Definition: pagination.php:26
Exception thrown if a value does not adhere to a defined valid data domain.
grabFile(\ElggFile $file)
Returns the contents of the file.
__construct($directory_root= '')
Construct a disk filestore using the given directory root.
A filestore that uses disk as storage.
elgg_is_empty($value)
Check if a value isn&#39;t empty, but allow 0 and &#39;0&#39;.
Definition: input.php:176
setParameters(array $parameters)
Sets parameters that should be saved to database.
elgg_extract($key, $array, $default=null, bool $strict=true)
Checks for $array[$key] and returns its value if it exists, else returns $default.
Definition: elgglib.php:254
getFilenameOnFilestore()
Return the filename of this file as it is/will be stored on the filestore, which may be different to ...
Definition: ElggFile.php:111
$path
Definition: details.php:70
if(!$entity instanceof\ElggUser) $data
Definition: attributes.php:13
$target
Definition: create.php:17
$owner_guid
const BUCKET_SIZE
Number of entries per matrix dir.
getFilename()
Return the filename.
Definition: ElggFile.php:96
makeDirectoryRoot($dirroot)
Create a directory $dirroot.
This class defines the interface for all elgg data repositories.
Definition: Filestore.php:8
tell($f)
Return the current location of the internal pointer.
exists(\ElggFile $file)
Tests if an file exists.
getFileSize(\ElggFile $file)
Returns the file size of an file.
getFilenameOnFilestore(\ElggFile $file)
Get the filename as saved on disk for an object.
write($f, $data)
Write data to a file.
static sanitize($path, $append_slash=true)
Sanitize file paths ensuring that they begin and end with slashes etc.
Definition: Paths.php:76
_elgg_services()
Get the global service provider.
Definition: elgglib.php:351
getParameters()
Returns a list of attributes to save to the database when saving the object using this file store...
eof($f)
Tests for end of file on a file pointer.
open(\ElggFile $file, string $mode)
Open a file for reading, writing, or both.