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调用Java对象的方法
Oct 09 PHP
php实现自动获取生成文章主题关键词功能的深入分析
Jun 03 PHP
php通过隐藏表单控件获取到前两个页面的url
Sep 09 PHP
PHP实现批量上传单个文件
Dec 29 PHP
ThinkPHP使用Smarty第三方插件方法小结
Mar 19 PHP
PHP使用Mysqli类库实现完美分页效果的方法
Apr 07 PHP
用HTML/JS/PHP方式实现页面延时跳转的简单实例
Jul 18 PHP
php array_map使用自定义的函数处理数组中的每个值
Oct 26 PHP
PHP基于反射机制实现插件的可插拔设计详解
Nov 10 PHP
PHP AjaxForm提交图片上传并显示图片源码
Nov 29 PHP
php基于自定义函数记录log日志方法
Jul 21 PHP
对laravel的csrf 防御机制详解,及form中csrf_token()的存在介绍
Oct 24 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
解析mysql 表中的碎片产生原因以及清理
2013/06/22 PHP
php删除字符串末尾子字符,删除开始字符,删除两端字符(实现代码)
2013/06/27 PHP
ThinkPHP 5.x远程命令执行漏洞复现
2019/09/23 PHP
javascript 函数调用的对象和方法
2010/07/01 Javascript
扩展JavaScript功能的正确方法(译文)
2012/04/12 Javascript
IE下window.onresize 多次调用与死循环bug处理方法介绍
2013/11/12 Javascript
js对文章内容进行分页示例代码
2014/03/05 Javascript
用unescape反编码得出汉字示例
2014/04/24 Javascript
兼容IE、firefox以及chrome的js获取时间(getFullYear)
2014/07/04 Javascript
node.js中的fs.chown方法使用说明
2014/12/16 Javascript
jQuery插件扩展extend的简单实现原理
2016/06/24 Javascript
JavaScript与java语言有什么不同
2016/09/22 Javascript
详解Vue爬坑之vuex初识
2017/06/14 Javascript
详解webpack + react + react-router 如何实现懒加载
2017/11/20 Javascript
ionic2中使用自动生成器的方法
2018/03/04 Javascript
微信小程序实现3D轮播图效果(非swiper组件)
2019/09/21 Javascript
JS使用正则表达式实现常用的表单验证功能分析
2020/04/30 Javascript
JQuery+drag.js上传图片并且实现图片拖曳
2020/11/18 jQuery
vue3.0中使用element的完整步骤
2021/03/04 Vue.js
Python判断操作系统类型代码分享
2014/11/22 Python
NumPy 数组使用大全
2019/04/25 Python
windows环境中利用celery实现简单任务队列过程解析
2019/11/29 Python
python opencv实现gif图片分解的示例代码
2019/12/13 Python
基于CSS3的CSS 多栏(Multi-column)实现瀑布流源码分享
2014/06/11 HTML / CSS
草莓网美国官网:Strawberrynet USA
2016/12/11 全球购物
美国高品质个性化珠宝销售网站:Jewlr
2018/05/03 全球购物
英国最大的滑板品牌选择:Route One
2019/09/22 全球购物
好的自荐信包括什么内容
2013/11/07 职场文书
高三地理教学反思
2014/01/11 职场文书
销售业务员岗位职责
2015/02/13 职场文书
2015年公司行政后勤工作总结
2015/05/20 职场文书
英雄儿女观后感
2015/06/09 职场文书
化验室安全管理制度
2015/08/06 职场文书
2016社区平安家庭事迹材料
2016/02/26 职场文书
写作技巧:优秀文案必备的3种结构
2019/08/19 职场文书
详解Mysql和Oracle之间的误区
2021/05/18 MySQL