首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >HTML Purifier对请求的拦截

问HTML Purifier对请求的拦截
EN

Stack Overflow用户
提问于 2011-08-22 00:57:23
回答 2查看 1K关注 0票数 3

像HTML Purifier或CSRF Magic这样的东西是如何实际拦截HTTP请求的?它的文档说它基于Python的Django Middleware框架的想法,但我还没有找到一些关于它如何拦截HTTP请求的文档。它实际上不需要安装任何PHP扩展就可以工作。

有没有人能解释一下这个问题?

问候

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-08-22 01:13:05

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

这最终要归结为line 371

代码语言:javascript
复制
if ($GLOBALS['csrf']['rewrite'])     ob_start('csrf_ob_handler');

这一行说明,如果条件为真(通常是真的),则启动输出缓冲区(ob_start),并在输出结束时对该输出运行csrf_ob_handler。csrf_ob_handler修改脚本的原始输出以添加隐藏输入,然后打印结果。

票数 1
EN

Stack Overflow用户

发布于 2011-08-22 01:13:01

如果没有笑话-“拦截”http请求并发送响应是任何web应用程序都应该做的事情。

你不需要任何扩展,因为PHP被设计成一个用来创建web应用程序的工具。

要读取HTTP-request的数据,可以使用数组$_GET、$_POST、$_SERVER (有时还有php://input ),而要发送响应,只需使用echo "that's my response!";即可。

我甚至可以给你们两个我的类来处理请求和响应,希望它会有用(或者至少是有趣的):

代码语言:javascript
复制
<?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;
    }
}

和响应:

代码语言:javascript
复制
<?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;
    }
}
票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7139692

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档