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

PHP 串流檔案傳輸:發送與接收大檔案完整實作

     編輯:PHP 綜合知識

利用 PHP 串流特性實現檔案內容直接以 HTTP POST 主體傳輸,避免將大檔案完整載入記憶體,適用於微服務間檔案傳遞、異步處理管道等場景。

發送端:sendStreamFile.php

<?php
/**
 * 以串流方式發送檔案
 * @param string $url 接收端 URL
 * @param string $file 要發送的本地檔案路徑
 * @return bool 發送是否成功
*/
function sendStreamFile($url, $file) {
    if (!file_exists($file)) {
        return false;
    }

    // 使用串流上下文發送 POST 請求
    $opts = [
        'http' => [
            'method' => 'POST',
            'header' => 'Content-Type: application/octet-stream', // 二進位串流
            'content' => fopen($file, 'rb'), // 關鍵:直接使用檔案控制代碼,不載入記憶體
            'timeout' => 300 // 大檔案需較長逾時
        ]
    ];

    $context = stream_context_create($opts);
    
    // 發送請求並取得回應
    $response = @file_get_contents($url, false, $context);
    
    if ($response === false) {
        return false;
    }

    $ret = json_decode($response, true);
    return $ret['success'] ?? false;
}

// 使用範例
$result = sendStreamFile('https://localhost/receiveStreamFile.php', 'large_file.zip');
var_dump($result);
?>

接收端:receiveStreamFile.php

<?php
/**
 * 接收串流檔案並儲存
 * @param string $receiveFile 儲存路徑
 * @return bool
*/
function receiveStreamFile($receiveFile) {
    // 讀取原始 POST 資料 (PHP 5.6+ 建議用 php://input)
    $streamData = file_get_contents('php://input');
    
    // 相容舊版:$GLOBALS['HTTP_RAW_POST_DATA'] (需 php.ini always_populate_raw_post_data=On)
    if (empty($streamData) && isset($GLOBALS['HTTP_RAW_POST_DATA'])) {
        $streamData = $GLOBALS['HTTP_RAW_POST_DATA'];
    }

    if (empty($streamData)) {
        return false;
    }

    // 直接寫入檔案 (串流寫入,低記憶體佔用)
    $bytesWritten = @file_put_contents($receiveFile, $streamData);
    
    return $bytesWritten !== false;
}

// 執行接收並回應 JSON
$receiveFile = 'received_' . date('Ymd_His') . '.dat';
$success = receiveStreamFile($receiveFile);

header('Content-Type: application/json');
echo json_encode(['success' => (bool)$success, 'file' => $receiveFile]);
?>

關鍵技術點解析

技術點說明優勢
php://input唯讀串流,直接讀取原始 POST 主體不依賴 php.ini 設定、效能優於 $HTTP_RAW_POST_DATA
fopen() 作為 content發送端直接傳入檔案控制代碼零拷貝,不佔用 PHP 記憶體緩衝區
Content-Type: application/octet-stream標準二進位串流 MIME 類型避免表單解析開銷,支援任意二進位檔案
file_put_contents 串流寫入單次寫入或配合 FILE_APPEND 分塊簡單高效,大檔案建議用 fopen/fwrite 循環

大檔案 (>100MB) 優化建議

// 發送端:分塊讀取 (需搭配支援 Chunked Transfer Encoding 的接收端)
$opts['http']['content'] = fopen($file, 'rb');
// 確保啟用 chunked transfer
$opts['http']['header'] = "Content-Type: application/octet-stream\r\nTransfer-Encoding: chunked";

// 接收端:分塊寫入避免記憶體峰值
$input = fopen('php://input', 'rb');
$output = fopen($receiveFile, 'wb');
stream_copy_to_stream($input, $output); // 內核級複製,最高效
fclose($input);
fclose($output);

安全性考量

  • 生產環境必須加入驗證:API Token、HMAC 簽名、IP 白名單
  • 限制上傳檔案大小:Nginx client_max_body_size、PHP post_max_size
  • 檔案類型驗證:finfo_file() 檢測真實 MIME 類型
  • 儲存路徑安全:防止目錄遍歷攻擊,使用隨機檔名
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved