[英]PHP, How to Redirect/Forward HTTP Request with header and body?
我有一個 PHP 頁面 main.php,它位於服務器 1 上。
我在服務器 2 上有一個 PHP 頁面 main.php(相同的頁面,不同的代碼)。
main.php 是一個 WebService。
我想將向服務器 1 發出的完整 HTTP 請求轉發到服務器 2,以便當用戶向 main.php(服務器 1)發送 HTTP 請求時,它會從服務器 2 上的 main.php 獲得響應。
我希望對服務器 2 的請求與對服務器 1 的原始請求完全相同。
我通過以下方式獲取 Http 請求數據:
$some_param = $_REQUEST['param']
$body =file_get_contents('php://input');
讓我們說我有
$server1_url = "11111";
$server2_url = "22222";
這樣做的動機是,我有一個生產服務器和一個登台服務器,我想將一些流量引導到新服務器以測試登台服務器上的新功能。
如何使用所有數據重定向請求或“克隆”完整請求,將其發送到新服務器並返回新響應?
謝謝你的幫助!
ps 我嘗試使用 php curl,但我不明白它是如何工作的,我也找到了各種答案,但沒有轉發請求參數和正文。
再次感謝!
如果您有權訪問 Apache 服務器配置,則可以使用以下設置創建虛擬主機:
ProxyPreserveHost Off
ProxyPass / http://remotesite.domain.tld/
ProxyPassReverse / http://remotesite.domain.tld/
ProxyPassReverseCookieDomain remotesite.domain.tld proxysite.tld
您需要為此啟用 mod_proxy 和 mod_proxy_http。 將 remotesite.domain.tld 替換為您轉發到的站點,將 proxysite.tld 替換為轉發器。
如果您無權訪問服務器配置文件,您仍然可以通過 php 手動設置 curl 並轉發所有內容。
<?php
error_reporting(E_ALL);
ini_set('display_errors', '1');
/* Set it true for debugging. */
$logHeaders = FALSE;
/* Site to forward requests to. */
$site = 'http://remotesite.domain.tld/';
/* Domains to use when rewriting some headers. */
$remoteDomain = 'remotesite.domain.tld';
$proxyDomain = 'proxysite.tld';
$request = $_SERVER['REQUEST_URI'];
$ch = curl_init();
/* If there was a POST request, then forward that as well.*/
if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $_POST);
}
curl_setopt($ch, CURLOPT_URL, $site . $request);
curl_setopt($ch, CURLOPT_HEADER, TRUE);
$headers = getallheaders();
/* Translate some headers to make the remote party think we actually browsing that site. */
$extraHeaders = array();
if (isset($headers['Referer']))
{
$extraHeaders[] = 'Referer: '. str_replace($proxyDomain, $remoteDomain, $headers['Referer']);
}
if (isset($headers['Origin']))
{
$extraHeaders[] = 'Origin: '. str_replace($proxyDomain, $remoteDomain, $headers['Origin']);
}
/* Forward cookie as it came. */
curl_setopt($ch, CURLOPT_HTTPHEADER, $extraHeaders);
if (isset($headers['Cookie']))
{
curl_setopt($ch, CURLOPT_COOKIE, $headers['Cookie']);
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
if ($logHeaders)
{
$f = fopen("headers.txt", "a");
curl_setopt($ch, CURLOPT_VERBOSE, TRUE);
curl_setopt($ch, CURLOPT_STDERR, $f);
}
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($ch);
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$headers = substr($response, 0, $header_size);
$body = substr($response, $header_size);
$headerArray = explode(PHP_EOL, $headers);
/* Process response headers. */
foreach($headerArray as $header)
{
$colonPos = strpos($header, ':');
if ($colonPos !== FALSE)
{
$headerName = substr($header, 0, $colonPos);
/* Ignore content headers, let the webserver decide how to deal with the content. */
if (trim($headerName) == 'Content-Encoding') continue;
if (trim($headerName) == 'Content-Length') continue;
if (trim($headerName) == 'Transfer-Encoding') continue;
if (trim($headerName) == 'Location') continue;
/* -- */
/* Change cookie domain for the proxy */
if (trim($headerName) == 'Set-Cookie')
{
$header = str_replace('domain='.$remoteDomain, 'domain='.$proxyDomain, $header);
}
/* -- */
}
header($header, FALSE);
}
echo $body;
if ($logHeaders)
{
fclose($f);
}
curl_close($ch);
?>
編輯:
當然,腳本必須位於(子)域的根目錄中。 你應該有一個 .htaccess 來重寫所有內容:
RewriteEngine On
RewriteRule .* index.php
這是我找到的解決方案(可能有更好的)
public static function getResponse ($url,$headers,$body)
{
$params = '?' . http_build_query($headers);
$redirect_url = $url . $params;
$ch = curl_init($redirect_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($ch);
if (!isset($response))
return null;
return $response;
}
我使用了 Rehmat 和 Calmarius 的代碼並進行了一些更改,因此現在它可以處理多個具有相同名稱的字段,例如
<input type="text" name="example[]">
<input type="text" name="example[]">
<input type="text" name="example[]">
並上傳文件,包括使用相同字段名稱的多個文件。
這是:
<?php
error_reporting(E_ALL);
ini_set('display_errors', '1');
class proxy {
private $logHeaders = false;
/* Site to forward requests to. */
private $site = 'http://redirectToSite';
/* Domains to use when rewriting some headers. */
private $remoteDomain = 'redirectToSite';
private $proxyDomain = 'yourproxydomain.com';
public function __construct() {
$request = $_SERVER['REQUEST_URI'];
$ch = curl_init();
/* If there was a POST request, then forward that as well.*/
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$post = $this->sanitizePostFields($_POST);
$files = $this->sanitizeFiles($_FILES);
if ($files) {
$post = array_merge($post, $files);
}
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
/*
// this is enough if not uploading files
curl_setopt(
$ch,
CURLOPT_POSTFIELDS,
http_build_query($_POST)
);
*/
}
curl_setopt($ch, CURLOPT_URL, $this->site . $request);
curl_setopt($ch, CURLOPT_HEADER, TRUE);
$headers = getallheaders();
/*
Translate some headers to make the remote party think we
actually browsing that site.
*/
$extraHeaders = array();
if (isset($headers['Referer'])) {
$extraHeaders[] = 'Referer: '. str_replace(
$this->proxyDomain,
$this->remoteDomain,
$headers['Referer']
);
}
if (isset($headers['Origin'])) {
$extraHeaders[] = 'Origin: '. str_replace(
$this->proxyDomain,
$this->remoteDomain,
$headers['Origin']
);
}
/*
Forward cookie as it came.
*/
curl_setopt($ch, CURLOPT_HTTPHEADER, $extraHeaders);
if (isset($headers['Cookie'])) {
curl_setopt($ch, CURLOPT_COOKIE, $headers['Cookie']);
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
if ($this->logHeaders) {
$f = fopen("headers.txt", "a");
curl_setopt($ch, CURLOPT_VERBOSE, TRUE);
curl_setopt($ch, CURLOPT_STDERR, $f);
}
//curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($ch);
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$headers = substr($response, 0, $header_size);
$body = substr($response, $header_size);
$headerArray = explode(PHP_EOL, $headers);
/* Process response headers. */
foreach($headerArray as $header) {
$colonPos = strpos($header, ':');
if ($colonPos !== FALSE) {
$headerName = substr($header, 0, $colonPos);
/*
Ignore content headers, let the webserver decide how to
deal with the content.
*/
if (trim($headerName) == 'Content-Encoding') continue;
if (trim($headerName) == 'Content-Length') continue;
if (trim($headerName) == 'Transfer-Encoding') continue;
//if (trim($headerName) == 'Location') continue;
/* -- */
/* Change cookie domain for the proxy */
if (trim($headerName) == 'Set-Cookie') {
$header = str_replace(
'domain='.$this->remoteDomain,
'domain='.$this->proxyDomain,
$header
);
}
/* -- */
if (trim($headerName) == 'Location') {
$header = str_replace(
$this->remoteDomain,
$this->proxyDomain,
$header
);
}
}
header($header, FALSE);
}
echo $body;
if ($this->logHeaders) {
fclose($f);
}
curl_close($ch);
}
private function sanitizePostFields($post, $fieldName = '') {
if (empty($post)) { return false; }
if (!is_array($post)) { return false; }
$result = [];
foreach ($post as $k => $v) {
if (is_string($v)) {
$result[($fieldName ? "{$fieldName}[{$k}]" : $k)] = $v;
}
elseif (is_array($v)) {
$result = array_merge(
$result,
$this->sanitizePostFields($v, $k)
);
}
}
return $result;
}
private function sanitizeFiles($files) {
if (empty($files)) { return false; }
if (!is_array($files)) { return false; }
$result = [];
foreach ($files as $k => $v) {
if (empty($v['name'])) { continue; }
if (is_array($v['name'])) {
// more than one file using the same name field[]
$nFields = count($v['name']);
for ($i = 0; $i < $nFields; $i++) {
if (empty($v['tmp_name'][$i])) { continue; }
$curl_file_upload = new CURLFile(
$v['tmp_name'][$i],
$v['type'][$i],
$v['name'][$i]
);
$result["{$k}[{$i}]"] = $curl_file_upload;
}
}
else {
$curl_file_upload = new CURLFile(
$v['tmp_name'],
$v['type'],
$v['name']
);
$result[$k] = $curl_file_upload;
}
}
return $result;
}
}
$proxy = new proxy();
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.