Friendica Communications Platform (please note that this is a clone of the repository at github, issues are handled there) https://friendi.ca
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

146 lines
3.5 KiB

  1. <?php
  2. /**
  3. * @file src/Model/Storage/Filesystem.php
  4. * @brief Storage backend system
  5. */
  6. namespace Friendica\Model\Storage;
  7. use Friendica\Core\Config;
  8. use Friendica\Core\L10n;
  9. use Friendica\Core\Logger;
  10. use Friendica\Util\Strings;
  11. /**
  12. * @brief Filesystem based storage backend
  13. *
  14. * This class manage data on filesystem.
  15. * Base folder for storage is set in storage.filesystem_path.
  16. * Best would be for storage folder to be outside webserver folder, we are using a
  17. * folder relative to code tree root as default to ease things for users in shared hostings.
  18. * Each new resource gets a value as reference and is saved in a
  19. * folder tree stucture created from that value.
  20. */
  21. class Filesystem implements IStorage
  22. {
  23. // Default base folder
  24. const DEFAULT_BASE_FOLDER = 'storage';
  25. private static function getBasePath()
  26. {
  27. $path = Config::get('storage', 'filesystem_path', self::DEFAULT_BASE_FOLDER);
  28. return rtrim($path, '/');
  29. }
  30. /**
  31. * @brief Split data ref and return file path
  32. * @param string $ref Data reference
  33. * @return string
  34. */
  35. private static function pathForRef($ref)
  36. {
  37. $base = self::getBasePath();
  38. $fold1 = substr($ref, 0, 2);
  39. $fold2 = substr($ref, 2, 2);
  40. $file = substr($ref, 4);
  41. return implode('/', [$base, $fold1, $fold2, $file]);
  42. }
  43. /**
  44. * @brief Create dirctory tree to store file, with .htaccess and index.html files
  45. * @param string $file Path and filename
  46. * @throws StorageException
  47. */
  48. private static function createFoldersForFile($file)
  49. {
  50. $path = dirname($file);
  51. if (!is_dir($path)) {
  52. if (!mkdir($path, 0770, true)) {
  53. Logger::log('Failed to create dirs ' . $path);
  54. throw new StorageException(L10n::t('Filesystem storage failed to create "%s". Check you write permissions.', $path));
  55. }
  56. }
  57. $base = self::getBasePath();
  58. while ($path !== $base) {
  59. if (!is_file($path . '/index.html')) {
  60. file_put_contents($path . '/index.html', '');
  61. }
  62. chmod($path . '/index.html', 0660);
  63. chmod($path, 0770);
  64. $path = dirname($path);
  65. }
  66. if (!is_file($path . '/index.html')) {
  67. file_put_contents($path . '/index.html', '');
  68. chmod($path . '/index.html', 0660);
  69. }
  70. }
  71. public static function get($ref)
  72. {
  73. $file = self::pathForRef($ref);
  74. if (!is_file($file)) {
  75. return '';
  76. }
  77. return file_get_contents($file);
  78. }
  79. public static function put($data, $ref = '')
  80. {
  81. if ($ref === '') {
  82. $ref = Strings::getRandomHex();
  83. }
  84. $file = self::pathForRef($ref);
  85. self::createFoldersForFile($file);
  86. $r = file_put_contents($file, $data);
  87. if ($r === FALSE) {
  88. Logger::log('Failed to write data to ' . $file);
  89. throw new StorageException(L10n::t('Filesystem storage failed to save data to "%s". Check your write permissions', $file));
  90. }
  91. chmod($file, 0660);
  92. return $ref;
  93. }
  94. public static function delete($ref)
  95. {
  96. $file = self::pathForRef($ref);
  97. // return true if file doesn't exists. we want to delete it: success with zero work!
  98. if (!is_file($file)) {
  99. return true;
  100. }
  101. return unlink($file);
  102. }
  103. public static function getOptions()
  104. {
  105. return [
  106. 'storagepath' => [
  107. 'input',
  108. L10n::t('Storage base path'),
  109. self::getBasePath(),
  110. L10n::t('Folder where uploaded files are saved. For maximum security, This should be a path outside web server folder tree')
  111. ]
  112. ];
  113. }
  114. public static function saveOptions($data)
  115. {
  116. $storagepath = defaults($data, 'storagepath', '');
  117. if ($storagepath === '' || !is_dir($storagepath)) {
  118. return [
  119. 'storagepath' => L10n::t('Enter a valid existing folder')
  120. ];
  121. };
  122. Config::set('storage', 'filesystem_path', $storagepath);
  123. return [];
  124. }
  125. }