在 PHP 開發中,經常需要向遠端伺服器發送 HTTP 請求。雖然 PHP 內建的 file_get_contents 或 cURL 套件功能強大,但有時我們需要一個輕量、不依賴擴充套件、且能直接操作 Socket 的解決方案。本文將介紹一個自訂的 HttpRequest 類別,它支援 GET、POST 以及 Multipart/form-data(檔案上傳)三種請求方式,並提供完整的程式碼與範例供參考。
HttpRequest 類別封裝了底層的 Socket 連線操作,核心屬性與方法如下:
setConfig():設定連線參數(IP、Host、URL、Port、Timeout)。setFormData():設定要發送的表單欄位陣列。setFileData():設定要上傳的檔案資訊陣列(需包含 name、filename、path)。send($type):統一發送入口,依 $type(get/post/multipart)分派處理邏輯。connect() / disconnect():建立與關閉 Socket 連線。sendGet():組裝 GET 請求標頭與查詢字串(不支援檔案)。sendPost():組裝 application/x-www-form-urlencoded 格式的 POST 請求,可選擇性讀取檔案內容並編碼。sendMultipart():組裝 multipart/form-data 請求,產生隨機 boundary,正確處理表單欄位與二進位檔案內容,適合大型檔案上傳。<?php
class HttpRequest {
private $_ip = ''; private $_host = ''; private $_url = ''; private $_port = '';
private $_errno = ''; private $_errstr = ''; private $_timeout = 15;
private $_fp = null; private $_formdata = array(); private $_filedata = array();
public function setConfig($config) {
$this->_ip = isset($config['ip']) ? $config['ip'] : '';
$this->_host = isset($config['host']) ? $config['host'] : '';
$this->_url = isset($config['url']) ? $config['url'] : '';
$this->_port = isset($config['port']) ? $config['port'] : '';
$this->_timeout = isset($config['timeout']) ? $config['timeout'] : 15;
if ($this->_ip === '') $this->_ip = $this->_host;
}
public function setFormData($formdata = array()) { $this->_formdata = $formdata; }
public function setFileData($filedata = array()) { $this->_filedata = $filedata; }
public function send($type = 'get') {
$type = strtolower($type);
if (!in_array($type, array('get','post','multipart'))) return false;
if (!$this->connect()) return false;
switch ($type) {
case 'get': $out = $this->sendGet(); break;
case 'post': $out = $this->sendPost(); break;
case 'multipart': $out = $this->sendMultipart(); break;
}
if (!$out) return false;
fputs($this->_fp, $out);
$response = '';
while ($row = fread($this->_fp, 4096)) $response .= $row;
$this->disconnect();
$pos = strpos($response, "\r\n\r\n");
return $pos !== false ? substr($response, $pos + 4) : $response;
}
private function connect() {
$this->_fp = fsockopen($this->_ip, $this->_port, $this->_errno, $this->_errstr, $this->_timeout);
return $this->_fp !== false;
}
private function disconnect() { if ($this->_fp) { fclose($this->_fp); $this->_fp = null; } }
private function sendGet() {
if (!$this->_formdata) return false;
$url = $this->_url . '?' . http_build_query($this->_formdata);
return "GET $url HTTP/1.1\r\nHost: {$this->_host}\r\nConnection: close\r\n\r\n";
}
private function sendPost() {
if (!$this->_formdata && !$this->_filedata) return false;
$data = $this->_formdata;
if ($this->_filedata) {
foreach ($this->_filedata as $f) {
if (file_exists($f['path'])) $data[$f['name']] = file_get_contents($f['path']);
}
}
if (!$data) return false;
$data = http_build_query($data);
return "POST {$this->_url} HTTP/1.1\r\nHost: {$this->_host}\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: " . strlen($data) . "\r\nConnection: close\r\n\r\n$data";
}
private function sendMultipart() {
if (!$this->_formdata && !$this->_filedata) return false;
$boundary = '---------------------------' . substr(md5(rand(0,32000)),0,10);
$body = '';
foreach ($this->_formdata as $k => $v) {
$body .= "--$boundary\r\nContent-Disposition: form-data; name=\"$k\"\r\nContent-Type: text/plain\r\n\r\n";
$body .= is_array($v) ? json_encode($v) : rawurlencode($v);
$body .= "\r\n";
}
foreach ($this->_filedata as $f) {
if (!file_exists($f['path'])) continue;
$body .= "--$boundary\r\nContent-Disposition: form-data; name=\"{$f['name']}\"; filename=\"{$f['filename']}\"\r\n";
$body .= "Content-Type: " . mime_content_type($f['path']) . "\r\n\r\n";
$body .= implode('', file($f['path'])) . "\r\n";
}
$body .= "--$boundary--\r\n\r\n";
return "POST {$this->_url} HTTP/1.1\r\nHost: {$this->_host}\r\nContent-Type: multipart/form-data; boundary=$boundary\r\nContent-Length: " . strlen($body) . "\r\nConnection: close\r\n\r\n$body";
}
}
?>
<?php
require('HttpRequest.class.php');
$config = array(
'ip' => 'demo.example.com',
'host' => 'demo.example.com',
'port' => 80,
'timeout' => 30,
'url' => '/api/upload.php'
);
$formdata = array('username' => 'tester', 'action' => 'upload');
$filedata = array(array('name' => 'file', 'filename' => 'photo.jpg', 'path' => 'photo.jpg'));
$http = new HttpRequest();
$http->setConfig($config);
$http->setFormData($formdata);
$http->setFileData($filedata);
// 發送 multipart 請求(含檔案)
$result = $http->send('multipart');
echo '<pre>'; print_r($result); echo '</pre>';
?>
stream_context_create 搭配 SSL 串流。完整原始碼可從本站下載。希望此類別能為您的 PHP 專案提供靈活的 HTTP 請求選項。