# largeFile/proxyServer

Upload/download proxy for Churchill "Large Files". Plain PHP (5.6+), no database, no extra services.
Browsers upload chunks straight here; Churchill (OMG2) then pulls the finished file server-to-server,
validates it and stores its own copy, and later redirects downloads here. Files are deleted 30 days after upload.

## Requirements
- Apache with `AllowOverride All` for this folder (`.htaccess` carries the PHP limits and blocks `storage/`)
- **HTTPS** for the hostname (browsers on https pages refuse to talk to plain http)
- Web user (e.g. `www-data`) can write to `storage/` (or to `FP_STORAGE` if moved)
- PHP limits: `upload_max_filesize` >= 16M, `post_max_size` >= 20M (set in `.htaccess` / `.user.ini`;
  for PHP-FPM `.user.ini` is cached ~5 min; otherwise set them in the pool config)

## Deploy
This folder is part of the Churchill repo but runs on its **own host** (not on the Churchill server). It is
self-contained: it does not load any Churchill code.

1. Check out the repo (or just this folder) on the HTTPS host, so it is reachable as `https://<host>/largeFile/proxyServer/`
   (or point a vhost at this folder directly).
2. `config.local.php` is already filled in (secret + allowed origins for test and prod). Change `FP_SECRET`
   only together with `FILE_PROXY_SECRET` in Churchill's `local.config.php`.
3. Optional: set `FP_STORAGE` to a folder **outside** the web root (preferred) with enough disk space.
4. Daily cron: `0 3 * * * php /path/to/largeFile/proxyServer/cleanup.php`
5. Smoke test: `curl -i https://<host>/<path>/exists.php` -> HTTP 403 `{"status":"error","error":"Invalid token."}`

Tell the Churchill side the URL of this folder (e.g. `https://host/largeFile/proxyServer`, no trailing slash).

## Files
| File | Purpose |
|---|---|
| `upload.php` | receives one chunk; assembles `data` after the last one (browser, CORS-enabled) |
| `download.php` | streams a file, Range supported (browser redirect + Churchill pull) |
| `exists.php` | does the file exist (Churchill) |
| `ack.php` | Churchill confirms it has its own copy -> `.synced` marker |
| `delete.php` | removes a file (Churchill, e.g. rejected upload) |
| `cleanup.php` | cron: removes expired files. `--dry` lists without deleting |
| `config.php` / `config.local.php` | defaults / deploy-specific values |
| `lib.php` | token check + helpers |

Every endpoint needs a signed token (`?t=`) minted by Churchill with the shared secret; each token is
valid for one operation on one file id and expires (upload 6 h, download 5 min, server calls 2 min).
Server clocks must be roughly in sync.

## Storage and retention
`storage/<2 chars>/<id>/` holds `data` (the file), `.synced` (Churchill has its copy) and, while an upload is
running, `part0..N`. The proxy never stores file names.

| State | Deleted |
|---|---|
| `data` + `.synced` | 30 days after upload |
| `data`, never synced (failed processing) | 60 days |
| only `part*` (abandoned upload) | 2 days |

Disk use is roughly (uploaded GB per 30 days) x 1.

## Troubleshooting
| Symptom | Cause |
|---|---|
| browser: mixed content | host is not on https |
| browser: CORS error | `FP_ALLOWED_ORIGINS` must contain the exact Churchill origin (scheme + host) |
| 403 `Invalid token` | secrets differ, or server clocks are far apart |
| 413 / `Missing/invalid chunk` | PHP upload limits not applied (see Requirements) |
| 500 `Storage is not writable` | web user cannot write to `storage/` |
