Skip to content

Commit 894765a

Browse files
Contribution by Dino Ciuffetti for the PHP proxy with transparent signin. This allow everybody that own a PHP hosting to use OrientDB database like NuvolaBase.com
1 parent f47f6b3 commit 894765a

1 file changed

Lines changed: 236 additions & 0 deletions

File tree

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
<?php
2+
/**
3+
* Copyright (c) 2011 Dino Ciuffetti, NuvolaBase, TuxWeb S.r.l.
4+
*
5+
* ajax_proxy is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU Lesser General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* ajax_proxy is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public License
16+
* along with ajax_proxy. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
/**
20+
* Welcome to ajax_proxy, the simple HTTP Proxy for cross domain ajax requests.
21+
* This is a simple and secure PHP script that aims to resolve the cross domain security
22+
* enforcement imposed by web browsers. That is done by handling the cross domain javascript
23+
* HTTP request locally. In other words, the browser will let your javascript code to GET/POST
24+
* the given uri because it's your PHP driven server to accomplish with the request to the real server.
25+
*
26+
* For security reasons ajax_proxy do not let your javascript to choose the destination server
27+
* at runtime, but that's imposed on a configuration variable.
28+
* We must do this because otherwise your server would become an open proxy, and that is absolutely not desiderable!
29+
*
30+
* The script is also good with HTTP GET/POST/PUT/DELETE requests, for example for REST.
31+
*/
32+
33+
// You have to define here your real destination server without a trailing slash following this syntax:
34+
// <http|https>://<user>:<password>@<host>
35+
// Example: http://jack:[email protected]
36+
$real_destination_host = "https://user:[email protected]";
37+
38+
// We split the response into small chunks (in kbyte) so that the browser (javascript) can parse data while we are
39+
// reading the response from the server. Do not set it too small, 32 is ok for most cases!
40+
$chunk_size_kb = 32;
41+
42+
// User-Agent for the client side of the proxy. The real server will see this User-Agent instead of the client's one.
43+
// If this is left empty, the real server will see the User-Agent of the client.
44+
// $user_agent = "ajax_proxy HTTP agent";
45+
$user_agent = 'ajax_proxy cross domain PHP script';
46+
47+
// Server side request timeout in ms. If the browser (javascript) does not complete the request into this timeout the
48+
// connection with the client will be aborted. Please note that timeout cannot exceed PHP limits (php.ini).
49+
// If the variable is setted to 0 the timeout will be disabled.
50+
$request_client_timeout_ms = 6000;
51+
52+
// Client side response timeout in ms. If the destination server does not complete the response into this timeout the
53+
// connection with the server will be aborted. Please note that timeout cannot exceed PHP limits (php.ini).
54+
// If the variable is setted to 0 the timeout will be disabled.
55+
// WARNING: you may send partial data to the browser (javascript) in case of timeout
56+
// (the connection will be closed before finish to complete the read from the destination server).
57+
$response_server_timeout_ms = 6000;
58+
59+
60+
// CLIENT SIDE PROXY (open and handle the request to the backend real HTTP server and return back headers and body)
61+
function send_datachunk_to_client($arg) { // this callback is assigned by ob_start and invoked on every ob_flush
62+
// if we like it we can modify the data before sending it to the browser... but now we don't.
63+
return false;
64+
}
65+
function check_timeout($handle) { // check if there was a timeout error with the backend server
66+
$info = @stream_get_meta_data($handle);
67+
if ($info['timed_out']) {
68+
return true; // there was a timeout
69+
} else {
70+
return false; // there was not a timeout
71+
}
72+
}
73+
function strip_header($h) { // strip out any HTTP backend server's response header we don't like
74+
$to_be_stripped = array("Content-Length", "Connection", "Accept-Ranges", "Date");
75+
$name = substr($h, 0, strpos($h, ":"));
76+
if ($name == "") { // this is a header without ":", return it full
77+
return $h;
78+
}
79+
if (in_array($name, $to_be_stripped)) { // this is a header that we don't like so we return false
80+
return false;
81+
}
82+
$value = substr($h, strpos($h, ":")+2);
83+
return "$name: $value"; // that's a header we like (may be...) so we are returning it
84+
}
85+
function handle_response_timeout($type) { // handle a timeout error. If type == 0 the problem is on header, else it's on body
86+
switch ($type) {
87+
case 0: // timeout connecting or reading headers
88+
generate_http_error("HTTP/1.1 500 Timeout waiting for destination server");
89+
break;
90+
default:
91+
case 1: // timeout on body read
92+
generate_http_error("HTTP/1.1 500 Timeout waiting for destination server");
93+
break;
94+
}
95+
return true;
96+
}
97+
function parse_headers($handle) { // here we parse HTTP backend server's response headers
98+
$info = @stream_get_meta_data($handle);
99+
if ($info['timed_out']) { // there was a connection/read timeout
100+
handle_response_timeout(0);
101+
return false;
102+
}
103+
for ($i=0; $i<count($info['wrapper_data']); $i++) { // for each response header, check if we like it or not
104+
$h = $info['wrapper_data'][$i];
105+
$hd = strip_header($h);
106+
if ($hd) { // we like it, and so we decide to pass it to the browser
107+
Header ($hd);
108+
}
109+
}
110+
// we add our custom headers here
111+
Header ("Connection: close");
112+
return $info;
113+
}
114+
function proxypass($url, $method, $parameters, $header_timeout_ms, $body_timeout_ms) {
115+
global $user_agent, $chunk_size_kb;
116+
117+
$opts = array();
118+
$opts['http'] = array();
119+
$opts['http']['method'] = $method;
120+
if ($user_agent == "") { // setting the user agent according to the user choise
121+
$opts['http']['user_agent'] = $_SERVER['HTTP_USER_AGENT'];
122+
} else {
123+
$opts['http']['user_agent'] = $user_agent;
124+
}
125+
if (($method == "POST") || ($method == "PUT") || ($method == "DELETE")) {
126+
$opts['http']['content'] = http_build_query($parameters);
127+
}
128+
129+
$context = stream_context_create($opts);
130+
131+
$handle = @fopen($url, "rb", false, $context);
132+
if (!$handle) {
133+
@fclose($handle);
134+
generate_http_error("HTTP/1.1 500 Backend Server Error");
135+
echo ": caused by: ";
136+
echo $http_response_header[0];
137+
// echo " opening url: $url\n"; // security issue here because the password is printed in the output
138+
echo " opening url: " . parse_url($url, PHP_URL_SCHEME) . "://_hidden_server_" . parse_url($url, PHP_URL_PATH);
139+
ob_end_flush();
140+
flush();
141+
exit;
142+
}
143+
if ($header_timeout_ms > 0) {
144+
@stream_set_timeout($handle, 0, $header_timeout_ms * 1000);
145+
}
146+
$info = parse_headers($handle);
147+
if ($body_timeout_ms > 0) {
148+
@stream_set_timeout($handle, 0, $body_timeout_ms * 1000);
149+
}
150+
while (!feof($handle)) {
151+
$res = @fread($handle, $chunk_size_kb); // read a chunk of data from the backend server
152+
if ($res === FALSE) {
153+
//generate_http_error("HTTP/1.1 500 Backend Server Error");
154+
ob_end_flush();
155+
flush();
156+
exit;
157+
}
158+
$i = check_timeout($handle); // check if there was a timeout error
159+
if (!$i) { // good! The server's response chunk was in time with our need
160+
print $res; // send it to the client
161+
ob_flush(); // be sure to send it to the client
162+
flush(); // be extra sure to send it to the client :-)
163+
} else { // mhhh... :-( there was a timeout reading data
164+
handle_response_timeout(1);
165+
break;
166+
}
167+
}
168+
@fclose($handle);
169+
ob_end_flush();
170+
}
171+
// END CLIENT SIDE PROXY
172+
173+
// SERVER SIDE PROXY (accept and handle the client request (browser/javascript)
174+
function generate_http_error($err) {
175+
Header ($err);
176+
echo "\n";
177+
echo $err;
178+
}
179+
function get_client_headers() { // here we get client (browser, javascript) headers
180+
$headers = array();
181+
foreach ($_SERVER as $k => $v) {
182+
if (substr($k, 0, 5) == "HTTP_") {
183+
$k = str_replace('_', ' ', substr($k, 5));
184+
$k = str_replace(' ', '-', ucwords(strtolower($k)));
185+
$headers[$k] = $v;
186+
}
187+
}
188+
return $headers;
189+
}
190+
function parse_client_parameters($method) { // parsing a client HTTP request
191+
switch ($method) {
192+
case "POST":
193+
return $_POST;
194+
break;
195+
case "PUT":
196+
return $_POST;
197+
break;
198+
case "GET":
199+
return $_GET;
200+
break;
201+
case "HEAD":
202+
return $_GET;
203+
break;
204+
case "DELETE":
205+
return $_GET;
206+
break;
207+
}
208+
}
209+
// END SERVER SIDE PROXY
210+
211+
212+
// SCRIPT STARTS HERE
213+
ob_start("send_datachunk_to_client", $chunk_size_kb);
214+
ini_set('user_agent', "MyUserAgent\r\nX-Powered-By: dAm2K");
215+
if ($chunk_size_kb < 1) $chunk_size_kb = 1;
216+
$chunk_size_kb = $chunk_size_kb * 1024;
217+
218+
// SERVER SIDE PROXY
219+
$client_headers = array();
220+
$client_headers = get_client_headers();
221+
$parameters = parse_client_parameters($_SERVER['REQUEST_METHOD']);
222+
if ($response_server_timeout_ms > 0) {
223+
ini_set("max_execution_time", $response_server_timeout_ms / 1000);
224+
ini_set("max_input_time", $response_server_timeout_ms / 1000);
225+
}
226+
227+
// CLIENT SIDE PROXY
228+
$url = $real_destination_host . $_SERVER['REQUEST_URI'];
229+
$url = str_replace($_SERVER["SCRIPT_NAME"], "", $url);
230+
$header_timeout_ms = $response_server_timeout_ms;
231+
$body_timeout_ms = $response_server_timeout_ms;
232+
233+
// SENDING DATA TO THE SERVER AND GETTING BACK DATA FOR THE CLIENT
234+
proxypass($url, $_SERVER['REQUEST_METHOD'], $parameters, $header_timeout_ms, $body_timeout_ms);
235+
236+
?>

0 commit comments

Comments
 (0)