2017-05-25 69 views
1

服务器A正在向服务器B发送消息。我需要在它们之间插入带有PHP脚本的服务器C.PHP。将请求按原样转发到另一台服务器

所以,我希望它是这样工作的:

服务器A - >服务器C(做一些东西与数据转发请求中还) - >服务器B.

我需要服务器B恰好收到同样的请求,这是从服务器A发送的。我不需要服务器C充当代理服务器,只是发送请求原样,这就是全部

我该怎么做?

我已经试过这样的事情,但没有奏效:

$ch = curl_init(); 
curl_setopt($ch, CURLOPT_URL, 'Server B URL'); 
curl_setopt($ch, CURLOPT_HEADER, 1); 
curl_setopt($ch, CURLOPT_POST, 1); 
curl_setopt($ch, CURLOPT_VERBOSE, 1); 
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); 
curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1); 
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
curl_setopt($ch, CURLINFO_HEADER_OUT, 1); 
curl_setopt($ch, CURLOPT_POSTFIELDS, $_POST); 
$response = curl_exec($ch); 

服务器B返回200,但什么也没做。我无法访问它,所以我不知道什么阻止了请求。

+0

这不是一个卷曲的工作,这个是socket_ * – hanshenrik

回答

2

确保准确卷曲复制到最小的细节的任何要求?这不是真正的卷曲工作,而是socket_ *。我敢打赌,有人会说这对于PHP来说并不是一份真正的工作,但是PHP肯定能够以单线程的方式来完成这项工作。使用套接字api接受来自服务器A的连接,读取请求,执行处理,将请求转发到服务器B(收到它),读取服务器B的响应,并将该响应发送回服务器A.

例子(可以称之为ServerC.php):

<?php 
declare(strict_types = 1); 
if(php_sapi_name() !== 'cli'){die('this script must run in cli mode.');} 
$port = 9999; 
$targetIP = gethostbyname ('example.org'); 
$targetPort = 80; 
assert (false !== filter_var ($targetIP, FILTER_VALIDATE_IP)); 
var_dump ($targetIP, $targetPort); 

y (($listen = socket_create (AF_INET, SOCK_STREAM, SOL_TCP))); 
register_shutdown_function (function() use (&$listen) { 
    socket_close ($listen); 
}); 
y (socket_bind ($listen, '0.0.0.0', $port)); 
y (socket_listen ($listen)); 
y (socket_set_block ($listen)); 
echo 'listening for connections... ', PHP_EOL; 
while (false !== ($newconn = socket_accept ($listen))) { 
    echo 'new connection from '; 
    socket_getpeername ($newconn, $peername, $peerport); 
    echo $peername . ':' . $peerport . PHP_EOL; 
    y (socket_set_block ($newconn)); 
    $data = ''; 
    echo 'reading request... '; 
    $data = socket_read_all ($newconn, 2); 
    var_dump ($data); 
    echo 'done.' . PHP_EOL; 
    // client didnt send any bytes in a while, assume we got the whole request... 
    { 
     // do whatever processing you need to do between requests in here. 
    } 
    { 
     // now to forward the request. 
     y (($targetSock = socket_create (AF_INET, SOCK_STREAM, SOL_TCP))); 
     y (socket_set_block ($targetSock)); 
     y (socket_connect ($targetSock, $targetIP, $targetPort)); 
     echo 'connected to target. forwarding request... '; 
     socket_write_all ($targetSock, $data); 
     echo 'done.', PHP_EOL; 
     unset ($data, $newdata); 
     $data = ''; 
     echo 'reading response... '; 
     $data = socket_read_all ($targetSock, 2); 
     var_dump ($data); 
     echo 'done.', PHP_EOL; 
     socket_close ($targetSock); 
    } 
    echo 'sending response back to client... '; 
    socket_write_all ($newconn, $data); 
    echo 'done.', PHP_EOL; 
    socket_close ($newconn); 
} 
function y($in) { 
    if (! $in) { 
     $str = hhb_return_var_dump (socket_last_error(), socket_strerror (socket_last_error())); 
     throw new \Exception ($str); 
    } 
    return $in; 
} 
function n($in) { 
    if (! ! $in) { 
     throw new \Exception(); 
    } 
    return $in; 
} 
function hhb_return_var_dump(): string // works like var_dump, but returns a string instead of printing it. 
{ 
    $args = func_get_args(); 
    ob_start(); 
    call_user_func_array ('var_dump', $args); 
    return ob_get_clean(); 
} 
function socket_write_all($sock, string $data) { 
    $len = strlen ($data); 
    while ($len > 0) { 
     $written = socket_write ($sock, $data); 
     if ($written === false) { 
      throw new RuntimeException ('socket_write failed. errno: ' . socket_last_error ($sock) . '. error: ' . socket_strerror (socket_last_error ($sock))); 
     } 
     $len -= $written; 
     $data = substr ($data, $written); 
    } 
    return; // all data written 
} 
function socket_read_all($sock, int $sleep_sec = 2): string { 
    $ret = ''; 
    while (true) { 
     sleep ($sleep_sec); // ... 
     $buf = ''; 
     $read = socket_recv ($sock, $buf, 9999, MSG_DONTWAIT); 
     if ($read === false || $read < 1) { 
      return $ret; 
     } 
     $ret .= $buf; 
    } 
} 

(该脚本是缓慢的,仅处理1个以时间(并发请求由OS为socket_accept缓冲,虽然)请求,和同步,但它可能。与socket_select & co完全异步,如果它的值得优化)

0

尝试改变该行

curl_setopt($ch, CURLOPT_POSTFIELDS, $_POST); 

到:

curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($_POST)); 

当您进行定期卷曲请求,则不能使用的阵列($_POST是一个数组)直接作为CURLOPT_POSTFIELDS的值。您必须将该数组转换为postdata字符串,这正是http_build_query()所做的。它可以转换例如

["name" => "my first name", "email" => "[email protected]"] 

到:

name=my%20first%20name&[email protected] 
+0

的工作,它不会转发GET数据,cookie数据或http头(例如用户代理),也不会保证发布数据被同等编码,甚至不会使用相同的编码(例如,您不能从$ _POST确定是使用了application/x-www-form-urlencoded还是'multipart/form-data',PHP会为您抽象并解码它。不管使用什么编码服务器A,你的http_build_query方法总是会导致使用'application/x-www-form-urlencoded'。) – hanshenrik

+0

此外,当服务器A实际使用'application/x-www-form-urlencoded'进行编码时,如果服务器A按照RFC1738,RFC3986或其他一些方案对数据进行编码,您将无法告知/复制(因为PHP同样解码它们) – hanshenrik

+0

至少'application/x-www-form-urlencoded'支持多次重新定义相同的变量,如'Content-Type:application/x-www-form-urlencoded foo = 9&foo = 8'(idk为什么人们会想要做到这一点,但我已经看到它在野外,并支持Firefox和Chrome) - 在这里,PHP只会把$ _POST ['foo'] foo的最后提供的值,并放弃任何以前的定义。这意味着当你http_build_query它时,以前的foo(在同一个请求中被覆盖)的定义将不会被转发到ServerB – hanshenrik

相关问题