Ty Clifford 4b4c18f2d9 - Added R2 multipart upload support and streamed fallback uploads in [R2Client.php](/Users/tyemeclifford/Documents/GH/CloudflareR2-Manager/src/R2/R2Client.php).
Added a shared resumable upload session service in 
[ResumableUploadService.php](/Users/tyemeclifford/Documents/GH/CloudflareR2-Manager/src/Service/ResumableUploadService.php).
Wired dashboard JSON upload endpoints in 
[AppController.php](/Users/tyemeclifford/Documents/GH/CloudflareR2-Manager/src/Controller/AppController.php).
Reworked the upload UI/JS to chunk files directly from the browser to 
presigned R2 multipart URLs in 
[app.js](/Users/tyemeclifford/Documents/GH/CloudflareR2-Manager/public/assets/app.js).
Added the dedicated iPhone/Safari side uploader at 
[side-upload.php](/Users/tyemeclifford/Documents/GH/CloudflareR2-Manager/public/side-upload.php), 
with its own password and fixed destination prefix via script constants, 
.env, or side-upload.json.
Added 
[side-upload.example.json](/Users/tyemeclifford/Documents/GH/CloudflareR2-Manager/side-upload.example.json), 
ignored the real side-upload.json, and documented setup/CORS in 
[README.md](/Users/tyemeclifford/Documents/GH/CloudflareR2-Manager/README.md).
2026-06-21 11:24:09 -04:00
2026-06-20 16:47:35 +00:00

CloudflareR2-Manager

A self-contained PHP web application for managing a Cloudflare R2 bucket with a local SQLite mirror.

Features

  • Simple password authentication with CSRF protection.
  • R2 object browser backed by SQLite, so normal navigation uses the local mirror instead of repeatedly listing the bucket.
  • Prefix/folder organization, including zero-byte marker objects for empty folders.
  • Upload one or more files directly to R2 with local tags, permission labels, and operator notes.
  • Resumable browser uploads using R2 multipart upload URLs, suitable for large files and mobile Safari.
  • Optional side upload page with its own password and fixed destination prefix for quick iPhone uploads.
  • Download, delete, copy, move, rename, and refresh object metadata.
  • Generate presigned GET, PUT, HEAD, and DELETE URLs.
  • Manage bucket CORS from JSON.
  • Track local usage events for sync, upload, download, copy, move, delete, CORS, and signed URL generation.
  • Optional public URL display for public buckets or custom R2 domains.

Cloudflare R2 Notes

Cloudflare R2 uses the S3-compatible API at https://<ACCOUNT_ID>.r2.cloudflarestorage.com and the S3 region is auto.

As of Cloudflare's R2 S3 compatibility docs updated June 8, 2026, S3 ACLs and object tagging APIs are not implemented by R2. This app therefore stores tags, permission labels, and notes locally in SQLite while keeping file bytes in R2. Bucket CORS, object list/get/put/delete/copy, and presigned URLs are handled through R2's S3-compatible API.

Requirements

  • PHP 8.1 or newer.
  • PHP extensions: pdo_sqlite, curl, simplexml, fileinfo.
  • A Cloudflare R2 bucket.
  • R2 API credentials with access to that bucket.

Composer is not required.

Setup

  1. Copy the environment example:

    cp .env.example .env
    
  2. Edit .env:

    APP_PASSWORD="choose-a-real-password"
    R2_ACCOUNT_ID="your-cloudflare-account-id"
    R2_ACCESS_KEY_ID="your-r2-access-key-id"
    R2_SECRET_ACCESS_KEY="your-r2-secret-access-key"
    R2_BUCKET="your-bucket-name"
    
  3. Start the PHP development server:

    php -S 127.0.0.1:8080 -t public
    
  4. Open http://127.0.0.1:8080, sign in, and run Sync current prefix.

Resumable Uploads

The dashboard upload form uses browser-side R2 multipart uploads when JavaScript is available. PHP creates the multipart upload, signs each part URL, records completed part ETags in storage/cache/uploads, and completes the upload when all parts are present. If a connection drops, choose the same file again and the app will reuse the saved multipart session.

Useful settings:

UPLOAD_PART_SIZE=8388608
UPLOAD_PART_URL_TTL=3600
UPLOAD_SESSION_TTL=604800
R2_REQUEST_TIMEOUT=300

UPLOAD_PART_SIZE is bytes. Keep it at or above 5242880 because S3-compatible multipart uploads require 5 MiB minimum parts except for the last part.

Because file chunks upload from the browser directly to R2, your bucket CORS policy must allow the app origin to PUT and expose ETag. The default CORS editor example already includes PUT and ETag; change AllowedOrigins to your deployed app origin.

Side Upload Page

/side-upload.php is a narrow upload-only page for quick mobile uploads. It uses a separate password from the main app and always uploads into a configured prefix.

Configure it in .env:

SIDE_UPLOAD_PASSWORD="choose-a-different-password"
SIDE_UPLOAD_PREFIX="iphone-uploads/"
SIDE_UPLOAD_TAGS="source=iphone"

You can also edit the constants at the top of public/side-upload.php. Or copy side-upload.example.json to side-upload.json and edit the password and prefix there. The real side-upload.json file is ignored by git.

Password Hashes

For a plain setup, use APP_PASSWORD. For a hashed password, generate a hash with PHP and set APP_PASSWORD_HASH instead:

php -r 'echo password_hash("your-password", PASSWORD_DEFAULT), PHP_EOL;'

Public URLs

If your bucket has public access or a custom domain, set:

R2_PUBLIC_URL="https://static.example.com"

The app will display copyable public links. It does not make a bucket public; public access is controlled in Cloudflare.

Usage Tracking

The usage dashboard is a local operational ledger. It records actions performed through this app and current mirrored storage size. It is useful for estimating activity, but it is not a replacement for Cloudflare's official billing or analytics.

CORS Format

Enter CORS as an array of S3-style rules:

[
  {
    "AllowedOrigins": ["https://example.com"],
    "AllowedMethods": ["GET", "PUT", "HEAD"],
    "AllowedHeaders": ["Content-Type"],
    "ExposeHeaders": ["ETag"],
    "MaxAgeSeconds": 3600
  }
]

Security

  • Keep .env outside version control.
  • Serve the app behind HTTPS in production.
  • Use least-privilege R2 credentials.
  • Restrict access at your web server or VPN if this manages production buckets.
S
Description
A CloudFlare R2 manager built for the web usage and command line. Focused on mirroring.
Readme Unlicense 100 KiB
Languages
PHP 87.9%
CSS 6.8%
JavaScript 5.3%