Skip to content

Commit f625b9a

Browse files
author
Simeon Bartley
committed
Allow optional config file and handle target HTTP method override
1 parent 67e83a8 commit f625b9a

File tree

4 files changed

+98
-13
lines changed

4 files changed

+98
-13
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
.vscode/
33

44
vendor/
5+
config.php

Proxy.php

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,12 @@ class Proxy
9696
*/
9797
public static $HEADER_HTTP_PROXY_TARGET_URL = 'HTTP_PROXY_TARGET_URL';
9898

99+
/**
100+
* Name of the target HTTP method override header
101+
* @var string
102+
*/
103+
public static $HEADER_HTTP_PROXY_TARGET_HTTP_METHOD = 'HTTP_PROXY_TARGET_HTTP_METHOD';
104+
99105
/**
100106
* Line break for debug purposes
101107
* @var string
@@ -111,6 +117,7 @@ protected static function getSkippedHeaders()
111117
static::$HEADER_HTTP_PROXY_TARGET_URL,
112118
static::$HEADER_HTTP_PROXY_AUTH,
113119
static::$HEADER_HTTP_PROXY_DEBUG,
120+
static::$HEADER_HTTP_PROXY_TARGET_HTTP_METHOD,
114121
'HTTP_HOST',
115122
'HTTP_ACCEPT_ENCODING'
116123
];
@@ -227,6 +234,16 @@ public static function isResponseCodeOk($responseCode)
227234
return preg_match('/^[23]\d\d$/', $responseCode) === 1;
228235
}
229236

237+
/**
238+
* @return void
239+
*/
240+
public static function loadConfig()
241+
{
242+
if (file_exists('config.php')) {
243+
include 'config.php';
244+
}
245+
}
246+
230247
/**
231248
* @return string
232249
*/
@@ -293,6 +310,24 @@ protected static function getIncomingRequestHeaders($skippedHeaders = [])
293310
return $results;
294311
}
295312

