- 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).
This commit is contained in:
Ty Clifford
2026-06-21 11:24:09 -04:00
parent 3518555d1e
commit 4b4c18f2d9
11 changed files with 1362 additions and 14 deletions
+33 -1
View File
@@ -8,6 +8,8 @@ A self-contained PHP web application for managing a Cloudflare R2 bucket with a
- 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.
@@ -55,6 +57,37 @@ Composer is not required.
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:
```dotenv
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`:
```dotenv
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:
@@ -99,4 +132,3 @@ Enter CORS as an array of S3-style rules:
- 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.