proxy.php

Simple redirection proxy
git clone git://git.finwo.net/misc/proxy.php
Log | Files | Refs | README

commit 6b38ad0dc0653c0bf097b64588b9e1c730d6d2c7
Author: Robin Bron <robin@finwo.nl>
Date:   Thu, 22 Dec 2016 14:51:59 +0100

Project init

Diffstat:
A.gitignore | 2++
Acomposer.json | 20++++++++++++++++++++
Acomposer.lock | 137+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aconfig/domains.yml | 4++++
Aconfig/index.php | 27+++++++++++++++++++++++++++
Adocs/.htaccess | 6++++++
Adocs/index.php | 41+++++++++++++++++++++++++++++++++++++++++
Aext/all.php | 11+++++++++++
Aext/hash.php | 21+++++++++++++++++++++
Aext/hash_algos.php | 8++++++++
Aext/mime_content_type.php | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aext/startsWith.php | 5+++++
Asrc/Finwo/Request.php | 151++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
13 files changed, 510 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1,2 @@ +.idea +vendor diff --git a/composer.json b/composer.json @@ -0,0 +1,20 @@ +{ + "name": "finwo/proxy", + "authors": [ + { + "name": "Robin Bron", + "email": "robin@finwo.nl" + } + ], + "autoload": { + "files": [ + "ext/all.php" + ], + "psr-4": { "": "src/" } + }, + "require": { + "mustangostang/spyc": "^0.6.1", + "finwo/property-accessor": "^0.1.4", + "jakeasmith/http_build_url": "^1.0" + } +} diff --git a/composer.lock b/composer.lock @@ -0,0 +1,137 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "hash": "bd593b7914da047594ca84f8572f646a", + "content-hash": "bcfdfa1717dfe7a6b695b8cbaba9a88c", + "packages": [ + { + "name": "finwo/property-accessor", + "version": "v0.1.4", + "source": { + "type": "git", + "url": "https://github.com/finwo/property-accessor.git", + "reference": "b87005786dbdd368628d586b9568db6e8aec11bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/finwo/property-accessor/zipball/b87005786dbdd368628d586b9568db6e8aec11bc", + "reference": "b87005786dbdd368628d586b9568db6e8aec11bc", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Finwo\\PropertyAccessor\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "authors": [ + { + "name": "Robin Bron", + "email": "robin@finwo.nl" + } + ], + "time": "2016-05-12 11:49:48" + }, + { + "name": "jakeasmith/http_build_url", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/jakeasmith/http_build_url.git", + "reference": "15bdd686e5178ddfa3e88de60fa585adffb292bb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jakeasmith/http_build_url/zipball/15bdd686e5178ddfa3e88de60fa585adffb292bb", + "reference": "15bdd686e5178ddfa3e88de60fa585adffb292bb", + "shasum": "" + }, + "require-dev": { + "phpunit/phpunit": "~3.7" + }, + "type": "library", + "autoload": { + "files": [ + "src/http_build_url.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jake A. Smith", + "email": "theman@jakeasmith.com" + } + ], + "description": "Provides functionality for http_build_url() to environments without pecl_http.", + "time": "2015-05-06 12:27:20" + }, + { + "name": "mustangostang/spyc", + "version": "0.6.1", + "source": { + "type": "git", + "url": "https://github.com/mustangostang/spyc.git", + "reference": "022532641d61d383fd3ae666982bd46e61e5915e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mustangostang/spyc/zipball/022532641d61d383fd3ae666982bd46e61e5915e", + "reference": "022532641d61d383fd3ae666982bd46e61e5915e", + "shasum": "" + }, + "require": { + "php": ">=5.3.1" + }, + "require-dev": { + "phpunit/phpunit": "4.3.*@dev" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.5.x-dev" + } + }, + "autoload": { + "files": [ + "Spyc.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "mustangostang", + "email": "vlad.andersen@gmail.com" + } + ], + "description": "A simple YAML loader/dumper class for PHP", + "homepage": "https://github.com/mustangostang/spyc/", + "keywords": [ + "spyc", + "yaml", + "yml" + ], + "time": "2016-10-21 00:03:34" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} diff --git a/config/domains.yml b/config/domains.yml @@ -0,0 +1,4 @@ +domains: + images.islive.robin: + scheme: http + host: images.islive.nl diff --git a/config/index.php b/config/index.php @@ -0,0 +1,27 @@ +<?php + +$config = array(); + +// First load yml files +foreach (glob(__DIR__ . '/**.yml') as $file) { + $config = array_merge($config, \Spyc::YAMLLoad($file)); +} + +$blacklist = array( + '/.*index.php/', +); + +foreach (glob(__DIR__ . '/**.php') as $file) { + foreach ($blacklist as $regex) { + if (preg_match($regex, $file)) { + continue 2; + } + } + $config = array_merge($config, require($file)); +} + +if (isset($config['_ENV'])) { + $_ENV = array_merge($_ENV, $config['_ENV']); +} + +return $config; diff --git a/docs/.htaccess b/docs/.htaccess @@ -0,0 +1,6 @@ +RewriteEngine On + +RewriteCond %{REQUEST_FILENAME} !-d +RewriteCond %{REQUEST_FILENAME} !-f + +RewriteRule . index.php diff --git a/docs/index.php b/docs/index.php @@ -0,0 +1,41 @@ +<?php + +// Start autoloader +require_once(__DIR__.'/../vendor/autoload.php'); + +// Useful tool +$accessor = new \Finwo\PropertyAccessor\PropertyAccessor(); + +// Fetch what we're hosting +$domain = \Finwo\Request::domain(); +$config = require(__DIR__.'/../config/index.php'); +$domainSettings = $accessor->getSafe($config, sprintf('domains|%s', $domain)); + +$headers = \Finwo\Request::headers(); +$url = http_build_url(array_merge(parse_url(\Finwo\Request::fulluri()), $domainSettings)); + +unset($headers['Host']); +unset($headers['Cookie']); + +// Pre-process the headers +foreach ($headers as $name => &$header) { + $header = sprintf("%s: %s", $name, $header); +} + +// Make request +$rawResult = \Finwo\Request::transmit($url, array( + 'headers' => $headers +)); + +// 'Parse' result +$result = explode("\r\n\r\n", $rawResult, 2); +$resultHeaders = explode("\r\n",array_shift($result)); +$resultBody = array_shift($result); + +// Transmit headers +foreach ($resultHeaders as $resultHeader) { + header($resultHeader); +} + +// Transmit body +print($resultBody); diff --git a/ext/all.php b/ext/all.php @@ -0,0 +1,11 @@ +<?php + +/** + * Include all files in the current directory + */ +foreach (glob(__DIR__.'/*.php') as $filename) { + if ($filename==__FILE__) { + continue; + } + include_once $filename; +} diff --git a/ext/hash.php b/ext/hash.php @@ -0,0 +1,21 @@ +<?php + +if (!function_exists('hash')) { + function hash($algo, $input, $raw_output = false) + { + if (!is_string($input)) { + $input = http_build_query($input); + } + $hash = 0; + if (!strlen($input)) { + return $hash; + } + $input = str_split($input); + while (count($input)) { + $character = ord(array_shift($input)); + $hash = (($hash << 5) - $hash) + $character; + } + + return $raw_output ? $hash : dechex($hash); + } +} diff --git a/ext/hash_algos.php b/ext/hash_algos.php @@ -0,0 +1,8 @@ +<?php + +if (!function_exists('hash_algos')) { + function hash_algos() + { + return array( 'none' ); + } +} diff --git a/ext/mime_content_type.php b/ext/mime_content_type.php @@ -0,0 +1,77 @@ +<?php + +if(!function_exists('mime_content_type')) { + + function mime_content_type($filename) { + + $mime_types = array( + + 'txt' => 'text/plain', + 'htm' => 'text/html', + 'html' => 'text/html', + 'php' => 'text/html', + 'css' => 'text/css', + 'js' => 'application/javascript', + 'json' => 'application/json', + 'xml' => 'application/xml', + 'swf' => 'application/x-shockwave-flash', + 'flv' => 'video/x-flv', + + // images + 'png' => 'image/png', + 'jpe' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'gif' => 'image/gif', + 'bmp' => 'image/bmp', + 'ico' => 'image/vnd.microsoft.icon', + 'tiff' => 'image/tiff', + 'tif' => 'image/tiff', + 'svg' => 'image/svg+xml', + 'svgz' => 'image/svg+xml', + + // archives + 'zip' => 'application/zip', + 'rar' => 'application/x-rar-compressed', + 'exe' => 'application/x-msdownload', + 'msi' => 'application/x-msdownload', + 'cab' => 'application/vnd.ms-cab-compressed', + + // audio/video + 'mp3' => 'audio/mpeg', + 'qt' => 'video/quicktime', + 'mov' => 'video/quicktime', + + // adobe + 'pdf' => 'application/pdf', + 'psd' => 'image/vnd.adobe.photoshop', + 'ai' => 'application/postscript', + 'eps' => 'application/postscript', + 'ps' => 'application/postscript', + + // ms office + 'doc' => 'application/msword', + 'rtf' => 'application/rtf', + 'xls' => 'application/vnd.ms-excel', + 'ppt' => 'application/vnd.ms-powerpoint', + + // open office + 'odt' => 'application/vnd.oasis.opendocument.text', + 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', + ); + + $ext = strtolower(@array_pop(explode('.',$filename))); + if (array_key_exists($ext, $mime_types)) { + return $mime_types[$ext]; + } + elseif (function_exists('finfo_open')) { + $finfo = finfo_open(FILEINFO_MIME); + $mimetype = finfo_file($finfo, $filename); + finfo_close($finfo); + return $mimetype; + } + else { + return 'application/octet-stream'; + } + } +} diff --git a/ext/startsWith.php b/ext/startsWith.php @@ -0,0 +1,5 @@ +<?php + +function startsWith($haystack, $needle) { + return !strlen($needle) || (substr($haystack, 0, strlen($needle)) == $needle); +} diff --git a/src/Finwo/Request.php b/src/Finwo/Request.php @@ -0,0 +1,151 @@ +<?php + +namespace Finwo; + +/** + * Class Request + * + * Handles some minor common functions + */ +class Request +{ + static function uri() + { + return $_SERVER['REQUEST_URI']; + } + + static function fulluri() + { + return http_build_url(array( + 'scheme' => Request::scheme(), + 'host' => Request::domain(), + 'path' => Request::uri(), + )); + } + + static function safeuri() + { + return urlencode(Request::fulluri()); + } + + static function scheme() + { + static $cache = null; + if (is_null($cache)) { + if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) { + $cache = $_SERVER['HTTP_X_FORWARDED_PROTO']; + } elseif (isset($_SERVER['REQUEST_SCHEME'])) { + $cache = $_SERVER['REQUEST_SCHEME']; + } elseif (intval($_SERVER['SERVER_PORT']) == 443) { + $cache = 'https'; + } else { + $cache = 'http'; + } + } + + return $cache; + } + + static function domain() + { + static $cache = null; + if (is_null($cache)) { + if (isset($_SERVER['HTTP_HOST'])) { + $cache = $_SERVER['HTTP_HOST']; + } elseif (isset($_SERVER['SERVER_NAME'])) { + $cache = $_SERVER['SERVER_NAME']; + } else { + $cache = 'islive.nl'; + } + } + + return $cache; + } + + /** + * Transmits a request to another host + * + * If returning response, beware that it's raw + * (includes headers, transfer encoding, etc) + * + * @param $url + * @param array $options + * + * @return bool|string + */ + static function transmit($url, $options = array()) + { + // Default options + $options = array_merge(array( + 'return' => true, + 'method' => 'GET', + 'headers' => array(), + 'body ' => null, + ), $options); + + // Disect the url + $parts = parse_url($url); + + // Convert the body if needed + if (in_array(gettype($options['body']), array( 'array', 'object' ))) { + $options['body'] = http_build_query($options['body']); + array_push($options['headers'], "Content-Type: application/x-www-form-urlencoded"); + } + + // Open a connection to the target host + $fp = fsockopen($parts['host'], isset($parts['port']) ? $parts['port'] : 80, $errno, $errstr, 30); + if (!$fp) { + return false; + } + + // Construct message to the host + $out = strtoupper($options['method']) . " " . $parts['path'] . (isset($parts['query']) ? '?' . $parts['query'] : '') . " HTTP/1.0\r\n"; + $out .= "Host: " . $parts['host'] . "\r\n"; + if (count($options['headers'])) { + $out .= \implode("\r\n", $options['headers']) . "\r\n"; + } + $out .= is_string($options['body']) ? sprintf("Content-Length: %s\r\n", strlen($options['body'])) : ''; + $out .= "Connection: Close\r\n\r\n"; + $out .= is_string($options['body']) ? $options['body'] : ''; + + // Send request + fwrite($fp, $out); + + // What we'll return + $result = true; + + // Return data if asked to + if ($options['return']) { + $result = stream_get_contents($fp); + } + + // Close the socket again + fclose($fp); + + // Return answer + return $result; + } + + /** + * Returns the request headers + * + * @return array + */ + static function headers() + { + // Fetch given headers + $headers = []; + foreach ($_SERVER as $name => $value) { + if (startsWith($name, 'HTTP_')) { + $name = explode('_', $name); + array_shift($name); + $name = implode('-', array_map(function ($element) { + return ucfirst(strtolower($element)); + }, $name)); + $headers[$name] = $value; + } + } + + return $headers; + } +}