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

PHP HTTP 請求類:支援 GET、POST、Multipart/form-data 完整實作

     編輯:PHP 綜合知識

類別概覽

HttpRequest 封裝底層 Socket 通訊,提供統一介面發送三種常見 HTTP 請求,支援表單欄位與檔案上傳。

核心代碼 (HttpRequest.class.php)

<?php
class HttpRequest {
    private $_ip = '';
    private $_host = '';
    private $_url = '';
    private $_port = '';
    private $_errno = '';
    private $_errstr = '';
    private $_timeout = 15;
    private $_fp = null;
    private $_formdata = [];
    private $_filedata = [];

    // 設定連線參數
    public function setConfig($config) {
        $this->_ip = $config['ip'] ?? '';
        $this->_host = $config['host'] ?? '';
        $this->_url = $config['url'] ?? '';
        $this->_port = $config['port'] ?? '';
        $this->_errno = $config['errno'] ?? '';
        $this->_errstr = $config['errstr'] ?? '';
        $this->_timeout = $config['timeout'] ?? 15;
        if ($this->_ip === '') $this->_ip = $this->_host;
    }

    public function setFormData(array $formdata) { $this->_formdata = $formdata; }
    public function setFileData(array $filedata) { $this->_filedata = $filedata; }

    // 發送請求總入口
    public function send($type = 'get') {
        $type = strtolower($type);
        if (!in_array($type, ['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); }

    // GET:查詢字串附加於 URL
    private function sendGet() {
        $query = http_build_query($this->_formdata);
        $url = $this->_url . ($query ? '?' . $query : '');
        return "GET $url HTTP/1.1\r\nHost: {$this->_host}\r\nConnection: close\r\n\r\n";
    }

    // POST:application/x-www-form-urlencoded
    private function sendPost() {
        $body = http_build_query($this->_formdata);
        return "POST {$this->_url} HTTP/1.1\r\n"
             . "Host: {$this->_host}\r\n"
             . "Content-Type: application/x-www-form-urlencoded\r\n"
             . "Content-Length: " . strlen($body) . "\r\n"
             . "Connection: close\r\n\r\n$body";
    }

    // Multipart:支援檔案上傳
    private function sendMultipart() {
        $boundary = '----HttpRequestBoundary' . md5(microtime());
        $body = '';
        foreach ($this->_formdata as $k => $v) {
            $body .= "--$boundary\r\n";
            $body .= "Content-Disposition: form-data; name=\"$k\"\r\n\r\n$v\r\n";
        }
        foreach ($this->_filedata as $k => $file) {
            // $file = ['path' => '', 'name' => '', 'type' => '']
            $content = file_get_contents($file['path']);
            $body .= "--$boundary\r\n";
            $body .= "Content-Disposition: form-data; name=\"$k\"; filename=\"{$file['name']}\"\r\n";
            $body .= "Content-Type: {$file['type']}\r\n\r\n";
            $body .= $content . "\r\n";
        }
        $body .= "--$boundary--\r\n";
        return "POST {$this->_url} HTTP/1.1\r\n"
             . "Host: {$this->_host}\r\n"
             . "Content-Type: multipart/form-data; boundary=$boundary\r\n"
             . "Content-Length: " . strlen($body) . "\r\n"
             . "Connection: close\r\n\r\n$body";
    }
}

使用範例

$http = new HttpRequest();
$http->setConfig(['host' => 'api.example.com', 'url' => '/upload', 'port' => 80]);
$http->setFormData(['user_id' => 123]);
$http->setFileData(['avatar' => ['path' => '/tmp/photo.jpg', 'name' => 'photo.jpg', 'type' => 'image/jpeg']]);
$response = $http->send('multipart');

設計亮點

  • 統一介面:同一類別處理三種請求類型,呼叫端僅切換 send() 參數。
  • 手動組裝 HTTP 報文:深度理解協議細節,適合教學或極簡環境(無 cURL 擴充)。
  • Multipart 邊界生成:使用 md5(microtime()) 確保唯一性。
  • 資源管理:確保 fsockopen 後必定 fclose。

注意事項

  • 生產環境建議改用 cURL 或 Guzzle,支援 HTTPS、重試、超時控制、並發等企業級特性。
  • 本類別未處理 Cookie、Redirect、GZIP 解壓、Chunked Transfer Encoding 等進階情境。
  • 大檔案上傳時 file_get_contents 會佔用大量記憶體,建議分塊讀取寫入 Socket。

結語

HttpRequest 類別展示了 PHP 底層 Socket 通訊的核心邏輯,是理解 HTTP 協議、打造自定義 HTTP 客戶端的優秀教學範例。實務專案中請優先採用成熟函式庫,專注於業務邏輯而非協議細節。

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