- Front controller and UI in [public/index.php](/Users/tyemeclifford/Documents/GH/CloudflareR2-Manager/public/index.php) and [views/dashboard.php](/Users/tyemeclifford/Documents/GH/CloudflareR2-Manager/views/dashboard.php)

R2 S3 Signature V4 client in 
[src/R2/R2Client.php](/Users/tyemeclifford/Documents/GH/CloudflareR2-Manager/src/R2/R2Client.php)
SQLite mirror, usage ledger, settings, local tags, permission labels, 
and signed URL history under 
[src/Repository](/Users/tyemeclifford/Documents/GH/CloudflareR2-Manager/src/Repository)
Simple password auth and CSRF protection
Uploads, folders, sync, copy/move/delete, downloads, presigned URLs, 
CORS JSON management, and usage/billing-style summaries
Setup docs in 
[README.md](/Users/tyemeclifford/Documents/GH/CloudflareR2-Manager/README.md) 
and config template in 
[.env.example](/Users/tyemeclifford/Documents/GH/CloudflareR2-Manager/.env.example)
Important R2 caveat: Cloudflare’s current R2 S3 compatibility docs say 
ACLs and object-tagging APIs are not implemented, so the app stores tags 
and permission labels locally in SQLite while keeping file bytes on R2. 
I used Cloudflare’s official docs for S3 compatibility, presigned URLs, 
and CORS.
This commit is contained in:
Ty Clifford
2026-06-20 13:57:21 -04:00
parent 1c7f697913
commit 3518555d1e
29 changed files with 3598 additions and 1 deletions
+50
View File
@@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
namespace R2Manager\Support;
final class Formatter
{
public static function bytes(int|float $bytes): string
{
$units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
$value = max(0, (float) $bytes);
$unit = 0;
while ($value >= 1024 && $unit < count($units) - 1) {
$value /= 1024;
$unit++;
}
return ($unit === 0 ? number_format($value, 0) : number_format($value, 2)) . ' ' . $units[$unit];
}
public static function date(?string $value): string
{
if ($value === null || $value === '') {
return 'Never';
}
$timestamp = strtotime($value);
if ($timestamp === false) {
return $value;
}
return date('M j, Y g:i A', $timestamp);
}
/**
* @param array<string, string> $tags
*/
public static function tagString(array $tags): string
{
$parts = [];
foreach ($tags as $key => $value) {
$parts[] = $key . '=' . $value;
}
return implode(', ', $parts);
}
}