Skip to the content.

BlackSwan Upload — upload.php

One PHP file. Move files anywhere. Pull a file from any URL, push files from your PC, relay through a second server when the source is blocked, browse and manage FTP/FTPS/SFTP servers, and diff-and-sync two servers — all from a single, dependency-free upload.php you drop in, use, and delete.

The upload.php interface: sidebar app shell, upload form with live progress, and the file-tree browser.

Latest release: v3.5.2 · 2026-06-04
Single file: upload.php — no install, no Composer, no build step. Tooltips (Tippy.js) are inlined; the optional in-browser code editor lazy-loads CodeMirror from a CDN only when you open it.
Zero server dependencies: pure PHP back-end + vanilla JS/CSS front-end. Works on shared hosting, cPanel, DirectAdmin, managed WordPress.


Why this exists

Sometimes you need to get a file onto a server and the usual tools aren’t there: wget/ssh are disabled, it’s locked-down shared hosting, or the box simply can’t reach the source. You have a browser, a URL, and maybe some FTP credentials.

upload.php is the bridge. Upload this one file, and the server does the heavy lifting:

Then click Self-Destruct and it’s gone.


What it does

📤 Upload

| Mode | What it does | | — | — | | Upload from URL | Server fetches any URL straight to disk, with live top-bar progress, size, elapsed time and ETA. Optional archive extraction (.zip .tar .tar.gz .tgz .gz) and a WordPress installer mode (extract → move to root → keep latest theme → wipe default plugins → Disallow: /). Bulk: paste many URLs, one per line, with per-item rows, retry, and a counter. | | Upload from PC | Pick files from your device and upload them to the server with a real, per-file progress bar (true byte progress). Selected files are listed before upload with per-item remove; pick again to add more. Bulk multi-file supported. | | MITM Relay | When the server can’t reach the source, a second server running this same script fetches it for you: A → asks Relay to fetch → A downloads from Relay → A optionally tells Relay to delete. Single or bulk. |

🗂️ Browse

| Tool | What it does | | — | — | | File Explorer | A single-folder view of the local server (classic file-manager style): click a folder to open it, or use the editable breadcrumb — click a crumb to jump, click the empty space to type a path (Enter to go) — plus an Up button. Upload here drops files into the open folder from PC, URL, or Relay (bulk, per-item progress, Stop, Retry). Each row’s actions live in one ⋯ menu: View as text, Edit as text, copy HTTP URL, rename, duplicate, move, delete. Multi-select bulk delete/copy. Shows size, modified time, and octal + symbolic permissions with plain-language tooltips. | | FTP Explorer | Connect to FTP / FTPS (TLS) / SFTP (self-signed certs OK) and browse the remote server the same single-folder way (editable breadcrumb + Up). Per-row ⋯ menu: View / Edit as text, rename, move, duplicate, delete, copy bare path or full HTTP URL, and save the file down to this server with a progress row. Upload into the folder you’re viewing from PC, URL, or Relay — bulk, with per-item progress, Stop, and Retry. Set an Initial Directory so a connection opens straight into /public_html (or anywhere). |

🔄 Sync

| Tool | What it does | | — | — | | FTPS Sync | Two panes, each independently Local or FTP/FTPS/SFTP, each with its own Root folder. Compare diffs the entire tree by each file’s path relative to its root (so /public_html/x.zip lines up with /w2w/x.zip), flagging identical / differs / only-left / only-right. Differing & one-side-only files are auto-selected. Sync in either direction — recreating sub-folders on the destination — via Direct (download+upload through this server), Plain FTP, Relay (MITM), or FXP (best-effort, falls back to Direct). The queue has a progress bar, per-item progress, Stop (whole queue or a single item), Retry (per item or all failed), and unchecks each file as it succeeds so a re-run only does what’s left. |

✏️ View & edit

🛠️ Tools

✨ Interface


How it works

upload.php is a single PHP file that serves both the HTML/CSS/JS front-end and a tiny JSON API from the same endpoint:

Everything is stateless: FTP credentials are passed per request and never stored server-side.


Requirements

Install (web)

  1. Download upload.php.
  2. Upload it (FTP/SFTP/cPanel File Manager) to the target directory.
  3. Open https://yoursite.com/upload.php.
  4. Use any mode from the sidebar.
  5. Self-Destruct when you’re done.

PHP CLI

php upload.php --url=<URL> --name=<filename> [options]

  --url=<URL>        Source URL                 (required)
  --name=<filename>  Destination filename       (required)
  --folder=<dir>     Sub-directory              (optional)
  --extract          Extract archive after download
  --wpinstall        WordPress installer mode
  --delete           Self-destruct
  --mitm=<URL>       Relay (MITM) server upload.php URL
  --mitm-keep        Keep the file on the relay after transfer
  --help             Show help

