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 }
$mode
Configure site maintenance mode.
$position
Definition: add.php:11
return[ 'admin/delete_admin_notices'=>['access'=> 'admin'], 'admin/menu/save'=>['access'=> 'admin'], 'admin/plugins/activate'=>['access'=> 'admin'], 'admin/plugins/activate_all'=>['access'=> 'admin'], 'admin/plugins/deactivate'=>['access'=> 'admin'], 'admin/plugins/deactivate_all'=>['access'=> 'admin'], 'admin/plugins/set_priority'=>['access'=> 'admin'], 'admin/security/security_txt'=>['access'=> 'admin'], 'admin/security/settings'=>['access'=> 'admin'], 'admin/security/regenerate_site_secret'=>['access'=> 'admin'], 'admin/site/cache/invalidate'=>['access'=> 'admin'], 'admin/site/flush_cache'=>['access'=> 'admin'], 'admin/site/icons'=>['access'=> 'admin'], 'admin/site/set_maintenance_mode'=>['access'=> 'admin'], 'admin/site/set_robots'=>['access'=> 'admin'], 'admin/site/theme'=>['access'=> 'admin'], 'admin/site/unlock_upgrade'=>['access'=> 'admin'], 'admin/site/settings'=>['access'=> 'admin'], 'admin/upgrade'=>['access'=> 'admin'], 'admin/upgrade/reset'=>['access'=> 'admin'], 'admin/user/ban'=>['access'=> 'admin'], 'admin/user/bulk/ban'=>['access'=> 'admin'], 'admin/user/bulk/delete'=>['access'=> 'admin'], 'admin/user/bulk/unban'=>['access'=> 'admin'], 'admin/user/bulk/validate'=>['access'=> 'admin'], 'admin/user/change_email'=>['access'=> 'admin'], 'admin/user/delete'=>['access'=> 'admin'], 'admin/user/login_as'=>['access'=> 'admin'], 'admin/user/logout_as'=>[], 'admin/user/makeadmin'=>['access'=> 'admin'], 'admin/user/resetpassword'=>['access'=> 'admin'], 'admin/user/removeadmin'=>['access'=> 'admin'], 'admin/user/unban'=>['access'=> 'admin'], 'admin/user/validate'=>['access'=> 'admin'], 'annotation/delete'=>[], 'avatar/upload'=>[], 'comment/save'=>[], 'diagnostics/download'=>['access'=> 'admin'], 'entity/chooserestoredestination'=>[], 'entity/delete'=>[], 'entity/mute'=>[], 'entity/restore'=>[], 'entity/subscribe'=>[], 'entity/trash'=>[], 'entity/unmute'=>[], 'entity/unsubscribe'=>[], 'login'=>['access'=> 'logged_out'], 'logout'=>[], 'notifications/mute'=>['access'=> 'public'], 'plugins/settings/remove'=>['access'=> 'admin'], 'plugins/settings/save'=>['access'=> 'admin'], 'plugins/usersettings/save'=>[], 'register'=>['access'=> 'logged_out', 'middleware'=>[\Elgg\Router\Middleware\RegistrationAllowedGatekeeper::class,],], 'river/delete'=>[], 'settings/notifications'=>[], 'settings/notifications/subscriptions'=>[], 'user/changepassword'=>['access'=> 'public'], 'user/requestnewpassword'=>['access'=> 'public'], 'useradd'=>['access'=> 'admin'], 'usersettings/save'=>[], 'widgets/add'=>[], 'widgets/delete'=>[], 'widgets/move'=>[], 'widgets/save'=>[],]
Definition: actions.php:73
if(! $entity instanceof \ElggUser) $data
Definition: attributes.php:13
getSubtype()
Get the entity subtype.
Definition: ElggEntity.php:504
getFilename()
Return the filename.
Definition: ElggFile.php:96
Exception thrown if a value does not adhere to a defined valid data domain.
An IO Exception, throw when an IO Exception occurs.
Definition: IOException.php:12
Exception thrown if an argument is not of the expected type.
A filestore that uses disk as storage.
read($f, int $length, int $offset=0)
Read data from a file.
getParameters()
Returns a list of attributes to save to the database when saving the \ElggFile object using this file...
eof($f)
Tests for end of file on a file pointer.
getFileSize(\ElggFile $file)
Returns the file size of an \ElggFile file.
seek($f, int $position)
Seek to the specified position.
__construct($directory_root='')
Construct a disk filestore using the given directory root.
getFilenameOnFilestore(\ElggFile $file)
Get the filename as saved on disk for an \ElggFile object.
makeDirectoryRoot($dirroot)
Create a directory $dirroot.
exists(\ElggFile $file)
Tests if an \ElggFile file exists.
grabFile(\ElggFile $file)
Returns the contents of the \ElggFile file.
setParameters(array $parameters)
Sets parameters that should be saved to database.
tell($f)
Return the current location of the internal pointer.
write($f, $data)
Write data to a file.
const BUCKET_SIZE
Number of entries per matrix dir.
open(\ElggFile $file, string $mode)
Open a file for reading, writing, or both.
This class defines the interface for all elgg data repositories.
Definition: Filestore.php:8
seek($f, int $position)
Seek a given position within a file handle.
Find Elgg and project paths.
Definition: Paths.php:8
static sanitize($path, $append_slash=true)
Sanitize file paths ensuring that they begin and end with slashes etc.
Definition: Paths.php:76
$owner_guid
_elgg_services()
Get the global service provider.
Definition: elgglib.php:353
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:256
elgg_is_empty($value)
Check if a value isn't empty, but allow 0 and '0'.
Definition: input.php:176
$target
Definition: create.php:17
$path
Definition: details.php:70
if(! $item instanceof \ElggEntity) $length
Definition: excerpt.php:16
if(empty($count)) $offset
Definition: pagination.php:26
if(parse_url(elgg_get_site_url(), PHP_URL_PATH) !=='/') if(file_exists(elgg_get_root_path() . 'robots.txt'))
Set robots.txt.
Definition: robots.php:10