仿Typecho中的Http请求过滤
19小时前
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数据、处理文件上传等。需要吗?
没有了