Skip to content

PHProxy/phproxy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

167 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PHProxy

License: GPL v3 PHP Single file

A small, fast, self-contained web proxy in one PHP file. Drop index.php into any PHP 8.1+ web root and it just works — no Composer, no dependencies, no vendor/, no build step. Rename it to proxy.php if you like; the script self-references.

Originally developed on SourceForge 2002–2007, then abandoned. Revived and modernised here for PHP 8.5 with a new HTML5 interface, encrypted-URL mode, full cookie/header management, and an inline settings panel injected into proxied pages.

Highlights

  • Single file. index.php is the whole product. No files/ directory, no includes, no autoloader.
  • Encrypted address bar by default. Each URL is AES-CTR encrypted with a rotating session seed (128/192/256-bit, configurable). Logs / browser history / referers become useless once the seed rotates.
  • Inline settings panel on every proxied page — a full-viewport overlay with Options, Cookies, Headers, and a Trace tab showing the exact HTTP request and response headers for the current URL.
  • Full cookie management — host, path, expiry, Secure, HttpOnly, SameSite, all per-cookie. Add, edit, delete, switch between decoded / raw value display.
  • Custom outbound headers — any Name: Value you want forwarded to the upstream. Plus a User-Agent picker with modern presets.
  • Privacy options — strip tracking params (utm_*, fbclid, gclid, …), block third-party resources, block iframes / web fonts / media, send DNT: 1 and Sec-GPC: 1, strip <title> / <meta>.
  • HTML5 UI with light & dark themes (manual toggle + prefers-color-scheme).
  • Two URL forms?_proxurl=… or index.php/<url>. Works on any PHP host, no Apache rewrite rules required.
  • PHP 8.5 clean — zero deprecations under E_ALL. CI lints on 8.1 + 8.5.

What it is

PHProxy is a web HTTP/HTTPS proxy you visit in a browser. You type a URL, the server fetches it on your behalf, rewrites links in the response so they route back through the proxy, and serves the result. Conceptually similar to CGIProxy or the discontinued Glype, only smaller and more modern.

It runs anywhere PHP runs. The server needs to be able to reach the target sites — your access to PHProxy doesn't change.

What it isn't

PHProxy is a regex-based HTML rewriter. It does not run a headless browser, evaluate JavaScript, solve CAPTCHAs, or negotiate token-bound TLS.

Modern JS-heavy sites that gate access behind Cloudflare challenges or require live client-side script execution (Google search, GitHub UI, most social networks, modern SaaS apps) will not work through PHProxy — that's a fundamental limitation of the architecture, not a bug. Use a real headless-browser-based proxy for those.

Install

Docker (recommended)

git clone https://github.com/PHProxy/phproxy.git
cd phproxy
docker compose up -d

Open http://localhost:8080/ — done.

The image is based on the official php:8.5-apache and needs no extra extensions. The shipped docker-compose.yml bind-mounts the source for development; for production, remove the volumes: block so the container runs the baked-in copy of index.php.

Bash (any PHP 8.1+ host)

cd /var/www/html
curl -O https://raw.githubusercontent.com/PHProxy/phproxy/master/index.php

That's it — one file is the entire script. Visit http://your-host/.

Standalone shared hosting

Download index.php and upload via FTP / your host's file manager to the web root.

PHP's built-in dev server

For local use without Apache / nginx / Docker:

php -S 0.0.0.0:8080 index.php

Then open http://localhost:8080/. Single-threaded; fine for personal use, not for production.

Rename to proxy.php (or anything else)

index.php self-references via $_SERVER['PHP_SELF']. Just rename — forms, redirects, and asset URLs all stay correct:

mv index.php proxy.php

Requirements

  • PHP ≥ 8.1, tested on 8.5.
  • fsockopen() not disabled. Most shared hosts allow it.
  • openssl extension for HTTPS targets and for the encrypted-URL mode (both are on by default in mainstream PHP builds).
  • zlib extension for output compression — optional.
  • file_uploads = On if you want POSTed file uploads to flow through.

URL forms

PHProxy accepts the target URL in two shapes:

Form Example
Query (default) https://proxy.example/?_proxurl=<encoded>
Path via index.php https://proxy.example/index.php/https://target/

Both work on any web server, no rewrite rules needed.

Anonymity

PHProxy is anonymous-by-default. The outbound request headers are built from a known-safe whitelist (method, path, Host, User-Agent, Accept, optional Referer, Cookie, Authorization, plus POST-body headers). The proxy never forwards X-Forwarded-For, X-Real-IP, Via, or Forwarded to the upstream — targets see this server's IP only.

For extra cover, the Encrypted URL-encoding mode (on by default) wraps each URL in an AES-CTR ciphertext keyed off a random per-session seed stored in a 1-hour cookie. Once the seed rotates, any URL that ended up in an access log, browser history, or Referer header becomes unusable — the ciphertext is mathematically meaningless without the now-gone key.

Both the seed lifetime and the key length (AES-128 / 192 / 256) are configurable from the Options → Address bar tab, along with a Rotate now button for immediate re-keying.

If you also want to hide the client User-Agent, set it to - in the Headers tab — no User-Agent header gets forwarded.

JSON API (?api=fetch)

POST a JSON envelope to index.php?api=fetch and the proxy makes the HTTP request for you, then returns either a JSON envelope (default) or the raw upstream response. No cookies, no flag bitfield, no encryption — just an HTTP fetch on your behalf, driven entirely by the JSON body.

curl -X POST 'https://proxy.example/index.php?api=fetch' \
  -H 'Content-Type: application/json' \
  -d '{
    "url": "https://api.github.com/repos/PHProxy/phproxy",
    "headers": { "Accept": "application/json", "User-Agent": "MyClient/1.0" },
    "cookies": { "session": "abc123" }
  }'

Request body

Field Type Default Notes
url string Required. http:// or https://.
method string GET Any HTTP verb. POST / PUT / PATCH / DELETE may carry a body.
headers object {} Map of Name: value to forward. Name must match [A-Za-z0-9-]+. CRLF-injection is filtered. Host, Connection, Content-Length are set by the proxy and not overridable.
cookies object {} Map of cookie name → value. Sent as a single Cookie: header.
body string "" Request body. Only attached for POST / PUT / PATCH / DELETE. If you don't set Content-Type, application/octet-stream is assumed.
timeout int 30 Seconds. Clamped to [1, 120].
follow_redirects bool false When true, the proxy follows 3xx Location headers.
max_redirects int 5 Clamped to [0, 10].
verify_ssl bool true Set false to accept self-signed / mismatched certs (use with care).
return string json json returns a structured envelope, raw streams the upstream response verbatim.

JSON response

{
  "ok": true,
  "url": "http://example.com/",
  "status": 200,
  "status_text": "OK",
  "headers": {
    "Date": "Thu, 28 May 2026 04:38:33 GMT",
    "Content-Type": "text/html",
    "Server": "cloudflare"
  },
  "set_cookies": [
    { "name": "sid", "value": "abc", "domain": ".example.com", "path": "/",
      "expires": "", "max_age": null, "secure": true, "httponly": true,
      "samesite": "Lax" }
  ],
  "redirects": [
    { "from": "...", "status": 302, "to": "..." }
  ],
  "body": "<!doctype html>…",
  "body_encoding": "utf8",
  "duration_ms": 61
}
  • body is the upstream response body. If it's valid UTF-8 (HTML, JSON, text, etc.), body_encoding is "utf8" and the bytes go directly into the JSON string. If it's binary (images, PDFs, octet streams), body_encoding is "base64" and body holds a Base64 string.
  • redirects is the chain of 3xx hops when follow_redirects was set.
  • Chunked transfer-encoding and gzip/deflate content-encoding are decoded automatically.

Raw mode

"return": "raw" makes the proxy emit the upstream response verbatim — the status code, the original Content-Type, the original body. Useful for downloading binary files through the proxy without Base64 round-tripping:

curl -X POST 'https://proxy.example/index.php?api=fetch' \
  -H 'Content-Type: application/json' \
  -d '{"url":"https://example.com/img.png","return":"raw"}' \
  -o img.png

Errors

Errors come back as JSON with "ok": false:

{"ok": false, "error": "Target host blacklisted or unparseable", "host": "127.0.0.1"}
{"ok": false, "error": "Connection timed out", "url": "..."}
{"ok": false, "error": "Too many redirects", "url": "...", "redirects": [...]}
HTTP status Cause
400 Missing url, target host blacklisted, malformed JSON
405 Non-POST request
200 Always — including for upstream 4xx/5xx; check status in the envelope

Security notes

  • The same SSRF guard the browser flow uses applies: requests to 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, localhost, and ::1 are rejected.
  • Header names are restricted to [A-Za-z0-9-]+ and CRLF in values is stripped to prevent request smuggling.
  • No authentication is built in — if you expose this publicly, put it behind your own auth layer (HTTP basic, an API key check at the top of the script, IP allowlist, …) or you've just shipped an open proxy.

Configuration

All options are toggleable per-session via the inline panel (gear icon in the top bar of every proxied page). They persist in cookies. Defaults are sane; you typically don't need to touch them.

For server-side defaults, the top of index.php has a $_config / $_flags / $_frozen_flags block — edit and you're done. Freezing a flag in $_frozen_flags removes it from the UI entirely.

Bugs and limitations

PHProxy inherits a few historical quirks from PHP's request handling, most notably the legacy dot→underscore conversion on incoming variable names (a register_globals-era footgun). Cookie names are restored to dotted form internally; URL query parameters are URL-encoded into a single carrier variable so this rarely matters in practice.

Things that simply will not work, ever, by design:

  • JavaScript-heavy sites. PHProxy doesn't run JS. Sites that build their UI client-side (everything from Gmail to most React/Vue apps) will partially work at best.
  • Cloudflare-gated / CAPTCHA-protected sites. No browser fingerprint, no challenge-solving.
  • Token-bound TLS (browser-only TLS extensions some sites require).
  • FTP / SFTP / WebDAV. HTTP/HTTPS only.
  • WebSockets, WebRTC, Server-Sent Events. Synchronous fetch only.
  • Flash, Java applets, plug-ins. Content fetched from inside these is invisible to the URL rewriter.

Support

License

GNU GPL v3 — see LICENSE.md.

Original authorship: A.A. (whitefyre), 2002–2007. Revival and modernisation (2025–2026): see the commit history.

About

PHP based web proxy. Initially developed by whitefyre

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages