Josef Straßl eecb5f0ccf adding drop, transfer.sh style sharing 4 өдөр өмнө
..
data eecb5f0ccf adding drop, transfer.sh style sharing 4 өдөр өмнө
.htaccess eecb5f0ccf adding drop, transfer.sh style sharing 4 өдөр өмнө
README.md eecb5f0ccf adding drop, transfer.sh style sharing 4 өдөр өмнө
index.php eecb5f0ccf adding drop, transfer.sh style sharing 4 өдөр өмнө

README.md

drop

A small temporary file drop in the spirit of transfer.sh, but plain PHP — no Go binary, no daemon, no database. One script, one storage folder.

Usage

curl --upload-file ./hello.txt https://tool.medowar.de/drop/

The response body is the download URL:

https://tool.medowar.de/drop/9f2c1ab73d40/hello.txt

Mind the trailing slashcurl --upload-file only appends the local filename when the URL ends in /. Without it the file is stored as upload.bin (or as whatever X-Filename: says).

Optional request headers:

Header Meaning
Max-Days: 1 Expire after 1 days instead of the default 3 (max 30).
Max-Downloads: 1 One-shot link — deleted after that many downloads.
X-Filename: name.txt Filename when the URL carries none.

Show the response headers to get the delete URL:

curl -D- -H 'Max-Downloads: 1' --upload-file ./secret.zip https://tool.medowar.de/drop/
X-Url-Delete: https://tool.medowar.de/drop/d/9f2c1ab73d40/8f3c…
X-Expires: Wed, 19 Aug 2026 09:12:44 GMT

Delete early:

curl -X DELETE https://tool.medowar.de/drop/d/9f2c1ab73d40/8f3c…

Opening that delete URL in a browser shows a confirmation page instead of deleting straight away, so link previews and prefetchers can't wipe a file.

There is also a browser UI at /drop/ with drag & drop and an upload progress bar, and ?meta=1 on a download URL returns the file's metadata as JSON.

Expiry

Every file gets an expiry timestamp at upload time (default 14 days). Expired files are refused on download and physically removed by a sweep that runs on roughly every 20th request — there is no cron job to set up. If the drop is idle for a long time, files simply linger on disk until the next request; add a cron entry if you want that tightened:

*/30 * * * * curl -sf -o /dev/null https://tool.medowar.de/drop/

Files

File Purpose
index.php Everything: router, upload, download, delete, web UI.
.htaccess Rewrites all paths to index.php, raises LimitRequestBody.
data/ One directory per file: blob + meta.json. Git-ignored.
data/.htaccess Denies direct web access to stored files.

Limits

Set at the top of index.php:

Constant Default Meaning
MAX_FILE_BYTES 512 MB Per file. Keep LimitRequestBody in .htaccess in sync.
MAX_TOTAL_BYTES 10 GB Whole drop; further uploads get a 507.
DEFAULT_DAYS 3 Default expiry.
MAX_DAYS 30 Ceiling for Max-Days.
MAX_PER_IP_HOUR 60 Uploads per IP per hour.
GC_CHANCE 20 1-in-N requests sweep expired files.

Notes / security

  • Links are the only access control. IDs are 48 bits of randomness and the drop has no listing, but anyone holding a URL can download the file. Use Max-Downloads: 1 for anything sensitive — or encrypt before uploading.
  • Downloads are always sent as application/octet-stream with Content-Disposition: attachment and nosniff. This host serves other tools from the same origin, so an uploaded .html must never render here.
  • Uploads stream to disk in 256 KB chunks, so PHP's memory_limit is not the constraint; LimitRequestBody and the PHP max_execution_time are.
  • upload_max_filesize / post_max_size only apply to the browser form fallback — a raw PUT body bypasses PHP's multipart parser entirely.
  • Filenames are reduced to a single path component and stripped of control characters; the on-disk name is always blob, so the client's name never touches the filesystem.
  • The download counter is incremented before the transfer starts, so aborting a download can't buy extra pulls on a one-shot link.