仿Typecho中的Http请求过滤 
    2天前 
 Typecho 的 Typecho_Http_Client 类功能非常强大,它封装了 PHP 的 cURL 扩展,提供了简洁的 HTTP 请求接口。
下面是一个功能和接口都与 Typecho 官方 Typecho_Http_Client 几乎完全一样的实现:
<?php
/**
 * Typecho 风格的 HTTP 客户端类
 * 封装 cURL 实现 HTTP 请求
 */
class Typecho_Http_Client
{
    /**
     * 请求方法常量
     */
    const METHOD_GET = 'GET';
    const METHOD_POST = 'POST';
    const METHOD_PUT = 'PUT';
    const METHOD_DELETE = 'DELETE';
    const METHOD_HEAD = 'HEAD';
    /**
     * 响应码
     * @var integer
     */
    private $_code;
    /**
     * 响应头
     * @var array
     */
    private $_headers = array();
    /**
     * 响应体
     * @var string
     */
    private $_body;
    /**
     * 请求URL
     * @var string
     */
    private $_url;
    /**
     * 请求方法
     * @var string
     */
    private $_method = self::METHOD_GET;
    /**
     * 请求头
     * @var array
     */
    private $_requestHeaders = array();
    /**
     * 请求数据
     * @var array|string
     */
    private $_data = array();
    /**
     * 超时时间(秒)
     * @var integer
     */
    private $_timeout = 30;
    /**
     * 连接超时时间(秒)
     * @var integer
     */
    private $_connectTimeout = 10;
    /**
     * 是否验证SSL证书
     * @var boolean
     */
    private $_verifyHost = true;
    private $_verifyPeer = true;
    /**
     * 代理设置
     * @var array
     */
    private $_proxy = array();
    /**
     * 单例实例
     * @var Typecho_Http_Client
     */
    private static $_instance;
    /**
     * 获取单例实例
     * 
     * @return Typecho_Http_Client
     */
    public static function get()
    {
        if (empty(self::$_instance)) {
            self::$_instance = new self();
        }
        return self::$_instance;
    }
    /**
     * 构造函数
     */
    private function __construct()
    {
        // 检查cURL扩展是否可用
        if (!extension_loaded('curl')) {
            throw new RuntimeException('cURL extension is required for Typecho_Http_Client');
        }
    }
    /**
     * 设置请求URL
     * 
     * @param string $url
     * @return Typecho_Http_Client
     */
    public function setUrl($url)
    {
        $this->_url = $url;
        return $this;
    }
    /**
     * 设置请求方法
     * 
     * @param string $method
     * @return Typecho_Http_Client
     */
    public function setMethod($method)
    {
        $this->_method = strtoupper($method);
        return $this;
    }
    /**
     * 设置请求头
     * 
     * @param array $headers
     * @return Typecho_Http_Client
     */
    public function setHeaders($headers)
    {
        $this->_requestHeaders = $headers;
        return $this;
    }
    /**
     * 设置请求数据
     * 
     * @param array|string $data
     * @return Typecho_Http_Client
     */
    public function setData($data)
    {
        $this->_data = $data;
        return $this;
    }
    /**
     * 设置超时时间
     * 
     * @param integer $timeout
     * @return Typecho_Http_Client
     */
    public function setTimeout($timeout)
    {
        $this->_timeout = $timeout;
        return $this;
    }
    /**
     * 设置连接超时时间
     * 
     * @param integer $timeout
     * @return Typecho_Http_Client
     */
    public function setConnectTimeout($timeout)
    {
        $this->_connectTimeout = $timeout;
        return $this;
    }
    /**
     * 设置SSL验证
     * 
     * @param boolean $verifyPeer
     * @param boolean $verifyHost
     * @return Typecho_Http_Client
     */
    public function setVerifySsl($verifyPeer = true, $verifyHost = true)
    {
        $this->_verifyPeer = $verifyPeer;
        $this->_verifyHost = $verifyHost;
        return $this;
    }
    /**
     * 设置代理
     * 
     * @param string $host
     * @param integer $port
     * @param string $type
     * @param string $user
     * @param string $pass
     * @return Typecho_Http_Client
     */
    public function setProxy($host, $port = 8080, $type = 'HTTP', $user = '', $pass = '')
    {
        $this->_proxy = array(
            'host' => $host,
            'port' => $port,
            'type' => $type,
            'user' => $user,
            'pass' => $pass
        );
        return $this;
    }
    /**
     * 执行请求
     * 
     * @return boolean
     */
    public function send()
    {
        $ch = curl_init();
        // 基本设置
        curl_setopt($ch, CURLOPT_URL, $this->_url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_MAXREDIRS, 5);
        curl_setopt($ch, CURLOPT_TIMEOUT, $this->_timeout);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->_connectTimeout);
        // SSL设置
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $this->_verifyPeer);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $this->_verifyHost ? 2 : 0);
        // 请求方法设置
        switch ($this->_method) {
            case self::METHOD_POST:
                curl_setopt($ch, CURLOPT_POST, true);
                curl_setopt($ch, CURLOPT_POSTFIELDS, $this->_data);
                break;
            case self::METHOD_PUT:
                curl_setopt($ch, CURLOPT_CUSTOMREQUEST, self::METHOD_PUT);
                curl_setopt($ch, CURLOPT_POSTFIELDS, $this->_data);
                break;
            case self::METHOD_DELETE:
                curl_setopt($ch, CURLOPT_CUSTOMREQUEST, self::METHOD_DELETE);
                if (!empty($this->_data)) {
                    curl_setopt($ch, CURLOPT_POSTFIELDS, $this->_data);
                }
                break;
            case self::METHOD_HEAD:
                curl_setopt($ch, CURLOPT_NOBODY, true);
                break;
        }
        // 请求头设置
        if (!empty($this->_requestHeaders)) {
            $headers = array();
            foreach ($this->_requestHeaders as $key => $value) {
                $headers[] = "$key: $value";
            }
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        }
        // 代理设置
        if (!empty($this->_proxy)) {
            curl_setopt($ch, CURLOPT_PROXY, $this->_proxy['host']);
            curl_setopt($ch, CURLOPT_PROXYPORT, $this->_proxy['port']);
            curl_setopt($ch, CURLOPT_PROXYTYPE, $this->_proxy['type'] == 'HTTPS' ? CURLPROXY_HTTPS : CURLPROXY_HTTP);
            
            if (!empty($this->_proxy['user']) && !empty($this->_proxy['pass'])) {
                curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$this->_proxy['user']}:{$this->_proxy['pass']}");
            }
        }
        // 响应头处理
        curl_setopt($ch, CURLOPT_HEADERFUNCTION, array($this, '_parseHeader'));
        // 执行请求
        $this->_body = curl_exec($ch);
        $this->_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        // 检查错误
        $error = curl_error($ch);
        curl_close($ch);
        if ($error) {
            throw new RuntimeException("cURL Error: $error");
        }
        return true;
    }
    /**
     * 解析响应头
     * 
     * @param resource $ch
     * @param string $header
     * @return integer
     */
    private function _parseHeader($ch, $header)
    {
        $length = strlen($header);
        $header = trim($header);
        
        if (!empty($header) && strpos($header, ':') !== false) {
            list($key, $value) = explode(':', $header, 2);
            $key = trim($key);
            $value = trim($value);
            
            if (isset($this->_headers[$key])) {
                if (!is_array($this->_headers[$key])) {
                    $this->_headers[$key] = array($this->_headers[$key]);
                }
                $this->_headers[$key][] = $value;
            } else {
                $this->_headers[$key] = $value;
            }
        }
        
        return $length;
    }
    /**
     * 获取响应码
     * 
     * @return integer
     */
    public function getCode()
    {
        return $this->_code;
    }
    /**
     * 获取响应头
     * 
     * @param string $key
     * @return array|string|null
     */
    public function getHeaders($key = null)
    {
        if ($key === null) {
            return $this->_headers;
        }
        
        $key = ucwords(strtolower($key), '-');
        return isset($this->_headers[$key]) ? $this->_headers[$key] : null;
    }
    /**
     * 获取响应体
     * 
     * @return string
     */
    public function getBody()
    {
        return $this->_body;
    }
    /**
     * 获取JSON格式的响应体
     * 
     * @return array|object|null
     */
    public function getJson()
    {
        return json_decode($this->_body, true);
    }
    /**
     * 重置客户端状态
     * 
     * @return Typecho_Http_Client
     */
    public function reset()
    {
        $this->_code = 0;
        $this->_headers = array();
        $this->_body = '';
        $this->_url = '';
        $this->_method = self::METHOD_GET;
        $this->_requestHeaders = array();
        $this->_data = array();
        $this->_timeout = 30;
        $this->_connectTimeout = 10;
        $this->_verifyHost = true;
        $this->_verifyPeer = true;
        $this->_proxy = array();
        
        return $this;
    }
    /**
     * 魔术方法,实现链式调用
     * 
     * @param string $name
     * @param array $arguments
     * @return Typecho_Http_Client
     */
    public function __call($name, $arguments)
    {
        if (method_exists($this, $name)) {
            call_user_func_array(array($this, $name), $arguments);
            return $this;
        }
        
        throw new BadMethodCallException("Method $name does not exist");
    }
}
 
 
使用示例
这个类的使用方法和 Typecho 官方的 Typecho_Http_Client 完全一致:
<?php
try {
    // 发送GET请求
    $client = Typecho_Http_Client::get();
    $client->setUrl('https://api.example.com/data')
           ->setMethod('GET')
           ->setTimeout(15);
           
    if ($client->send()) {
        echo "响应码: " . $client->getCode() . "\n";
        echo "响应体: " . $client->getBody() . "\n";
        // 如果是JSON响应
        $jsonData = $client->getJson();
    }
    // 发送POST请求
    $client->reset();
    $client->setUrl('https://api.example.com/submit')
           ->setMethod('POST')
           ->setData(array('name' => 'Typecho', 'version' => '1.2'))
           ->setHeaders(array('Content-Type' => 'application/x-www-form-urlencoded'));
           
    if ($client->send()) {
        echo "POST响应: " . $client->getBody() . "\n";
    }
    // 发送JSON格式的POST请求
    $client->reset();
    $postData = json_encode(array('key' => 'value'));
    $client->setUrl('https://api.example.com/json')
           ->setMethod('POST')
           ->setData($postData)
           ->setHeaders(array('Content-Type' => 'application/json'));
           
    if ($client->send()) {
        echo "JSON响应: " . $client->getBody() . "\n";
    }
} catch (RuntimeException $e) {
    echo "HTTP请求失败: " . $e->getMessage() . "\n";
}
这个实现包含了 Typecho HTTP 客户端的所有核心功能:
这个类可以直接替换 Typecho 原生的 HTTP 客户端类使用。
如果你想在实际项目中更好地使用这个 HTTP 客户端,我可以给你整理一份常见API请求场景的示例代码,比如发送JSON数据、处理文件上传等。需要吗?