J'ai aussi fait un proxy, récemment. Et - il y a une troisième option. N'a même pas besoin de s'appeler ou un autre script, il est complètement autonome, et multiplate-forme ...
Donc - première chose est que j'ai fait cela en utilisant des sockets. Je suppose que vous l'avez fait aussi, mais juste en l'écrivant ici au cas où vous ne l'auriez pas fait. J'ai placé le proxy dans le navigateur à un port spécifique, qui est autorisé à travers le pare-feu dans le script PHP écoute. Pour le faire commencer à écouter, je dois "exécuter" le script sur le port 80, donc j'ai aussi une console en temps réel. Donc, le script écoute sur le socket, et il est réglé sur NON-BLOCKING. Cela fonctionne avec une boucle (infinie, expire en utilisant break si nécessaire) - * @ socket_accept() * est utilisé pour voir s'il y a une nouvelle connexion, vérifiée si! == false. Enfin, la boucle boucle (: D) à travers toutes les sockets enfant engendrées, qui sont stockées dans un tableau. C'est un proxy HTTP, donc ils ont tous quelques étapes spécifiques (envoi des en-têtes du client, tentative d'atteindre le serveur distant, envoi des en-têtes du client, réception des données du serveur distant). Des choses comme la lecture qui serait (sur la socket distante ouverte avec fsockopen()) normalement être bloquées, et il n'y a aucun moyen de régler cela à non-bloquant sur celles-ci, "émulant" le mode non-bloquant par un délai d'expiration très - comme 5 microsecondes, et max. les caractères lus sont 128.
tl; dr; Essentiellement, c'est comme un processeur multi-threading.
TOUTEFOIS !!! vous avez besoin de prises si c'est fait comme ça.
EDIT: l'ajout d'un code exemple dépouillé de toutes les actions personnalisées: (oui, il est temps)
set_time_limit(0); // so we don't get a timeout from PHP
// - can lead to sockets left open...
$config_port = 85; // port
$config_address = "192.168.0.199"; // IP address, most likely local with router
// if there's not a router between server and wan, use the wan IP
$config_to = 30; // global timeout in seconds
$config_connect_to = 2; // timeout for connecting to remote server
$config_client_to = 0.1; // timeout for reading client data
$config_remote_to = 10; // timeout for reading remote data (microseconds)
$config_remote_stage_to = 15; // timeout for last stage (seconds)
$config_backlog = 5000; // max backlogs, the more the better (usually)
$parent_sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); // parent socket
$tmp_res = @socket_bind($parent_sock, $config_address, $config_port);
if ($tmp_res === false){
echo "Can't bind socket.";
exit;
// address or port in use, for example by Apache
}
$tmp_res = @socket_listen($parent_sock, $config_backlog);
if ($tmp_res === false){
echo "Can't start socket listener.";
exit;
// hard to tell what can cause this
}
socket_set_nonblock($parent_sock); // non-blocking mode
$sockets = array(); // children sockets
$la = time(); // last activity
while (time() - $la < $config_to){
$spawn = @socket_accept($parent_sock); // check for new connection
if ($spawn !== false){
$la = time();
$ni = count($sockets);
$sockets[$ni] = array();
$sockets[$ni]["handle"] = $spawn;
$sockets[$ni]["stage"] = 1;
$sockets[$ni]["la"] = time(); // for some stages
$sockets[$ni]["client_data"] = "";
$sockets[$ni]["headers"] = array();
$sockets[$ni]["remote"] = false;
}
foreach ($sockets as &$sock){ // &$sock because we're gonna edit the var
switch ($sock["stage"]){
case 1: // receive client data
$read_data = @socket_read($sock["handle"], 2048);
if ($read_data !== false && $read_data !== ""){
$la = time();
$sock["la"] = microtime(true);
$sock["client_data"] .= $read_data;
} else if (microtime(true) - $sock["la"] > $config_client_to) {
// client data received (or too slow :D)
$sock["stage"] = 2; // go on
}
break;
case 2: // connect to remote
$headers = explode("\r\n", $sock["client_data"]);
foreach ($headers as $hdr){
$h_pos = strpos($hdr, ":");
if ($h_pos !== false){
$nhid = count($sock["headers"]);
$sock["headers"][strtolower(substr($hdr, 0, $h_pos))] = ltrim(substr($hdr, $h_pos + 1));
}
}
// we'll have to use the "Host" header to know target server
$sock["remote"] = @fsockopen($sock["headers"]["host"], 80, $sock["errno"], $sock["errstr"], $config_connect_to);
if ($sock["remote"] === false){
// error, echo it and close client socket, set stage to 0
echo "Socket error: #".$sock["errno"].": ".$sock["errstr"]."<br />\n";
flush(); // immediately show the error
@socket_close($sock["handle"]);
$sock["handle"] = 0;
} else {
$la = time();
// okay - connected
$sock["stage"] = 3;
}
break;
case 3: // send client data
$tmp_res = @fwrite($sock["remote"], $sock["client_data"]);
// this currently supports just client data up to 8192 bytes long
if ($tmp_res === false){
// error
echo "Couldn't send client data to remote server!<br />\n";
flush();
@socket_close($sock["handle"]);
@fclose($sock["remote"]);
$sock["stage"] = 0;
} else {
// client data sent
$la = time();
stream_set_timeout($sock["remote"], $config_remote_to);
$sock["la"] = time(); // we'll need this in stage 4
$sock["stage"] = 4;
}
break;
case 4:
$remote_read = @fread($sock["remote"], 128);
if ($remote_read !== false && $remote_read !== ""){
$la = time();
$sock["la"] = time();
@socket_write($sock["handle"], $remote_read);
} else {
if (time() - $sock["la"] >= $config_remote_stage_to){
echo "Timeout.<br />\n";
flush();
@socket_close($sock["handle"]);
@fclose($sock["remote"]);
$sock["stage"] = 0;
}
}
break;
}
}
}
foreach($sockets as $sock){
@socket_close($sock["handle"]);
@fclose($sock["remote"]);
}
@socket_close($parent_sock);
Ajout d'un code exemple loooooong. –