# Compare & Sync (recursive, by path relative to each root)
php upload.php --compare --left=<spec> --right=<spec> \
  [--sync --dir=lr|rl --method=direct|ftp|relay|fxp --relay=<URL> --yes]
#   <spec> = local:/abs/path | ftp://user:pass@host:port/root   (ftps:// sftp://)
# WordPress in one line
php upload.php --url=https://wordpress.org/latest.zip --name=wp.zip --wpinstall

# Relay around a block
php upload.php --mitm=https://relay.example.com/upload.php \
  --url=https://blocked-source.com/file.zip --name=file.zip

# Dry-run a sync, then perform it
php upload.php --compare --left=ftp://u:p@a.com/w2w --right=ftp://u:p@b.com/htdocs
php upload.php --compare --left=ftp://u:p@a.com/w2w --right=ftp://u:p@b.com/htdocs \
  --sync --dir=lr --method=direct --yes

Removing PHP limits & timeouts (big / slow files)

The script already calls set_time_limit(0) and raises limits at runtime, but many hosts override that. To move large files without 504 / Maximum execution time exceeded, raise limits at the server level. Find your active php.ini under PHP Info → Loaded Configuration File.

; php.ini  (or .user.ini in this folder on PHP-FPM/CGI shared hosting)
max_execution_time = 0
max_input_time = -1
memory_limit = 1024M
upload_max_filesize = 5G     ; only for "Upload from PC"
post_max_size = 5G           ; must be >= upload_max_filesize
default_socket_timeout = 3600
# .htaccess  (Apache + mod_php only)
php_value max_execution_time 0
php_value memory_limit 1024M
php_value upload_max_filesize 5G
php_value post_max_size 5G
# Nginx + PHP-FPM
client_max_body_size 5G;
fastcgi_read_timeout 3600s;
# php-fpm pool (www.conf):  request_terminate_timeout = 0

Note: Upload from URL, MITM Relay, FTP Save-to-server, and Sync stream through the server and are bound by max_execution_time, not upload_max_filesize. Only Upload from PC is bound by upload_max_filesize / post_max_size.

The full matrix (including mod_fcgid, mod_proxy_fcgi, and Apache Timeout) is in the in-app Help tab.

Self-Update (from GitHub Releases)

Update → Check for updates will:

  1. Query the GitHub Releases API for amirhp-com/upload-url-to-server and read the latest release tag (e.g. v3.0.0).
  2. Compare that tag to this file’s APP_VER with version_compare().
  3. If newer, download upload.php — preferring a release asset named upload.php, otherwise the raw file at that tag.
  4. Verify the download contains a newer APP_VER, back up the current file as upload.php.bak, then overwrite upload.php in place.

Needs: the file must be writable by PHP, and the server must reach api.github.com + raw.githubusercontent.com. Roll back anytime by restoring upload.php.bak.

Testing it: run an older copy (lower APP_VER) on a writable host and click Check for updates — it should offer the latest release and update on confirm. Or from the CLI on the server: curl -s https://api.github.com/repos/amirhp-com/upload-url-to-server/releases/latest | grep tag_name to confirm what the script will see.

Web endpoints

URL Action
upload.php App (all modes/tools).
upload.php?phpinfo=1 Full native phpinfo().
upload.php?delete=true Self-destruct.
POST _a=fetch / mitm_fetch / del_by_name MITM relay JSON API.
POST _a=fb_upload Upload PC/URL/relay file into the open local folder.
POST _a=ftp_upload Upload PC/URL/relay file into an FTP folder.
POST _a=read \| write \| ftp_read \| ftp_write Read/save a text file (local or FTP) for the in-browser editor.
POST _a=xfer_direct\|ftp\|relay\|fxp Compare-&-Sync transfer engine.
POST _a=check_update / do_update Self-update.

⚠️ Security

This tool is intentionally permissive — built to be uploaded, used, and immediately deleted. Treat it as a temporary utility, not part of your app.

Changelog

Full history: CHANGELOG.md. Recent highlights:

Contributing

PRs welcome. Keep it a single file — features land in upload.php. Branch off main, update CHANGELOG.md, and include a screenshot for UI changes.

License

MIT — see LICENSE.

Disclaimer

Provided as-is. The author accepts no responsibility for misuse, lost data, or security incidents from leaving this script accessible on a production server. Self-destruct it the moment you’re done.

— Lead developer: amirhp-com