Skip to content

Instantly share code, notes, and snippets.

@ariankordi
Last active December 13, 2022 17:52
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ariankordi/e987c6c47500ce8583ed6afc869953fb to your computer and use it in GitHub Desktop.
Save ariankordi/e987c6c47500ce8583ed6afc869953fb to your computer and use it in GitHub Desktop.
Reverse proxy to a UNIX socket with PHP, for when you are running Go web apps on cPanel servers or something like that LOL (complete with header and multipart POST form parsing!) Doesn't work with WebSocket though.
<?php
// This works best on Apache, and if you have enable_post_data_reading off.
// Set "php_flag enable_post_data_reading off" in your htaccess. It'll avoid having to parse multipart forms.
// enter the sock to connect to here
const SOCK_TO_CONNECT_TO = './run.sock';
// Close the session right now, because it might make everything faster, and we don't know how long the response will last for.
session_write_close();
$sock = @stream_socket_client('unix://' . SOCK_TO_CONNECT_TO, $errno, $errstr);
if(!$sock) {
http_response_code(502);
header('Content-Type: text/plain');
exit('errno ' . $errno . ': ' . $errstr);
}
// make raw http request into $request
$request = $_SERVER['REQUEST_METHOD'] . ' ' . $_SERVER['REQUEST_URI'] . ' ' . $_SERVER['SERVER_PROTOCOL'] . "\r\n";
$request .= "Connection: close\r\n";
$request .= 'X-Forwarded-For: ' . $_SERVER['REMOTE_ADDR'] . "\r\n";
$request .= 'X-Forwarded-Proto: ' . (!empty($_SERVER['HTTPS']) ? 'https' : 'http') . "\r\n";
fwrite($sock, $request);
if(function_exists('getallheaders')) {
// getallheaders exists with apache but not some servers
foreach(getallheaders() as $name => $value) {
if($name === 'Connection' || $name === 'X-Https') {
continue;
}
$header = $name . ': ' . $value . "\r\n";
fwrite($sock, $header);
}
} else {
// polyfill if there is no getallheaders
foreach($_SERVER as $name => $value) {
if(substr($name, 0, 5) === 'HTTP_') {
// strip http_ part, replace underscores with dashes
$name = str_replace('_', '-', substr($name, 5));
if($name === 'CONNECTION') {
continue;
}
$header = $name . ': ' . $value . "\r\n";
fwrite($sock, $header);
}
}
}
fwrite($sock, "\r\n");
// read POST data
$input = fopen('php://input', 'r');
while(!feof($input)) {
$data = fgets($input, 1024);
if(empty($data) && (!empty($_POST) || !empty($_FILES))) {
// polyfill for if enable_post_data_reading is on, start parsing $_POST to a "raw" post data equivalent
// see what content type is there (there should be a content type at this point, if php is parsing post data)
// actually, i found out that only multipart/form-data should be parsed here?
// also see if it is long enough to have a boundary
if(substr($_SERVER['HTTP_CONTENT_TYPE'], 0, 19) === 'multipart/form-data' && strlen($_SERVER['HTTP_CONTENT_TYPE']) > 30) {
$boundary = '--' . substr($_SERVER['HTTP_CONTENT_TYPE'], 30);
foreach($_POST as $name => $value) {
// key/values...
$part = $boundary . "\r\n" . 'Content-Disposition: form-data; name="' . $name . '"' . "\r\n\r\n" . $value . "\r\n";
fwrite($sock, $part);
}
// files
$out = fopen('php://stdout', 'w');
foreach($_FILES as $name => $value) {
$part = $boundary . "\r\n" . 'Content-Disposition: form-data; name="' . $name . '"; filename="' . $value['name'] . '"' . "\r\nContent-Type: " . $value['type'] . "\r\n\r\n";
fwrite($sock, $part);
$file = fopen($value['tmp_name'], 'r');
// $file is sometimes falsey but i can't reproduce it
if($file) {
while(!feof($file)) {
$data = fgets($file, 1024);
fwrite($sock, $data);
}
}
fwrite($sock, "\r\n");
fclose($file);
}
$part = $boundary . '--';
fwrite($sock, $part);
}
break;
}
fwrite($sock, $data);
}
fclose($input);
fwrite($sock, "\r\n");
// start parsing response
$is_done_with_headers = false;
while(!feof($sock)) {
if(!$is_done_with_headers) {
$header = fgets($sock, 1024);
if($header === "\r\n") {
$is_done_with_headers = true;
continue;
}
header($header);
continue;
}
echo fgets($sock, 1024);
}
fclose($sock);
@alandipert
Copy link

Brilliant!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment