3518555d1e
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.
51 lines
1.1 KiB
PHP
51 lines
1.1 KiB
PHP
<?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);
|
|
}
|
|
}
|
|
|