313+
/**
314+
* Merge pull request https://github.com/zounar/php-proxy/pull/17/files
315+
* https://gist.github.com/yisraeldov/ec29d520062575c204be7ab71d3ecd2f
316+
*/
317+
protected static function build_post_fields($data, $existingKeys = '', &$returnArray = [])
318+
{
319+
if(($data instanceof CURLFile) or !(is_array($data) or is_object($data))) {
320+
$returnArray[$existingKeys]=$data;
321+
return $returnArray;
322+
}
323+
else {
324+
foreach ($data as $key => $item) {
325+
static::build_post_fields($item,$existingKeys?$existingKeys."[$key]":$key,$returnArray);
326+
}
327+
return $returnArray;
328+
}
329+
}
330+
296331
/**
297332
* @param string $targetURL
298333
* @return false|resource
@@ -302,10 +337,11 @@ protected static function createRequest($targetURL)
302337
$request = curl_init($targetURL);
303338

304339
// Set input data
305-
$requestMethod = strtoupper(static::ri($_SERVER['REQUEST_METHOD']));
306-
if ($requestMethod === "PUT" || $requestMethod === "PATCH") {
340+
$incomingRequestMethod = strtoupper(static::ri($_SERVER['REQUEST_METHOD']));
341+
342+
if ($incomingRequestMethod === 'PUT' || $incomingRequestMethod === 'PATCH') {
307343
curl_setopt($request, CURLOPT_POSTFIELDS, file_get_contents('php://input'));
308-
} elseif ($requestMethod === "POST") {
344+
} elseif ($incomingRequestMethod === 'POST') {
309345
$data = array();
310346

311347
if (!empty($_FILES)) {
@@ -324,18 +360,27 @@ protected static function createRequest($targetURL)
324360
}
325361
}
326362

327-
curl_setopt($request, CURLOPT_POSTFIELDS, $data + $_POST);
363+
curl_setopt($request, CURLOPT_POSTFIELDS, static::build_post_fields($data + $_POST));
328364
}
329365

330366
$headers = static::getIncomingRequestHeaders(static::getSkippedHeaders());
331-
332-
curl_setopt_array($request, [
367+
$curlSettings = [
333368
CURLOPT_FOLLOWLOCATION => true,
334369
CURLOPT_HEADER => static::$CURLOPT_HEADER,
335370
CURLOPT_RETURNTRANSFER => static::$CURLOPT_RETURNTRANSFER,
336371
CURLINFO_HEADER_OUT => true,
337372
CURLOPT_HTTPHEADER => $headers
338-
]);
373+
];
374+
375+
if ($incomingRequestMethod === 'POST') {
376+
// Check if target request should use a different HTTP method:
377+
$targetRequestMethod = strtoupper(static::ri($_SERVER[static::$HEADER_HTTP_PROXY_TARGET_HTTP_METHOD], $incomingRequestMethod));
378+
if ($targetRequestMethod !== $incomingRequestMethod) {
379+
$curlSettings[CURLOPT_CUSTOMREQUEST] = $targetRequestMethod;
380+
}
381+
}
382+
383+
curl_setopt_array($request, $curlSettings);
339384

340385
return $request;
341386
}
@@ -460,6 +505,7 @@ public static function run()
460505
if (!Proxy::isInstalledWithComposer()) {
461506
Proxy::checkCompatibility();
462507
Proxy::registerErrorHandlers();
508+
Proxy::loadConfig();
463509
$responseCode = Proxy::run();
464510

465511
if (Proxy::isResponseCodeOk($responseCode)) {

README.md

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
# Simple PHP Proxy
22

3-
This proxy script allows you to forward all HTTP/HTTPS requests to another server. Works for all common request types
4-
including GET, POST requests with files, PATCH and PUT requests. It has minimal set of requirements
5-
(PHP >=5.6, libcurl, gzip) which are available even on the smallest free hostings and has its own simple authorization
3+
This proxy script allows you to forward all HTTP/HTTPS requests to another server. Works for all common request types
4+
including GET, POST requests with files, PATCH and PUT requests. It has minimal set of requirements
5+
(PHP >=5.6, libcurl, gzip) which are available even on the smallest free hostings and has its own simple authorization
66
and cookie support.
77

88
## How to use
9+
910
* Copy the [Proxy.php](Proxy.php) script to publicly-accessible folder of a PHP web server (the script is standalone and has no PHP dependencies)
1011
* Make a cURL request targeting this script
1112
* Add **Proxy-Auth** header with auth key [found here](https://github.com/zounar/php-proxy/blob/master/Proxy.php#L40)
@@ -15,14 +16,16 @@ and cookie support.
1516
In order to protect using proxy by unauthorized users, consider changing `Proxy-Auth` token in [proxy source file](https://github.com/zounar/php-proxy/blob/master/Proxy.php#L40) and in all your requests.
1617

1718
## How to use (via composer)
18-
This might be useful when you want to redirect requests coming into your app.
19+
20+
This might be useful when you want to redirect requests coming into your app.
1921

2022
* Run `composer require zounar/php-proxy`
2123
* Add `Proxy::run();` line to where you want to execute it (usually into a controller action)
2224
* In this example, the script is in `AppController` - `actionProxy`:
25+
2326
```
2427
use Zounar\PHPProxy\Proxy;
25-
28+
2629
class AppController extends Controller {
2730
2831
public function actionProxy() {
@@ -34,6 +37,7 @@ This might be useful when you want to redirect requests coming into your app.
3437
}
3538
}
3639
```
40+
3741
* Make a cURL request to your web
3842
* In the example, it would be `http://your-web.com/app/proxy`
3943
* Add **Proxy-Auth** header with auth key [found here](https://github.com/zounar/php-proxy/blob/master/Proxy.php#L40)
@@ -44,7 +48,8 @@ In order to protect using proxy by unauthorized users, consider changing `Proxy-
4448
`Proxy::$AUTH_KEY = '<your-new-key>';` before `Proxy::run()`. Then change the token in all your requests.
4549
4650
## Usage example
47-
Following example shows how to execute GET request to https://www.github.com. Proxy script is at http://www.foo.bar/Proxy.php. All proxy settings are kept default, the response is automatically echoed.
51+
52+
Following example shows how to execute GET request to <https://www.github.com>. Proxy script is at <http://www.foo.bar/Proxy.php>. All proxy settings are kept default, the response is automatically echoed.
4853
4954
```php
5055
$request = curl_init('http://www.foo.bar/Proxy.php');
@@ -57,7 +62,29 @@ curl_setopt($request, CURLOPT_HTTPHEADER, array(
5762
curl_exec($request);
5863
```
5964

65+
## Overriding the Incoming HTTP Method
66+
67+
To override POST with a different HTTP method to the target, use the Proxy-Target-HTTP-Method header.
68+
69+
E.g. for PATCH:
70+
71+
```php
72+
$request = curl_init('http://www.foo.bar/Proxy.php');
73+
74+
curl_setopt($curl, CURLOPT_POST, true);
75+
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query(['key1' => 'value1']));
76+
77+
curl_setopt($request, CURLOPT_HTTPHEADER, array(
78+
'Proxy-Auth: Bj5pnZEX6DkcG6Nz6AjDUT1bvcGRVhRaXDuKDX9CjsEs2',
79+
'Proxy-Target-URL: https://www.github.com',
80+
'Proxy-Target-HTTP-Method: PATCH'
81+
));
82+
83+
curl_exec($request);
84+
```
85+
6086
## Debugging
87+
6188
In order to show some debug info from the proxy, add `Proxy-Debug: 1` header into the request. This will show debug info in plain-text containing request headers, response headers and response body.
6289

6390
```php
@@ -73,6 +100,7 @@ curl_exec($request);
73100
```
74101

75102
## Specifying User-Agent
103+
76104
Some sites may return different content for different user agents. In such case add `User-Agent` header to cURL request, it will be automatically passed to the request for target site. In this case it's Firefox 70 for Ubuntu.
77105

78106
```php
@@ -88,6 +116,7 @@ curl_exec($request);
88116
```
89117

90118
## Error 301 Moved permanently
119+
91120
It might occur that there's a redirection when calling the proxy (not the target site), eg. during `http -> https` redirection. You can either modify/fix the proxy URL (which is recommended), or add `CURLOPT_FOLLOWLOCATION` option before `curl_exec`.
92121

93122
```php
@@ -103,6 +132,7 @@ curl_exec($request);
103132
```
104133

105134
## Save response into variable
135+
106136
The default cURL behavior is to echo the response of `curl_exec`. In order to save response into variable, all you have to do is to add `CURLOPT_RETURNTRANSFER` cURL option.
107137

108138
```php

config-sample.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
static::$AUTH_KEY = 'Bj5pnZEX6DkcG6Nz6AjDUT1bvcGRVhRaXDuKDX9CjsEs2';
4+
static::$ENABLE_AUTH = true;
5+
static::$DEBUG = false;
6+
static::$TARGET_URL = '';
7+
8+
?>

0 commit comments

Comments
 (0)