2017-05-25 1 views
1

A envoie des messages au serveur B. J'ai besoin d'insérer le serveur C avec un script PHP entre eux.PHP. demande avant vers un autre serveur comme serveur est

Je veux que cela fonctionne comme ceci:

serveur A -> Serveur C (faire des choses avec des données et demande avant plus) -> Serveur B.

J'ai besoin Serveur B pour recevoir exactement la même demande, qui a été envoyé à partir du serveur R. Je ne ai pas besoin du serveur C sert de serveur mandataire, il suffit d'envoyer la demande en est, et qui est tout

Comment pourrais-je le faire?

J'ai essayé quelque chose comme ça, mais ne fonctionne pas:

$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); 

serveur B retourné 200, mais n'a rien fait. Je n'y ai pas accès, donc je ne sais pas ce qui a bloqué la demande.

+0

ce n'est pas un emploi pour curl, ce est un travail pour socket_ * – hanshenrik

Répondre

2

faisant friser vous exactement reproduit toute demande dans les moindres détails? ce n'est pas vraiment un travail pour curl, mais pour socket_ *. Je parie que certains diront que ce n'est pas vraiment un travail pour PHP non plus, mais PHP est certainement capable de le faire, d'une manière mono-thread. utilisez le socket api pour accepter les connexions du serveur A, lisez la requête, effectuez votre traitement, transférez la requête au serveur B tel qu'il a été reçu, lisez la réponse du serveur B et renvoyez cette réponse au serveur A.

exemple (pourrait appeler cette 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; 
    } 
} 

(ce script est lent, ne traite que 1 demande à un moment (demandes simultanées sont mises en mémoire tampon par le système d'exploitation pour socket_accept, bien), et synchrone, mais il pourrait. être optimisé et fait entièrement avec async socket_select & co, si sa valeur d'optimisation)

0

Essayez de changer cette ligne

curl_setopt($ch, CURLOPT_POSTFIELDS, $_POST); 

à:

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

Lorsque vous faites une demande régulière de cURL, vous ne pouvez pas utiliser un tableau ($_POST est un tableau) directement en tant que valeur pour CURLOPT_POSTFIELDS. Vous devez transformer ce tableau en une chaîne postdata, ce que fait exactement http_build_query(). Il convertit par exemple

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

dans:

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

qui ne seraient pas en avant GET données, les données de cookie, ni les en-têtes HTTP (comme agent utilisateur), ne serait-il garantir que les données de poste ont été codées de manière égale, ni même que le même codage utilisé (par exemple , vous ne pouvez pas déterminer à partir de $ _POST si 'application/x-www-form-urlencoded' ou' multipart/form-data' a été utilisé, résumés PHP et pour vous décode. votre approche http_build_query serait toujours donner lieu à l'aide de 'application/x-www-form-urlencoded', quel que soit ce serveur de codage A utilisé. – hanshenrik

+0

également, lorsque le serveur A est réellement codé avec 'application/x-www-form-urlencoded', vous ne pourrez pas dire/répliquer si le serveur A a encodé les données par RFC1738, RFC3986 ou un autre schéma (parce que PHP décode les deux à la fois) – hanshenrik

+0

aussi, au moins 'application/x-www-form-urlencoded' prend en charge la redéfinition de la même variable plusieurs fois, comme' Content-Type: application/x-www-form-urlencoded foo = 9 & foo = 8' (idk pourquoi les gens voudraient vraiment faire cela, mais je l'ai vu dans la nature, et il est pris en charge par Firefox et Chrome) - ici, PHP va juste mettre $ _POST ['foo'] à la dernière valeur fournie de foo, et rejeter toutes les définitions précédentes. ce qui signifie que lorsque vous http_build_query, les définitions précédentes de foo (qui est écrasé dans la même demande) ne seront pas transmises à ServerB – hanshenrik