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

PHP 檔案上傳進度條實現:APC 與 uploadprogress 雙方案詳解

     編輯:PHP 相關知識

為什麼原生 PHP 無法做進度條?

PHP 執行模型決定了腳本只有在檔案完全寫入暫存目錄後才會啟動。此時 $_FILES 已包含完整資訊,但「上傳過程」已結束。要在上傳「過程中」獲取進度,必須繞過這個限制,透過擴展模組在暫存階段記錄進度資料,供另一請求讀取。

方案一:APC (Alternative PHP Cache) 實現

安裝與配置

# 安裝 (舊版 PHP)
pecl install apc

; php.ini
apc.enabled=1
apc.rfc1867=1          ; 關鍵:啟用 RFC1867 上傳進度追蹤
apc.rfc1867_prefix="upload_"
apc.rfc1867_name="APC_UPLOAD_PROGRESS"
apc.rfc1867_freq="0"   ; 更新頻率 0=盡可能頻繁
apc.rfc1867_ttl=3600   ; 進度資料保留秒數

前端表單關鍵欄位

<form method="POST" enctype="multipart/form-data" action="upload.php">
  <input type="hidden" name="APC_UPLOAD_PROGRESS" value="<?php echo uniqid(); ?>">
  <input type="file" name="file">
  <input type="submit">
</form>
<div id="progress">0%</div>
<script>
// 定時輪詢進度
setInterval(() => {
    fetch('progress.php?key=' + document.querySelector('[name=APC_UPLOAD_PROGRESS]').value)
        .then(r => r.json())
        .then(data => { if(data) document.getElementById('progress').textContent = Math.round((data.current/data.total)*100) + '%'; });
}, 500);
</script>

進度查詢端點 (progress.php)

<?php
if (isset($_GET['key'])) {
    $status = apc_fetch('upload_' . $_GET['key']);
    header('Content-Type: application/json');
    echo json_encode($status ?: ['current'=>0, 'total'=>0]);
    exit;
}
// 正常上傳處理邏輯...
?>

方案二:uploadprogress PECL 擴展實現

安裝與配置

pecl install uploadprogress

; php.ini
extension=uploadprogress.so
uploadprogress.file.filename_template="/tmp/upd_%s.txt"
; 可選:uploadprogress.get_contents=1

前端表單關鍵欄位

<form method="POST" enctype="multipart/form-data" action="upload.php">
  <input type="hidden" name="UPLOAD_IDENTIFIER" value="<?php echo uniqid(); ?>">
  <input type="file" name="upfile">
  <input type="submit">
</form>

上傳處理與進度查詢 (同一支 upload.php)

<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // 正常上傳處理
    if (is_uploaded_file($_FILES['upfile']['tmp_name'])) {
        $uploadDir = 'uploads/';
        $ext = strrchr($_FILES['upfile']['name'], '.');
        $sessId = $_POST['UPLOAD_IDENTIFIER'];
        $target = $uploadDir . $sessId . $ext;
        move_uploaded_file($_FILES['upfile']['tmp_name'], $target);
        echo '上傳完成';
    }
    exit;
}

if (!empty($_GET['sessid'])) {
    // 進度查詢
    header('Content-Type: application/json');
    header('Cache-Control: no-cache, must-revalidate');
    header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
    
    $info = uploadprogress_get_info($_GET['sessid']);
    echo is_array($info) ? json_encode($info) : json_encode(['error'=>'not found']);
    exit;
}

// 顯示表單頁面...
?>

兩方案對比與選擇

特性APCuploadprogress
PHP 版本相容PHP 5.4 前PHP 5.3 - 8.x
安裝難度較複雜pecl 安裝簡單
效能共用記憶體快取檔案儲存,稍慢
維護狀態已棄用,被 OPcache 取代較活躍維護

現代最佳實踐:HTML5 + 分塊上傳

現代專案應棄用伺服器端擴展方案,改用:

  1. 前端:XMLHttpRequest.upload.onprogress 或 fetch + ReadableStream 即時顯示
  2. 大檔案:前端分片(如 5MB/片),併發上傳,後端合併
  3. 斷點續傳:記錄已上傳分片清單,重啟時跳過
  4. 雲端直傳:簽名 URL 直傳 S3/OSS,後端僅驗證回調

擴展方案適合維護無法升級前端的舊系統;新專案請採用原生瀏覽器 API 架構。

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