首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 實現支援 GET、POST 與 Multipart/form-data 的 HTTP 請求類別

     編輯:PHP 綜合知識

在 PHP 開發中,經常需要向遠端伺服器發送 HTTP 請求。雖然 PHP 內建的 file_get_contents 或 cURL 套件功能強大,但有時我們需要一個輕量、不依賴擴充套件、且能直接操作 Socket 的解決方案。本文將介紹一個自訂的 HttpRequest 類別,它支援 GET、POST 以及 Multipart/form-data(檔案上傳)三種請求方式,並提供完整的程式碼與範例供參考。

類別設計架構

HttpRequest 類別封裝了底層的 Socket 連線操作,核心屬性與方法如下:

  • 私有屬性:儲存目標 IP、主機名、URL 路徑、連接埠、逾時時間、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>';
?>

適用場景與注意事項

  • 無 cURL 環境:伺服器未安裝 cURL 擴充套件時的替代方案。
  • 教學與除錯:程式碼清晰展示 HTTP 協定細節,適合學習 Socket 程式設計。
  • 效能考量:大量高併發請求建議改用 cURL 或非阻塞 I/O(如 Swoole、Workerman)。
  • HTTPS 不支援:本類別僅支援 HTTP,若需 HTTPS 請改用 cURL 或 stream_context_create 搭配 SSL 串流。

完整原始碼可從本站下載。希望此類別能為您的 PHP 專案提供靈活的 HTTP 請求選項。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved