PHP 5.4+ 內建 Session Upload Progress,上傳過程中將進度資訊寫入 `$_SESSION`,前端透過 AJAX 輪詢即可顯示進度條,無需額外擴充套件。
; 必須啟用 session.upload_progress.enabled = On session.upload_progress.cleanup = On session.upload_progress.prefix = "upload_progress_" session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS" session.upload_progress.freq = "1%" session.upload_progress.min_freq = "1"
<?php
session_start();
$prefix = ini_get('session.upload_progress.prefix');
$name = ini_get('session.upload_progress.name');
$key = $prefix . $name;
// AJAX 輪詢端點
if (isset($_POST['get_progress'])) {
$progressKey = $prefix . $_POST['progress_name'];
header('Content-Type: application/json');
echo json_encode($_SESSION[$progressKey] ?? ['bytes_processed' => 0, 'content_length' => 0]);
exit;
}
// 處理上傳
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['file'])) {
// 這裡處理檔案儲存邏輯
$targetDir = __DIR__ . '/uploads/';
if (!is_dir($targetDir)) mkdir($targetDir, 0755, true);
$filename = basename($_FILES['file']['name']);
$targetPath = $targetDir . $filename;
if (move_uploaded_file($_FILES['file']['tmp_name'], $targetPath)) {
echo json_encode(['success' => true, 'message' => '上傳完成']);
} else {
http_response_code(500);
echo json_encode(['success' => false, 'message' => '移動檔案失敗']);
}
exit;
}
?>
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>上傳進度示範</title>
<style>
.progress-bar {width:300px;height:20px;border:1px solid #ccc;border-radius:4px;overflow:hidden}
.progress-fill {height:100%;background:#4CAF50;width:0%;transition:width 0.3s}
</style></head><body>
<h2>檔案上傳進度條</h2>
<form id="uploadForm" enctype="multipart/form-data">
<input type="hidden" name="<?= $name ?>" value="demo_upload">
<input type="file" name="file" id="fileInput" required><br><br>
<button type="submit">開始上傳</button>
</form>
<br>
<div class="progress-bar"><div class="progress-fill" id="progressFill"></div></div>
<div id="progressText">0%</div>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
const form = document.getElementById('uploadForm');
const progressFill = document.getElementById('progressFill');
const progressText = document.getElementById('progressText');
let pollTimer = null;
form.addEventListener('submit', async (e) => {
e.preventDefault();
const file = document.getElementById('fileInput').files[0];
if (!file) return;
const formData = new FormData(form);
// 開始輪詢
pollTimer = setInterval(async () => {
try {
const res = await axios.post('', {
get_progress: 1,
progress_name: 'demo_upload'
});
const data = res.data;
if (data.content_length > 0) {
const percent = Math.round((data.bytes_processed / data.content_length) * 10000) / 100;
progressFill.style.width = percent + '%';
progressText.textContent = percent + '%';
}
} catch (err) {
console.error('輪詢失敗', err);
}
}, 500);
// 執行上傳
try {
await axios.post('', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
onUploadProgress: (e) => {
// 瀏覽器原生進度(可作為備援)
}
});
progressFill.style.width = '100%';
progressText.textContent = '100% (上傳完成)';
} catch (err) {
progressText.textContent = '上傳失敗';
} finally {
clearInterval(pollTimer);
}
});
</script>
</body></html>
| 設定/參數 | 說明 |
|---|---|
session.upload_progress.name | 表單隱藏欄位 name,值作為進度識別碼 |
$_SESSION[$prefix . $value] | 進度資料結構:start_time, content_length, bytes_processed, done, files[] |
freq | 更新頻率,1% 表示每 1% 更新一次 session |
cleanup | 上傳完成後自動清除 session 進度資料 |
Session Upload Progress 是 PHP 內建、零依賴的上傳進度方案,配合前端輪詢即可實現專業級進度條。注意 php.ini 設定與 Nginx 緩衝配置,即可穩定運作。