PHP反向代理类代码


Posted in PHP onAugust 15, 2014

改自PHP Reverse Proxy PRP,修改了原版中的一些错误,支持了文件上传以及上传文件类型识别,支持指定IP,自适应SAE环境。

使用方法

<?php
$proxy=new PhpReverseProxy();
$proxy->port="8080";
$proxy->host="3water.com";
//$proxy->ip="1.1.1.1";
$proxy->forward_path="";
$proxy->connect();
$proxy->output();
?>

源代码

<?php
//Source Code: http://www.xiumu.org/technology/php-reverse-proxy-class.shtml
class PhpReverseProxy{
 public $publicBaseURL;
 public $outsideHeaders;
 public $XRequestedWith;
 public $sendPost;
 public $port,$host,$ip,$content,$forward_path,$content_type,$user_agent,
  $XFF,$request_method,$IMS,$cacheTime,$cookie,$authorization;
 private $http_code,$lastModified,$version,$resultHeader;
 const chunkSize = 10000;
 function __construct(){
  $this->version="PHP Reverse Proxy (PRP) 1.0";
  $this->port="8080";
  $this->host="127.0.0.1";
  $this->ip="";
  $this->content="";
  $this->forward_path="";
  $this->path="";
  $this->content_type="";
  $this->user_agent="";
  $this->http_code="";
  $this->XFF="";
  $this->request_method="GET";
  $this->IMS=false;
  $this->cacheTime=72000;
  $this->lastModified=gmdate("D, d M Y H:i:s",time()-72000)." GMT";
  $this->cookie="";
  $this->XRequestedWith = "";
  $this->authorization = "";
 }
 function translateURL($serverName) {
  $this->path=$this->forward_path.$_SERVER['REQUEST_URI'];
  if(IS_SAE)
   return $this->translateServer($serverName).$this->path;
  if($_SERVER['QUERY_STRING']=="")
   return $this->translateServer($serverName).$this->path;
  else
  return $this->translateServer($serverName).$this->path."?".$_SERVER['QUERY_STRING'];
 }
 function translateServer($serverName) {
  $s = empty($_SERVER["HTTPS"]) ? ''
   : ($_SERVER["HTTPS"] == "on") ? "s"
   : "";
  $protocol = $this->left(strtolower($_SERVER["SERVER_PROTOCOL"]), "/").$s;
  if($this->port=="") 
   return $protocol."://".$serverName;
  else
   return $protocol."://".$serverName.":".$this->port;
 }
 function left($s1, $s2) {
  return substr($s1, 0, strpos($s1, $s2));
 }
 function preConnect(){
  $this->user_agent=$_SERVER['HTTP_USER_AGENT'];
  $this->request_method=$_SERVER['REQUEST_METHOD'];
  $tempCookie="";
  foreach ($_COOKIE as $i => $value) {
   $tempCookie=$tempCookie." $i=$_COOKIE[$i];";
  }
  $this->cookie=$tempCookie;
  if(empty($_SERVER['HTTP_X_FORWARDED_FOR'])){
   $this->XFF=$_SERVER['REMOTE_ADDR'];
  } else {
   $this->XFF=$_SERVER['HTTP_X_FORWARDED_FOR'].", ".$_SERVER['REMOTE_ADDR'];
  }
 
 }
 function connect(){
  if(empty($_SERVER['HTTP_IF_MODIFIED_SINCE'])){
   $this->preConnect();
   $ch=curl_init();
   if($this->request_method=="POST"){
    curl_setopt($ch, CURLOPT_POST,1);
 
    $postData = array();
    $filePost = false;
    $uploadPath = 'uploads/';
    if (IS_SAE)
      $uploadPath = SAE_TMP_PATH;
 
    if(count($_FILES)>0){
      if(!is_writable($uploadPath)){
        die('You cannot upload to the specified directory, please CHMOD it to 777.');
      }
      foreach($_FILES as $key => $fileArray){ 
        copy($fileArray["tmp_name"], $uploadPath . $fileArray["name"]);
        $proxyLocation = "@" . $uploadPath . $fileArray["name"] . ";type=" . $fileArray["type"];
        $postData = array($key => $proxyLocation);
        $filePost = true;
      }
    }
 
    foreach($_POST as $key => $value){
      if(!is_array($value)){
     $postData[$key] = $value;
      }
      else{
     $postData[$key] = serialize($value);
      }
    }
 
    if(!$filePost){
      //$postData = http_build_query($postData);
      $postString = "";
      $firstLoop = true;
      foreach($postData as $key => $value){
      $parameterItem = urlencode($key)."=".urlencode($value);
      if($firstLoop){
     $postString .= $parameterItem;
      }
      else{
     $postString .= "&".$parameterItem;
      }
      $firstLoop = false; 
      }
      $postData = $postString;
    }
 
    //echo print_r($postData);
 
    //curl_setopt($ch, CURLOPT_VERBOSE, 0);
    //curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    //curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible;)");
    $this->sendPost = $postData;
    //var_dump(file_exists(str_replace('@','',$postData['imgfile'])));exit;
    curl_setopt($ch, CURLOPT_POSTFIELDS,$postData);
    //curl_setopt($ch, CURLOPT_POSTFIELDS,file_get_contents($proxyLocation));
    //curl_setopt($ch, CURLOPT_POSTFIELDS,file_get_contents("php://input"));
   }
 
   //gets rid of mulitple ? in URL
   $translateURL = $this->translateURL(($this->ip)?$this->ip:$this->host);
   if(substr_count($translateURL, "?")>1){
     $firstPos = strpos($translateURL, "?", 0);
     $secondPos = strpos($translateURL, "?", $firstPos + 1);
     $translateURL = substr($translateURL, 0, $secondPos);
   }
 
   curl_setopt($ch,CURLOPT_URL,$translateURL);
 
   $proxyHeaders = array(
     "X-Forwarded-For: ".$this->XFF,
     "User-Agent: ".$this->user_agent,
     "Host: ".$this->host
   );
 
   if(strlen($this->XRequestedWith)>1){
     $proxyHeaders[] = "X-Requested-With: ".$this->XRequestedWith;
     //echo print_r($proxyHeaders);
   }
 
   curl_setopt($ch,CURLOPT_HTTPHEADER, $proxyHeaders);
 
   if($this->cookie!=""){
    curl_setopt($ch,CURLOPT_COOKIE,$this->cookie);
   }
   curl_setopt($ch,CURLOPT_FOLLOWLOCATION,false); 
   curl_setopt($ch,CURLOPT_AUTOREFERER,true); 
   curl_setopt($ch,CURLOPT_HEADER,true);
   curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
 
   $output=curl_exec($ch);
   $info = curl_getinfo( $ch );
   curl_close($ch);
   $this->postConnect($info,$output);
  }else {
   $this->lastModified=$_SERVER['HTTP_IF_MODIFIED_SINCE'];
   $this->IMS=true;
  }
 }
 function postConnect($info,$output){
  $this->content_type=$info["content_type"];
  $this->http_code=$info['http_code'];
  //var_dump($info);exit;
  if(!empty($info['last_modified'])){
   $this->lastModified=$info['last_modified'];
  }
  $this->resultHeader=substr($output,0,$info['header_size']);
  $content = substr($output,$info['header_size']);
 
  if($this->http_code=='200'){
   $this->content=$content;
  }elseif( ($this->http_code=='302' || $this->http_code=='301') && isset($info['redirect_url'])){
   $redirect_url = str_replace($this->host,$_SERVER['HTTP_HOST'],$info['redirect_url']);
   if (IS_SAE)
     $redirect_url = str_replace('http://fetchurl.sae.sina.com.cn/','',$info['redirect_url']);
   header("Location: $redirect_url");
   exit;
  }elseif($this->http_code=='404'){
   header("HTTP/1.1 404 Not Found");
   exit("HTTP/1.1 404 Not Found");
  }elseif($this->http_code=='500'){
   header('HTTP/1.1 500 Internal Server Error');
   exit("HTTP/1.1 500 Internal Server Error");
  }else{
   exit("HTTP/1.1 ".$this->http_code." Internal Server Error");
  }
 }
 
 function output(){
  $currentTimeString=gmdate("D, d M Y H:i:s",time());
  $expiredTime=gmdate("D, d M Y H:i:s",(time()+$this->cacheTime));
 
  $doOriginalHeaders = true;
  if($doOriginalHeaders){
    if($this->IMS){
     header("HTTP/1.1 304 Not Modified");
     header("Date: Wed, $currentTimeString GMT");
     header("Last-Modified: $this->lastModified");
     header("Server: $this->version");
    }else{
 
     header("HTTP/1.1 200 OK");
     header("Date: Wed, $currentTimeString GMT");
     header("Content-Type: ".$this->content_type);
     header("Last-Modified: $this->lastModified");
     header("Cache-Control: max-age=$this->cacheTime");
     header("Expires: $expiredTime GMT");
     header("Server: $this->version");
     preg_match("/Set-Cookie:[^\n]*/i",$this->resultHeader,$result);
     foreach($result as $i=>$value){
      header($result[$i]);
     }
     preg_match("/Content-Encoding:[^\n]*/i",$this->resultHeader,$result);
     foreach($result as $i=>$value){
      //header($result[$i]);
     }
     preg_match("/Transfer-Encoding:[^\n]*/i",$this->resultHeader,$result);
     foreach($result as $i=>$value){
      //header($result[$i]);
     }
     echo($this->content);
     /*
     if(stristr($this->content, "error")){
    echo print_r($this->sendPost);
     }
     */
    }
  }
  else{
    $headerString = $this->resultHeader; //string 
    $headerArray = explode("\n", $headerString);
    foreach($headerArray as $privHeader){
   header($privHeader);
    }
 
    if(stristr($headerString, "Transfer-encoding: chunked")){
   flush();
   ob_flush();
   $i = 0;
   $maxLen = strlen($this->content);
 
   while($i < $maxLen){
     $endChar = $i + self::chunkSize;
     if($endChar >= $maxLen){
    $endChar = $maxLen - 1;
     }
     $chunk = substr($this->content, $i, $endChar);
     $this->dump_chunk($chunk);
     flush();
     ob_flush();
     $i = $i + $endChar;
   }
    }
    else{
    echo($this->content);
    }
 
    //echo "header: ".print_r($headerArray);
    //header($this->resultHeader);
  }
 
 }
 
 
 function dump_chunk($chunk) {
   echo sprintf("%x\r\n", strlen($chunk));
   echo $chunk;
   echo "\r\n";
 }
 
 
 function getOutsideHeaders(){
   $headers = array();
   foreach ($_SERVER as $name => $value){ 
  if (substr($name, 0, 5) == 'HTTP_') { 
    $name = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5))))); 
    $headers[$name] = $value; 
  }elseif ($name == "CONTENT_TYPE") { 
    $headers["Content-Type"] = $value; 
  }elseif ($name == "CONTENT_LENGTH") { 
    $headers["Content-Length"] = $value; 
  }elseif(stristr($name, "X-Requested-With")) { 
    $headers["X-Requested-With"] = $value;
    $this->XRequestedWith = $value;
  }
   } 
 
   //echo print_r($headers);
 
   $this->outsideHeaders = $headers;
   return $headers;
 } 
 
}
?>
PHP 相关文章推荐
PHP项目开发中最常用的自定义函数整理
Dec 02 PHP
php实现自动获取生成文章主题关键词功能的深入分析
Jun 03 PHP
thinkphp控制器调度使用示例
Feb 24 PHP
非常实用的PHP常用函数汇总
Dec 17 PHP
php自动更新版权信息显示的方法
Jun 19 PHP
Zend Framework实现将session存储在memcache中的方法
Mar 22 PHP
浅析Yii2集成富文本编辑器redactor实例教程
Apr 25 PHP
浅谈PHP eval()函数定义和用法
Jun 21 PHP
PHP自定义错误用法示例
Sep 28 PHP
利用php做服务器和web前端的界面进行交互
Oct 31 PHP
WHOOPS PHP调试库的使用
Sep 29 PHP
php操作redis数据库常见方法实例总结
Feb 20 PHP
ThinkPHP中自定义目录结构的设置方法
Aug 15 #PHP
win7 64位系统 配置php最新版开发环境(php+Apache+mysql)
Aug 15 #PHP
php获取apk包信息的方法
Aug 15 #PHP
phpmyadmin出现Cannot start session without errors问题解决方法
Aug 14 #PHP
PHP解码unicode编码的中文字符代码分享
Aug 13 #PHP
使用ob系列函数实现PHP网站页面静态化
Aug 13 #PHP
PHP语法自动检查的Vim插件
Aug 11 #PHP
You might like
PHP缩略图等比例无损压缩,可填充空白区域补充色
2011/06/10 PHP
php无限遍历目录示例
2014/02/21 PHP
ThinkPHP标签制作教程
2014/07/10 PHP
php微信支付之APP支付方法
2015/03/04 PHP
php实现购物车功能(下)
2016/01/05 PHP
Linux下快速搭建php开发环境
2017/03/13 PHP
原生JS实现Ajax通过GET方式与PHP进行交互操作示例
2018/05/12 PHP
TP5框架实现上传多张图片的方法分析
2020/03/29 PHP
javascript的事件描述
2006/09/08 Javascript
jQuery写的日历(包括日历的样式及功能)
2013/04/23 Javascript
使用JS取得焦点(focus)元素代码
2014/03/22 Javascript
动态创建script在IE中缓存js文件时导致编码的解决方法
2014/05/04 Javascript
JS生成不重复的随机数组的简单实例
2016/07/10 Javascript
详解HTML5 使用video标签实现选择摄像头功能
2017/10/25 Javascript
浅谈es6 javascript的map数据结构
2017/12/14 Javascript
Vue下路由History模式打包后页面空白的解决方法
2018/06/29 Javascript
详解如何构建一个Angular6的第三方npm包
2018/09/07 Javascript
vue单页缓存存在的问题及解决方案(小结)
2018/09/25 Javascript
微信小程序中的video视频实现 自定义播放按钮、封面图、视频封面上文案
2020/01/02 Javascript
详细分析React 表单与事件
2020/07/08 Javascript
解决vue bus.$emit触发第一次$on监听不到问题
2020/07/28 Javascript
探究一道价值25k的蚂蚁金服异步串行面试题
2020/08/21 Javascript
linux下python抓屏实现方法
2015/05/22 Python
Python中Threading用法详解
2017/12/27 Python
python pcm音频添加头转成Wav格式文件的方法
2019/01/09 Python
Python3.5文件读与写操作经典实例详解
2019/05/01 Python
Python 处理文件的几种方式
2019/08/23 Python
Numpy中对向量、矩阵的使用详解
2019/10/29 Python
Python结合百度语音识别实现实时翻译软件的实现
2021/01/18 Python
携程旅行网:中国领先的在线旅行服务公司
2017/02/17 全球购物
手工制作的意大利皮革运动鞋:KOIO
2020/01/05 全球购物
乐高瑞士官方商店:LEGO CH
2020/08/16 全球购物
Sunglass Hut巴西网上商店:男女太阳镜
2020/10/04 全球购物
幼儿园运动会口号
2014/06/07 职场文书
关于Nginx中虚拟主机的一些冷门知识小结
2022/03/03 Servers
Win11使用CAD卡顿或者致命错误怎么办?Win11无法正常使用CAD的解决方法
2022/07/23 数码科技