使用socket 來實作 proxy 功能
<?php
$targetHost = "192.168.123.123; //要轉送的目的HOST(另一台伺服器)
$targetPort = 80;
$targetPath = "/target.php"; //要轉發的目的路徑
// 取得原始請求的方法
$method = $_SERVER['REQUEST_METHOD'];
// 取得原始請求的所有參數
$params = http_build_query($_REQUEST);
// 建立原始請求頭
$requestHeaders = "$method $targetPath HTTP/1.1\r\n";
$requestHeaders .= "Host: $targetHost\r\n";
$requestHeaders .= "Content-Length: " . strlen($params) . "\r\n";
$requestHeaders .= "Content-Type: application/x-www-form-urlencoded\r\n";
$requestHeaders .= "Connection: close\r\n\r\n";
// 開啟與目標伺服器的連接
$socket = fsockopen($targetHost, $targetPort, $errno, $errstr, 30);
if (!$socket) {
header('HTTP/1.1 500 Internal Server Error');
echo "Error: $errstr ($errno)";
} else {
fwrite($socket, $requestHeaders . $params); // 傳送原始請求
$isFlush = false;
$byteArray = unpack('C*', 'abce'); // 初始化4個byte的array
while (!feof($socket)) {
$byte = fread($socket, 1); // 從目標伺服器讀取回應並即時傳送給客戶端
if(!$isFlush){
array_shift($byteArray); // 迭代控管用的array,為了過濾\r\n\r\n
array_push($byteArray, tobyte($byte));
if(byteArray2String($byteArray) == "\r\n\r\n"){ //過濾掉header,後續的才傳送
$isFlush = true;
}
}else{
echo $byte; //這邊才是內容
flush();
}
}
fclose($socket); // 關閉連線
}
function byteArray2String($byteArray) {
$chars = array_map("chr", $byteArray);
return join($chars);
}
function tobyte($str){
$tmpAry = unpack('C*', $str);
return $tmpAry[1];
}
?>
注意:
1. php 預設沒有byte 型態,所以要放入byte array 的字串必須轉型
2. fread 讀取出來的其實是字串
3. unpack這個function 會return 一個index 從1 開始的 array
Caution
If you do not name an element, numeric indices starting from 1 are used. Be aware that if you have more than one unnamed element, some data is overwritten because the numbering restarts from 1 for each element.
參考資料: