3 * @file src/Model/Storage/Filesystem.php
4 * @brief Storage backend system
7 namespace Friendica\Model\Storage;
9 use Friendica\Core\Config;
10 use Friendica\Core\L10n;
11 use Friendica\Core\Logger;
12 use Friendica\Util\Strings;
15 * @brief Filesystem based storage backend
17 * This class manage data on filesystem.
18 * Base folder for storage is set in storage.filesystem_path.
19 * Best would be for storage folder to be outside webserver folder, we are using a
20 * folder relative to code tree root as default to ease things for users in shared hostings.
21 * Each new resource gets a value as reference and is saved in a
22 * folder tree stucture created from that value.
24 class Filesystem implements IStorage
26 // Default base folder
27 const DEFAULT_BASE_FOLDER = 'storage';
29 private static function getBasePath()
31 return Config::get('storage', 'filesystem_path', self::DEFAULT_BASE_FOLDER);
35 * @brief Split data ref and return file path
36 * @param string $ref Data reference
39 private static function pathForRef($ref)
41 $base = self::getBasePath();
42 $fold1 = substr($ref, 0, 2);
43 $fold2 = substr($ref, 2, 2);
44 $file = substr($ref, 4);
46 return implode('/', [$base, $fold1, $fold2, $file]);
51 * @brief Create dirctory tree to store file, with .htaccess and index.html files
52 * @param string $file Path and filename
53 * @throws StorageException
55 private static function createFoldersForFile($file)
57 $path = dirname($file);
60 if (!mkdir($path, 0770, true)) {
61 Logger::log('Failed to create dirs ' . $path);
62 throw new StorageException(L10n::t('Filesystem storage failed to create "%s". Check you write permissions.', $path));
66 $base = self::getBasePath();
68 while ($path !== $base) {
69 if (!is_file($path . '/index.html')) {
70 file_put_contents($path . '/index.html', '');
72 $path = dirname($path);
74 if (!is_file($path . '/index.html')) {
75 file_put_contents($path . '/index.html', '');
79 public static function get($ref)
81 $file = self::pathForRef($ref);
82 if (!is_file($file)) {
86 return file_get_contents($file);
89 public static function put($data, $ref = '')
92 $ref = Strings::getRandomHex();
94 $file = self::pathForRef($ref);
96 self::createFoldersForFile($file);
98 $r = file_put_contents($file, $data);
100 Logger::log('Failed to write data to ' . $file);
101 throw new StorageException(L10n::t('Filesystem storage failed to save data to "%s". Check your write permissions', $file));
106 public static function delete($ref)
108 $file = self::pathForRef($ref);
109 // return true if file doesn't exists. we want to delete it: success with zero work!
110 if (!is_file($file)) {
113 return unlink($file);
116 public static function getOptions()
121 L10n::t('Storage base path'),
123 L10n::t('Folder were uploaded files are saved. For maximum security, This should be a path outside web server folder tree')
128 public static function saveOptions($data)
130 $storagepath = defaults($data, 'storagepath', '');
131 if ($storagepath === '' || !is_dir($storagepath)) {
133 'storagepath' => L10n::t('Enter a valid existing folder')
136 Config::set('storage', 'filesystem_path', $storagepath);