2011-08-21 151 views
3

HTML Purifier或CSRF Magic如何拦截HTTP请求?它的文档说它基于Django中间件Python框架的想法,但我还没有找到一些关于如何拦截HTTP请求的文档。它的工作原理并不需要安装任何PHP扩展。HTML净化器拦截请求

任何人都可以解释一下这个问题?

问候

回答

1

CSRF Magic使用PHP的output control函数。它捕获脚本的输出,修改它,并使用特殊的处理函数修改它在打印之前捕获的输出。所以,真正的魔力在于ob_start。如果你有兴趣,请阅读它。此外,由于CSRF Magic是一个开源项目,您可以read the script itself for more detailed information

它最终归结为line 371

if ($GLOBALS['csrf']['rewrite'])  ob_start('csrf_ob_handler'); 

该行表示,如果条件为真(它通常是这样),当输出完成后启动输出缓冲(ob_start)和, ,在该输出上运行csrf_ob_handlercsrf_ob_handler修改脚本的原始输出以添加隐藏的输入,然后输出结果。

+0

'$ GLOBALS ['csrf'] ['rewrite']'[什么是...代码](http://www.bigbible.org/blog/uploaded_images/242640415_46bf42b3a7-784053.jpg) –

+0

无论如何,这是行XP – Matchu

-1

如果没有笑话 - “拦截” HTTP请求和响应发送什么是任何Web应用程序应该做的。
而且您不需要任何扩展,因为PHP的设计正好是创建Web应用程序的工具。
要读取HTTP请求的数据,请使用数组$ _GET,$ _POST,$ _SERVER(有时需要php://input),并发送响应,您可以仅使用echo "that's my response!";

我甚至可以给你我的两个班,请求和响应工作,希望这将是有用的(或只是有趣,至少):

<?php 
namespace Jamm\HTTP; 

class Request 
{ 
    protected $method; 
    protected $headers; 
    protected $data; 
    protected $accept; 

    const method_GET = 'GET'; 
    const method_POST = 'POST'; 
    const method_PUT = 'PUT'; 
    const method_DELETE = 'DELETE'; 

    /** 
    * @param bool $parse - parse current input to object's variables (input request) 
    * @return \Jamm\HTTP\Request 
    * 
    */ 
    public function __construct($parse = false) 
    { 
     $this->method = self::method_GET; 
     if ($parse) $this->BuildFromInput(); 
     $this->setHeader('Content-type', 'text/plain'); 
    } 

    public function BuildFromInput() 
    { 
     $this->headers = $_SERVER; 
     $this->accept = isset($_SERVER['HTTP_ACCEPT']) ? $_SERVER['HTTP_ACCEPT'] : ''; 
     $this->method = $_SERVER['REQUEST_METHOD']; 
     switch ($this->method) 
     { 
      case 'HEAD': 
      case 'GET': 
       $this->data = $_GET; 
       break; 
      case 'POST': 
       $this->data = $_POST; 
       break; 
      default: 
       parse_str(file_get_contents('php://input'), $this->data); 
     } 
    } 

    /** 
    * Return header from array by key, or all keys 
    * @param string $key 
    * @return null|array|mixed 
    */ 
    public function getHeaders($key = null) 
    { 
     if (!empty($key)) 
     { 
      return isset($this->headers[$key]) ? $this->headers[$key] : NULL; 
     } 
     else return $this->headers; 
    } 

    /** 
    * Get type of request method 
    * @return string 
    */ 
    public function getMethod() 
    { 
     return $this->method; 
    } 

    /** 
    * Return key or all the keys of request 
    * @param string $key 
    * @return null|array|string|numeric 
    */ 
    public function getData($key = null) 
    { 
     if (empty($key)) return $this->data; 
     else 
     { 
      return isset($this->data[$key]) ? $this->data[$key] : NULL; 
     } 
    } 

    /** 
    * Return HTTP_ACCEPT header 
    * @return string 
    */ 
    public function getAccept() 
    { 
     return $this->accept; 
    } 

    /** 
    * Check, if this type is acceptable 
    * @param string $type 
    * @return bool 
    */ 
    public function isAcceptable($type) 
    { 
     if (empty($type) || (stripos($this->getAccept(), $type)!==false)) return true; 
     return false; 
    } 

    public function setHeader($header, $value) 
    { 
     $this->headers[$header] = $value; 
    } 

    /** 
    * Set the request method 
    * @param $method 
    * @return void 
    */ 
    public function setMethod($method) 
    { 
     $this->method = strtoupper($method); 
     if ($this->method!=self::method_GET) $this->setHeader('Content-type', 'application/x-www-form-urlencoded'); 
    } 

    public function setDataKey($key, $value) 
    { 
     $this->data[$key] = $value; 
    } 

    public function SetAccept($accept) 
    { 
     $this->accept = $accept; 
    } 

    /** 
    * Send request by URL. Pass $Response argument, if you need response 
    * @param $URL 
    * @param IResponse|null $Response 
    * @return bool|IResponse 
    */ 
    public function Send($URL, IResponse $Response = NULL) 
    { 
     $url_data = parse_url($URL); 
     $fp = fsockopen($url_data['host'], 80); 
     if (!$fp) return false; 
     $path = (isset($url_data['path']) ? $url_data['path'] : '/'). 
       (isset($url_data['query']) ? '?'.$url_data['query'] : ''); 
     $data = $this->getData(); 
     if (!empty($data) && is_array($data)) $data = http_build_query($data); 

     if ($this->method==self::method_GET) 
     { 
      fwrite($fp, $this->method." $path?$data HTTP/1.0\r\n"); 
     } 
     else 
     { 
      fwrite($fp, $this->method." $path HTTP/1.0\r\n"); 
      fwrite($fp, "Content-Length: ".strlen($data)."\r\n"); 
     } 
     fwrite($fp, "Host: {$url_data['host']}\r\n"); 
     foreach ($this->getHeaders() as $header_name => $header_value) 
     { 
      fwrite($fp, "$header_name: $header_value\r\n"); 
     } 

     fwrite($fp, "Connection: Close\r\n\r\n"); 

     if ($this->method!=self::method_GET) 
     { 
      fwrite($fp, $data); 
     } 
     if (!empty($Response)) return $this->ReadResponse($fp, $Response); 
     else return true; 
    } 

    /** 
    * @param \resource $fresource 
    * @param IResponse $response 
    * @return IResponse 
    */ 
    protected function ReadResponse($fresource, IResponse $response) 
    { 
     //read headers 
     $status_header = ''; 
     $headers = array(); 
     while (!feof($fresource)) 
     { 
      $header = trim(fgets($fresource)); 
      if (!empty($header)) 
      { 
       if (empty($status_header)) $status_header = $header; 
       if (strpos($header, ':')!==false) 
       { 
        $header = explode(':', $header); 
        $headers[trim($header[0])] = trim($header[1]); 
       } 
       else $headers[] = $header; 
      } 
      else break; 
     } 
     $response->setHeaders($headers); 
     if (!empty($status_header)) 
     { 
      $status_header = explode(' ', $status_header); 
      $response->setStatusCode(intval(trim($status_header[1]))); 
     } 

     //read body 
     $body = ''; 
     while (!feof($fresource)) $body .= fread($fresource, 4096); 
     fclose($fresource); 

     if (!empty($body)) $response->setBody($body); 

     return $response; 
    } 

    /** 
    * Set array of data 
    * @param array $values 
    */ 
    public function setData(array $values) 
    { 
     $this->data = $values; 
    } 
} 

和响应:

<?php 
namespace Jamm\HTTP; 

class Response implements IResponse 
{ 
    protected $status_code; 
    protected $body; 
    protected $headers; 
    protected $serialize_method; 

    const serialize_JSON = 'JSON'; 
    const serialize_XML = 'XML'; 
    const serialize_PHP = 'PHP'; 

    const header_Serialized = 'API-Serialized'; 

    public function __construct($body = '', $status_code = 200) 
    { 
     $this->body = $body; 
     $this->status_code = $status_code; 
     $this->serialize_method = self::serialize_JSON; 
    } 

    public function getStatusCode() 
    { 
     return $this->status_code; 
    } 

    /** @param int $status_code */ 
    public function setStatusCode($status_code) 
    { 
     $this->status_code = (int)$status_code; 
    } 

    /** 
    * Set header for the response 
    * @param string $header 
    * @param string|numeric $value 
    */ 
    public function setHeader($header, $value) 
    { 
     $this->headers[$header] = $value; 
     if ($header==='Location' && $this->status_code==200) $this->setStatusCode(301); 
    } 

    public function getHeader($header) 
    { 
     return isset($this->headers[$header]) ? $this->headers[$header] : NULL; 
    } 

    /** 
    * Get body of the response 
    * @return string 
    */ 
    public function getBody() 
    { 
     return $this->body; 
    } 

    /** 
    * Get Result of response - unpack value of body and headers 
    * @return bool|mixed 
    */ 
    public function getResult() 
    { 
     if ($this->getStatusCode() >= 400) return false; 

     if (($serialization_method = $this->getHeader(self::header_Serialized))) 
     { 
      $this->serialize_method = $serialization_method; 
      return $this->unserialize($this->body); 
     } 
     else return $this->body; 
    } 

    /** 
    * Set body of the response 
    * @param $body 
    */ 
    public function setBody($body) 
    { 
     if (!is_scalar($body)) 
     { 
      $this->body = $this->serialize($body); 
      $this->setHeader(self::header_Serialized, $this->serialize_method); 
     } 
     else $this->body = $body; 
    } 

    public function getHeaders() 
    { 
     return $this->headers; 
    } 

    public function setHeaders(array $headers) 
    { 
     $this->headers = $headers; 
    } 

    public function serialize($content) 
    { 
     switch ($this->serialize_method) 
     { 
      case self::serialize_JSON: 
       return json_encode($content); 
      default: 
       return serialize($content); 
     } 
    } 

    public function unserialize($content) 
    { 
     switch ($this->serialize_method) 
     { 
      case self::serialize_JSON: 
       return json_decode($content, true); 
      default: 
       return unserialize($content); 
     } 
    } 

    /** 
    * Send headers and body to output 
    */ 
    public function Send() 
    { 
     $headers = $this->getHeaders(); 
     if (!empty($headers)) 
     { 
      foreach ($headers as $header_key => $header_value) 
      { 
       header($header_key.': '.$header_value, true, $this->status_code); 
      } 
     } 
     print $this->body; 
    } 
} 
+0

这可能是一个以标准方式处理请求的框架,但问题似乎是“需要”顶部的CSRF Magic脚本如何在发送之前自动重写脚本的输出。 – Matchu

+0

@Matchu你说的是回应,而不是要求。 –

+1

你在谈论与o.o问题完全无关的事情。让我看看我是否可以简化它:“当我所做的所有事情都包含在顶部时,CSRF Magic这样的脚本如何拦截我的请求?这些类的有用性似乎与我们正在讨论的更具体的案例无关。这不是“我应该如何拦截请求?”这是“他们如何拦截请求?” – Matchu