Сервер A отправляет сообщения на сервер B. Мне нужно вставить сервер 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, но ничего не сделал. У меня нет доступа к нему, поэтому я не знаю, что заблокировало запрос.
убедиться, что curl точно повторяет любой запрос до мельчайших деталей? это не совсем работа для curl, но для 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 запрос за раз (хотя ОС одновременно буферизует одновременные запросы для socket_accept) и синхронный. Но его можно оптимизировать и сделать полностью асинхронным с socket_select & совместно, если его стоит оптимизировать)
Попробуйте изменить эту строку
curl_setopt($ch, CURLOPT_POSTFIELDS, $_POST);
чтобы:
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($_POST));
Когда вы делаете обычный запрос cURL, вы не можете использовать массив ($_POST
является массивом) непосредственно в качестве значения для CURLOPT_POSTFIELDS
, Вы должны преобразовать этот массив в строку постданных, что именно http_build_query()
делает. Конвертирует например
["name" => "my first name", "email" => "[email protected]"]
в:
name=my%20first%20name&[email protected]