Storage
Filesystem abstraction for working with local and remote file storage.
Namespace: VelvetCMS\Services\StorageManager
StorageManager #
Manages filesystem disks configured in config/filesystems.php.
Definition #
class StorageManager
{
public function __construct(array $config);
public function disk(?string $name = null): FilesystemInterface;
}
Accessing Storage #
// Via container
$storage = app('storage');
// Get default disk
$disk = $storage->disk();
// Get specific disk
$disk = $storage->disk('local');
$disk = $storage->disk('public');
FilesystemInterface #
All disks implement this interface.
Definition #
interface FilesystemInterface
{
public function exists(string $path): bool;
public function get(string $path): ?string;
public function put(string $path, mixed $contents, array $config = []): bool;
public function delete(string $path): bool;
public function makeDirectory(string $path): bool;
public function size(string $path): int;
public function lastModified(string $path): int;
public function files(string $directory, bool $recursive = false): array;
public function url(string $path): string;
public function path(string $path): string;
}
Methods #
exists() #
Check if a file exists.
public function exists(string $path): bool
Example:
$disk = app('storage')->disk();
if ($disk->exists('uploads/photo.jpg')) {
// File exists
}
get() #
Read file contents.
public function get(string $path): ?string
Returns: File contents or null if not found
Example:
$content = $disk->get('config/settings.json');
if ($content !== null) {
$settings = json_decode($content, true);
}
put() #
Write content to a file. Creates directories automatically.
public function put(string $path, mixed $contents, array $config = []): bool
| Parameter | Type | Description |
|---|---|---|
$path |
string |
File path |
$contents |
string|resource |
Content to write |
$config |
array |
Optional configuration |
Returns: true on success
Example:
// Write string content
$disk->put('notes/hello.txt', 'Hello, World!');
// Write JSON
$disk->put('data/users.json', json_encode($users, JSON_PRETTY_PRINT));
// Write from stream
$stream = fopen('php://input', 'r');
$disk->put('uploads/file.bin', $stream);
delete() #
Delete a file.
public function delete(string $path): bool
Returns: true on success (also returns true if file didn't exist)
Example:
$disk->delete('temp/cache.tmp');
makeDirectory() #
Create a directory.
public function makeDirectory(string $path): bool
Example:
$disk->makeDirectory('uploads/2026/01');
size() #
Get file size in bytes.
public function size(string $path): int
Example:
$bytes = $disk->size('uploads/video.mp4');
$mb = round($bytes / 1024 / 1024, 2);
echo "File size: {$mb} MB";
lastModified() #
Get file modification timestamp.
public function lastModified(string $path): int
Returns: Unix timestamp
Example:
$timestamp = $disk->lastModified('data/cache.json');
$date = date('Y-m-d H:i:s', $timestamp);
// Check if file is stale
if (time() - $timestamp > 3600) {
$this->refreshCache();
}
files() #
List files in a directory.
public function files(string $directory, bool $recursive = false): array
| Parameter | Type | Default | Description |
|---|---|---|---|
$directory |
string |
- | Directory path |
$recursive |
bool |
false |
Include subdirectories |
Returns: Array of relative file paths
Example:
// List files in directory
$files = $disk->files('uploads');
// ['uploads/photo1.jpg', 'uploads/photo2.png']
// List recursively
$allFiles = $disk->files('uploads', true);
// ['uploads/photo1.jpg', 'uploads/2026/01/doc.pdf']
url() #
Get public URL for a file.
public function url(string $path): string
Throws: RuntimeException if disk doesn't support URLs
Example:
$disk = app('storage')->disk('public');
$url = $disk->url('images/logo.png');
// https://example.com/storage/images/logo.png
path() #
Get absolute filesystem path.
public function path(string $path): string
Example:
$absolutePath = $disk->path('uploads/file.txt');
// /var/www/app/storage/uploads/file.txt
Configuration #
Configure disks in config/filesystems.php:
return [
'default' => 'local',
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
],
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => '/storage',
],
'uploads' => [
'driver' => 'local',
'root' => base_path('uploads'),
'url' => '/uploads',
'permissions' => 0755,
],
],
];
LocalDriver #
The built-in local filesystem driver.
Namespace: VelvetCMS\Drivers\Storage\LocalDriver
Features #
- Automatic directory creation
- Path traversal prevention (sanitizes
..) - Stream support for large files
- Configurable permissions
Configuration Options #
| Option | Type | Default | Description |
|---|---|---|---|
root |
string |
- | Base directory path |
url |
string |
null |
Public URL prefix |
permissions |
int |
0755 |
Directory permissions |
Usage Examples #
File Upload Handler #
class UploadController
{
public function store(Request $request): Response
{
$file = $request->file('document');
if (!$file) {
return Response::json(['error' => 'No file uploaded'], 400);
}
$disk = app('storage')->disk('uploads');
// Generate unique filename
$filename = sprintf(
'%s/%s_%s',
date('Y/m'),
uniqid(),
$file['name']
);
// Save file
$stream = fopen($file['tmp_name'], 'r');
$disk->put($filename, $stream);
fclose($stream);
return Response::json([
'path' => $filename,
'url' => $disk->url($filename),
'size' => $disk->size($filename),
], 201);
}
}
Backup Service #
class BackupService
{
public function __construct(
private readonly StorageManager $storage
) {}
public function createBackup(): string
{
$disk = $this->storage->disk('local');
$backupDisk = $this->storage->disk('backups');
$timestamp = date('Y-m-d_His');
$backupDir = "backup_{$timestamp}";
// Copy all content files
$files = $disk->files('content', true);
foreach ($files as $file) {
$content = $disk->get($file);
$backupDisk->put("{$backupDir}/{$file}", $content);
}
return $backupDir;
}
public function cleanOldBackups(int $keepDays = 7): int
{
$disk = $this->storage->disk('backups');
$cutoff = time() - ($keepDays * 86400);
$deleted = 0;
$files = $disk->files('', true);
foreach ($files as $file) {
if ($disk->lastModified($file) < $cutoff) {
$disk->delete($file);
$deleted++;
}
}
return $deleted;
}
}
Cache File Manager #
class FileCacheManager
{
private FilesystemInterface $disk;
public function __construct(StorageManager $storage)
{
$this->disk = $storage->disk('local');
}
public function get(string $key): mixed
{
$path = $this->path($key);
if (!$this->disk->exists($path)) {
return null;
}
$content = $this->disk->get($path);
$data = json_decode($content, true);
if ($data['expires'] < time()) {
$this->disk->delete($path);
return null;
}
return $data['value'];
}
public function set(string $key, mixed $value, int $ttl = 3600): void
{
$path = $this->path($key);
$data = [
'value' => $value,
'expires' => time() + $ttl,
];
$this->disk->put($path, json_encode($data));
}
private function path(string $key): string
{
return 'cache/' . md5($key) . '.json';
}
}
Image Processing #
class ImageService
{
public function __construct(
private readonly StorageManager $storage
) {}
public function resize(string $path, int $width, int $height): string
{
$disk = $this->storage->disk('public');
// Get original
$original = $disk->get($path);
// Create resized version
$image = imagecreatefromstring($original);
$resized = imagescale($image, $width, $height);
// Generate new path
$info = pathinfo($path);
$newPath = sprintf(
'%s/%s_%dx%d.%s',
$info['dirname'],
$info['filename'],
$width,
$height,
$info['extension']
);
// Save
ob_start();
imagejpeg($resized, null, 85);
$content = ob_get_clean();
$disk->put($newPath, $content);
imagedestroy($image);
imagedestroy($resized);
return $newPath;
}
}
Path Safety #
The LocalDriver prevents directory traversal attacks:
// These paths are sanitized
$disk->get('../../../etc/passwd'); // Becomes: /root/etc/passwd
$disk->get('uploads/../../../secret'); // Becomes: /root/uploads/secret
// '..' segments are stripped, keeping you within the disk root